Ticket #13289: improve_MultipolygonBuilder.patch
File improve_MultipolygonBuilder.patch, 9.4 KB (added by , 9 years ago) |
---|
-
src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java
36 36 private static final ForkJoinPool THREAD_POOL = 37 37 Utils.newForkJoinPool("multipolygon_creation.numberOfThreads", "multipolygon-builder-%d", Thread.NORM_PRIORITY); 38 38 39 private static class IntersectionMatrix { 40 Geometry.PolygonIntersection[] results; 41 private final int dim; 42 private long countCheck; 43 private long countMiss; 44 45 public IntersectionMatrix(Collection<JoinedPolygon> polygons) { 46 int id = 0; 47 for (JoinedPolygon p : polygons) 48 p.setCacheId(id++); 49 50 this.dim = id; 51 results = new Geometry.PolygonIntersection[dim*dim]; 52 } 53 54 private PolygonIntersection getReverseIntersectionResult(PolygonIntersection intersection) { 55 if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND){ 56 return PolygonIntersection.SECOND_INSIDE_FIRST; 57 } else if (intersection == PolygonIntersection.SECOND_INSIDE_FIRST) 58 return PolygonIntersection.FIRST_INSIDE_SECOND; 59 return intersection; 60 } 61 62 private void checkId (JoinedPolygon poly){ 63 if (poly.id < 0 || poly.id >= dim ){ 64 throw new JoinedPolygonCreationException(tr("Internal error: unexpected id in polygon", poly.id)); 65 } 66 67 } 68 private synchronized void setResult(JoinedPolygon pa, JoinedPolygon pb, PolygonIntersection intersection){ 69 checkId(pa); 70 checkId(pb); 71 int posAB = pa.id * dim + pb.id; 72 int posBA = pb.id * dim + pa.id; 73 results[posAB] = intersection; 74 results[posBA] = getReverseIntersectionResult(intersection); 75 } 76 77 private synchronized PolygonIntersection getResult(JoinedPolygon pa, JoinedPolygon pb){ 78 checkId(pa); 79 checkId(pb); 80 countCheck++; 81 int posAB = pa.id * dim + pb.id; 82 if (results[posAB] == null) 83 countMiss++; 84 return results[posAB]; 85 } 86 87 @Override 88 public String toString() { 89 return "Tests: " + countCheck + " hit/miss " + (countCheck - countMiss) + "/" + countMiss; 90 } 91 } 92 39 93 /** 40 94 * Represents one polygon that consists of multiple ways. 41 95 */ … … 45 99 public final List<Node> nodes; 46 100 public final Area area; 47 101 public final Rectangle bounds; 102 private int id; 48 103 104 49 105 /** 50 106 * Constructs a new {@code JoinedPolygon} from given list of ways. 51 107 * @param ways The ways used to build joined polygon … … 57 113 this.nodes = this.getNodes(); 58 114 this.area = Geometry.getArea(nodes); 59 115 this.bounds = area.getBounds(); 116 this.id = -1; 60 117 } 61 118 62 119 /** … … 91 148 92 149 return nodes; 93 150 } 151 152 /** 153 * Set id that is used in ResultCache 154 * @param id 155 */ 156 public void setCacheId(int id) { 157 this.id = id; 158 } 94 159 } 95 160 96 161 /** … … 240 305 usedWays.addAll(collectedWays); 241 306 joinedWays.add(new JoinedPolygon(collectedWays, collectedWaysReverse)); 242 307 } 243 244 308 return joinedWays; 245 309 } 246 310 … … 271 335 return null; 272 336 } 273 337 274 private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates( JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) {338 private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates(IntersectionMatrix cache, JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) { 275 339 boolean outerGood = true; 276 340 List<JoinedPolygon> innerCandidates = new ArrayList<>(); 277 341 … … 283 347 // Preliminary computation on bounds. If bounds do not intersect, no need to do a costly area intersection 284 348 if (outerWay.bounds.intersects(innerWay.bounds)) { 285 349 // Bounds intersection, let's see in detail 286 PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area); 350 PolygonIntersection intersection = cache.getResult(outerWay, innerWay); 351 if (intersection == null){ 352 intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area); 353 cache.setResult(outerWay, innerWay, intersection); 354 } 287 355 288 356 if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) { 289 357 outerGood = false; // outer is inside another polygon … … 305 373 * @param boundaryWays boundary ways 306 374 * @return the outermostWay, or {@code null} if intersection found. 307 375 */ 308 private static List<PolygonLevel> findOuterWaysMultiThread(List<JoinedPolygon> boundaryWays) { 309 return THREAD_POOL.invoke(new Worker(boundaryWays, 0, boundaryWays.size(), new ArrayList<PolygonLevel>(), 376 private List<PolygonLevel> findOuterWaysMultiThread(List<JoinedPolygon> boundaryWays) { 377 IntersectionMatrix im = new IntersectionMatrix(boundaryWays); 378 List<PolygonLevel> res = THREAD_POOL.invoke(new Worker(im, boundaryWays, 0, boundaryWays.size(), new ArrayList<PolygonLevel>(), 310 379 Math.max(32, boundaryWays.size() / THREAD_POOL.getParallelism() / 3))); 380 // if (!boundaryWays.isEmpty()) 381 // Main.debug("mp cache: " + im.toString()); 382 return res; 311 383 } 312 384 313 385 private static class Worker extends RecursiveTask<List<PolygonLevel>> { … … 321 393 private final transient List<PolygonLevel> output; 322 394 private final int directExecutionTaskSize; 323 395 324 Worker(List<JoinedPolygon> input, int from, int to, List<PolygonLevel> output, int directExecutionTaskSize) { 396 private IntersectionMatrix cache; 397 398 Worker(IntersectionMatrix cache, List<JoinedPolygon> input, int from, int to, List<PolygonLevel> output, int directExecutionTaskSize) { 399 this.cache = cache; 325 400 this.input = input; 326 401 this.from = from; 327 402 this.to = to; … … 332 407 /** 333 408 * Collects outer way and corresponding inner ways from all boundaries. 334 409 * @param level nesting level 410 * @param cache cache that tracks previously calculated results 335 411 * @param boundaryWays boundary ways 336 412 * @return the outermostWay, or {@code null} if intersection found. 337 413 */ 338 private static List<PolygonLevel> findOuterWaysRecursive(int level, List<JoinedPolygon> boundaryWays) {414 private static List<PolygonLevel> findOuterWaysRecursive(int level, IntersectionMatrix cache, List<JoinedPolygon> boundaryWays) { 339 415 340 416 final List<PolygonLevel> result = new ArrayList<>(); 341 417 342 418 for (JoinedPolygon outerWay : boundaryWays) { 343 if (processOuterWay(level, boundaryWays, result, outerWay) == null) {419 if (processOuterWay(level, cache, boundaryWays, result, outerWay) == null) { 344 420 return null; 345 421 } 346 422 } … … 348 424 return result; 349 425 } 350 426 351 private static List<PolygonLevel> processOuterWay(int level, List<JoinedPolygon> boundaryWays,427 private static List<PolygonLevel> processOuterWay(int level, IntersectionMatrix cache, List<JoinedPolygon> boundaryWays, 352 428 final List<PolygonLevel> result, JoinedPolygon outerWay) { 353 Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates( outerWay, boundaryWays);429 Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates(cache, outerWay, boundaryWays); 354 430 if (p == null) { 355 431 // ways intersect 356 432 return null; … … 362 438 363 439 //process inner ways 364 440 if (!p.b.isEmpty()) { 365 List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, p.b);441 List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, cache, p.b); 366 442 if (innerList == null) { 367 443 return null; //intersection found 368 444 } … … 388 464 } else { 389 465 final Collection<ForkJoinTask<List<PolygonLevel>>> tasks = new ArrayList<>(); 390 466 for (int fromIndex = from; fromIndex < to; fromIndex += directExecutionTaskSize) { 391 tasks.add(new Worker( input, fromIndex, Math.min(fromIndex + directExecutionTaskSize, to),467 tasks.add(new Worker(cache, input, fromIndex, Math.min(fromIndex + directExecutionTaskSize, to), 392 468 new ArrayList<PolygonLevel>(), directExecutionTaskSize)); 393 469 } 394 470 for (ForkJoinTask<List<PolygonLevel>> task : ForkJoinTask.invokeAll(tasks)) { … … 404 480 405 481 List<PolygonLevel> computeDirectly() { 406 482 for (int i = from; i < to; i++) { 407 if (processOuterWay(0, input, output, input.get(i)) == null) {483 if (processOuterWay(0, cache, input, output, input.get(i)) == null) { 408 484 return null; 409 485 } 410 486 }