Search in sources :

Example 6 with Line3d

use of org.twak.utils.geom.Line3d in project chordatlas by twak.

the class ProfileGen method processMegaFaces.

private void processMegaFaces() {
    addOnJmeThread.clear();
    if (faces == null || faces.isEmpty()) {
        JOptionPane.showMessageDialog(tweed.frame(), "Failed to cluster facades");
        return;
    }
    Node mfNode = new Node();
    // Node cProfileNode = new Node();
    Random randy = new Random(2);
    dbgProfileLookup.clear();
    final boolean DBG = true;
    computeProfiles(faces);
    int i = 0;
    for (MegaFacade mf : faces) {
        // if (i == 4)
        {
            System.out.println("building profiles over megafacade " + i + "/" + faces.size());
            ColorRGBA dispCol = new ColorRGBA(color.getRed() * randy.nextFloat() / 255f, color.getGreen() * randy.nextFloat() / 255f, color.getBlue() * randy.nextFloat() / 255f, 1);
            if (DBG) {
                List<Line3d> dbg = new ArrayList();
                for (int d : mf.keySet()) {
                    for (Line l2 : mf.get(d)) {
                        Line3d oLine = new Line3d(l2.start.x, getHeight(d), l2.start.y, l2.end.x, getHeight(d), l2.end.y);
                        dbg.add(oLine);
                    }
                }
                mfNode.attachChild(Jme3z.lines(tweed.getAssetManager(), dbg, dispCol, 0.1f, true));
                Line l2 = mf.origin.line;
                Line3d oLine = new Line3d(l2.start.x, getHeight(mf.origin.height), l2.start.y, l2.end.x, getHeight(mf.origin.height), l2.end.y);
            // mfNode.attachChild( Jme3z.lines( tweed.getAssetManager(), Collections.singletonList( oLine ), dispCol, 0.5f, true ) );
            }
            {
                Line l3 = mf.origin.line;
                // if ( mf.profiles.values().stream().mapToDouble( p -> p.get( 0 ).y ).min().getAsDouble() > 8 )
                // continue;
                totalPlanLineLength += l3.length();
                Line3d oLine = new Line3d(l3.start.x, getHeight(mf.origin.height), l3.start.y, l3.end.x, getHeight(mf.origin.height), l3.end.y);
                List<SuperLine> pLines = Prof.findProfileLines(mf.profiles.values(), oLine);
                for (int pi = 0; pi < pLines.size(); pi++) {
                    SuperLine profileLine = pLines.get(pi);
                    // if ( distance ( gis, profileLine.start ) > 2 || distance ( gis, profileLine.end ) > 2 )
                    // continue;
                    Node profileNode = new Node();
                    // dispCol = new ColorRGBA( randy.nextFloat(), randy.nextFloat(), randy.nextFloat(), 1 );
                    MegaFacade pMF = mf.moveTo(profileLine);
                    if (pi >= 1) {
                        Line newOrigin = null;
                        double bestDist = Double.MAX_VALUE;
                        Point3d plCen = Pointz.to3(profileLine.fromPPram(0.5), getHeight(mf.hExtentMin));
                        for (int li = mf.hExtentMin; li <= mf.hExtentMax; li++) for (Line l : mf.get(li)) {
                            double dist = Pointz.to3(l.fromPPram(0.5), getHeight(li)).distance(plCen);
                            if (dist < bestDist) {
                                newOrigin = l;
                                bestDist = dist;
                            }
                        }
                        if (newOrigin != null) {
                            pMF.setOrigin(new LineAtHeight(pMF.hExtentMin, newOrigin));
                            pMF.computeProfiles(ProfileGen.this);
                        }
                    }
                    profileLine.setMega(pMF);
                    footprint.add(profileLine);
                    dbgProfileLookup.put(i++, pMF);
                    if (DBG) {
                        profileNode.attachChild(Jme3z.lines(tweed.getAssetManager(), Collections.singletonList(new Line3d(profileLine.start.x, 0, profileLine.start.y, profileLine.end.x, 0, profileLine.end.y)), dispCol, 0.3f, true));
                        render(new ArrayList<>(pMF.profiles.values()), tweed, dispCol, profileNode);
                        // List<Prof> cleans = new ArrayList<>();
                        // for ( Prof p : pMF.profiles.values() ) {
                        // p.render( tweed, profileNode, dispCol, 1f );
                        // cleans.add( new Prof( p ).parameterize() );
                        // .render( tweed, cProfileNode, dispCol.add( ColorRGBA.Gray ), 1f );
                        // 
                        // }
                        // render ( cleans, tweed, cProfileNode );
                        profileNode.attachChild(Jme3z.lines(tweed.getAssetManager(), Collections.singletonList(oLine), dispCol, 0.3f, true));
                        profileNode.setUserData(ProfileGen.class.getSimpleName(), i);
                        addOnJmeThread.add(profileNode);
                    }
                }
            }
        }
    }
    if (DBG)
        tweed.frame.addGen(new JmeGen("horizontal lines", tweed, mfNode), false);
    // tweed.frame.addGen( new JmeGen( "clean profiles", tweed, cProfileNode ), false );
    calculateOnJmeThread();
}
Also used : Node(com.jme3.scene.Node) ArrayList(java.util.ArrayList) CullHint(com.jme3.scene.Spatial.CullHint) Line3d(org.twak.utils.geom.Line3d) Line(org.twak.utils.Line) SuperLine(org.twak.viewTrace.SuperLine) Random(java.util.Random) ColorRGBA(com.jme3.math.ColorRGBA) Point3d(javax.vecmath.Point3d) SuperLine(org.twak.viewTrace.SuperLine) List(java.util.List) ArrayList(java.util.ArrayList)

