nextWayMap.put(parts.get(pos), parts.get((pos + 1) % parts.size()));
prevWayMap.put(parts.get(pos), parts.get((pos + parts.size() - 1) % parts.size()));
}
//find the node with minimum y - it's guaranteed to be outer. (What about the south pole?)
Way topWay = null;
Node topNode = null;
int topIndex = 0;
double minY = Double.POSITIVE_INFINITY;
for (Way way : parts) {
for (int pos = 0; pos < way.getNodesCount(); pos ++) {
Node node = way.getNode(pos);
if (node.getEastNorth().getY() < minY) {
minY = node.getEastNorth().getY();
topWay = way;
topNode = node;
topIndex = pos;
}
}
}
//get the upper way and it's orientation.
boolean wayClockwise; // orientation of the top way.
if (topNode.equals(topWay.firstNode()) || topNode.equals(topWay.lastNode())) {
Node headNode = null; // the node at junction
Node prevNode = null; // last node from previous path
wayClockwise = false;
//node is in split point - find the outermost way from this point
headNode = topNode;
//make a fake node that is downwards from head node (smaller Y). It will be a division point between paths.
prevNode = new Node(new EastNorth(headNode.getEastNorth().getX(), headNode.getEastNorth().getY() - 1e5));
topWay = null;
wayClockwise = false;
Node bestWayNextNode = null;
for (Way way : parts) {
if (way.firstNode().equals(headNode)) {
Node nextNode = way.getNode(1);
if (topWay == null || !Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) {
//the new way is better
topWay = way;
wayClockwise = true;
bestWayNextNode = nextNode;
}
}
if (way.lastNode().equals(headNode)) {
//end adjacent to headNode
Node nextNode = way.getNode(way.getNodesCount() - 2);
if (topWay == null || !Geometry.isToTheRightSideOfLine(prevNode, headNode, bestWayNextNode, nextNode)) {
//the new way is better
topWay = way;
wayClockwise = false;
bestWayNextNode = nextNode;
}
}
}
} else {
//node is inside way - pick the clockwise going end.
Node prev = topWay.getNode(topIndex - 1);
Node next = topWay.getNode(topIndex + 1);
//there will be no parallel segments in the middle of way, so all fine.
wayClockwise = Geometry.angleIsClockwise(prev, topNode, next);
}
Way curWay = topWay;
boolean curWayInsideToTheRight = wayClockwise ^ isInner;
//iterate till full circle is reached
while (true) {
//add cur way
WayInPolygon resultWay = new WayInPolygon(curWay, curWayInsideToTheRight);
result.add(resultWay);
//process next way
Way nextWay = nextWayMap.get(curWay);
Node prevNode = curWay.getNode(curWay.getNodesCount() - 2);
Node headNode = curWay.lastNode();
Node nextNode = nextWay.getNode(1);
if (nextWay == topWay) {
//full loop traversed - all done.
break;
}
//find intersecting segments
// the intersections will look like this:
//
// ^
// |
// X wayBNode
// |
// wayB |
// |
// curWay | nextWay
//----X----------------->X----------------------X---->
// prevNode ^headNode nextNode
// |
// |
// wayA |
// |
// X wayANode
// |
int intersectionCount = 0;
for (Way wayA : parts) {
if (wayA == curWay) {
continue;
}
if (wayA.lastNode().equals(headNode)) {
Way wayB = nextWayMap.get(wayA);
//test if wayA is opposite wayB relative to curWay and nextWay
Node wayANode = wayA.getNode(wayA.getNodesCount() - 2);
Node wayBNode = wayB.getNode(1);
boolean wayAToTheRight = Geometry.isToTheRightSideOfLine(prevNode, headNode, nextNode, wayANode);
boolean wayBToTheRight = Geometry.isToTheRightSideOfLine(prevNode, headNode, nextNode, wayBNode);
if (wayAToTheRight != wayBToTheRight) {