use of org.twak.utils.geom.HalfMesh2.HalfFace in project chordatlas by twak.
the class SkelFootprint method mergeSmallFaces.
private static void mergeSmallFaces(SolverState SS) {
Set<HalfFace> togo = new LinkedHashSet(SS.mesh.faces);
while (!togo.isEmpty()) {
HalfFace f = togo.iterator().next();
togo.remove(f);
if (-f.area() < 5) {
double bestLen = 0;
HalfEdge longest = null;
for (HalfEdge e : f) {
double len = e.length();
if (e.over != null && e.over.face != f && len > bestLen) {
bestLen = len;
longest = e;
}
}
if (longest != null) {
togo.remove(f);
longest.dissolve(SS.mesh);
togo.add(longest.face);
}
}
}
}
use of org.twak.utils.geom.HalfMesh2.HalfFace in project chordatlas by twak.
the class SkelFootprint method assignGreedyProfiles.
private static void assignGreedyProfiles(SolverState SS) {
Prof defaultProf = defaultProf(null);
for (HalfFace f : SS.mesh) for (List<HalfEdge> le : f.parallelFaces(0.1)) {
List<Prof> profs = new ArrayList();
for (HalfEdge he : le) {
SuperLine sl = ((SuperEdge) he).profLine;
if (sl != null) {
MegaFacade mf = sl.getMega();
if (mf != null)
profs.addAll(mf.getTween(he.start, he.end, 0));
}
}
Prof p = null;
if (!profs.isEmpty())
p = Prof.parameterize(profs);
else
p = defaultProf;
for (HalfEdge he : le) ((SuperEdge) he).prof = p;
}
}
use of org.twak.utils.geom.HalfMesh2.HalfFace in project chordatlas by twak.
the class SkelFootprint method cleanFootprints.
private static void cleanFootprints(HalfMesh2 mesh) {
for (HalfFace hf : mesh.faces) for (HalfEdge e : hf.edges()) if (e.over != null && e.over.face != e.face)
e.over = null;
Map<HalfEdge, Double> mergePoint = new HashMap();
Predicate<HalfEdge> badEdges = new Predicate<HalfMesh2.HalfEdge>() {
@Override
public boolean test(HalfEdge t) {
if (// is edge within a single face
t.over != null)
// preserve as hole-marker
return false;
double len = t.length();
if (t.length() < 0.2) {
mergePoint.put(t, 0.5);
return true;
}
double angleNext = t.line().absAngle(t.next.line());
final double tol = 0.1;
if (t.next.over == null && len < t.next.length() && angleNext > Math.PI - tol) {
mergePoint.put(t, 0.);
return true;
}
if (t.next.over == null && angleNext < tol) {
mergePoint.put(t, 0.);
return true;
}
HalfEdge prev = t.findBefore();
double anglePrev = t.line().absAngle(prev.line());
if (prev.over == null && len <= prev.length() && anglePrev > Math.PI - tol) {
mergePoint.put(t, 1.);
return true;
}
if (prev.over == null && anglePrev < tol) {
mergePoint.put(t, 1.);
return true;
}
return false;
}
};
f: for (HalfFace f : new ArrayList<>(mesh.faces)) {
Set<HalfEdge> togo = Streamz.stream(f.edges()).filter(badEdges).collect(Collectors.toSet());
while (!togo.isEmpty()) {
HalfEdge g = togo.iterator().next(), p = g.findBefore(), n = g.next;
togo.remove(g);
togo.remove(p);
togo.remove(n);
if (g.replaceByPoint(mesh, g.line().fromPPram(mergePoint.get(g))))
continue f;
HalfEdge pp = p.findBefore();
Streamz.stream(pp, p, n, n.next).forEach(o -> togo.remove(o));
Streamz.stream(pp, p, n, n.next).filter(badEdges).forEach(e -> togo.add(e));
}
}
for (HalfFace f : mesh.faces) {
Set<Point2d> seen = new HashSet<>();
for (HalfEdge e : f) {
if (seen.contains(e.end) && e.over == null && e.next.over == null) {
HalfEdge n = e.next;
Point2d edited;
Vector2d b4 = e.line().dir(), af = n.line().dir();
b4.normalize();
af.normalize();
b4.set(b4.y, -b4.x);
af.set(af.y, -af.x);
b4.add(af);
b4.scale(1 / b4.length());
edited = new Point2d(b4);
edited.add(e.end);
n.start = edited;
e.end = new Point2d(edited);
}
seen.add(e.end);
}
}
}
use of org.twak.utils.geom.HalfMesh2.HalfFace 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.geom.HalfMesh2.HalfFace in project chordatlas by twak.
the class SkelFootprint method removeExposedFaces.
public static void removeExposedFaces(HalfMesh2 mesh) {
System.out.println("removing exposed faces....");
Set<HalfFace> togo = new HashSet<>(mesh.faces);
while (!togo.isEmpty()) {
// for ( HalfFace hf : new ArrayList<HalfFace>( mesh.faces ) ) {
HalfFace hf = togo.iterator().next();
togo.remove(hf);
double exposed = 0, safe = 0;
for (HalfEdge e : hf.edges()) {
if (e.over == null && ((SuperEdge) e).profLine == null)
exposed += e.length();
else
safe += e.length();
}
if (exposed > exposedFaceFrac * safe) {
togo.addAll(hf.getNeighbours());
hf.remove(mesh);
}
}
}
Aggregations