use of org.twak.utils.Cach 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");
}
use of org.twak.utils.Cach 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.Cach in project chordatlas by twak.
the class SkelFootprint method mergeOnProfiles.
private void mergeOnProfiles(HalfMesh2 mesh, List<Line> footprint) {
System.out.println("merging over profiles...");
TreeSet<HalfFace> togo = new TreeSet<>((HalfFace o1, HalfFace o2) -> Double.compare(o1.area(), o2.area()));
togo.addAll(mesh.faces);
int count = 0;
while (!togo.isEmpty()) {
HalfFace f = togo.pollFirst();
Cache<HalfEdge, MutableDouble> crossedBy = new Cach<>(e -> new MutableDouble(0));
for (HalfEdge e : f) {
SuperEdge se = (SuperEdge) e;
if (se.profLine != null) {
MegaFacade mf = ((SuperLine) se.profLine).mega;
if (mf != null)
for (Prof p : mf.getTween(se.start, se.end, 0)) {
Line proj = new Line(Pointz.to2(p.to3d(p.get(0))), Pointz.to2(p.to3d(p.get(p.size() - 1))));
for (HalfEdge e2 : f) {
SuperEdge se2 = (SuperEdge) e2;
if (se2.profLine == null && (se2.over == null || ((SuperEdge) se2.over).profLine == null) && e2.over != null && e2.line().intersects(proj) != null && Mathz.inRange(e2.line().absAngle(proj), 0.25 * Math.PI, 0.75 * Math.PI)) {
crossedBy.get(e2).d += TweedSettings.settings.profileHSampleDist;
}
}
}
}
}
count += crossedBy.cache.size();
Optional<Map.Entry<HalfEdge, MutableDouble>> longestO = crossedBy.cache.entrySet().stream().filter(//
e1 -> ((SuperEdge) e1.getKey()).profLine == null && e1.getValue().d > 0).max((e1, e2) -> Double.compare(e1.getValue().d, e2.getValue().d));
if (longestO.isPresent()) {
Map.Entry<HalfEdge, MutableDouble> longest = longestO.get();
if (longest.getValue().d > 0.6 * longest.getKey().length()) {
HalfFace tgf = longest.getKey().over.face;
togo.remove(tgf);
longest.getKey().face.merge(mesh, tgf);
((SuperFace) longest.getKey().face).mergeFrom((SuperFace) tgf);
togo.add(f);
}
}
}
System.out.println("found crossings " + count);
killDoubleEdges(mesh);
}
use of org.twak.utils.Cach in project chordatlas by twak.
the class VizSkelGen method toHalf.
private SuperFace toHalf(Loop<Point3d> loop) {
Cache<Point3d, Point2d> look = new Cach<>(x -> Pointz.to2(x));
HalfEdge last = null, first = null;
SuperFace out = new SuperFace();
for (Loopable<Point3d> edge : loop.loopableIterator()) {
SuperEdge e = new SuperEdge(look.get(edge.get()), look.get(edge.getNext().get()), null);
if (first == null)
first = e;
if (last != null)
last.next = e;
e.face = out;
// !
e.prof = null;
e.mini = Collections.EMPTY_LIST;
if (mode == Mode.Profiles)
for (Line l : footprint) {
if (l.absAngle(e.line()) < 0.1 && l.distance(e.start, true) < 1.5 && l.distance(e.end, true) < 1.5) {
SuperLine sl = (SuperLine) l;
MegaFacade mf = sl.getMega();
e.prof = findProf(e.start, e.end, sl, mf);
}
}
last = e;
}
last.next = first;
out.e = first;
SkelFootprint.meanModeHeightColor(Loopz.toXZLoop(loop), out, blockGen);
if (mode == Mode.CE) {
for (HalfEdge ee : out) {
SuperEdge e = (SuperEdge) ee;
Matrix4d m = new Matrix4d();
m.setIdentity();
e.prof = new Prof(m, new Vector3d());
e.prof.add(new Point2d(0, 0));
e.prof.add(new Point2d(0, out.height));
e.prof.add(new Point2d(-1, out.height + 1));
}
}
return out;
}
Aggregations