Example 7 with Line3d

use of org.twak.utils.geom.Line3d in project chordatlas by twak.

the class CutHoles method find.

public static Point3d find(Point2d pt, Map<Point2d, Point3d> root, Map<Point2d, Line> created) {
    if (root.containsKey(pt))
        return root.get(pt);
    else {
        Line l = created.get(pt);
        Point3d a = find(l.start, root, created), b = find(l.end, root, created);
        return new Line3d(a, b).fromPPram(l.findPPram(pt));
    }
}
Also used : Line(org.twak.utils.Line) Point3d(javax.vecmath.Point3d) Line3d(org.twak.utils.geom.Line3d)

Example 8 with Line3d

use of org.twak.utils.geom.Line3d in project chordatlas by twak.

the class Prof method climb.

private static void climb(List<Line3d> lines, Line3d first, Prof monotonic, double max, boolean isUp) {
    Point3d end = isUp ? highestEnd(first) : lowestEnd(first), extrema = end;
    monotonic.add(isUp ? monotonic.size() : 0, end);
    Map<Line3d, Object> ends = new IdentityHashMap();
    BetterThan bt = new BetterThan() {

        @Override
        public boolean betterThan(double h1, double h2) {
            return isUp ? h1 > h2 : h1 < h2;
        }

        @Override
        public boolean betterThanOrEqualTo(double h1, double h2) {
            return isUp ? h1 >= h2 : h1 <= h2;
        }
    };
    Line3d next = null;
    boolean worseThanExtrema = false;
    double BIG_JUMP = TweedSettings.settings.meshHoleJumpSize;
    do {
        double bestDist = 1;
        int startOrEnd = -1;
        next = null;
        for (Line3d l : lines) {
            if ((bt.betterThan(l.end.y, extrema.y) || bt.betterThan(l.start.y, extrema.y)) && !ends.containsKey(l)) {
                for (int i = 0; i < 2; i++) {
                    double dist = l.points()[i].distance(worseThanExtrema ? extrema : end);
                    if (dist < bestDist) {
                        bestDist = dist;
                        startOrEnd = i;
                        next = l;
                    }
                }
            }
        }
        if (next == null) {
            // nothing strictly montonic, try near...limit search to near extrema (balcony width)
            bestDist = BIG_JUMP;
            for (Line3d l : lines) {
                if (!ends.containsKey(l)) {
                    for (int i = 0; i < 2; i++) {
                        double dist = l.points()[i].distance(extrema);
                        if (dist < bestDist) {
                            // 
                            bestDist = dist;
                            startOrEnd = i;
                            next = l;
                        }
                    }
                }
            }
        }
        if (next != null) {
            ends.put(next, next);
            end = next.points()[1 - startOrEnd];
            if (bt.betterThanOrEqualTo(end.y, extrema.y)) {
                if (worseThanExtrema) {
                    // add intermediate point
                    double angle = next.angle(UP);
                    if (angle < Math.PI / 2 - 0.2 || angle > Math.PI / 2 + 0.2) {
                        // intersecting with horizontal lines is messy.
                        Point3d pt = new LinearForm3D(UP, extrema).collide(end, next.dir(), next.length());
                        if (bt.betterThan(max, pt.y))
                            monotonic.add(isUp ? monotonic.size() : 0, pt);
                    }
                }
                extrema = end;
                Point3d toAdd = end;
                if (bt.betterThan(end.y, max)) {
                    // trim to max
                    toAdd = new LinearForm3D(UP, new Vector3d(0, max, 0)).collide(next.points()[startOrEnd], next.dir(), next.length());
                    if (// intersection failed
                    toAdd.getClass() != Point3d.class && bt.betterThan(max, toAdd.y))
                        toAdd = new Point3d(end.x, max, end.z);
                    else
                        toAdd = null;
                    next = null;
                }
                if (toAdd != null)
                    monotonic.add(isUp ? monotonic.size() : 0, toAdd);
                worseThanExtrema = false;
            } else
                worseThanExtrema = true;
        }
    } while (next != null);
}
Also used : Vector3d(javax.vecmath.Vector3d) Point3d(javax.vecmath.Point3d) IdentityHashMap(java.util.IdentityHashMap) LinearForm3D(org.twak.utils.geom.LinearForm3D) Line3d(org.twak.utils.geom.Line3d)

