On 17.04.2010 20:00, WanMil wrote:
I am thinking about how to handle boundary multipolygons and want get
some feedback and ideas from you.
There are two possible ways to use boundary information:
1. Draw the boundaries as lines
2. Draw the boundaries as polygons with different colours for different
administrative levels
I think the 2nd option cannot be realized (at the moment). I see no way
how to define a style that differently colours adjoining polygons with
rather identical tags (e.g. boundary=adminstrative, admin_level=2).
So let's concentrate on the 1st option.
One way may be part of different boundary relations. (admin_level=2&&
admin_level=3&& admin_level=4 ....). To be able to process all of them
with the style system the way must be duplicated for each relation.
The multipolygon handling of boundaries might work as follows:
For all ways (role=outer and inner) part of the boundary relation
- Clone the original way
- Tag the cloned way with the boundary information of the mp
- Remove all tags from the original way that are also contained in the
mp (with the same value)
- Split all closed ways (polygons) in two ways to ensure that only ways
are tagged with the boundary information
What do you think? If no one really complains I will start implementing
this (and expect that it will be accepted when I am ready :-).
In case other multipolygon type also require such a processing we might
add a config file in future which types are handled in this way. So this
is ready to be more generic.
WanMil
Why talking so long? Implementation was quite easy so please try this
patch and post what you think about this patch.
I will post v2 with some more comments in the source code if it should
be committed.
WanMil
Hallo WanMil
Well I do think the patch is working as supposed. However that is not
really what I find useful. Now on country boundaries there are sometimes
10 boundaries on top of each other - is this what you want to achieve?
I'ld much rather have only the boundary with the highest admin level -
and have taken quite a bit of code into the style-file to make sure ONLY
the boundary with the lowest admin_level is put inside the map. Your
patch makes my style-file useless.
I don't really understand what this patch is trying to achieve. There is
a patch by Thilo Hanneman (I'm attaching it for you) that makes it
possible to directly render relations from the relations file, I think
that is more useful - or don't I understand something here that you
intend to achieve???
BTW - I'ld much rather have a patch that disables sea, if there are more
than 500 highway=residential inside the sea polygone, or something
similar to detect that nothing is flooding. Just day before yesterdays
alp extract from Geofabrik had one tile inside flooded, and there is the
dreaded flooding inside Germany as allways (well this one due to
geofabrik cutting). Maybe you could write a patch for that problem. I
get tons of comments on my website about sea flooding, no matter in how
many places I write that this is not solvable and any comment regarding
sea flooding will get into the trashbin...
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev
Index: uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java (revision 1580)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java (working copy)
@@ -19,8 +19,10 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
@@ -49,6 +51,7 @@
import uk.me.parabola.mkgmap.general.RoadNetwork;
import uk.me.parabola.mkgmap.reader.osm.CoordPOI;
import uk.me.parabola.mkgmap.reader.osm.Element;
+import uk.me.parabola.mkgmap.reader.osm.FakeIdGenerator;
import uk.me.parabola.mkgmap.reader.osm.GType;
import uk.me.parabola.mkgmap.reader.osm.Node;
import uk.me.parabola.mkgmap.reader.osm.OsmConverter;
@@ -173,6 +176,14 @@
private static final Pattern commaPattern = Pattern.compile(",");
+ private String makeKeyFromGType(GType type) {
+ String key = String.valueOf(type.getFeatureKind()) + "," + String.valueOf(type.getType()) + "," + String.valueOf(type.getMinResolution())
+ + "," + String.valueOf(type.getMaxResolution());
+ if (type.isRoad())
+ key += "," + String.valueOf(type.getRoadClass()) + "," + String.valueOf(type.getRoadSpeed());
+ return key;
+ }
+
private GType makeGTypeFromTags(Element element) {
String[] vals = commaPattern.split(element.getTag("mkgmap:gtype"));
@@ -442,10 +453,38 @@
*
* @param relation The relation to convert.
*/
- public void convertRelation(Relation relation) {
- // Relations never resolve to a GType and so we ignore the return
- // value.
- relationRules.resolveType(relation, TypeResult.NULL_RESULT);
+ public void convertRelation(Relation relation, final Map<Long, Way> wayMap) {
+ // If the relation resolves to a GType of a way then add that way to the map
+ preConvertRules(relation);
+ relationRules.resolveType(relation, new TypeResult() {
+ public void add(Element el, GType type) {
+ Relation relation = (Relation) el;
+ postConvertRules(relation, type);
+
+ // Create a hash set from the relation elements. This makes sure that each element
+ // occurs at most once.
+ HashSet<Element> elements = new HashSet(relation.getElements().size());
+ for (Map.Entry<String,Element> mapEntry : relation.getElements()) {
+ elements.add(mapEntry.getValue());
+ }
+
+ // Extract all the ways that belong to the relation
+ List<Way> ways = new ArrayList<Way>(elements.size());
+ for (Element ele : elements) {
+ if (ele instanceof Way)
+ addWayToListAndChainIfPossible(ways, (Way) ele, type.isRoad()); // care about oneways if it is a road
+ }
+
+ for (Way w : ways) {
+ w.setName(relation.getName());
+ // Using mkgmap:gtype way to promote the attributes, so that the generated ways can go through the same
+ // process as the ways that come directly from the osm data
+ type.setFeatureKind(GType.POLYLINE);
+ w.addTag("mkgmap:gtype",makeKeyFromGType(type));
+ wayMap.put(FakeIdGenerator.makeFakeId(),w);
+ }
+ }
+ });
if(relation instanceof RestrictionRelation) {
RestrictionRelation rr = (RestrictionRelation)relation;
@@ -463,6 +502,133 @@
}
}
+ private void addWayToListAndChainIfPossible(List<Way> ways, Way newWay, boolean careAboutOneways) {
+ outer_loop: for (;;) {
+ List<Coord> newWayCoords = newWay.getPoints();
+ int newWayNumPoints = newWayCoords.size();
+ if (newWayNumPoints == 0) return;
+
+ Coord newWayFirstCoord = newWayCoords.get(0);
+ Coord newWayLastCoord = newWayCoords.get(newWayNumPoints-1);
+
+ ListIterator<Way> listIterator = ways.listIterator();
+ while (listIterator.hasNext()) {
+ Way existantWay = listIterator.next();
+ List<Coord> existantWayCoords = existantWay.getPoints();
+ int existantWayNumPoints = existantWayCoords.size();
+ if (existantWayNumPoints == 0) continue;
+
+ Coord existantWayFirstCoord = existantWayCoords.get(0);
+ Coord existantWayLastCoord = existantWayCoords.get(existantWayNumPoints-1);
+
+ // Test coordinates to see whether two way can be chained together
+ // If they are chained together the only tag we will copy is the oneway tag (if we care about them).
+ // Access tags will have to be set by the relation!
+ // TODO: Handle the oneway=-1 tag in a useful way, now it prevents chaining of the ways.
+
+ // Both ways share the same first point. So the new way is connected in reverse, but if we care about oneways
+ // then only if none of them is one.
+ if (existantWayFirstCoord.equals(newWayFirstCoord)
+ && (!careAboutOneways || (!existantWay.isBoolTag("oneway") && !newWay.isBoolTag("oneway")))) {
+
+ Way replacementWay = new Way(existantWay.getId());
+
+ // Add points of new way in reverse
+ ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator(newWayNumPoints);
+ while (newWayCoordIterator.hasPrevious()) {
+ replacementWay.addPoint(newWayCoordIterator.previous());
+ }
+ // And of the existant way in order (starting from the second point)
+ ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator(1);
+ while (existantWayCoordIterator.hasNext()) {
+ replacementWay.addPoint(existantWayCoordIterator.next());
+ }
+ // Remove the existant way that was chained to the new way and start the search again.
+ listIterator.remove();
+ newWay = replacementWay;
+ continue outer_loop;
+ // The last point of the existant way is the same as the first point of the new way, so they are
+ // connected in order, but if we care about oneways then only if they either both have the oneway tag or both have not.
+ } else if (existantWayLastCoord.equals(newWayFirstCoord)
+ && (!careAboutOneways || !(existantWay.isBoolTag("oneway") ^ newWay.isBoolTag("oneway")))) {
+
+ Way replacementWay = new Way(existantWay.getId());
+ if (careAboutOneways) {
+ String onewayValue = existantWay.getTag("oneway");
+ if (onewayValue != null)
+ replacementWay.addTag("oneway",onewayValue);
+ }
+
+ // Add points of existant way in order
+ ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator();
+ while (existantWayCoordIterator.hasNext()) {
+ replacementWay.addPoint(existantWayCoordIterator.next());
+ }
+ // And of the new way also in order (starting from the second point)
+ ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator(1);
+ while (newWayCoordIterator.hasNext()) {
+ replacementWay.addPoint(newWayCoordIterator.next());
+ }
+ // Remove the existant way that was chained to the new way and start the search again.
+ listIterator.remove();
+ newWay = replacementWay;
+ continue outer_loop;
+ // The first point of the existant way is the same as the last point of the new way, so connect them,
+ // but starting with the new way and if we care about oneways then only if they either both have the
+ // oneway tag or both have not.
+ } else if (existantWayFirstCoord.equals(newWayLastCoord)
+ && (!careAboutOneways || (!(existantWay.isBoolTag("oneway") ^ newWay.isBoolTag("oneway"))))) {
+
+ Way replacementWay = new Way(existantWay.getId());
+ if (careAboutOneways) {
+ String onewayValue = existantWay.getTag("oneway");
+ if (onewayValue != null)
+ replacementWay.addTag("oneway",onewayValue);
+ }
+
+ // Add points of the new way in order
+ ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator();
+ while (newWayCoordIterator.hasNext()) {
+ replacementWay.addPoint(newWayCoordIterator.next());
+ }
+ // And of the existant way also in order (starting from the second point)
+ ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator(1);
+ while (existantWayCoordIterator.hasNext()) {
+ replacementWay.addPoint(existantWayCoordIterator.next());
+ }
+ // Remove the existant way that was chained to the new way and start the search again.
+ listIterator.remove();
+ newWay = replacementWay;
+ continue outer_loop;
+ // The last points of the existant and the new way are the same. So the new way is connected in reverse,
+ // but if we care about oneways than only if neither of them has the oneway tag set.
+ } else if (existantWayLastCoord.equals(newWayLastCoord)
+ && (!careAboutOneways || (!existantWay.isBoolTag("oneway") && !newWay.isBoolTag("oneway")))) {
+
+ Way replacementWay = new Way(existantWay.getId());
+
+ // Add points of existant way in order
+ ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator();
+ while (existantWayCoordIterator.hasNext()) {
+ replacementWay.addPoint(existantWayCoordIterator.next());
+ }
+ // And of the new way in reverse (starting from the second last point)
+ ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator(newWayNumPoints-1);
+ while (newWayCoordIterator.hasPrevious()) {
+ replacementWay.addPoint(newWayCoordIterator.previous());
+ }
+ // Remove the existant way that was chained to the new way and start the search again.
+ listIterator.remove();
+ newWay = replacementWay;
+ continue outer_loop;
+ }
+ }
+ // If we get here no way was found anymore that we could chain to. Add the way and return.
+ ways.add(newWay);
+ return;
+ }
+ }
+
private void addLine(Way way, GType gt) {
List<Coord> wayPoints = way.getPoints();
List<Coord> points = new ArrayList<Coord>(wayPoints.size());
Index: src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java (revision 1580)
+++ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java (working copy)
@@ -16,6 +16,8 @@
*/
package uk.me.parabola.mkgmap.reader.osm;
+import java.util.Map;
+
import uk.me.parabola.imgfmt.app.Area;
/**
@@ -52,7 +54,7 @@
*
* @param relation The relation to convert.
*/
- public void convertRelation(Relation relation);
+ public void convertRelation(Relation relation, Map<Long, Way> wayMap);
/**
* Set the bounding box for this map. This should be set before any other
Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java (revision 1580)
+++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java (working copy)
@@ -623,7 +623,7 @@
long start = System.currentTimeMillis();
for (Relation r : relationMap.values())
- converter.convertRelation(r);
+ converter.convertRelation(r, wayMap);
for (Node n : nodeMap.values())
converter.convertNode(n);
Index: src/uk/me/parabola/mkgmap/reader/osm/GType.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/GType.java (revision 1580)
+++ src/uk/me/parabola/mkgmap/reader/osm/GType.java (working copy)
@@ -34,7 +34,7 @@
public static final int POLYLINE = 2;
public static final int POLYGON = 3;
- private final int featureKind;
+ private int featureKind;
private final int type;
private int minResolution = 24;
@@ -79,6 +79,10 @@
}
}
+ public void setFeatureKind(int featureKind) {
+ this.featureKind = featureKind;
+ }
+
public int getFeatureKind() {
return featureKind;
}
Index: src/uk/me/parabola/mkgmap/main/StyleTester.java
===================================================================
--- src/uk/me/parabola/mkgmap/main/StyleTester.java (revision 1580)
+++ src/uk/me/parabola/mkgmap/main/StyleTester.java (working copy)
@@ -29,6 +29,7 @@
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;
@@ -273,8 +274,8 @@
converter.convertNode(node);
}
- public void convertRelation(Relation relation) {
- converter.convertRelation(relation);
+ public void convertRelation(Relation relation, Map<Long, Way> wayMap) {
+ converter.convertRelation(relation, wayMap);
}
public void setBoundingBox(Area bbox) {
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev