Search in sources :

Example 36 with Line

use of org.twak.utils.Line in project chordatlas by twak.

the class CutHoles method cutHoles.

public static void cutHoles(LoopL<Point2d> out, double tol, Map<Point2d, Line> created) {
    MultiMap<Boolean, Loop<Point2d>> holeToLoop = new MultiMap<>();
    Iterator<Loop<Point2d>> lit = out.iterator();
    while (lit.hasNext()) {
        // a hole can be a backwards loop...
        Loop<Point2d> loop = lit.next();
        double area = Loopz.area(loop);
        if (Math.abs(area) < tol * tol)
            lit.remove();
        boolean isHole = area > 0;
        holeToLoop.put(isHole, loop);
        for (Loop<Point2d> h : loop.holes) {
            if (Loopz.area(h) > 0)
                h.reverse();
            holeToLoop.put(false, h);
        }
    }
    for (Loop<Point2d> hole : holeToLoop.get(false)) {
        Point2d origin = new Point2d(Double.MAX_VALUE, 0);
        Loopable<Point2d> originL = null;
        for (Loopable<Point2d> p : hole.loopableIterator()) {
            if (p.get().x < origin.x) {
                originL = p;
                origin = originL.get();
            }
        }
        LinearForm ray = new LinearForm(0, 1);
        ray.findC(origin);
        double nearestD = Double.MAX_VALUE;
        Loopable<Point2d> nearestL = null;
        Point2d nearestH = null;
        for (Loop<Point2d> loop : out) {
            for (Loopable<Point2d> line : loop.loopableIterator()) {
                Point2d a = line.get(), b = line.getNext().get();
                if (a.y > origin.y && b.y < origin.y || a.y < origin.y && b.y > origin.y) {
                    Point2d hit = new Line(a, b).intersects(ray);
                    if (hit != null && hit.x < origin.x && (origin.x - hit.x < nearestD)) {
                        nearestD = origin.x - hit.x;
                        nearestL = line;
                        nearestH = hit;
                    }
                }
            }
        }
        if (nearestH == null)
            System.err.println("failed to find outer ring for hole");
        else {
            if (created != null)
                created.put(nearestH, new Line(nearestL.get(), nearestL.getNext().get()));
            Loopable<Point2d> hitPtF = new Loopable<Point2d>(nearestH), hitPtS = new Loopable<Point2d>(nearestH), originL2 = new Loopable(origin);
            hitPtS.setNext(nearestL.getNext());
            hitPtF.setPrev(nearestL);
            hitPtS.getNext().setPrev(hitPtS);
            hitPtF.getPrev().setNext(hitPtF);
            originL.getNext().setPrev(originL2);
            originL2.setNext(originL.getNext());
            originL.setNext(hitPtS);
            hitPtS.setPrev(originL);
            hitPtF.setNext(originL2);
            originL2.setPrev(hitPtF);
        }
        out.remove(hole);
    }
}
Also used : Loop(org.twak.utils.collections.Loop) LinearForm(org.twak.utils.geom.LinearForm) Line(org.twak.utils.Line) Loopable(org.twak.utils.collections.Loopable) MultiMap(org.twak.utils.collections.MultiMap) Point2d(javax.vecmath.Point2d)

Example 37 with Line

use of org.twak.utils.Line in project chordatlas by twak.

the class Concarnie method findSupporting.

private Line findSupporting(Loopable<Point2d> pt, int dir) {
    double totalDist = 0;
    Point2d ptg = pt.get();
    Loopable<Point2d> current = pt;
    int count = 0;
    do {
        Point2d a = current.get(), b = current.move(dir).get();
        if (dir < 0) {
            Point2d tmp = a;
            a = b;
            b = tmp;
        }
        Line hull = new Line(a, b);
        double bestDist = Double.MAX_VALUE;
        Line bestLine = null;
        for (Line l : new ItComb<>(in.getNear(hull.start, 0.5), in.getNear(hull.end, 0.5))) if (Anglez.dist(l.aTan2(), hull.aTan2()) < 0.2 && maxPerpDistance(l, hull) < 0.2) {
            double dist = l.distance(ptg, true);
            if (dist < bestDist) {
                bestDist = dist;
                bestLine = l;
            }
        }
        if (bestLine != null)
            return bestLine;
        totalDist += hull.length();
        current = current.move(dir);
    } while (totalDist < 1 && count++ < 30);
    return null;
}
Also used : Line(org.twak.utils.Line) Point2d(javax.vecmath.Point2d) ItComb(org.twak.utils.collections.ItComb) Paint(java.awt.Paint)