Example 9 with Line3d

use of org.twak.utils.geom.Line3d in project chordatlas by twak.

the class Prof method findProfileLines.

/**
 * We find an initial base offset. Then we cluster the start point of all
 * (clean) profiles. If any are a good distance from the initial base, we
 * add those as their own profile lines.
 *
 * The original line is offset by the remaiing data.
 */
public static List<SuperLine> findProfileLines(Collection<Prof> profiles, Line3d line) {
    List<SuperLine> out = new ArrayList();
    // PaintThing.debug.clear();
    SuperLine superLine = new SuperLine(line.start.x, line.start.z, line.end.x, line.end.z);
    double outLen = superLine.length();
    double min = Double.MAX_VALUE, max = -Double.MAX_VALUE;
    Cache<Prof, Double> vLength = new Cache<Prof, Double>() {

        @Override
        public Double create(Prof i) {
            return i.verticalLength(0.5);
        }
    };
    double vLen = profiles.stream().mapToDouble(p -> vLength.get(p)).sum();
    boolean useVertical = vLen / profiles.size() > 1;
    class Wrapper implements Clusterable {

        double[] pt;

        public Wrapper(Point2d pt) {
            this.pt = new double[] { pt.x, pt.y };
        }

        @Override
        public double[] getPoint() {
            return pt;
        }
    }
    List<Wrapper> toCluster = new ArrayList();
    List<Double> baseLineOffset = new ArrayList();
    for (Prof p : profiles) {
        if (// vLen / (5*profiles.size()))
        useVertical && vLength.get(p) < 1)
            continue;
        Prof clean = p.parameterize();
        Point2d pt = clean.get(0);
        Point3d pt3 = clean.to3d(pt);
        double ppram = superLine.findPPram(new Point2d(pt3.x, pt3.z));
        baseLineOffset.add(pt.x);
        toCluster.add(new Wrapper(new Point2d(pt.x, ppram * outLen)));
        min = Math.min(min, ppram);
        max = Math.max(max, ppram);
    }
    if (min == max || toCluster.isEmpty())
        return out;
    if (true) {
        baseLineOffset.sort(Double::compareTo);
        double modeBaselineOffset = baseLineOffset.get(baseLineOffset.size() / 2);
        DBSCANClusterer<Wrapper> cr = new DBSCANClusterer<>(1.5, 0);
        List<Cluster<Wrapper>> results = cr.cluster(toCluster);
        Iterator<Cluster<Wrapper>> cit = results.iterator();
        while (cit.hasNext()) {
            Cluster<Wrapper> cw = cit.next();
            if (cw.getPoints().size() < 2 / TweedSettings.settings.profileHSampleDist) {
                cit.remove();
                double cMeanY = cw.getPoints().stream().mapToDouble(x -> x.pt[1]).average().getAsDouble();
                double bestDist = Double.MAX_VALUE;
                Cluster<Wrapper> bestWrapper = null;
                for (Cluster<Wrapper> near : results) {
                    double meanY = near.getPoints().stream().mapToDouble(x -> x.pt[1]).average().getAsDouble();
                    double dist = Math.abs(meanY - cMeanY);
                    if (dist < bestDist) {
                        bestDist = dist;
                        bestWrapper = near;
                    }
                }
                if (bestWrapper != null)
                    bestWrapper.getPoints().addAll(cw.getPoints());
            }
        }
        {
            baseLineOffset.clear();
            int c = 0;
            for (Cluster<Wrapper> cw : results) {
                double[] minMax = cw.getPoints().stream().map(p -> new double[] { p.pt[1] }).collect(new InAxDoubleArray());
                double[] offsetA = cw.getPoints().stream().mapToDouble(p -> p.pt[0]).sorted().toArray();
                double offset = offsetA[offsetA.length / 2];
                if (offset - modeBaselineOffset < 1) {
                    for (Wrapper w : cw.getPoints()) baseLineOffset.add(w.pt[0]);
                    continue;
                }
                SuperLine sl = new SuperLine(superLine.fromPPram(minMax[0] / outLen), superLine.fromPPram(minMax[1] / outLen));
                sl.moveLeft(offset);
                out.add(sl);
                List<Point2d> pts = cw.getPoints().stream().map(w -> new Point2d(w.pt[0], w.pt[1])).collect(Collectors.toList());
                PaintThing.debug(Rainbow.getColour(c++), 1, pts);
            }
        }
    }
    Point2d nStart = superLine.fromPPram(min), nEnd = superLine.fromPPram(max);
    superLine.start = nStart;
    superLine.end = nEnd;
    baseLineOffset.sort(Double::compare);
    if (!baseLineOffset.isEmpty())
        superLine.moveLeft(baseLineOffset.get(baseLineOffset.size() / 2));
    out.add(0, superLine);
    return out;
}
Also used : ConsecutivePairs(org.twak.utils.collections.ConsecutivePairs) Matrix4d(javax.vecmath.Matrix4d) ConsecutiveItPairs(org.twak.utils.collections.ConsecutiveItPairs) SliceParameters(org.twak.viewTrace.SliceParameters) Arrayz(org.twak.utils.collections.Arrayz) Node(com.jme3.scene.Node) ObjRead(org.twak.utils.geom.ObjRead) Map(java.util.Map) Cache(org.twak.utils.Cache) Material(com.jme3.material.Material) Point3d(javax.vecmath.Point3d) VertexBuffer(com.jme3.scene.VertexBuffer) IdentityHashMap(java.util.IdentityHashMap) Collection(java.util.Collection) Line(org.twak.utils.Line) FindLines(org.twak.viewTrace.FindLines) Set(java.util.Set) Vector2d(javax.vecmath.Vector2d) LinearForm(org.twak.utils.geom.LinearForm) Collectors(java.util.stream.Collectors) List(java.util.List) Rainbow(org.twak.utils.ui.Rainbow) Line3d(org.twak.utils.geom.Line3d) Mesh(com.jme3.scene.Mesh) Geometry(com.jme3.scene.Geometry) DBSCANClusterer(org.apache.commons.math3.ml.clustering.DBSCANClusterer) LinearForm3D(org.twak.utils.geom.LinearForm3D) Bin(org.twak.viewTrace.Bin) Pair(org.twak.utils.Pair) Vector3d(javax.vecmath.Vector3d) Clusterable(org.apache.commons.math3.ml.clustering.Clusterable) Tweed(org.twak.tweed.Tweed) ArrayList(java.util.ArrayList) TweedSettings(org.twak.tweed.TweedSettings) HashSet(java.util.HashSet) PanMouseAdaptor(org.twak.utils.PanMouseAdaptor) Graphics2D(java.awt.Graphics2D) ICanPaintU(org.twak.utils.PaintThing.ICanPaintU) Mathz(org.twak.utils.Mathz) PaintThing(org.twak.utils.PaintThing) Iterator(java.util.Iterator) Point2d(javax.vecmath.Point2d) SuperLine(org.twak.viewTrace.SuperLine) Cluster(org.apache.commons.math3.ml.clustering.Cluster) ColorRGBA(com.jme3.math.ColorRGBA) Comparator(java.util.Comparator) InAxDoubleArray(org.twak.utils.streams.InAxDoubleArray) Collections(java.util.Collections) ObjSlice(org.twak.viewTrace.ObjSlice) ArrayList(java.util.ArrayList) Cluster(org.apache.commons.math3.ml.clustering.Cluster) Clusterable(org.apache.commons.math3.ml.clustering.Clusterable) InAxDoubleArray(org.twak.utils.streams.InAxDoubleArray) Point2d(javax.vecmath.Point2d) Point3d(javax.vecmath.Point3d) SuperLine(org.twak.viewTrace.SuperLine) List(java.util.List) ArrayList(java.util.ArrayList) DBSCANClusterer(org.apache.commons.math3.ml.clustering.DBSCANClusterer) Cache(org.twak.utils.Cache)

