Changeset 7052 in josm
- Timestamp:
- 2014-05-02T16:52:55+02:00 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java
r7025 r7052 185 185 * Assumes you are going in clockwise orientation. 186 186 * @author viesturs 187 *188 187 */ 189 188 private static class WayTraverser { 190 189 190 /** Set of {@link WayInPolygon} to be joined by walk algorithm */ 191 191 private Set<WayInPolygon> availableWays; 192 /** Current state of walk algorithm */ 192 193 private WayInPolygon lastWay; 194 /** Direction of current way */ 193 195 private boolean lastWayReverse; 194 196 197 /** Constructor */ 195 198 public WayTraverser(Collection<WayInPolygon> ways) { 196 197 199 availableWays = new HashSet<>(ways); 198 200 lastWay = null; 199 201 } 200 202 203 /** 204 * Remove ways from available ways 205 * @param ways Collection of WayInPolygon 206 */ 201 207 public void removeWays(Collection<WayInPolygon> ways) { 202 208 availableWays.removeAll(ways); 203 209 } 204 210 211 /** 212 * Remove a single way from available ways 213 * @param way WayInPolygon 214 */ 205 215 public void removeWay(WayInPolygon way) { 206 216 availableWays.remove(way); 207 217 } 208 218 219 /** 220 * Reset walk algorithm to a new start point 221 * @param way New start point 222 */ 209 223 public void setStartWay(WayInPolygon way) { 210 224 lastWay = way; … … 212 226 } 213 227 228 /** 229 * Reset walk algorithm to a new start point. 230 * @return The new start point or null if no available way remains 231 */ 214 232 public WayInPolygon startNewWay() { 215 233 if (availableWays.isEmpty()) { … … 224 242 225 243 /** 244 * Walking through {@link WayInPolygon} segments, head node is the current position 245 * @return Head node 246 */ 247 private Node getHeadNode() { 248 return !lastWayReverse ? lastWay.way.lastNode() : lastWay.way.firstNode(); 249 } 250 251 /** 252 * Node just before head node. 253 * @return Previous node 254 */ 255 private Node getPrevNode() { 256 return !lastWayReverse ? lastWay.way.getNode(lastWay.way.getNodesCount() - 2) : lastWay.way.getNode(1); 257 } 258 259 /** 260 * Oriented angle (N1N2, N1N3) in range [0; 2*Math.PI[ 261 */ 262 private static double getAngle(Node N1, Node N2, Node N3) { 263 EastNorth en1 = N1.getEastNorth(); 264 EastNorth en2 = N2.getEastNorth(); 265 EastNorth en3 = N3.getEastNorth(); 266 double angle = Math.atan2(en3.getY() - en1.getY(), en3.getX() - en1.getX()) - 267 Math.atan2(en2.getY() - en1.getY(), en2.getX() - en1.getX()); 268 while(angle >= 2*Math.PI) 269 angle -= 2*Math.PI; 270 while(angle < 0) 271 angle += 2*Math.PI; 272 return angle; 273 } 274 275 /** 226 276 * Get the next way creating a clockwise path, ensure it is the most right way. #7959 227 277 * @return The next way. 228 278 */ 229 279 public WayInPolygon walk() { 230 Node headNode = !lastWayReverse ? lastWay.way.lastNode() : lastWay.way.firstNode();231 Node prevNode = !lastWayReverse ? lastWay.way.getNode(lastWay.way.getNodesCount() - 2) : lastWay.way.getNode(1);280 Node headNode = getHeadNode(); 281 Node prevNode = getPrevNode(); 232 282 233 283 double headAngle = Math.atan2(headNode.getEastNorth().east() - prevNode.getEastNorth().east(), … … 276 326 lastWay = bestWay; 277 327 lastWayReverse = bestWayReverse; 278 279 328 return lastWay; 329 } 330 331 /** 332 * Search for an other way coming to the same head node at left side from last way. #9951 333 * @return left way or null if none found 334 */ 335 public WayInPolygon leftComingWay() { 336 Node headNode = getHeadNode(); 337 Node prevNode = getPrevNode(); 338 339 WayInPolygon mostLeft = null; // most left way connected to head node 340 boolean comingToHead = false; // true if candidate come to head node 341 double angle = 2*Math.PI; 342 343 for (WayInPolygon candidateWay : availableWays) { 344 boolean candidateComingToHead; 345 Node candidatePrevNode; 346 347 if(candidateWay.way.firstNode().equals(headNode)) { 348 candidateComingToHead = !candidateWay.insideToTheRight; 349 candidatePrevNode = candidateWay.way.getNode(1); 350 } else if(candidateWay.way.lastNode().equals(headNode)) { 351 candidateComingToHead = candidateWay.insideToTheRight; 352 candidatePrevNode = candidateWay.way.getNode(candidateWay.way.getNodesCount() - 2); 353 } else 354 continue; 355 if(candidateWay.equals(lastWay) && candidateComingToHead) 356 continue; 357 358 double candidateAngle = getAngle(headNode, candidatePrevNode, prevNode); 359 360 if(mostLeft == null || candidateAngle < angle || (candidateAngle == angle && !candidateComingToHead)) { 361 // Candidate is most left 362 mostLeft = candidateWay; 363 comingToHead = candidateComingToHead; 364 angle = candidateAngle; 365 } 366 } 367 368 return comingToHead ? mostLeft : null; 280 369 } 281 370 } … … 959 1048 * @return A list of ways that form the outer and inner boundaries of the multigon. 960 1049 */ 961 public static List<AssembledPolygon> findBoundaryPolygons(Collection<WayInPolygon> multigonWays, List<Way> discardedResult) { 1050 public static List<AssembledPolygon> findBoundaryPolygons(Collection<WayInPolygon> multigonWays, 1051 List<Way> discardedResult) { 962 1052 //first find all discardable ways, by getting outer shells. 963 1053 //this will produce incorrect boundaries in some cases, but second pass will fix it. … … 980 1070 while((startWay = traverser.startNewWay()) != null) { 981 1071 ArrayList<WayInPolygon> path = new ArrayList<>(); 1072 List<WayInPolygon> startWays = new ArrayList<>(); 982 1073 path.add(startWay); 983 1074 while(true) { 1075 WayInPolygon leftComing; 1076 while((leftComing = traverser.leftComingWay()) != null) { 1077 if(startWays.contains(leftComing)) 1078 break; 1079 // Need restart traverser walk 1080 path.clear(); 1081 path.add(leftComing); 1082 traverser.setStartWay(leftComing); 1083 startWays.add(leftComing); 1084 break; 1085 } 984 1086 WayInPolygon nextWay = traverser.walk(); 985 1087 if(nextWay == null) 986 1088 throw new RuntimeException("Join areas internal error."); 987 1089 if(path.get(0) == nextWay) { 1090 // path is closed -> stop here 988 1091 AssembledPolygon ring = new AssembledPolygon(path); 989 1092 if(ring.getNodes().size() <= 2) {
Note:
See TracChangeset
for help on using the changeset viewer.