From 16922dffc8a1e229367fca443d76d15fe77b075b Mon Sep 17 00:00:00 2001 From: Pavol Zibrita Date: Sun, 15 Jul 2012 04:53:37 +0200 Subject: [PATCH] Extracted Multipolygon class from Boundary class and tested with junits. This could resolve some address issues, we will need to check. (recreate maps, etc...) --- .../net/osmand/data/MultipolygonTest.java | 173 +++++++++++ .../src/net/osmand/data/Boundary.java | 155 +--------- .../src/net/osmand/data/Multipolygon.java | 278 ++++++++++++++++++ .../data/preparation/IndexAddressCreator.java | 24 +- .../preparation/IndexVectorMapCreator.java | 3 +- 5 files changed, 467 insertions(+), 166 deletions(-) create mode 100644 DataExtractionOSM/src-tests/net/osmand/data/MultipolygonTest.java create mode 100644 DataExtractionOSM/src/net/osmand/data/Multipolygon.java diff --git a/DataExtractionOSM/src-tests/net/osmand/data/MultipolygonTest.java b/DataExtractionOSM/src-tests/net/osmand/data/MultipolygonTest.java new file mode 100644 index 0000000000..7e57693303 --- /dev/null +++ b/DataExtractionOSM/src-tests/net/osmand/data/MultipolygonTest.java @@ -0,0 +1,173 @@ +package net.osmand.data; + +import static org.junit.Assert.*; + +import net.osmand.osm.LatLon; +import net.osmand.osm.Node; +import net.osmand.osm.Way; + +import org.junit.Before; +import org.junit.Test; + +public class MultipolygonTest { + + private Multipolygon testee; + private Way poly1_1_of_2; + private Way poly1_2_of_2; + private int wayid; + private Way poly2; + private Way openedBaseCircle; + private Way closedBaseCircle; + + @Before + public void setUp() + { + testee = new Multipolygon(); + poly1_1_of_2 = polygon(n(0,0),n(1,0),n(1,1),n(1,2)); + poly1_2_of_2 = polygon(n(1,2),n(0,2),n(-1,2),n(0,0)); + poly2 = polygon(n(4,4), n(4,5), n(3,5), n(4,4)); + openedBaseCircle = polygon(n(1,-1), n(1,1), n(-1,1), n(-1,-1)); + closedBaseCircle = polygon(n(1,-1), n(1,1), n(-1,1), n(-1,-1), n(1,-1)); + } + + public Way polygon(Node... n) { + Way way = new Way(wayid++); + for (Node nn : n) { + way.addNode(nn); + } + return way; + } + + public Way scale(int i, Way w) { + Way way = new Way(wayid++); + for (Node nn : w.getNodes()) { + way.addNode(n(i*(int)nn.getLatitude(),i*(int)nn.getLongitude())); + } + return way; + } + + public Way move(int i, int j, Way w) { + Way way = new Way(wayid++); + for (Node nn : w.getNodes()) { + way.addNode(n(i+(int)nn.getLatitude(),j+(int)nn.getLongitude())); + } + return way; + } + + public Node n(int i, int j) { + return new Node(i, j, i*i + j*j + i*j + i + j); //Node has ID derived from i,j + } + + @Test + public void test_twoWayPolygon() { + testee.addOuterWay(poly1_1_of_2); + testee.addOuterWay(poly1_2_of_2); + assertEquals(1, testee.countOuterPolygons()); + assertFalse(testee.hasOpenedPolygons()); + } + + @Test + public void test_oneWayPolygon() { + testee.addOuterWay(poly2); + assertEquals(1, testee.countOuterPolygons()); + assertFalse(testee.hasOpenedPolygons()); + } + + @Test + public void test_containsPoint() + { + testee.addOuterWay(scale(4,poly2)); + LatLon center = testee.getCenterPoint(); + assertTrue(testee.containsPoint(center)); + } + + @Test + public void test_containsPointOpenedCircle() + { + testee.addOuterWay(scale(4,openedBaseCircle)); + LatLon center = testee.getCenterPoint(); + assertTrue(testee.containsPoint(center)); + } + + @Test + public void test_containsPointClosedCircle() + { + testee.addOuterWay(scale(4,openedBaseCircle)); + LatLon center = testee.getCenterPoint(); + assertTrue(testee.containsPoint(center)); + } + + @Test + public void test_oneInnerRingOneOuterRingOpenedCircle() + { + test_oneInnerRingOneOuterRing(openedBaseCircle); + } + + @Test + public void test_oneInnerRingOneOuterRingClosedCircle() + { + test_oneInnerRingOneOuterRing(closedBaseCircle); + } + + public void test_oneInnerRingOneOuterRing(Way polygon) + { + testee.addOuterWay(scale(4,polygon)); + LatLon center = testee.getCenterPoint(); + assertTrue(testee.containsPoint(center)); + + Multipolygon mpoly2 = new Multipolygon(); + mpoly2.addOuterWay(polygon); + + assertTrue(testee.containsPoint(mpoly2.getCenterPoint())); + + testee.addInnerWay(polygon); + + assertFalse(testee.containsPoint(mpoly2.getCenterPoint())); + } + + @Test + public void test_twoInnerRingsOneOuterRingOpenedCircle() + { + test_twoInnerRingsOneOuterRing(openedBaseCircle); + } + + @Test + public void test_twoInnerRingsOneOuterRingClosedCircle() + { + test_twoInnerRingsOneOuterRing(closedBaseCircle); + } + + public void test_twoInnerRingsOneOuterRing(Way polygon) + { + testee.addOuterWay(scale(40,polygon)); + LatLon center = testee.getCenterPoint(); + assertTrue(testee.containsPoint(center)); + + Multipolygon mpoly2 = new Multipolygon(); + mpoly2.addOuterWay(polygon); + Multipolygon movepoly2 = new Multipolygon(); + movepoly2.addOuterWay(move(10,10,polygon)); + + assertTrue(testee.containsPoint(mpoly2.getCenterPoint())); + assertTrue(testee.containsPoint(movepoly2.getCenterPoint())); + + testee.addInnerWay(polygon); + testee.addInnerWay(move(10,10,polygon)); + + assertFalse(testee.containsPoint(mpoly2.getCenterPoint())); + assertFalse(testee.containsPoint(movepoly2.getCenterPoint())); + } + + @Test + public void test_multipolygon1twoWay2oneWay() + { + testee.addOuterWay(poly1_1_of_2); + testee.addOuterWay(poly1_2_of_2); + testee.addOuterWay(poly2); + assertEquals(2, testee.countOuterPolygons()); + assertFalse(testee.hasOpenedPolygons()); + } + + + +} diff --git a/DataExtractionOSM/src/net/osmand/data/Boundary.java b/DataExtractionOSM/src/net/osmand/data/Boundary.java index ee0c06e8ae..b840ccee75 100644 --- a/DataExtractionOSM/src/net/osmand/data/Boundary.java +++ b/DataExtractionOSM/src/net/osmand/data/Boundary.java @@ -1,146 +1,18 @@ package net.osmand.data; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import net.osmand.osm.LatLon; -import net.osmand.osm.MapUtils; -import net.osmand.osm.Node; -import net.osmand.osm.Way; -public class Boundary { +public class Boundary + extends Multipolygon +{ private long boundaryId; private String name; private int adminLevel; - - // not necessary ready rings - private List outerWays = new ArrayList(1); - private List innerWays = new ArrayList(0); - private boolean closedWay; private long adminCenterId; - public Boundary(boolean closedWay){ - this.closedWay = closedWay; - } - - public boolean isClosedWay() { - return closedWay; - } - - public void setClosedWay(boolean closedWay) { - this.closedWay = closedWay; - } - - public boolean computeIsClosedWay() { - if (getOuterWays().size() > 0) { - // now we try to merge the ways until we have only one - int oldSize = 0; - while (getOuterWays().size() != oldSize && !getOuterWays().isEmpty()) { - oldSize = getOuterWays().size(); - mergeOuterWays(); - } - if (!getOuterWays().isEmpty()) { - // there is one way and last element is equal to the first... - List nodes = getOuterWays().get(0).getNodes(); - closedWay = getOuterWays().size() == 1 && nodes.get(0).getId() == nodes.get(nodes.size() - 1).getId(); - //if not closed, but we have only one way, make it close - if (!closedWay && getOuterWays().size() == 1) { - nodes.add(nodes.get(0)); - closedWay = true; - } - } - } else { - closedWay = false; - } - return closedWay; - } - - - private void mergeOuterWays() { - Way way = getOuterWays().get(0); - List nodes = way.getNodes(); - if (!nodes.isEmpty()) { - int nodesSize = nodes.size(); - Node first = nodes.get(0); - Node last = nodes.get(nodesSize-1); - int size = getOuterWays().size(); - for (int i = size-1; i >= 1; i--) { - //try to find way, that matches the one ... - Way anotherWay = getOuterWays().get(i); - if (anotherWay.getNodes().isEmpty()) { - //remove empty one... - getOuterWays().remove(i); - } else { - if (anotherWay.getNodes().get(0).getId() == first.getId()) { - //reverese this way and add it to the actual - Collections.reverse(anotherWay.getNodes()); - way.getNodes().addAll(0,anotherWay.getNodes()); - getOuterWays().remove(i); - } else if (anotherWay.getNodes().get(0).getId() == last.getId()) { - way.getNodes().addAll(anotherWay.getNodes()); - getOuterWays().remove(i); - } else if (anotherWay.getNodes().get(anotherWay.getNodes().size()-1).getId() == first.getId()) { - //add at begging - way.getNodes().addAll(0,anotherWay.getNodes()); - getOuterWays().remove(i); - } else if (anotherWay.getNodes().get(anotherWay.getNodes().size()-1).getId() == last.getId()) { - Collections.reverse(anotherWay.getNodes()); - way.getNodes().addAll(anotherWay.getNodes()); - getOuterWays().remove(i); - } - } - } - } else { - //remove way with no nodes! - getOuterWays().remove(0); - } - } - - public boolean containsPoint(LatLon point) { - return containsPoint(point.getLatitude(), point.getLongitude()); - } - - public boolean containsPoint(double latitude, double longitude) { - int intersections = 0; - for(Way w : outerWays){ - for(int i=0; i points = new ArrayList(); - for(Way w : outerWays){ - points.addAll(w.getNodes()); - } - for(Way w : innerWays){ - points.addAll(w.getNodes()); - } - return MapUtils.getWeightCenterForNodes(points); - } - - - private List getOuterWays() { - return outerWays; - } - - private List getInnerWays() { - return innerWays; + public Boundary() { } public long getBoundaryId() { @@ -169,7 +41,7 @@ public class Boundary { @Override public String toString() { - return getName() + " alevel:" + getAdminLevel() + " type: relation closed:" + isClosedWay(); + return getName() + " alevel:" + getAdminLevel() + " type: has opened polygons:" + hasOpenedPolygons() + " no. of outer polygons:" + countOuterPolygons(); } public void setAdminCenterId(long l) { @@ -180,21 +52,4 @@ public class Boundary { return adminCenterId; } - public void addInnerWay(Way es) { - innerWays.add(new Way(es)); - } - - public void addOuterWay(Way es) { - outerWays.add(new Way(es)); - } - - public void copyWaysFrom(Boundary boundary) { - getInnerWays().addAll(boundary.getInnerWays()); - getOuterWays().addAll(boundary.getOuterWays()); - } - - public void addOuterWays(List ring) { - outerWays.addAll(ring); - } - } diff --git a/DataExtractionOSM/src/net/osmand/data/Multipolygon.java b/DataExtractionOSM/src/net/osmand/data/Multipolygon.java new file mode 100644 index 0000000000..47bd17601c --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/data/Multipolygon.java @@ -0,0 +1,278 @@ +package net.osmand.data; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Stack; + +import net.osmand.osm.LatLon; +import net.osmand.osm.MapUtils; +import net.osmand.osm.Node; +import net.osmand.osm.Way; + +/** + * The idea of multipolygon: + * - we treat each outer way as closed polygon + * - multipolygon is always closed! + * - each way we try to assign to existing way and form + * so a more complex polygon + * - number of outer ways, is number of polygons + * + * @author Pavol Zibrita + */ +public class Multipolygon { + + protected List closedOuterWays; + protected List outerWays; + protected List closedInnerWays; + protected List innerWays; + + protected IdentityHashMap> outerInnerMapping; + + private void addNewPolygonPart(List polygons, List closedPolygons, Way newPoly) { + if (isClosed(newPoly)) { + closedPolygons.add(newPoly); //if closed, put directly to closed polygons + } else if (polygons.isEmpty()) { + polygons.add(newPoly); //if open, and first, put to polygons.. + } else { + // now we try to merge the ways to form bigger polygons + Stack wayStack = new Stack(); + wayStack.push(newPoly); + addAndMergePolygon(polygons, closedPolygons, wayStack); + } + //reset the mapping + outerInnerMapping = null; + } + + private boolean isClosed(Way newPoly) { + List ns = newPoly.getNodes(); + return !ns.isEmpty() && ns.get(0).getId() == ns.get(ns.size()-1).getId(); + } + + private void addAndMergePolygon(List polygons, List closedPolygons, Stack workStack) { + while (!workStack.isEmpty()) { + Way changedWay = workStack.pop(); + List nodes = changedWay.getNodes(); + if (nodes.isEmpty()) { + //don't bother with it! + continue; + } + if (isClosed(changedWay)) { + polygons.remove(changedWay); + closedPolygons.add(changedWay); + continue; + } + + Node first = nodes.get(0); + Node last = nodes.get(nodes.size()-1); + for (Way anotherWay : polygons) { + if (anotherWay == changedWay) { + continue; + } + //try to find way, that matches the one ... + if (anotherWay.getNodes().get(0).getId() == first.getId()) { + Collections.reverse(changedWay.getNodes()); + anotherWay.getNodes().addAll(0,changedWay.getNodes()); + workStack.push(anotherWay); + break; + } else if (anotherWay.getNodes().get(0).getId() == last.getId()) { + anotherWay.getNodes().addAll(0,changedWay.getNodes()); + workStack.push(anotherWay); + break; + } else if (anotherWay.getNodes().get(anotherWay.getNodes().size()-1).getId() == first.getId()) { + anotherWay.getNodes().addAll(changedWay.getNodes()); + workStack.push(anotherWay); + break; + } else if (anotherWay.getNodes().get(anotherWay.getNodes().size()-1).getId() == last.getId()) { + Collections.reverse(changedWay.getNodes()); + anotherWay.getNodes().addAll(changedWay.getNodes()); + workStack.push(anotherWay); + break; + } + } + //if we could not merge the new polygon, and it is not already there, add it! + if (workStack.isEmpty() && !polygons.contains(changedWay)) { + polygons.add(changedWay); + } + } + } + + public boolean containsPoint(LatLon point) { + return containsPoint(point.getLatitude(), point.getLongitude()); + } + + public boolean containsPoint(double latitude, double longitude) { + return containsPointInPolygons(closedOuterWays, latitude, longitude) || containsPointInPolygons(outerWays, latitude, longitude); + } + + private boolean containsPointInPolygons(List outerPolygons, double latitude, double longitude) { + if (outerPolygons != null) { + for (Way polygon : outerPolygons) { + List inners = getOuterInnerMapping().get(polygon); + if (polygonContainsPoint(latitude, longitude, polygon, inners)) { + return true; + } + } + } + return false; + } + + private boolean polygonContainsPoint(double latitude, double longitude, + Way polygon, List inners) { + int intersections = 0; + intersections = countIntersections(latitude, longitude, polygon, + intersections); + if (inners != null) { + for (Way w : inners) { + intersections = countIntersections(latitude, longitude, w, + intersections); + } + } + return intersections % 2 == 1; + } + + private int countIntersections(double latitude, double longitude, + Way polygon, int intersections) { + List polyNodes = polygon.getNodes(); + for (int i = 0; i < polyNodes.size() - 1; i++) { + if (MapAlgorithms.ray_intersect_lon(polyNodes.get(i), + polyNodes.get(i + 1), latitude, longitude) != -360d) { + intersections++; + } + } + // special handling, also count first and last, might not be closed, but + // we want this! + if (MapAlgorithms.ray_intersect_lon(polyNodes.get(0), + polyNodes.get(polyNodes.size() - 1), latitude, longitude) != -360d) { + intersections++; + } + return intersections; + } + + private IdentityHashMap> getOuterInnerMapping() { + if (outerInnerMapping == null) { + outerInnerMapping = new IdentityHashMap>(); + //compute the mapping + if ((innerWays != null || closedInnerWays != null) + && countOuterPolygons() != 0) { + fillOuterInnerMapping(closedOuterWays); + fillOuterInnerMapping(outerWays); + } + } + return outerInnerMapping; + } + + private void fillOuterInnerMapping(List outerPolygons) { + for (Way outer : outerPolygons) { + List inners = new ArrayList(); + inners.addAll(findInnersFor(outer, innerWays)); + inners.addAll(findInnersFor(outer, closedInnerWays)); + outerInnerMapping.put(outer, inners); + } + } + + private Collection findInnersFor(Way outer, List inners) { + List result = new ArrayList(inners.size()); + for (Way in : inners) { + boolean inIsIn = true; + for (Node n : in.getNodes()) { + if (!polygonContainsPoint(n.getLatitude(), n.getLongitude(), outer, null)) { + inIsIn = false; + break; + } + } + if (inIsIn) { + result.add(in); + } + } + return result; + } + + private List getOuterWays() { + if (outerWays == null) { + outerWays = new ArrayList(1); + } + return outerWays; + } + + private List getClosedOuterWays() { + if (closedOuterWays == null) { + closedOuterWays = new ArrayList(1); + } + return closedOuterWays; + } + + + private List getInnerWays() { + if (innerWays == null) { + innerWays = new ArrayList(1); + } + return innerWays; + } + + private List getClosedInnerWays() { + if (closedInnerWays == null) { + closedInnerWays = new ArrayList(1); + } + return closedInnerWays; + } + + public int countOuterPolygons() + { + return zeroSizeIfNull(outerWays) + zeroSizeIfNull(closedOuterWays); + } + + public boolean hasOpenedPolygons() + { + return zeroSizeIfNull(outerWays) != 0; + } + + private int zeroSizeIfNull(List list) { + return list != null ? list.size() : 0; + } + + public void addInnerWay(Way es) { + addNewPolygonPart(getInnerWays(), getClosedInnerWays(), new Way(es)); + } + + public void addOuterWay(Way es) { + addNewPolygonPart(getOuterWays(), getClosedOuterWays(), new Way(es)); + } + + public void copyPolygonsFrom(Multipolygon multipolygon) { + for (Way inner : multipolygon.getInnerWays()) { + addInnerWay(inner); + } + for (Way outer : multipolygon.getOuterWays()) { + addOuterWay(outer); + } + getClosedInnerWays().addAll(multipolygon.getClosedInnerWays()); + getClosedOuterWays().addAll(multipolygon.getClosedOuterWays()); + } + + public void addOuterWays(List ring) { + for (Way outer : ring) { + addOuterWay(outer); + } + } + + public LatLon getCenterPoint() { + List points = new ArrayList(); + collectPoints(points, outerWays); + collectPoints(points, closedOuterWays); + collectPoints(points, innerWays); + collectPoints(points, closedInnerWays); + return MapUtils.getWeightCenterForNodes(points); + } + + private void collectPoints(List points, List polygons) { + if (polygons != null) { + for(Way w : polygons){ + points.addAll(w.getNodes()); + } + } + } + +} diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java index c24884c37b..8191722f8e 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexAddressCreator.java @@ -33,6 +33,7 @@ import net.osmand.data.City; import net.osmand.data.City.CityType; import net.osmand.data.DataTileManager; import net.osmand.data.MapObject; +import net.osmand.data.Multipolygon; import net.osmand.data.Street; import net.osmand.data.WayBoundary; import net.osmand.data.preparation.DBStreetDAO.SimpleStreet; @@ -134,7 +135,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ public void indexBoundariesRelation(Entity e, OsmDbAccessorContext ctx) throws SQLException { Boundary boundary = extractBoundary(e, ctx); - if (boundary != null && boundary.isClosedWay() && boundary.getAdminLevel() >= 4 && boundary.getCenterPoint() != null && !Algoritms.isEmpty(boundary.getName())) { + if (boundary != null && boundary.getAdminLevel() >= 4 && boundary.getCenterPoint() != null && !Algoritms.isEmpty(boundary.getName())) { LatLon boundaryCenter = boundary.getCenterPoint(); List citiesToSearch = new ArrayList(); citiesToSearch.addAll(cityManager.getClosestObjects(boundaryCenter.getLatitude(), boundaryCenter.getLongitude(), 3)); @@ -170,11 +171,11 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ putCityBoundary(boundary, cityFound); } allBoundaries.add(boundary); - } else if (boundary != null && !boundary.isClosedWay()){ + } else if (boundary != null){ if(logMapDataWarn != null) { - logMapDataWarn.warn("Not using opened boundary: " + boundary); + logMapDataWarn.warn("Not using boundary: " + boundary); } else { - log.info("Not using opened boundary: " + boundary); + log.info("Not using boundary: " + boundary); } } } @@ -261,9 +262,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ && oldBoundary != boundary && boundary.getName().equalsIgnoreCase( oldBoundary.getName())) { - if (!oldBoundary.isClosedWay() && !boundary.isClosedWay()) { - oldBoundary.copyWaysFrom(boundary); - } + oldBoundary.copyPolygonsFrom(boundary); } } else { cityBoundaries.put(cityFound, boundary); @@ -299,7 +298,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ if (e instanceof Relation) { Relation aRelation = (Relation) e; ctx.loadEntityRelation(aRelation); - boundary = new Boundary(true); //is computed later + boundary = new Boundary(); //is computed later boundary.setName(aRelation.getTag(OSMTagKey.NAME)); boundary.setBoundaryId(aRelation.getId()); boundary.setAdminLevel(extractBoundaryAdminLevel(aRelation)); @@ -321,14 +320,9 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ boundary.setAdminCenterId(es.getId()); } } - boundary.computeIsClosedWay(); } else if (e instanceof Way) { if (!visitedBoundaryWays.contains(e.getId())) { - boolean closed = false; - if(((Way) e).getNodeIds().size() > 1){ - closed = ((Way) e).getFirstNodeId() == ((Way) e).getLastNodeId(); - } - boundary = new WayBoundary(closed); + boundary = new WayBoundary(); boundary.setName(e.getTag(OSMTagKey.NAME)); boundary.setBoundaryId(e.getId()); boundary.setAdminLevel(extractBoundaryAdminLevel(e)); @@ -543,7 +537,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{ nearestObjects.addAll(cityVillageManager.getClosestObjects(location.getLatitude(),location.getLongitude())); //either we found a city boundary the street is in for (City c : nearestObjects) { - Boundary boundary = cityBoundaries.get(c); + Multipolygon boundary = cityBoundaries.get(c); if (isInNames.contains(c.getName()) || (boundary != null && boundary.containsPoint(location))) { result.add(c); } diff --git a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java index b1e0c9d900..7a96264123 100644 --- a/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java +++ b/DataExtractionOSM/src/net/osmand/data/preparation/IndexVectorMapCreator.java @@ -222,7 +222,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { private Node checkOuterWaysEncloseInnerWays(List> completedRings, Map entities) { List> innerWays = new ArrayList>(); - Boundary outerBoundary = new Boundary(true); + Boundary outerBoundary = new Boundary(); Node toReturn = null; for (List ring : completedRings) { boolean innerType = "inner".equals(entities.get(ring.get(0))); //$NON-NLS-1$ @@ -263,6 +263,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator { return w1; } + //TODO Can the Multipolygon class be the one that replaces this? private void combineMultiPolygons(Way w, List> completedRings, List> incompletedRings) { long lId = w.getEntityIds().get(w.getEntityIds().size() - 1).getId().longValue(); long fId = w.getEntityIds().get(0).getId().longValue();