use of org.twak.utils.geom.HalfMesh2 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);
}
}
}
use of org.twak.utils.geom.HalfMesh2 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;
}
use of org.twak.utils.geom.HalfMesh2 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);
}
}
}
use of org.twak.utils.geom.HalfMesh2 in project chordatlas by twak.
the class HouseTool method clickedOn.
@Override
public void clickedOn(Spatial target, Vector3f loc, Vector2f cursorPosition) {
// (Line) new XStream().fromXML( new File( "/home/twak/data/regent/March_30/congo/1/line.xml" ) ));
MegaFeatures mf = new MegaFeatures(new Line(0, 0, 10, 0));
// FeatureCache.readFeatures( new File( "/home/twak/data/regent/March_30/congo/1/0" ), mf );
ImageFeatures imf = new ImageFeatures();
imf.mega = mf;
double[] minMax = new double[] { 0, 15, 0, 25 };
HalfMesh2.Builder builder = new HalfMesh2.Builder(SuperEdge.class, SuperFace.class);
builder.newPoint(new Point2d(minMax[0] + loc.x, minMax[3] + loc.z));
builder.newPoint(new Point2d(minMax[1] + loc.x, minMax[3] + loc.z));
builder.newPoint(new Point2d(minMax[1] + loc.x, minMax[2] + loc.z));
builder.newPoint(new Point2d(minMax[0] + loc.x, minMax[2] + loc.z));
builder.newFace();
HalfMesh2 mesh = builder.done();
Prof p = new Prof();
p.add(new Point2d(0, 0));
p.add(new Point2d(0, 20));
p.add(new Point2d(-5, 25));
boolean first = true;
for (HalfFace f : mesh) {
for (HalfEdge e : f) {
SuperEdge se = (SuperEdge) e;
se.prof = p;
MiniFacade mini = newMini(imf, se.length());
if (true) {
se.addMini(mini);
se.proceduralFacade = mf;
se.toEdit = mini;
if (first)
se.addMini(mini);
}
first = false;
}
SuperFace sf = (SuperFace) f;
sf.maxProfHeights = new ArrayList();
sf.maxProfHeights.add(Double.valueOf(100));
sf.height = 100;
}
SkelGen sg = new SkelGen(mesh, tweed, null);
tweed.frame.addGen(sg, true);
}
use of org.twak.utils.geom.HalfMesh2 in project chordatlas by twak.
the class SkelFootprint method killDoubleEdges.
public static void killDoubleEdges(HalfMesh2 mesh) {
for (HalfFace f : mesh) {
boolean iDidSomething;
do {
iDidSomething = false;
for (HalfEdge e : f) {
if (e.next.over == e) {
e.dissolve(mesh);
iDidSomething = true;
}
}
} while (iDidSomething);
}
}
Aggregations