Ticket #13289: cache_Area_intersection_v1.patch

File cache_Area_intersection_v1.patch, 9.9 KB (added by GerdP, 5 years ago)
  • src/org/openstreetmap/josm/data/osm/MultipolygonBuilder.java

     
    3636    private static final ForkJoinPool THREAD_POOL =
    3737            Utils.newForkJoinPool("multipolygon_creation.numberOfThreads", "multipolygon-builder-%d", Thread.NORM_PRIORITY);
    3838
     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
    3987    /**
    4088     * Represents one polygon that consists of multiple ways.
    4189     */
     
    4593        public final List<Node> nodes;
    4694        public final Area area;
    4795        public final Rectangle bounds;
     96        private int id;
    4897
     98
    4999        /**
    50100         * Constructs a new {@code JoinedPolygon} from given list of ways.
    51101         * @param ways The ways used to build joined polygon
     
    57107            this.nodes = this.getNodes();
    58108            this.area = Geometry.getArea(nodes);
    59109            this.bounds = area.getBounds();
     110            this.id = -1;
    60111        }
    61112
    62113        /**
     
    91142
    92143            return nodes;
    93144        }
     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        }
    94153    }
    95154
    96155    /**
     
    240299            usedWays.addAll(collectedWays);
    241300            joinedWays.add(new JoinedPolygon(collectedWays, collectedWaysReverse));
    242301        }
    243 
    244302        return joinedWays;
    245303    }
    246304
     
    271329        return null;
    272330    }
    273331
    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) {
    275333        boolean outerGood = true;
    276334        List<JoinedPolygon> innerCandidates = new ArrayList<>();
    277335
     
    283341            // Preliminary computation on bounds. If bounds do not intersect, no need to do a costly area intersection
    284342            if (outerWay.bounds.intersects(innerWay.bounds)) {
    285343                // 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);
    287346
    288347                if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) {
    289348                    outerGood = false;  // outer is inside another polygon
     
    305364     * @param boundaryWays boundary ways
    306365     * @return the outermostWay, or {@code null} if intersection found.
    307366     */
    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>(),
    310370                Math.max(32, boundaryWays.size() / THREAD_POOL.getParallelism() / 3)));
     371        if (!boundaryWays.isEmpty())
     372            Main.debug("mp cache: " + cache.toString());
     373        return res;
    311374    }
    312375
    313376    private static class Worker extends RecursiveTask<List<PolygonLevel>> {
     
    321384        private final transient List<PolygonLevel> output;
    322385        private final int directExecutionTaskSize;
    323386
    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;
    325391            this.input = input;
    326392            this.from = from;
    327393            this.to = to;
     
    332398        /**
    333399         * Collects outer way and corresponding inner ways from all boundaries.
    334400         * @param level nesting level
     401         * @param cache cache that tracks previously calculated results
    335402         * @param boundaryWays boundary ways
    336403         * @return the outermostWay, or {@code null} if intersection found.
    337404         */
    338         private static List<PolygonLevel> findOuterWaysRecursive(int level, List<JoinedPolygon> boundaryWays) {
     405        private static List<PolygonLevel> findOuterWaysRecursive(int level, ResultCache cache, List<JoinedPolygon> boundaryWays) {
    339406
    340407            final List<PolygonLevel> result = new ArrayList<>();
    341408
    342409            for (JoinedPolygon outerWay : boundaryWays) {
    343                 if (processOuterWay(level, boundaryWays, result, outerWay) == null) {
     410                if (processOuterWay(level, cache, boundaryWays, result, outerWay) == null) {
    344411                    return null;
    345412                }
    346413            }
     
    348415            return result;
    349416        }
    350417
    351         private static List<PolygonLevel> processOuterWay(int level, List<JoinedPolygon> boundaryWays,
     418        private static List<PolygonLevel> processOuterWay(int level, ResultCache cache, List<JoinedPolygon> boundaryWays,
    352419                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);
    354421            if (p == null) {
    355422                // ways intersect
    356423                return null;
     
    362429
    363430                //process inner ways
    364431                if (!p.b.isEmpty()) {
    365                     List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, p.b);
     432                    List<PolygonLevel> innerList = findOuterWaysRecursive(level + 1, cache, p.b);
    366433                    if (innerList == null) {
    367434                        return null; //intersection found
    368435                    }
     
    388455            } else {
    389456                final Collection<ForkJoinTask<List<PolygonLevel>>> tasks = new ArrayList<>();
    390457                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),
    392459                            new ArrayList<PolygonLevel>(), directExecutionTaskSize));
    393460                }
    394461                for (ForkJoinTask<List<PolygonLevel>> task : ForkJoinTask.invokeAll(tasks)) {
     
    404471
    405472        List<PolygonLevel> computeDirectly() {
    406473            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) {
    408475                    return null;
    409476                }
    410477            }
  • src/org/openstreetmap/josm/tools/Geometry.java

     
    545545     * @since 6841
    546546     */
    547547    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;
    549551    }
    550552
    551553    /**