Rev 3081 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2006 - 2012.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package uk.me.parabola.mkgmap.reader.osm;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import uk.me.parabola.imgfmt.app.Area;
import uk.me.parabola.imgfmt.app.Coord;
/**
* Base class for OSM file handlers.
*
* @author Steve Ratcliffe
*/
public class OsmHandler
{
// Elements that are read are saved/further processed by these two classes.
protected ElementSaver saver
;
protected OsmReadingHooks hooks
;
private final Map<String,
Long> fakeIdMap =
new HashMap<String,
Long>();
private Map<String,
Set<String>> deletedTags
;
private Map<String,
String> usedTags
;
// Node references within a way
protected long firstNodeRef
;
protected long lastNodeRef
;
protected boolean missingNodeRef
;
/**
* Tag that is set to <code>true</code> if one or more tags are not loaded.
* Only used for multipolygons yet.
*/
public static final String TAGS_INCOMPLETE_TAG =
"mkgmap:tagsincomplete";
/**
* Set a set of tags with values that are to be deleted on input.
* For each key there is a set of values. If the value set is empty then
* all tags with the given key are deleted. If the value set is not empty
* then only tags with the given key that has one of the given values are
* deleted.
*
* @param deletedTags A map of tag key, to a set of values to be deleted.
*/
public void setTagsToDelete
(Map<String,
Set<String>> deletedTags
) {
this.
deletedTags = deletedTags
;
}
/**
* This sets a list of all the tags that are used in the system.
*
* Assuming this list is complete, no other tag can have an effect on the output
* and can therefore be dropped on input. This reduces memory usage, sometimes
* dramatically if there are many useless tags in the input.
*
* We keep a map of tag-name to tag-name. This allows us to keep only a single
* copy of each string. This also results in a reasonable reduction in memory usage.
*
* @param used The complete set of tags that are used to form the output.
*/
public void setUsedTags
(Set<String> used
) {
if (used ==
null || used.
isEmpty()) {
usedTags =
null;
return;
}
usedTags =
new HashMap<String,
String>();
for (String s : used
) {
if (s ==
null) {
continue;
}
// intern the keys
s = s.
intern();
usedTags.
put(s, s
);
}
}
/**
* Some tags are dropped at the input stage. We drop tags that are not going
* to be used and there is also an option to provide a file containing tags to
* be dropped.
*
* @param key The tag key.
* @param val The tag value.
* @return Returns the tag key if this tag should be kept. Returns null if the tag
* should be discarded.
*/
protected String keepTag
(String key,
String val
) {
if(deletedTags
!=
null) {
Set<String> vals = deletedTags.
get(key
);
if(vals
!=
null && (vals.
isEmpty() || vals.
contains(val
))) {
return null;
}
}
// By returning the value stored in usedTags, instead of the key, we ensure
// that the same string is always used so saving some memory.
if (usedTags
!=
null)
return usedTags.
get(key
);
return key
;
}
/**
* Actually set the bounding box. The boundary values are given.
*/
protected void setBBox
(double minlat,
double minlong,
double maxlat,
double maxlong
) {
Area bbox =
new Area(minlat, minlong, maxlat, maxlong
);
saver.
setBoundingBox(bbox
);
}
/**
* Convert an id as a string to a number. If the id is not a number, then create
* a unique number instead.
* @param id The id as a string. Does not have to be a numeric quantity.
* @return A long id, either parsed from the input, or a unique id generated internally.
*/
protected long idVal
(String id
) {
try {
// attempt to parse id as a number
return Long.
parseLong(id
);
} catch (NumberFormatException e
) {
// if that fails, fake a (hopefully) unique value
Long fakeIdVal = fakeIdMap.
get(id
);
if(fakeIdVal ==
null) {
fakeIdVal = FakeIdGenerator.
makeFakeId();
fakeIdMap.
put(id, fakeIdVal
);
}
//System.out.printf("%s = 0x%016x\n", id, fakeIdVal);
return fakeIdVal
;
}
}
public void setElementSaver
(ElementSaver elementSaver
) {
this.
saver = elementSaver
;
}
public void setHooks
(OsmReadingHooks plugin
) {
this.
hooks = plugin
;
}
/**
* Common actions to take when creating a new way.
* Reset some state and create the Way object.
* @param id The osm id of the new way.
* @return The new Way itself.
*/
protected Way startWay
(long id
) {
firstNodeRef =
0;
lastNodeRef =
0;
missingNodeRef =
false;
return new Way
(id
);
}
/**
* Common actions to take when a way has been completely read by the parser.
* It is saved
* @param way The way that was read.
*/
protected void endWay
(Way way
) {
way.
setClosedInOSM(firstNodeRef == lastNodeRef
);
way.
setComplete(!missingNodeRef
);
saver.
addWay(way
);
hooks.
onAddWay(way
);
}
/**
* Add a coordinate point to the way.
* @param way The Way.
* @param id The coordinate id.
*/
protected void addCoordToWay
(Way way,
long id
) {
lastNodeRef = id
;
if (firstNodeRef ==
0) firstNodeRef = id
;
Coord co = saver.
getCoord(id
);
if (co
!=
null) {
hooks.
onCoordAddedToWay(way, id, co
);
co = saver.
getCoord(id
);
way.
addPoint(co
);
} else {
missingNodeRef =
true;
}
}
}