Ticket #13289: cache_Area_intersection_v1.patch
File cache_Area_intersection_v1.patch, 9.9 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 ResultCache { 40 Geometry.PolygonIntersection[] results; 41 private final int dim; 42 private long countCheck; 43 private long countMiss; 44 45 public ResultCache(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 55 private synchronized PolygonIntersection getCachedResult(JoinedPolygon pa, JoinedPolygon pb){ 56 if (pa.id < 0 || pa.id >= dim ){ 57 throw new JoinedPolygonCreationException(tr("Internal error: unexpected id in 1st polygon", pa.id)); 58 } 59 if (pb.id < 0 || pb.id >= dim ){ 60 throw new JoinedPolygonCreationException(tr("Internal error: unexpected id in 2nd polygon", pb.id)); 61 } 62 countCheck++; 63 int posAB = pa.id * dim + pb.id; 64 if (results[posAB] == null){ 65 countMiss++; 66 PolygonIntersection intersection = Geometry.polygonIntersection(pa.area, pb.area); 67 results[posAB] = intersection; 68 // set the results for exchanged parameters (a is outer b also means b is outer a etc.) 69 int posBA = pb.id * dim + pa.id; 70 if (intersection == PolygonIntersection.OUTSIDE || intersection == PolygonIntersection.CROSSING){ 71 results[posBA] = intersection; 72 } else if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND){ 73 results[posBA] = PolygonIntersection.SECOND_INSIDE_FIRST; 74 } else if (intersection == PolygonIntersection.SECOND_INSIDE_FIRST) 75 results[posBA] = PolygonIntersection.FIRST_INSIDE_SECOND; 76 77 } 78 return results[posAB]; 79 } 80 81 @Override 82 public String toString() { 83 return "Tests: " + countCheck + " hit/miss " + (countCheck - countMiss) + "/" + countMiss; 84 } 85 } 86 39 87 /** 40 88 * Represents one polygon that consists of multiple ways. 41 89 */ … … 45 93 public final List<Node> nodes; 46 94 public final Area area; 47 95 public final Rectangle bounds; 96 private int id; 48 97 98 49 99 /** 50 100 * Constructs a new {@code JoinedPolygon} from given list of ways. 51 101 * @param ways The ways used to build joined polygon … … 57 107 this.nodes = this.getNodes(); 58 108 this.area = Geometry.getArea(nodes); 59 109 this.bounds = area.getBounds(); 110 this.id = -1; 60 111 } 61 112 62 113 /** … … 91 142 92 143 return nodes; 93 144 } 145 146 /** 147 * Set id that is used in ResultCache 148 * @param id 149 */ 150 public void setCacheId(int id) { 151 this.id = id; 152 } 94 153 } 95 154 96 155 /** … … 240 299 usedWays.addAll(collectedWays); 241 300 joinedWays.add(new JoinedPolygon(collectedWays, collectedWaysReverse)); 242 301 } 243 244 302 return joinedWays; 245 303 } 246 304 … … 271 329 return null; 272 330 } 273 331 274 private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates( JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) {332 private static Pair<Boolean, List<JoinedPolygon>> findInnerWaysCandidates(ResultCache cache, JoinedPolygon outerWay, Collection<JoinedPolygon> boundaryWays) { 275 333 boolean outerGood = true; 276 334 List<JoinedPolygon> innerCandidates = new ArrayList<>(); 277 335 … … 283 341 // Preliminary computation on bounds. If bounds do not intersect, no need to do a costly area intersection 284 342 if (outerWay.bounds.intersects(innerWay.bounds)) { 285 343 // Bounds intersection, let's see in detail 286 PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area); 344 PolygonIntersection intersection = cache.getCachedResult(outerWay, innerWay); 345 // PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.area, innerWay.area); 287 346 288 347 if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) { 289 348 outerGood = false; // outer is inside another polygon … … 305 364 * @param boundaryWays boundary ways 306 365 * @return the outermostWay, or {@code null} if intersection found. 307 366 */ 308 private static List<PolygonLevel> findOuterWaysMultiThread(List<JoinedPolygon> boundaryWays) { 309 return THREAD_POOL.invoke(new Worker(boundaryWays, 0, boundaryWays.size(), new ArrayList<PolygonLevel>(), 367 private List<PolygonLevel> findOuterWaysMultiThread(List<JoinedPolygon> boundaryWays) { 368 ResultCache cache = new ResultCache(boundaryWays); 369 List<PolygonLevel> res = THREAD_POOL.invoke(new Worker(cache, boundaryWays, 0, boundaryWays.size(), new ArrayList<PolygonLevel>(), 310 370 Math.max(32, boundaryWays.size() / THREAD_POOL.getParallelism() / 3))); 371 if (!boundaryWays.isEmpty()) 372 Main.debug("mp cache: " + cache.toString()); 373 return res; 311 374 } 312 375 313 376 private static class Worker extends RecursiveTask<List<PolygonLevel>> { … … 321 384 private final transient List<PolygonLevel> output; 322 385 private final int directExecutionTaskSize; 323 386 324 Worker(List<JoinedPolygon> input, int from, int to, List<PolygonLevel> output, int directExecutionTaskSize) { 387 private ResultCache cache; 388 389 Worker(ResultCache cache, List<JoinedPolygon> input, int from, int to, List<PolygonLevel> output, int directExecutionTaskSize) { 390 this.cache = cache; 325 391 this.input = input; 326 392 this.from = from; 327 393 this.to = to; … … 332 398 /** 333 399 * Collects outer way and corresponding inner ways from all boundaries. 334 400 * @param level nesting level 401 * @param cache cache that tracks previously calculated results 335 402 * @param boundaryWays boundary ways 336 403 * @return the outermostWay, or {@code null} if intersection found. 337 404 */ 338 private static List<PolygonLevel> findOuterWaysRecursive(int level, List<JoinedPolygon> boundaryWays) {405 private static List<PolygonLevel> findOuterWaysRecursive(int level, ResultCache cache, List<JoinedPolygon> boundaryWays) { 339 406 340 407 final List<PolygonLevel> result = new ArrayList<>(); 341 408 342 409 for (JoinedPolygon outerWay : boundaryWays) { 343 if (processOuterWay(level, boundaryWays, result, outerWay) == null) {410 if (processOuterWay(level, cache, boundaryWays, result, outerWay) == null) { 344 411 return null; 345 412 } 346 413 } … … 348 415 return result; 349 416 } 350 417 351 private static List<PolygonLevel> processOuterWay(int level, List<JoinedPolygon> boundaryWays,418 private static List<PolygonLevel> processOuterWay(int level, ResultCache cache, List<JoinedPolygon> boundaryWays, 352 419 final List<PolygonLevel> result, JoinedPolygon outerWay) { 353 Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates( outerWay, boundaryWays);420 Pair<Boolean, List<JoinedPolygon>> p = findInnerWaysCandidates(cache, outerWay, boundaryWays); 354 421 if (p == null) { 355 422 // ways intersect 356 423 return null; … … 362 429 363 430 //process inner ways 364 431 if (!p.b.isEmpty()) { 365 List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, p.b);432 List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, cache, p.b); 366 433 if (innerList == null) { 367 434 return null; //intersection found 368 435 } … … 388 455 } else { 389 456 final Collection<ForkJoinTask<List<PolygonLevel>>> tasks = new ArrayList<>(); 390 457 for (int fromIndex = from; fromIndex < to; fromIndex += directExecutionTaskSize) { 391 tasks.add(new Worker( input, fromIndex, Math.min(fromIndex + directExecutionTaskSize, to),458 tasks.add(new Worker(cache, input, fromIndex, Math.min(fromIndex + directExecutionTaskSize, to), 392 459 new ArrayList<PolygonLevel>(), directExecutionTaskSize)); 393 460 } 394 461 for (ForkJoinTask<List<PolygonLevel>> task : ForkJoinTask.invokeAll(tasks)) { … … 404 471 405 472 List<PolygonLevel> computeDirectly() { 406 473 for (int i = from; i < to; i++) { 407 if (processOuterWay(0, input, output, input.get(i)) == null) {474 if (processOuterWay(0, cache, input, output, input.get(i)) == null) { 408 475 return null; 409 476 } 410 477 } -
src/org/openstreetmap/josm/tools/Geometry.java
545 545 * @since 6841 546 546 */ 547 547 public static PolygonIntersection polygonIntersection(Area a1, Area a2) { 548 return polygonIntersection(a1, a2, 1.0); 548 PolygonIntersection res = polygonIntersection(a1, a2, 1.0); 549 // System.out.println(res + " " + a1.getBounds() + " " + a2.getBounds()); 550 return res; 549 551 } 550 552 551 553 /**