Example 38 with Line

use of org.twak.utils.Line in project chordatlas by twak.

the class FindLines method findNextAngle.

// private double findNextAngle2(GBias bias, Set<Line> remaining, Bin directionBias, double remainingLength) {
// 
// Bin aBin = buildNormalized(remaining, remainingLength);
// 
// aBin.multiply(directionBias, 0.5);
// 
// int aBinI = aBin.maxI();
// return aBin.val(aBinI);
// 
// }
// private Bin buildNormalized(Set<Line> remaining, double length) {
// double delta = Math.PI / P.FL_BINS;
// Bin<Line> aBin = new Bin(-Math.PI - delta, Math.PI + delta, P.FL_BINS, true); // angle bin
// 
// for (Line l : remaining) {
// double len = l.length();
// aBin.add( l.aTan2(), len, l );
// }
// 
// aBin.multiply(1/length);
// return aBin;
// }
private double findNextAngle(Set<Line> remaining) {
    double delta = Math.PI / P.FL_BINS;
    // angle bin
    Bin<Line> aBin = new Bin(-Math.PI - delta, Math.PI + delta, P.FL_BINS * 2, true);
    for (Line l : remaining) {
        double len = l.length();
        double angle = l.aTan2();
        aBin.add(angle, len, l);
    }
    int aBinI = aBin.maxI();
    return aBin.val(aBinI);
}
Also used : Line(org.twak.utils.Line)

Example 39 with Line

use of org.twak.utils.Line in project chordatlas by twak.

the class FindLines method rotateToAngle.

public static Line rotateToAngle(Line nLine, Point2d cen, double angle) {
    double len = nLine.length() / 2;
    Vector2d dir = new Vector2d(-Math.cos(angle) * len, -Math.sin(angle) * len);
    Point2d start = new Point2d(cen), end = new Point2d(cen);
    start.add(dir);
    end.sub(dir);
    return new Line(start, end);
}
Also used : Line(org.twak.utils.Line) Vector2d(javax.vecmath.Vector2d) Point2d(javax.vecmath.Point2d)

Example 40 with Line

use of org.twak.utils.Line in project chordatlas by twak.

the class FindLines method forClique.

