Extracted Multipolygon class from Boundary class and tested with junits.
This could resolve some address issues, we will need to check. (recreate maps, etc...)
This commit is contained in:
parent
547b156c5b
commit
16922dffc8
5 changed files with 467 additions and 166 deletions
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,146 +1,18 @@
|
||||||
package net.osmand.data;
|
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 long boundaryId;
|
||||||
private String name;
|
private String name;
|
||||||
private int adminLevel;
|
private int adminLevel;
|
||||||
|
|
||||||
|
|
||||||
// not necessary ready rings
|
|
||||||
private List<Way> outerWays = new ArrayList<Way>(1);
|
|
||||||
private List<Way> innerWays = new ArrayList<Way>(0);
|
|
||||||
private boolean closedWay;
|
|
||||||
private long adminCenterId;
|
private long adminCenterId;
|
||||||
|
|
||||||
public Boundary(boolean closedWay){
|
public Boundary() {
|
||||||
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<Node> 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<Node> 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<w.getNodes().size() - 1; i++){
|
|
||||||
if(MapAlgorithms.ray_intersect_lon(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude) != -360d){
|
|
||||||
intersections ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(Way w : innerWays){
|
|
||||||
for(int i=0; i<w.getNodes().size() - 1; i++){
|
|
||||||
if(MapAlgorithms.ray_intersect_lon(w.getNodes().get(i), w.getNodes().get(i+1), latitude, longitude) != -360d){
|
|
||||||
intersections ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersections % 2 == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LatLon getCenterPoint(){
|
|
||||||
List<Node> points = new ArrayList<Node>();
|
|
||||||
for(Way w : outerWays){
|
|
||||||
points.addAll(w.getNodes());
|
|
||||||
}
|
|
||||||
for(Way w : innerWays){
|
|
||||||
points.addAll(w.getNodes());
|
|
||||||
}
|
|
||||||
return MapUtils.getWeightCenterForNodes(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private List<Way> getOuterWays() {
|
|
||||||
return outerWays;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Way> getInnerWays() {
|
|
||||||
return innerWays;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getBoundaryId() {
|
public long getBoundaryId() {
|
||||||
|
@ -169,7 +41,7 @@ public class Boundary {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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) {
|
public void setAdminCenterId(long l) {
|
||||||
|
@ -180,21 +52,4 @@ public class Boundary {
|
||||||
return adminCenterId;
|
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<Way> ring) {
|
|
||||||
outerWays.addAll(ring);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
278
DataExtractionOSM/src/net/osmand/data/Multipolygon.java
Normal file
278
DataExtractionOSM/src/net/osmand/data/Multipolygon.java
Normal file
|
@ -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<Way> closedOuterWays;
|
||||||
|
protected List<Way> outerWays;
|
||||||
|
protected List<Way> closedInnerWays;
|
||||||
|
protected List<Way> innerWays;
|
||||||
|
|
||||||
|
protected IdentityHashMap<Way,List<Way>> outerInnerMapping;
|
||||||
|
|
||||||
|
private void addNewPolygonPart(List<Way> polygons, List<Way> 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<Way> wayStack = new Stack<Way>();
|
||||||
|
wayStack.push(newPoly);
|
||||||
|
addAndMergePolygon(polygons, closedPolygons, wayStack);
|
||||||
|
}
|
||||||
|
//reset the mapping
|
||||||
|
outerInnerMapping = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isClosed(Way newPoly) {
|
||||||
|
List<Node> ns = newPoly.getNodes();
|
||||||
|
return !ns.isEmpty() && ns.get(0).getId() == ns.get(ns.size()-1).getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAndMergePolygon(List<Way> polygons, List<Way> closedPolygons, Stack<Way> workStack) {
|
||||||
|
while (!workStack.isEmpty()) {
|
||||||
|
Way changedWay = workStack.pop();
|
||||||
|
List<Node> 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<Way> outerPolygons, double latitude, double longitude) {
|
||||||
|
if (outerPolygons != null) {
|
||||||
|
for (Way polygon : outerPolygons) {
|
||||||
|
List<Way> inners = getOuterInnerMapping().get(polygon);
|
||||||
|
if (polygonContainsPoint(latitude, longitude, polygon, inners)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean polygonContainsPoint(double latitude, double longitude,
|
||||||
|
Way polygon, List<Way> 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<Node> 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<Way, List<Way>> getOuterInnerMapping() {
|
||||||
|
if (outerInnerMapping == null) {
|
||||||
|
outerInnerMapping = new IdentityHashMap<Way, List<Way>>();
|
||||||
|
//compute the mapping
|
||||||
|
if ((innerWays != null || closedInnerWays != null)
|
||||||
|
&& countOuterPolygons() != 0) {
|
||||||
|
fillOuterInnerMapping(closedOuterWays);
|
||||||
|
fillOuterInnerMapping(outerWays);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outerInnerMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillOuterInnerMapping(List<Way> outerPolygons) {
|
||||||
|
for (Way outer : outerPolygons) {
|
||||||
|
List<Way> inners = new ArrayList<Way>();
|
||||||
|
inners.addAll(findInnersFor(outer, innerWays));
|
||||||
|
inners.addAll(findInnersFor(outer, closedInnerWays));
|
||||||
|
outerInnerMapping.put(outer, inners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Way> findInnersFor(Way outer, List<Way> inners) {
|
||||||
|
List<Way> result = new ArrayList<Way>(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<Way> getOuterWays() {
|
||||||
|
if (outerWays == null) {
|
||||||
|
outerWays = new ArrayList<Way>(1);
|
||||||
|
}
|
||||||
|
return outerWays;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Way> getClosedOuterWays() {
|
||||||
|
if (closedOuterWays == null) {
|
||||||
|
closedOuterWays = new ArrayList<Way>(1);
|
||||||
|
}
|
||||||
|
return closedOuterWays;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private List<Way> getInnerWays() {
|
||||||
|
if (innerWays == null) {
|
||||||
|
innerWays = new ArrayList<Way>(1);
|
||||||
|
}
|
||||||
|
return innerWays;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Way> getClosedInnerWays() {
|
||||||
|
if (closedInnerWays == null) {
|
||||||
|
closedInnerWays = new ArrayList<Way>(1);
|
||||||
|
}
|
||||||
|
return closedInnerWays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countOuterPolygons()
|
||||||
|
{
|
||||||
|
return zeroSizeIfNull(outerWays) + zeroSizeIfNull(closedOuterWays);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasOpenedPolygons()
|
||||||
|
{
|
||||||
|
return zeroSizeIfNull(outerWays) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int zeroSizeIfNull(List<Way> 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<Way> ring) {
|
||||||
|
for (Way outer : ring) {
|
||||||
|
addOuterWay(outer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LatLon getCenterPoint() {
|
||||||
|
List<Node> points = new ArrayList<Node>();
|
||||||
|
collectPoints(points, outerWays);
|
||||||
|
collectPoints(points, closedOuterWays);
|
||||||
|
collectPoints(points, innerWays);
|
||||||
|
collectPoints(points, closedInnerWays);
|
||||||
|
return MapUtils.getWeightCenterForNodes(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectPoints(List<Node> points, List<Way> polygons) {
|
||||||
|
if (polygons != null) {
|
||||||
|
for(Way w : polygons){
|
||||||
|
points.addAll(w.getNodes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ import net.osmand.data.City;
|
||||||
import net.osmand.data.City.CityType;
|
import net.osmand.data.City.CityType;
|
||||||
import net.osmand.data.DataTileManager;
|
import net.osmand.data.DataTileManager;
|
||||||
import net.osmand.data.MapObject;
|
import net.osmand.data.MapObject;
|
||||||
|
import net.osmand.data.Multipolygon;
|
||||||
import net.osmand.data.Street;
|
import net.osmand.data.Street;
|
||||||
import net.osmand.data.WayBoundary;
|
import net.osmand.data.WayBoundary;
|
||||||
import net.osmand.data.preparation.DBStreetDAO.SimpleStreet;
|
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 {
|
public void indexBoundariesRelation(Entity e, OsmDbAccessorContext ctx) throws SQLException {
|
||||||
Boundary boundary = extractBoundary(e, ctx);
|
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();
|
LatLon boundaryCenter = boundary.getCenterPoint();
|
||||||
List<City> citiesToSearch = new ArrayList<City>();
|
List<City> citiesToSearch = new ArrayList<City>();
|
||||||
citiesToSearch.addAll(cityManager.getClosestObjects(boundaryCenter.getLatitude(), boundaryCenter.getLongitude(), 3));
|
citiesToSearch.addAll(cityManager.getClosestObjects(boundaryCenter.getLatitude(), boundaryCenter.getLongitude(), 3));
|
||||||
|
@ -170,11 +171,11 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
|
||||||
putCityBoundary(boundary, cityFound);
|
putCityBoundary(boundary, cityFound);
|
||||||
}
|
}
|
||||||
allBoundaries.add(boundary);
|
allBoundaries.add(boundary);
|
||||||
} else if (boundary != null && !boundary.isClosedWay()){
|
} else if (boundary != null){
|
||||||
if(logMapDataWarn != null) {
|
if(logMapDataWarn != null) {
|
||||||
logMapDataWarn.warn("Not using opened boundary: " + boundary);
|
logMapDataWarn.warn("Not using boundary: " + boundary);
|
||||||
} else {
|
} 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
|
&& oldBoundary != boundary
|
||||||
&& boundary.getName().equalsIgnoreCase(
|
&& boundary.getName().equalsIgnoreCase(
|
||||||
oldBoundary.getName())) {
|
oldBoundary.getName())) {
|
||||||
if (!oldBoundary.isClosedWay() && !boundary.isClosedWay()) {
|
oldBoundary.copyPolygonsFrom(boundary);
|
||||||
oldBoundary.copyWaysFrom(boundary);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cityBoundaries.put(cityFound, boundary);
|
cityBoundaries.put(cityFound, boundary);
|
||||||
|
@ -299,7 +298,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
|
||||||
if (e instanceof Relation) {
|
if (e instanceof Relation) {
|
||||||
Relation aRelation = (Relation) e;
|
Relation aRelation = (Relation) e;
|
||||||
ctx.loadEntityRelation(aRelation);
|
ctx.loadEntityRelation(aRelation);
|
||||||
boundary = new Boundary(true); //is computed later
|
boundary = new Boundary(); //is computed later
|
||||||
boundary.setName(aRelation.getTag(OSMTagKey.NAME));
|
boundary.setName(aRelation.getTag(OSMTagKey.NAME));
|
||||||
boundary.setBoundaryId(aRelation.getId());
|
boundary.setBoundaryId(aRelation.getId());
|
||||||
boundary.setAdminLevel(extractBoundaryAdminLevel(aRelation));
|
boundary.setAdminLevel(extractBoundaryAdminLevel(aRelation));
|
||||||
|
@ -321,14 +320,9 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
|
||||||
boundary.setAdminCenterId(es.getId());
|
boundary.setAdminCenterId(es.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boundary.computeIsClosedWay();
|
|
||||||
} else if (e instanceof Way) {
|
} else if (e instanceof Way) {
|
||||||
if (!visitedBoundaryWays.contains(e.getId())) {
|
if (!visitedBoundaryWays.contains(e.getId())) {
|
||||||
boolean closed = false;
|
boundary = new WayBoundary();
|
||||||
if(((Way) e).getNodeIds().size() > 1){
|
|
||||||
closed = ((Way) e).getFirstNodeId() == ((Way) e).getLastNodeId();
|
|
||||||
}
|
|
||||||
boundary = new WayBoundary(closed);
|
|
||||||
boundary.setName(e.getTag(OSMTagKey.NAME));
|
boundary.setName(e.getTag(OSMTagKey.NAME));
|
||||||
boundary.setBoundaryId(e.getId());
|
boundary.setBoundaryId(e.getId());
|
||||||
boundary.setAdminLevel(extractBoundaryAdminLevel(e));
|
boundary.setAdminLevel(extractBoundaryAdminLevel(e));
|
||||||
|
@ -543,7 +537,7 @@ public class IndexAddressCreator extends AbstractIndexPartCreator{
|
||||||
nearestObjects.addAll(cityVillageManager.getClosestObjects(location.getLatitude(),location.getLongitude()));
|
nearestObjects.addAll(cityVillageManager.getClosestObjects(location.getLatitude(),location.getLongitude()));
|
||||||
//either we found a city boundary the street is in
|
//either we found a city boundary the street is in
|
||||||
for (City c : nearestObjects) {
|
for (City c : nearestObjects) {
|
||||||
Boundary boundary = cityBoundaries.get(c);
|
Multipolygon boundary = cityBoundaries.get(c);
|
||||||
if (isInNames.contains(c.getName()) || (boundary != null && boundary.containsPoint(location))) {
|
if (isInNames.contains(c.getName()) || (boundary != null && boundary.containsPoint(location))) {
|
||||||
result.add(c);
|
result.add(c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
|
||||||
|
|
||||||
private Node checkOuterWaysEncloseInnerWays(List<List<Way>> completedRings, Map<Entity, String> entities) {
|
private Node checkOuterWaysEncloseInnerWays(List<List<Way>> completedRings, Map<Entity, String> entities) {
|
||||||
List<List<Way>> innerWays = new ArrayList<List<Way>>();
|
List<List<Way>> innerWays = new ArrayList<List<Way>>();
|
||||||
Boundary outerBoundary = new Boundary(true);
|
Boundary outerBoundary = new Boundary();
|
||||||
Node toReturn = null;
|
Node toReturn = null;
|
||||||
for (List<Way> ring : completedRings) {
|
for (List<Way> ring : completedRings) {
|
||||||
boolean innerType = "inner".equals(entities.get(ring.get(0))); //$NON-NLS-1$
|
boolean innerType = "inner".equals(entities.get(ring.get(0))); //$NON-NLS-1$
|
||||||
|
@ -263,6 +263,7 @@ public class IndexVectorMapCreator extends AbstractIndexPartCreator {
|
||||||
return w1;
|
return w1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Can the Multipolygon class be the one that replaces this?
|
||||||
private void combineMultiPolygons(Way w, List<List<Way>> completedRings, List<List<Way>> incompletedRings) {
|
private void combineMultiPolygons(Way w, List<List<Way>> completedRings, List<List<Way>> incompletedRings) {
|
||||||
long lId = w.getEntityIds().get(w.getEntityIds().size() - 1).getId().longValue();
|
long lId = w.getEntityIds().get(w.getEntityIds().size() - 1).getId().longValue();
|
||||||
long fId = w.getEntityIds().get(0).getId().longValue();
|
long fId = w.getEntityIds().get(0).getId().longValue();
|
||||||
|
|
Loading…
Reference in a new issue