Search in sources :

Example 1 with HalfEdge

use of org.twak.utils.geom.HalfMesh2.HalfEdge in project chordatlas by twak.

the class SuperMeshPainter method paint.

@Override
public void paint(Object oa, Graphics2D g2, PanMouseAdaptor ma) {
    HalfMesh2 o = (HalfMesh2) oa;
    double scatterRadius = 0.0;
    if (o.faces.isEmpty())
        return;
    double maxHeight = o.faces.stream().mapToDouble(x -> ((SuperFace) x).height).max().getAsDouble();
    // (int) ( Math.random() * 100 );
    int fc = 0;
    for (HalfFace f : o.faces) {
        fc++;
        Polygon pwt = new Polygon();
        try {
            for (HalfEdge e : f.edges()) {
                pwt.addPoint(ma.toX(e.start.x + Math.random() * scatterRadius), ma.toY(e.start.y + Math.random() * scatterRadius));
            // PaintThing.paint(e.start, g2, ma);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        SuperFace sf = (SuperFace) f;
        Color c;
        if (false) {
            int h = (int) Mathz.clamp(((SuperFace) f).height * 5, 0, 255);
            if (((SuperFace) f).height == -Double.MAX_VALUE)
                c = Color.green;
            else if (((SuperFace) f).height < 0)
                c = Color.red;
            else
                c = new Color(h, h, h);
        } else if (sf.height == -Double.MAX_VALUE) {
            c = Color.yellow;
        } else if (sf.classification == -1 || sf.height < 0) {
            c = Color.red;
        } else {
            // c = Color.white;
            c = Rainbow.getColour(sf.classification + 1);
        // c = Rainbow.getColour( fc++ + 1 );
        }
        // c = Color.white;
        // new Color( c.getRed(), c.getGreen(), c.getBlue(), 50 ) );
        g2.setColor(c);
        g2.fill(pwt);
    // Loop<Point2d> pts = new Loop<>();
    // for ( HalfEdge e : f.edges() )
    // pts.append(e.end);
    // 
    // if ( ( Loopz.area( pts ) ) < 0.1 ) {
    // g2.setColor(Color.red);
    // g2.setStroke( new BasicStroke( 4f ) );
    // g2.draw( pwt );
    // }
    }
    for (HalfFace f : o.faces) {
        g2.setColor(Color.black);
        try {
            for (HalfEdge e : f) {
                SuperEdge se = (SuperEdge) e;
                g2.setColor(Color.black);
                if (se.proceduralFacade != null) {
                    g2.setStroke(new BasicStroke(3f));
                } else {
                    g2.setStroke(new BasicStroke(1f));
                }
            // if ( se.profLine != null || ( se.over != null && ((SuperEdge)se.over).profLine != null ) ) {
            // g2.setStroke( new BasicStroke( 2f ) );
            // g2.setColor( new Color (255, 0, 0 ) );
            // }
            // else
            // {
            // g2.setStroke( new BasicStroke( 1f ) );
            // g2.setColor( Color.black );
            // }
            // g2.setColor( ((SuperEdge)e).profLine == null? Color.green : Color.magenta);
            // PaintThing.paint ( e.line(), g2, ma );
            // }
            }
        } catch (Throwable th) {
            th.printStackTrace();
        }
        g2.setStroke(new BasicStroke(3));
        if (false)
            for (HalfEdge e : f.edges()) {
                SuperEdge se = (SuperEdge) e;
                if (se.profLine != null) {
                    // g2.setColor( Color.BLACK );
                    // new Line (new Point2d (e.start), new Point2d (e.end));
                    Line l = se.line();
                    // PaintThing.drawArrow( g2, ma, l, 5 );
                    g2.drawLine(ma.toX(l.start.x), ma.toY(l.start.y), ma.toX(l.end.x), ma.toY(l.end.y));
                }
            // if (e.over != null)
            // {
            // l.moveLeft( ma.fromZoom( 2 ) );
            // 
            // double delta = Math.abs (  ((SuperEdge)e).localHeight - ((SuperEdge)e.over).localHeight );
            // 
            // int h =  (int) Math.min(255, delta * 10 ) ;
            // g2.setColor ( new Color (0,h,h) );
            // g2.setStroke (new BasicStroke( 3f ));
            // 
            // }
            // if ( ( (SuperEdge) e ).debug ) {
            // if ( e.over == null || ((SuperFace)e.over.face).classification != ((SuperFace)f).classification ) {
            // g2.setColor( Color.black );
            // g2.setStroke( new BasicStroke( 2 ) );
            // PaintThing.paint( e.line(), g2, ma );
            // }
            }
    }
    fc = 0;
    if (false)
        for (HalfFace f : o.faces) {
            for (HalfEdge e : f.edges()) {
                // Point2d pt = new Point2d(e.start);
                // pt.add( off );
                // Point2d pt2 = new Point2d(e.end);
                // pt2.add( off );
                // 
                // PaintThing.paint( new Line (pt, pt2) , g2, ma );
                g2.setColor(new Color(255, 0, 0, 20));
                if (e.line().absAngle(e.next.line()) > Math.PI - 0.001) {
                    g2.setColor(new Color(0, 255, 0, 255));
                }
                PaintThing.paint(new Line(e.start, e.end), g2, ma);
                PaintThing.paint(new Line(e.next.start, e.next.end), g2, ma);
            }
        // for ( HalfEdge e : f.edges() ) {
        // PaintThing.drawArrow( g2, ma, e.line(), 5 );
        // }
        }
    if (false)
        for (HalfFace f : o.faces) for (HalfEdge e : f.edges()) {
            if (e.face != f || (e.over != null && (e.over.over != e || !o.faces.contains(e.over.face))) || e.face == null || e.start == null || e.end == null || e.next == null) {
                g2.setColor(Color.red);
                g2.setStroke(new BasicStroke(4));
                PaintThing.paint(e.line(), g2, ma);
            }
        }
}
Also used : BasicStroke(java.awt.BasicStroke) Line(org.twak.utils.Line) Color(java.awt.Color) HalfEdge(org.twak.utils.geom.HalfMesh2.HalfEdge) HalfFace(org.twak.utils.geom.HalfMesh2.HalfFace) Polygon(java.awt.Polygon) SuperFace(org.twak.tweed.gen.SuperFace) SuperEdge(org.twak.tweed.gen.SuperEdge) HalfMesh2(org.twak.utils.geom.HalfMesh2)

Example 2 with HalfEdge

use of org.twak.utils.geom.HalfMesh2.HalfEdge in project chordatlas by twak.

the class GurobiSkelSolver method dumpModelStats.

private void dumpModelStats(List<HalfEdge> edges) throws GRBException {
    print("profile count " + (globalProfs == null ? 0 : globalProfs.size()));
    print("acute corner constraints " + countBadCorners);
    print("parallel edge constraints " + countBadEdges);
    print("nearby profile terms " + countNearbyProfiles);
    print("total half edges " + edges.size());
    print("total faces " + faceInfo.size());
    if (profFit.get(edges.get(0)) != null)
        print("total profiles " + profFit.get(edges.get(0)).length);
    print("total edge length " + totalEdgeLength);
    print("\nobjective fn breakdown follows...\n");
    Cache<String, Double> penalties = new Cach<String, Double>(x -> 0.);
    Cache<String, Integer> count = new Cach<String, Integer>(x -> 0);
    for (GRBVar v : model.getVars()) {
        penalties.cache.put(v.get(StringAttr.VarName), penalties.get(v.get(StringAttr.VarName)) + v.get(GRB.DoubleAttr.Obj) * v.get(GRB.DoubleAttr.X));
        count.cache.put(v.get(StringAttr.VarName), count.get(v.get(StringAttr.VarName)) + 1);
    }
    List<String> vals = new ArrayList<>(penalties.cache.keySet());
    Collections.sort(vals);
    double obj = penalties.cache.values().stream().mapToDouble(x -> x).sum();
    for (String k : vals) print(k + "(" + count.get(k) + ") :: " + penalties.get(k) + " ");
    print("\ntotal obj " + obj + "\n\n");
}
Also used : Color(java.awt.Color) GRBQuadExpr(gurobi.GRBQuadExpr) DumbCluster1D(org.twak.utils.DumbCluster1D) GRBException(gurobi.GRBException) Cache2(org.twak.utils.Cache2) StringAttr(gurobi.GRB.StringAttr) OptionalDouble(java.util.OptionalDouble) HalfFace(org.twak.utils.geom.HalfMesh2.HalfFace) HashMap(java.util.HashMap) Random(java.util.Random) Cach(org.twak.utils.Cach) Tweed(org.twak.tweed.Tweed) ArrayList(java.util.ArrayList) TweedSettings(org.twak.tweed.TweedSettings) HashSet(java.util.HashSet) GRBModel(gurobi.GRBModel) Map(java.util.Map) Cache(org.twak.utils.Cache) Mathz(org.twak.utils.Mathz) PaintThing(org.twak.utils.PaintThing) ProgressMonitor(javax.swing.ProgressMonitor) GRBVar(gurobi.GRBVar) Iterator(java.util.Iterator) ImageFeatures(org.twak.tweed.gen.FeatureCache.ImageFeatures) GRBLinExpr(gurobi.GRBLinExpr) MultiMap(org.twak.utils.collections.MultiMap) Line(org.twak.utils.Line) HalfEdge(org.twak.utils.geom.HalfMesh2.HalfEdge) Set(java.util.Set) HalfMesh2(org.twak.utils.geom.HalfMesh2) DoubleAttr(gurobi.GRB.DoubleAttr) MegaFeatures(org.twak.tweed.gen.FeatureCache.MegaFeatures) LinearForm(org.twak.utils.geom.LinearForm) Collectors(java.util.stream.Collectors) File(java.io.File) MFPoint(org.twak.tweed.gen.FeatureCache.MFPoint) Point2d(javax.vecmath.Point2d) List(java.util.List) Collections(java.util.Collections) GRBEnv(gurobi.GRBEnv) GRB(gurobi.GRB) ArrayList(java.util.ArrayList) GRBVar(gurobi.GRBVar) Cach(org.twak.utils.Cach) OptionalDouble(java.util.OptionalDouble)

Example 3 with HalfEdge

use of org.twak.utils.geom.HalfMesh2.HalfEdge in project chordatlas by twak.

the class GurobiSkelSolver method findNear.

public static List<HalfEdge> findNear(Line l, Point2d start, HalfMesh2 mesh2) {
    double tol = 4;
    l = new Line(l);
    l.moveLeft(tol);
    List<HalfEdge> out = new ArrayList<>();
    for (HalfFace f : mesh2) try {
        for (HalfEdge e : f) {
            if (e.end.distanceSquared(start) < tol * tol && l.isOnLeft(e.start) && l.isOnLeft(e.end) && Mathz.inRangeTol(e.line().absAngle(e.next.line()), Mathz.PI2, 1)) {
                double angle = l.absAngle(e.line());
                if (// regular T-jn on edge or left corner
                (e.next.over == null && Mathz.inRangeTol(angle, Mathz.PI2, 1)) || // right corner
                (e.over == null && e.next.over == null && angle < 1))
                    out.add(e);
            }
        }
    } catch (Throwable th) {
        th.printStackTrace();
    }
    return out;
}
Also used : Line(org.twak.utils.Line) ArrayList(java.util.ArrayList) HalfEdge(org.twak.utils.geom.HalfMesh2.HalfEdge) HalfFace(org.twak.utils.geom.HalfMesh2.HalfFace)

Example 4 with HalfEdge

use of org.twak.utils.geom.HalfMesh2.HalfEdge in project chordatlas by twak.

the class GurobiSkelSolver method buildMini.

private void buildMini() throws GRBException {
    Cache<HalfEdge, GRBLinExpr> isMiniExpr = new Cach<HalfMesh2.HalfEdge, GRBLinExpr>(he -> new GRBLinExpr());
    if (minis == null)
        return;
    for (MegaFeatures mf : minis.keySet()) {
        List<MiniPtCluster> clusterVars = new ArrayList<>();
        mega2clusters.put(mf, clusterVars);
        double mLen = mf.megafacade.length();
        DumbCluster1D<MFPoint> clusters = clusterMinis(mf, minis);
        for (DumbCluster1D.Cluster<MFPoint> d : clusters) {
            // for each cluster, we pick a single MFPoint as the boundary
            MiniPtCluster miniPtVar = new MiniPtCluster();
            Cache<HalfEdge, GRBLinExpr> isEdgeBind = new Cach<HalfMesh2.HalfEdge, GRBLinExpr>(he -> new GRBLinExpr());
            GRBLinExpr selectHE = new GRBLinExpr();
            boolean one = false;
            for (MFPoint pt : d.things) {
                MiniSelectEdge miniSelectEdge = new MiniSelectEdge();
                miniPtVar.put(pt, miniSelectEdge);
                List<HalfEdge> nearCorners = findNear(mf.megafacade, pt, mesh);
                try {
                    for (HalfEdge he : nearCorners) {
                        GRBVar heVar = model.addVar(0.0, 1.0, 0, GRB.BINARY, MINI_TO_EDGE);
                        miniSelectEdge.edge.put(he, heVar);
                        selectHE.addTerm(1, heVar);
                        double cost = he.end.distance(pt);
                        if (he.over != null) {
                            if (pt.right != null)
                                cost += Math.abs(pt.right.height - ((SuperFace) he.face).height);
                            if (pt.left != null)
                                cost += Math.abs(pt.left.height - ((SuperFace) he.over.face).height);
                            isEdgeBind.get(he).addTerm(1, heVar);
                        } else
                            // bonus for being on a corner;
                            cost -= totalEdgeLength * 0.1;
                        target.addTerm(cost, heVar);
                        isMiniExpr.get(he).addTerm(1, heVar);
                        one = true;
                    }
                } catch (Throwable th) {
                    th.printStackTrace();
                }
            }
            if (one) {
                clusterVars.add(miniPtVar);
                model.addConstr(selectHE, GRB.EQUAL, 1, "pick one near " + d.things.iterator().next());
            } else
                print("warning skipping minifacade loction " + d.things.size());
            for (HalfEdge he : isEdgeBind.cache.keySet()) model.addConstr(isEdgeBind.get(he), GRB.EQUAL, edgeInfo.get(he).isEdge, "minifacade boundary must terminate on edge " + he);
            miniPtVar.mean = mf.megafacade.fromPPram(d.mean / mLen);
        }
    }
    double penalty = totalEdgeLength * 0.1;
    for (HalfEdge he : edges) {
        if (he.over != null && he.next.over == null) {
            // edge comes to boundary without minifacade --> penalty
            OptionalDouble miniDist = minis.keySet().stream().map(mf -> mf.megafacade).mapToDouble(line -> line.distance(he.end, true)).min();
            if (!miniDist.isPresent() || miniDist.getAsDouble() > 4)
                continue;
            EdgeVars ei = edgeInfo.get(he);
            ei.edgeNoMini = model.addVar(0.0, 1.0, 0, GRB.BINARY, EDGE_NO_MINI);
            if (isMiniExpr.cache.containsKey(he)) {
                ei.isMini = model.addVar(0.0, 1.0, 0, GRB.BINARY, IS_MINI);
                GRBLinExpr is = isMiniExpr.get(he);
                /* ei.isMini might take 0 or positive integer... assume it's below 10 (0.1 = 1/10) */
                model.addConstr(ei.isMini, GRB.LESS_EQUAL, is, "is minifacade on edge " + he);
                model.addConstr(scale(0.1, is), GRB.LESS_EQUAL, ei.isMini, "is minifacade on edge " + he);
                GRBLinExpr expr = new GRBLinExpr();
                expr.addTerm(1, ei.isEdge);
                expr.addTerm(1, ei.isMini);
                model.addConstr(ei.edgeNoMini, GRB.LESS_EQUAL, expr, null);
                expr = new GRBLinExpr();
                expr.addTerm(1, ei.edgeNoMini);
                expr.addTerm(1, ei.isMini);
                model.addConstr(expr, GRB.LESS_EQUAL, 1, null);
                expr = new GRBLinExpr();
                expr.addTerm(1, ei.isEdge);
                expr.addTerm(-1, ei.isMini);
                model.addConstr(ei.edgeNoMini, GRB.GREATER_EQUAL, expr, null);
            } else {
                // no mini, but easier debug
                model.addConstr(ei.edgeNoMini, GRB.EQUAL, ei.isEdge, null);
            }
            target.addTerm(penalty, ei.edgeNoMini);
        }
    }
}
Also used : Color(java.awt.Color) GRBQuadExpr(gurobi.GRBQuadExpr) DumbCluster1D(org.twak.utils.DumbCluster1D) GRBException(gurobi.GRBException) Cache2(org.twak.utils.Cache2) StringAttr(gurobi.GRB.StringAttr) OptionalDouble(java.util.OptionalDouble) HalfFace(org.twak.utils.geom.HalfMesh2.HalfFace) HashMap(java.util.HashMap) Random(java.util.Random) Cach(org.twak.utils.Cach) Tweed(org.twak.tweed.Tweed) ArrayList(java.util.ArrayList) TweedSettings(org.twak.tweed.TweedSettings) HashSet(java.util.HashSet) GRBModel(gurobi.GRBModel) Map(java.util.Map) Cache(org.twak.utils.Cache) Mathz(org.twak.utils.Mathz) PaintThing(org.twak.utils.PaintThing) ProgressMonitor(javax.swing.ProgressMonitor) GRBVar(gurobi.GRBVar) Iterator(java.util.Iterator) ImageFeatures(org.twak.tweed.gen.FeatureCache.ImageFeatures) GRBLinExpr(gurobi.GRBLinExpr) MultiMap(org.twak.utils.collections.MultiMap) Line(org.twak.utils.Line) HalfEdge(org.twak.utils.geom.HalfMesh2.HalfEdge) Set(java.util.Set) HalfMesh2(org.twak.utils.geom.HalfMesh2) DoubleAttr(gurobi.GRB.DoubleAttr) MegaFeatures(org.twak.tweed.gen.FeatureCache.MegaFeatures) LinearForm(org.twak.utils.geom.LinearForm) Collectors(java.util.stream.Collectors) File(java.io.File) MFPoint(org.twak.tweed.gen.FeatureCache.MFPoint) Point2d(javax.vecmath.Point2d) List(java.util.List) Collections(java.util.Collections) GRBEnv(gurobi.GRBEnv) GRB(gurobi.GRB) GRBLinExpr(gurobi.GRBLinExpr) MegaFeatures(org.twak.tweed.gen.FeatureCache.MegaFeatures) ArrayList(java.util.ArrayList) HalfEdge(org.twak.utils.geom.HalfMesh2.HalfEdge) DumbCluster1D(org.twak.utils.DumbCluster1D) OptionalDouble(java.util.OptionalDouble) MFPoint(org.twak.tweed.gen.FeatureCache.MFPoint) GRBVar(gurobi.GRBVar) Cach(org.twak.utils.Cach) HalfMesh2(org.twak.utils.geom.HalfMesh2)

Example 5 with HalfEdge

use of org.twak.utils.geom.HalfMesh2.HalfEdge in project chordatlas by twak.

the class GurobiSkelSolver method buildProblem.

public void buildProblem() throws GRBException {
    model = new GRBModel(new GRBEnv(Tweed.SCRATCH + System.currentTimeMillis() + ".log"));
    target = new GRBQuadExpr();
    edgeInfo = new HashMap<>();
    faceInfo = new HashMap<>();
    buildColouringProblem();
    buildIsEdge();
    buildBadGeom(false);
    if (globalProfs != null)
        buildProfiles();
    if (minis != null && !minis.isEmpty())
        buildMini();
    for (HalfEdge he : edges) {
        target.addTerm(20 * he.length(), edgeInfo.get(he).edgeNoProfile);
        target.addTerm(40 * he.length(), edgeInfo.get(he).profileNoEdge);
    }
    // target.addTerm( 50 * he.length(), edgeInfo.get(he).isEdge );
    double isEdgeHeight = 0, isNotEdgeHeight = 0;
    for (HalfEdge e : edges) {
        double cost;
        if (e.over != null) {
            cost = e.length() * Math.abs(((SuperFace) e.face).height - ((SuperFace) e.over.face).height);
            isEdgeHeight += cost;
            isNotEdgeHeight += cost;
            // target.addTerm (      cost, edgeInfo.get(e).isNotEdge );
            target.addTerm(-4 * cost, edgeInfo.get(e).isEdge);
        }
    }
    print("is not edge height penalty " + isNotEdgeHeight + " (" + (isNotEdgeHeight / faceInfo.size()) + ")");
    print("is edge height penalty " + isEdgeHeight);
    model.setObjective(target, GRB.MINIMIZE);
}
Also used : GRBModel(gurobi.GRBModel) GRBQuadExpr(gurobi.GRBQuadExpr) HalfEdge(org.twak.utils.geom.HalfMesh2.HalfEdge) GRBEnv(gurobi.GRBEnv)

Aggregations

HalfEdge (org.twak.utils.geom.HalfMesh2.HalfEdge)31 HalfFace (org.twak.utils.geom.HalfMesh2.HalfFace)25 Point2d (javax.vecmath.Point2d)15 MFPoint (org.twak.tweed.gen.FeatureCache.MFPoint)13 Line (org.twak.utils.Line)13 SuperLine (org.twak.viewTrace.SuperLine)11 ArrayList (java.util.ArrayList)10 HashMap (java.util.HashMap)8 HashSet (java.util.HashSet)8 MegaFeatures (org.twak.tweed.gen.FeatureCache.MegaFeatures)8 HalfMesh2 (org.twak.utils.geom.HalfMesh2)7 Color (java.awt.Color)6 LinkedHashSet (java.util.LinkedHashSet)6 List (java.util.List)6 Map (java.util.Map)6 MultiMap (org.twak.utils.collections.MultiMap)6 File (java.io.File)5 Set (java.util.Set)5 Vector2d (javax.vecmath.Vector2d)5 Cach (org.twak.utils.Cach)5