private void forClique(Set<Line> remaining, List<Line> out, int debugLine, int clique) {
    Iterator<Line> filter = remaining.iterator();
    while (filter.hasNext()) {
        Line l = filter.next();
        // double l = filter.next().length();
        if (l.lengthSquared() == 0 || l.hasNaN())
            filter.remove();
    }
    if (remaining.isEmpty())
        return;
    int count = 0;
    while (!remaining.isEmpty()) {
        double angle = nextAngle(remaining, count);
        // offset bin
        Bin.Builder<Line> oBBin = new Bin.Builder<>();
        LinearForm lfPerp = new LinearForm(Math.cos(angle), Math.sin(angle));
        for (Line l : remaining) {
            if (Anglez.dist(l.aTan2(), angle) < Math.PI / 2) {
                // and line angle near angle+-180
                oBBin.add(lfPerp.findPParam(l.start), l.length(), l);
                oBBin.add(lfPerp.findPParam(l.end), l.length(), l);
            }
        }
        // we're super sensitive to the number of orientation bins :(
        Bin<Line> oBin = oBBin.done(P.FL_BINS * 2, false);
        int oBinI = oBin.maxI();
        int[] oBinM = oBin.maxMode(1, 10);
        LinearForm lfDir = new LinearForm(lfPerp.y, -lfPerp.x);
        lfDir.findC(lfPerp.fromPParam(oBin.val(oBinI)));
        RangeMerge<Line> rm = new RangeMerge(P.FL_GAP_TOL, P.FL_GAP_TOL / 2);
        for (Line w : oBin.getThings(oBinI, oBinM)) {
            if (lfDir.distance(w.start) < getTolNearLine(w.start) && lfDir.distance(w.end) < getTolNearLine(w.end) && // and line angle near angle+-180
            Anglez.dist(w.aTan2(), angle) < Math.PI / 2.5) {
                rm.add(lfDir.findPParam(w.start), lfDir.findPParam(w.end), w);
            }
        }
        List<Result<Line>> merged = rm.getResults();
        if (merged.isEmpty()) {
            for (Line w : oBin.getThings(oBinI, oBinM)) remaining.remove(w);
        } else {
            double maxP = merged.stream().map(x -> x.max - x.min).max(Double::compare).get();
            for (Result<Line> r : merged) {
                if (r.max - r.min < 0.2 * maxP)
                    continue;
                Line line = null;
                if (P.FL_REGRESS)
                    line = regress(r.things, lfDir);
                if (line == null)
                    line = new Line(lfDir, r.min, r.max);
                Iterator<Line> rit = remaining.iterator();
                boolean removed = false;
                Bin<Line> counts = null;
                if (P.MIN_LINES > 1)
                    counts = new Bin<>(0, 1, 50, false);
                while (rit.hasNext()) {
                    Line rine = rit.next();
                    if (line.distance(rine.start, true) < getTolNearLine2(rine.start) && line.distance(rine.end, true) < getTolNearLine2(rine.end) && Anglez.dist(line.aTan2(), rine.aTan2()) < getTolRemoveAngle(rine)) {
                        if (counts != null)
                            counts.addRange(line.findPPram(rine.start), line.findPPram(rine.end), 1, rine);
                        removed = true;
                        rit.remove();
                    }
                }
                if (counts != null) {
                    // for (Pair<Double, Double > d : new ConsecutiveItPairs<>( counts.getRegionAbove( P.MIN_LINES ) )) {
                    // 
                    // Point2d start = line.fromPPram( counts.getFirst( P.MIN_LINES ) ),
                    // end   = line.fromPPram( counts.getLast( P.MIN_LINES ) );
                    // 
                    // if ( start != null && end != null ) {
                    // out.add( new Line(start, end) );
                    // }
                    // }
                    Point2d start = line.fromPPram(counts.getFirst(P.MIN_LINES)), end = line.fromPPram(counts.getLast(P.MIN_LINES));
                    if (start != null && end != null) {
                        line.start = start;
                        line.end = end;
                    } else
                        line = null;
                }
                if (!removed)
                    for (Line l : r.things) {
                        if (remaining.contains(l)) {
                            remaining.remove(l);
                        }
                    }
                if (line != null) {
                    if (bias != null) {
                        Point2d cen = line.fromPPram(0.5);
                        Double toGIS = bias.getAngle(line, cen);
                        if (toGIS != null)
                            line = rotateToAngle(line, cen, toGIS);
                    }
                    if (debugFilter(count, debugLine) && line.start.distanceSquared(line.end) > 0.001) {
                        out.add(line);
                        cliques.put(line, clique);
                    }
                }
            }
        }
        count++;
    }
}
Also used : LinearForm(org.twak.utils.geom.LinearForm) Result(org.twak.viewTrace.RangeMerge.Result) Line(org.twak.utils.Line) Point2d(javax.vecmath.Point2d)

Aggregations

Line (org.twak.utils.Line)59 Point2d (javax.vecmath.Point2d)38 ArrayList (java.util.ArrayList)25 SuperLine (org.twak.viewTrace.SuperLine)22 List (java.util.List)16 Point3d (javax.vecmath.Point3d)14 HashSet (java.util.HashSet)13 LinearForm (org.twak.utils.geom.LinearForm)13 HashMap (java.util.HashMap)12 Map (java.util.Map)11 Set (java.util.Set)11 HalfEdge (org.twak.utils.geom.HalfMesh2.HalfEdge)11 HalfFace (org.twak.utils.geom.HalfMesh2.HalfFace)11 Collectors (java.util.stream.Collectors)10 Vector2d (javax.vecmath.Vector2d)10 Iterator (java.util.Iterator)9 Vector3d (javax.vecmath.Vector3d)9 Tweed (org.twak.tweed.Tweed)8 TweedSettings (org.twak.tweed.TweedSettings)8 MFPoint (org.twak.tweed.gen.FeatureCache.MFPoint)8