Search in sources :

Example 1 with MultiMapSet

use of org.twak.utils.collections.MultiMapSet in project chordatlas by twak.

the class Concarnie method apply.

private List<Problem> apply(Problem problem, int count) {
    if (depth > 10 || problem.soup.isEmpty()) {
        problem.addPortal();
        return Collections.emptyList();
    }
    Set<Line> portals = new HashSet<>();
    Set<Line> in = new HashSet<>(problem.soup);
    for (Line sl : problem.hull) {
        RangeMerge<Line> rm = new RangeMerge<>(P.CON_TOL, P.CON_TOL);
        LinearForm lf = new LinearForm(sl);
        for (Line l : problem.soup) {
            if (onHull(sl, l)) {
                double pps = lf.findPParam(l.start), ppe = lf.findPParam(l.end);
                rm.add(pps, ppe, l);
                in.remove(l);
            }
        }
        List<Double> rmGet = rm.get();
        if (rmGet.isEmpty()) {
            if (!sl.start.equals(sl.end)) {
                if (Double.isNaN(sl.start.x))
                    System.out.println("help!");
                // whole thing is portal
                portals.add(sl);
            }
        } else {
            List<Point2d> occupied = new ArrayList();
            {
                double lf1 = lf.findPParam(sl.start), lf2 = lf.findPParam(sl.end);
                if (lf1 > lf2) {
                    double tmp = lf1;
                    lf1 = lf2;
                    lf2 = tmp;
                }
                for (double d : rmGet) {
                    d = Mathz.clamp(d, lf1, lf2);
                    occupied.add(lf.fromPParam(d));
                }
            }
            boolean onHull = false;
            {
                Point2d snapE = occupied.get(0), snapS = occupied.get(occupied.size() - 1);
                if (snapS.distance(sl.start) < P.CON_TOL)
                    snapS.set(sl.start);
                else {
                    occupied.add(new Point2d(sl.start));
                }
                if (snapE.distance(sl.end) < P.CON_TOL)
                    snapE.set(sl.end);
                else {
                    occupied.add(0, new Point2d(sl.end));
                    onHull = true;
                }
            }
            for (Pair<Point2d, Point2d> pair : new ConsecutiveItPairs<Point2d>(occupied)) {
                onHull = !onHull;
                if (pair.first().equals(pair.second()))
                    continue;
                Line line = new Line(pair.first(), pair.second());
                if (onHull) {
                    if (depth % 2 == 0)
                        line = line.reverse();
                    graph.add(line);
                } else {
                    portals.add(line.reverse());
                }
            }
        }
    }
    if (in.size() == problem.soup.size()) {
        // we didn't do anything! remove something, anything...
        List<Line> d = new ArrayList(in);
        Collections.sort(d, (a, b) -> Double.compare(a.length(), b.length()));
        for (// remove the shortest 1/3 lines
        int i = 0; // remove the shortest 1/3 lines
        i < Math.max(1, in.size() * 0.33); // remove the shortest 1/3 lines
        i++) in.remove(d.get(i));
    }
    List<Portal> mergedPortals = mergeConsecutive(portals);
    // assign each member of in to a portal
    MultiMapSet<Portal, Line> subproblems = new MultiMapSet();
    if (!mergedPortals.isEmpty()) {
        // O(n^3) closest-clique assignment
        MultiMapSet<Portal, Line> sub2 = new MultiMapSet();
        for (Portal p : mergedPortals) sub2.putAll(p, p.lines);
        while (!in.isEmpty()) {
            double bestDist = Double.MAX_VALUE;
            Portal bestP = null;
            Line bestL = null;
            for (Line l : in) for (Portal p : sub2.keySet()) for (Line sl : sub2.get(p)) {
                double dlsl = l.distance(sl);
                if (// ignore lines a long way away
                dlsl > Math.max(P.CON_TOL * 3, p.length * 0.5))
                    continue;
                double dist = dlsl + 0.1 * l.distance(p.summary);
                if (dist < bestDist) {
                    bestP = p;
                    bestDist = dist;
                    bestL = l;
                }
            }
            if (bestL == null)
                break;
            in.remove(bestL);
            double lenBestL = bestL.length();
            if (lenBestL > P.CON_TOL && lenBestL > 0.5 * bestP.summary.length()) {
                in.add(new Line(bestL.start, bestL.fromPPram(0.5)));
                in.add(new Line(bestL.fromPPram(0.5), bestL.end));
            } else {
                subproblems.put(bestP, bestL);
                sub2.put(bestP, bestL);
            }
        }
    } else {
        mergedPortals.add(null);
        subproblems.putAll(null, in);
    }
    return mergedPortals.stream().map(x -> new Problem(x == null ? Collections.emptyList() : x.lines, subproblems.get(x))).collect(Collectors.toList());
}
Also used : Arrays(java.util.Arrays) Location(org.apache.commons.math3.geometry.partitioning.Region.Location) ConsecutivePairs(org.twak.utils.collections.ConsecutivePairs) Segment(org.apache.commons.math3.geometry.euclidean.twod.Segment) ConvexHull2D(org.apache.commons.math3.geometry.euclidean.twod.hull.ConvexHull2D) MultiMapSet(org.twak.utils.collections.MultiMapSet) HashMap(java.util.HashMap) Graph2D(org.twak.utils.geom.Graph2D) Pair(org.twak.utils.Pair) ConsecutiveItPairs(org.twak.utils.collections.ConsecutiveItPairs) Vector2D(org.apache.commons.math3.geometry.euclidean.twod.Vector2D) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Loop(org.twak.utils.collections.Loop) Map(java.util.Map) Mathz(org.twak.utils.Mathz) PaintThing(org.twak.utils.PaintThing) Euclidean2D(org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D) MathIllegalArgumentException(org.apache.commons.math3.exception.MathIllegalArgumentException) LoopL(org.twak.utils.collections.LoopL) UnionWalker(org.twak.utils.geom.UnionWalker) Iterator(java.util.Iterator) Collection(java.util.Collection) Line(org.twak.utils.Line) Set(java.util.Set) MonotoneChain(org.apache.commons.math3.geometry.euclidean.twod.hull.MonotoneChain) Region(org.apache.commons.math3.geometry.partitioning.Region) Vector2d(javax.vecmath.Vector2d) LinearForm(org.twak.utils.geom.LinearForm) Collectors(java.util.stream.Collectors) Point2d(javax.vecmath.Point2d) List(java.util.List) Paint(java.awt.Paint) ItComb(org.twak.utils.collections.ItComb) Loopable(org.twak.utils.collections.Loopable) InsufficientDataException(org.apache.commons.math3.exception.InsufficientDataException) Anglez(org.twak.utils.geom.Anglez) Collections(java.util.Collections) ConsecutiveItPairs(org.twak.utils.collections.ConsecutiveItPairs) ArrayList(java.util.ArrayList) LinearForm(org.twak.utils.geom.LinearForm) Paint(java.awt.Paint) Line(org.twak.utils.Line) Point2d(javax.vecmath.Point2d) HashSet(java.util.HashSet) MultiMapSet(org.twak.utils.collections.MultiMapSet)

Aggregations

Paint (java.awt.Paint)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Iterator (java.util.Iterator)1 List (java.util.List)1 Map (java.util.Map)1 Set (java.util.Set)1 Collectors (java.util.stream.Collectors)1 Point2d (javax.vecmath.Point2d)1 Vector2d (javax.vecmath.Vector2d)1 InsufficientDataException (org.apache.commons.math3.exception.InsufficientDataException)1 MathIllegalArgumentException (org.apache.commons.math3.exception.MathIllegalArgumentException)1 Euclidean2D (org.apache.commons.math3.geometry.euclidean.twod.Euclidean2D)1 Segment (org.apache.commons.math3.geometry.euclidean.twod.Segment)1 Vector2D (org.apache.commons.math3.geometry.euclidean.twod.Vector2D)1 ConvexHull2D (org.apache.commons.math3.geometry.euclidean.twod.hull.ConvexHull2D)1