Example 10 with Line3d

use of org.twak.utils.geom.Line3d in project chordatlas by twak.

the class Prof method retarget.

public static Prof retarget(Prof p, SuperLine profileLine) {
    Line3d l = new Line3d(Pointz.to3(profileLine));
    Prof out = buildProfile(new Line3d(Pointz.to3(profileLine)), l.closestPointOn(p.to3d(p.get(0)), false));
    for (Point2d p2 : p) out.add(p.to3d(p2));
    return out;
}
Also used : Point2d(javax.vecmath.Point2d) Line3d(org.twak.utils.geom.Line3d)

Aggregations

Line3d (org.twak.utils.geom.Line3d)17 Point3d (javax.vecmath.Point3d)15 ArrayList (java.util.ArrayList)10 LinearForm3D (org.twak.utils.geom.LinearForm3D)10 List (java.util.List)8 Point2d (javax.vecmath.Point2d)8 Vector3d (javax.vecmath.Vector3d)7 Vector2d (javax.vecmath.Vector2d)5 Loop (org.twak.utils.collections.Loop)5 ColorRGBA (com.jme3.math.ColorRGBA)4 Line (org.twak.utils.Line)4 Pair (org.twak.utils.Pair)4 Material (com.jme3.material.Material)3 Geometry (com.jme3.scene.Geometry)3 Node (com.jme3.scene.Node)3 File (java.io.File)3 HashSet (java.util.HashSet)3 Map (java.util.Map)3 Collectors (java.util.stream.Collectors)3 Matrix4d (javax.vecmath.Matrix4d)3