Rings simplify cache, remove obsolete methods and get rid of some
unexpected behaviours
This commit is contained in:
parent
611e16ecf1
commit
e2877d3519
2 changed files with 204 additions and 178 deletions
|
@ -105,23 +105,34 @@ public class Multipolygon {
|
|||
* @return true if this multipolygon is correct and contains the point
|
||||
*/
|
||||
public boolean containsPoint(double latitude, double longitude) {
|
||||
boolean outerContain = false;
|
||||
for (Ring outer : getOuterRings()) {
|
||||
Ring containedInOuter = null;
|
||||
// use a sortedset to get the smallest outer containing the point
|
||||
SortedSet<Ring> outers = new TreeSet<Ring> (getOuterRings());
|
||||
for (Ring outer : outers) {
|
||||
if (outer.containsPoint(latitude, longitude)) {
|
||||
outerContain = true;
|
||||
containedInOuter = outer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!outerContain) {
|
||||
|
||||
if (containedInOuter == null) {
|
||||
return false;
|
||||
}
|
||||
for (Ring inner : getInnerRings()) {
|
||||
|
||||
//use a sortedSet to get the smallest inner Ring
|
||||
SortedSet<Ring> inners = new TreeSet<Ring> (getInnerRings());
|
||||
Ring containedInInner = null;
|
||||
for (Ring inner : inners) {
|
||||
if (inner.containsPoint(latitude, longitude)) {
|
||||
return false;
|
||||
containedInInner = inner;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if (containedInInner == null) return true;
|
||||
|
||||
// if it is both, in an inner and in an outer, check if the inner is indeed the smallest one
|
||||
return !containedInInner.isIn(containedInOuter);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,7 +342,7 @@ public class Multipolygon {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method only works when the multipolygon has exaclt one outer Ring
|
||||
* This method only works when the multipolygon has exactly one outer Ring
|
||||
* @return the list of nodes in the outer ring
|
||||
*/
|
||||
public List<Node> getOuterNodes() {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package net.osmand.data;
|
||||
|
||||
import gnu.trove.list.array.TLongArrayList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -26,7 +25,7 @@ public class Ring implements Comparable<Ring> {
|
|||
|
||||
/**
|
||||
* a concatenation of the ways to form the border
|
||||
* this is not necessarily a closed way
|
||||
* this is NOT necessarily a CLOSED way
|
||||
* The id is random, so this may never leave the Ring object
|
||||
*/
|
||||
private Way border;
|
||||
|
@ -49,7 +48,7 @@ public class Ring implements Comparable<Ring> {
|
|||
* @return the ways added to the Ring
|
||||
*/
|
||||
public List<Way> getWays() {
|
||||
return ways;
|
||||
return new ArrayList<Way>(ways);
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,182 +65,124 @@ public class Ring implements Comparable<Ring> {
|
|||
* get a single closed way that represents the border
|
||||
* this method is CPU intensive
|
||||
* @return a list of Nodes that represents the border
|
||||
* if the border can't be created, an empty list will be returned
|
||||
*/
|
||||
public List<Node> getBorder() {
|
||||
mergeWays();
|
||||
List<Node> l = border.getNodes();
|
||||
if (!isClosed()) {
|
||||
if (border.getNodes().size() != 0 && !isClosed()) {
|
||||
l.add(border.getNodes().get(0));
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge all ways from the closedways into a single way
|
||||
* If the original ways are initialized with nodes, the new one will be so too
|
||||
* Merge all ways from the into a single border way
|
||||
* If the original ways are initialized with nodes, the border will be so too
|
||||
* If the original ways aren't initialized with nodes, the border won't be either
|
||||
* If only some original ways are initialized with nodes, the border will only have the nodes of the initialized ways
|
||||
*/
|
||||
private void mergeWays() {
|
||||
if (border != null) return;
|
||||
|
||||
List<Way> closedWays = closeWays();
|
||||
|
||||
border = new Way(randId());
|
||||
|
||||
Long previousConnection = getMultiLineEndNodes(closedWays)[0];
|
||||
//make a copy of the ways
|
||||
List<Way> ways = new ArrayList<Way>(getWays());
|
||||
|
||||
for (Way w : closedWays) {
|
||||
boolean firstNode = true;
|
||||
TLongArrayList nodeIds = w.getNodeIds();
|
||||
List<Node> nodes = w.getNodes();
|
||||
// do we have to include ways with uninitialized nodes?
|
||||
// Only if all ways have uninitialized nodes
|
||||
boolean unInitializedNodes = true;
|
||||
|
||||
for (Way w : ways) {
|
||||
if (w.getNodes() != null && w.getNodes().size() != 0) {
|
||||
unInitializedNodes = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<Way> borderWays = new ArrayList<Way>();
|
||||
|
||||
|
||||
for (Way w : ways) {
|
||||
// if the way has no nodes initialized, and we should initialize them, continue
|
||||
if ((w.getNodes() == null || w.getNodes().size() == 0) &&
|
||||
!unInitializedNodes) continue;
|
||||
|
||||
if (w.getFirstNodeId() == previousConnection) {
|
||||
|
||||
for (int i = 0; i< nodeIds.size(); i++) {
|
||||
// don't need to add the first node, that one was added by the previous way
|
||||
if (!firstNode) {
|
||||
if(nodes == null || i>=nodes.size()) {
|
||||
border.addNode(nodeIds.get(i));
|
||||
} else {
|
||||
border.addNode(nodes.get(i));
|
||||
}
|
||||
|
||||
}
|
||||
firstNode = false;
|
||||
Way newWay = null;
|
||||
Way addedTo = null;
|
||||
|
||||
// merge the Way w with the first borderway suitable;
|
||||
for (Way borderWay : borderWays) {
|
||||
if (w.getFirstNodeId() == borderWay.getFirstNodeId()) {
|
||||
newWay = combineTwoWays(w, borderWay, true, true);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
} else if (w.getFirstNodeId() == borderWay.getLastNodeId()) {
|
||||
newWay = combineTwoWays(w, borderWay, true, false);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
} else if (w.getLastNodeId() == borderWay.getLastNodeId()) {
|
||||
newWay = combineTwoWays(w, borderWay, false, false);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
} else if (w.getLastNodeId() == borderWay.getFirstNodeId()) {
|
||||
newWay = combineTwoWays(w, borderWay, false, true);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
}
|
||||
|
||||
previousConnection = w.getLastNodeId();
|
||||
}
|
||||
|
||||
if (newWay == null) {
|
||||
// no suitable borderWay has been found, add this way as one of the boundaries
|
||||
borderWays.add(w);
|
||||
} else {
|
||||
// ways are combined, remove the original borderway
|
||||
borderWays.remove(addedTo);
|
||||
|
||||
// add the nodes in reverse order
|
||||
for (int i = nodeIds.size() - 1; i >= 0; i--) {
|
||||
// don't need to add the first node, that one was added by the previous way
|
||||
if (!firstNode) {
|
||||
if(nodes == null || i>=nodes.size()) {
|
||||
border.addNode(nodeIds.get(i));
|
||||
} else {
|
||||
border.addNode(nodes.get(i));
|
||||
}
|
||||
addedTo = null;
|
||||
// search if it can be combined with something else
|
||||
for (Way borderWay : borderWays) {
|
||||
if (newWay.getFirstNodeId() == borderWay.getFirstNodeId()) {
|
||||
newWay = combineTwoWays(newWay, borderWay, true, true);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
} else if (newWay.getFirstNodeId() == borderWay.getLastNodeId()) {
|
||||
newWay = combineTwoWays(newWay, borderWay, true, false);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
} else if (newWay.getLastNodeId() == borderWay.getLastNodeId()) {
|
||||
newWay = combineTwoWays(newWay, borderWay, false, false);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
} else if (newWay.getLastNodeId() == borderWay.getFirstNodeId()) {
|
||||
newWay = combineTwoWays(newWay, borderWay, false, true);
|
||||
addedTo = borderWay;
|
||||
break;
|
||||
}
|
||||
firstNode = false;
|
||||
}
|
||||
|
||||
previousConnection = w.getFirstNodeId();
|
||||
if (addedTo != null) {
|
||||
// newWay has enlarged a second time
|
||||
borderWays.remove(addedTo);
|
||||
}
|
||||
// newWay is now a concatenation of 2 or 3 ways, needs to be added to the borderWays
|
||||
borderWays.add(newWay);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (borderWays.size() != 1) {
|
||||
border = new Way(randId());
|
||||
return;
|
||||
}
|
||||
|
||||
border = borderWays.get(0);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if there exists a cache, if so, return it
|
||||
* If there isn't a cache, sort the ways to form connected strings <p />
|
||||
*
|
||||
* If a Ring contains a gap, one way (without initialized nodes and id=0) is added to the list
|
||||
*/
|
||||
private List<Way> closeWays(){
|
||||
List<Way> closedWays = new ArrayList<Way>();
|
||||
if (ways.size() == 0) {
|
||||
closedWays = new ArrayList<Way>();
|
||||
return closedWays;
|
||||
}
|
||||
closedWays = new ArrayList<Way>(ways);
|
||||
|
||||
long[] endNodes = getMultiLineEndNodes(ways);
|
||||
if (endNodes[0] != endNodes[1]) {
|
||||
if(ways.get(0).getNodes() == null) {
|
||||
Way w = new Way(randId());
|
||||
w.addNode(endNodes[0]);
|
||||
w.addNode(endNodes[1]);
|
||||
closedWays.add(w);
|
||||
} else {
|
||||
Node n1 = null, n2 = null;
|
||||
if (ways.get(0).getFirstNodeId() == endNodes[0]) {
|
||||
n1 = ways.get(0).getNodes().get(0);
|
||||
} else {
|
||||
int index = ways.get(0).getNodes().size() - 1;
|
||||
n1 = ways.get(0).getNodes().get(index);
|
||||
}
|
||||
|
||||
int lastML = ways.size() - 1;
|
||||
if (ways.get(lastML).getFirstNodeId() == endNodes[0]) {
|
||||
n2 = ways.get(lastML).getNodes().get(0);
|
||||
} else {
|
||||
int index = ways.get(lastML).getNodes().size() - 1;
|
||||
n2 = ways.get(lastML).getNodes().get(index);
|
||||
}
|
||||
|
||||
Way w = new Way(randId());
|
||||
w.addNode(n1);
|
||||
w.addNode(n2);
|
||||
closedWays.add(w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return closedWays;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the end nodes of a multiLine
|
||||
* The ways in the multiLine don't have to be initialized for this.
|
||||
*
|
||||
* @param multiLine the multiLine to get the end nodes of
|
||||
* @return an array of size two with the end nodes on both sides. <br />
|
||||
* * The first node is the end node of the first way in the multiLine. <br />
|
||||
* * The second node is the end node of the last way in the multiLine.
|
||||
*/
|
||||
private long[] getMultiLineEndNodes(List<Way> multiLine) {
|
||||
|
||||
// special case, the multiLine contains only a single way, return the end nodes of the way
|
||||
if (multiLine.size() == 1){
|
||||
return new long[] {multiLine.get(0).getFirstNodeId(), multiLine.get(0).getLastNodeId()};
|
||||
}
|
||||
|
||||
if (multiLine.size() == 2) {
|
||||
// ring of two elements, arbitrary choice of the end nodes
|
||||
if(multiLine.get(0).getFirstNodeId() == multiLine.get(1).getFirstNodeId() &&
|
||||
multiLine.get(0).getLastNodeId() == multiLine.get(1).getLastNodeId()) {
|
||||
return new long[] {multiLine.get(0).getFirstNodeId(), multiLine.get(0).getFirstNodeId()};
|
||||
} else if(multiLine.get(0).getFirstNodeId() == multiLine.get(1).getLastNodeId() &&
|
||||
multiLine.get(0).getLastNodeId() == multiLine.get(1).getFirstNodeId()) {
|
||||
return new long[] {multiLine.get(0).getFirstNodeId(), multiLine.get(0).getFirstNodeId()};
|
||||
}
|
||||
}
|
||||
|
||||
// For all other multiLine lenghts, or for non-closed multiLines with two elements, proceed
|
||||
|
||||
long n1 = 0, n2 = 0;
|
||||
|
||||
if (multiLine.get(0).getFirstNodeId() == multiLine.get(1).getFirstNodeId() ||
|
||||
multiLine.get(0).getFirstNodeId() == multiLine.get(1).getLastNodeId()) {
|
||||
n1 = multiLine.get(0).getLastNodeId();
|
||||
} else if (multiLine.get(0).getLastNodeId() == multiLine.get(1).getFirstNodeId() ||
|
||||
multiLine.get(0).getLastNodeId() == multiLine.get(1).getLastNodeId()) {
|
||||
n1 = multiLine.get(0).getFirstNodeId();
|
||||
}
|
||||
|
||||
int lastIdx = multiLine.size()-1;
|
||||
|
||||
if (multiLine.get(lastIdx).getFirstNodeId() == multiLine.get(1).getFirstNodeId() ||
|
||||
multiLine.get(lastIdx).getFirstNodeId() == multiLine.get(1).getLastNodeId()) {
|
||||
n2 = multiLine.get(lastIdx).getLastNodeId();
|
||||
} else if (multiLine.get(lastIdx).getLastNodeId() == multiLine.get(lastIdx - 1).getFirstNodeId() ||
|
||||
multiLine.get(lastIdx).getLastNodeId() == multiLine.get(lastIdx - 1).getLastNodeId()) {
|
||||
n2 = multiLine.get(lastIdx).getFirstNodeId();
|
||||
}
|
||||
|
||||
return new long[] {n1, n2};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* check if this Ring contains the node
|
||||
|
@ -272,7 +213,6 @@ public class Ring implements Comparable<Ring> {
|
|||
private int countIntersections(double latitude, double longitude) {
|
||||
int intersections = 0;
|
||||
|
||||
mergeWays();
|
||||
List<Node> polyNodes = getBorder();
|
||||
for (int i = 0; i < polyNodes.size() - 1; i++) {
|
||||
if (MapAlgorithms.ray_intersect_lon(polyNodes.get(i),
|
||||
|
@ -289,23 +229,6 @@ public class Ring implements Comparable<Ring> {
|
|||
return intersections;
|
||||
}
|
||||
|
||||
/**
|
||||
* collect the points of all ways added by the user <br />
|
||||
* automatically added ways because of closing the Ring won't be added <br />
|
||||
* Only ways with initialized points can be handled.
|
||||
* @return a List with nodes
|
||||
*/
|
||||
public List<Node> collectPoints() {
|
||||
|
||||
ArrayList<Node> collected = new ArrayList<Node>();
|
||||
|
||||
for (Way w : ways) {
|
||||
collected.addAll(w.getNodes());
|
||||
}
|
||||
|
||||
return collected;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is in Ring r
|
||||
|
@ -317,7 +240,7 @@ public class Ring implements Comparable<Ring> {
|
|||
* bi-directional check is needed because some concave rings can intersect
|
||||
* and would only fail on one of the checks
|
||||
*/
|
||||
List<Node> points = this.collectPoints();
|
||||
List<Node> points = this.getBorder();
|
||||
|
||||
// r should contain all nodes of this
|
||||
for(Node n : points) {
|
||||
|
@ -326,7 +249,7 @@ public class Ring implements Comparable<Ring> {
|
|||
}
|
||||
}
|
||||
|
||||
points = r.collectPoints();
|
||||
points = r.getBorder();
|
||||
|
||||
// this should not contain a node from r
|
||||
for(Node n : points) {
|
||||
|
@ -603,5 +526,97 @@ public class Ring implements Comparable<Ring> {
|
|||
private static long randId() {
|
||||
return Math.round(Math.random()*Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* make a new Way with the nodes from two other ways
|
||||
* @param w1 the first way
|
||||
* @param w2 the second way
|
||||
* @param firstNodeW1 set true if the first node of w1 is also in the other way
|
||||
* @param firstNodeW2 set true if the first node of w2 is also in the other way
|
||||
*/
|
||||
private static Way combineTwoWays(Way w1, Way w2, boolean firstNodeW1, boolean firstNodeW2) {
|
||||
Way newWay = new Way(randId());
|
||||
if(w1.getNodes() != null || w1.getNodes().size() != 0) {
|
||||
if (firstNodeW1 && firstNodeW2) {
|
||||
// add the nodes of w1 in reversed order, without the first node
|
||||
for (int i = w1.getNodes().size() - 1; i>0; i--) {
|
||||
newWay.addNode(w1.getNodes().get(i));
|
||||
}
|
||||
//add the nodes from w2
|
||||
for (Node n : w2.getNodes()) {
|
||||
newWay.addNode(n);
|
||||
}
|
||||
} else if (firstNodeW1 && !firstNodeW2) {
|
||||
// add all nodes from w2
|
||||
for (Node n : w2.getNodes()) {
|
||||
newWay.addNode(n);
|
||||
}
|
||||
// add the nodes from w1, except the first one
|
||||
for (int i = 1; i < w1.getNodes().size(); i++) {
|
||||
newWay.addNode(w1.getNodes().get(i));
|
||||
}
|
||||
} else if (!firstNodeW1 && firstNodeW2) {
|
||||
// add all nodes from w1
|
||||
for (Node n : w1.getNodes()) {
|
||||
newWay.addNode(n);
|
||||
}
|
||||
// add the nodes from w2, except the first one
|
||||
for (int i = 1; i < w2.getNodes().size(); i++) {
|
||||
newWay.addNode(w2.getNodes().get(i));
|
||||
}
|
||||
} else if (!firstNodeW1 && !firstNodeW2) {
|
||||
// add all nodes from w1
|
||||
for (Node n : w1.getNodes()) {
|
||||
newWay.addNode(n);
|
||||
}
|
||||
// add the nodes from w2 in reversed order, except the last one
|
||||
for (int i = w2.getNodes().size() -2 ; i >= 0; i--) {
|
||||
newWay.addNode(w2.getNodes().get(i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (firstNodeW1 && firstNodeW2) {
|
||||
// add the nodes of w1 in reversed order, without the first node
|
||||
for (int i = w1.getNodeIds().size() - 1; i>0; i--) {
|
||||
newWay.addNode(w1.getNodeIds().get(i));
|
||||
}
|
||||
//add the nodes from w2
|
||||
for (int i = 0; i < w2.getNodeIds().size(); i++) {
|
||||
newWay.addNode(w2.getNodeIds().get(i));
|
||||
}
|
||||
} else if (firstNodeW1 && !firstNodeW2) {
|
||||
// add all nodes from w2
|
||||
for (int i = 0; i < w2.getNodeIds().size(); i++) {
|
||||
newWay.addNode(w2.getNodeIds().get(i));
|
||||
}
|
||||
// add the nodes from w1, except the first one
|
||||
for (int i = 1; i < w1.getNodeIds().size(); i++) {
|
||||
newWay.addNode(w1.getNodeIds().get(i));
|
||||
}
|
||||
} else if (!firstNodeW1 && firstNodeW2) {
|
||||
// add all nodes from w1
|
||||
for (int i = 0; i < w1.getNodeIds().size(); i++) {
|
||||
newWay.addNode(w1.getNodeIds().get(i));
|
||||
}
|
||||
// add the nodes from w2, except the first one
|
||||
for (int i = 1; i < w2.getNodeIds().size(); i++) {
|
||||
newWay.addNode(w2.getNodeIds().get(i));
|
||||
}
|
||||
} else if (!firstNodeW1 && !firstNodeW2) {
|
||||
// add all nodes from w1
|
||||
for (int i = 0; i < w1.getNodeIds().size(); i++) {
|
||||
newWay.addNode(w1.getNodeIds().get(i));
|
||||
}
|
||||
// add the nodes from w2 in reversed order, except the last one
|
||||
for (int i = w2.getNodeIds().size() -2 ; i >= 0; i--) {
|
||||
newWay.addNode(w2.getNodeIds().get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newWay;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue