use of org.twak.utils.geom.Line3d in project chordatlas by twak.
the class Tube method tube.
public static void tube(MeshBuilder out, Collection<LinearForm3D> before, Collection<LinearForm3D> after, Line3d line, LinearForm3D left, LinearForm3D right, CrossGen gen) {
if (angle(before, line) < 0.1 || angle(after, line) < 0.1)
// too pointy to touch
return;
Point3d middle = line.fromPPram(0.5);
Vector3d along = line.dir();
along.normalize();
Vector3d nAlong = new Vector3d(along);
nAlong.negate();
Vector3d o1 = left.normal(), u1 = new Vector3d();
u1.cross(along, o1);
Frame frame = Mathz.buildFrame(o1, u1, along, middle);
Vector3d u2 = right.normal();
u2.cross(u2, along);
// u2.add( middle );
Vector2d leftDir = Mathz.toXY(frame, u1);
Vector2d rightDir = Mathz.toXY(frame, u2);
List<Point3d> profilePts = gen.gen(leftDir, rightDir).stream().map(p -> Mathz.fromXY(frame, p)).collect(Collectors.toList());
List<LinearForm3D> dummy = new ArrayList<>();
for (Pair<Point3d, Point3d> pair : new ConsecutivePairs<Point3d>(profilePts, true)) {
Point3d f1 = clip(pair.first(), along, after, dummy), f2 = clip(pair.second(), along, after, dummy), b1 = clip(pair.first(), nAlong, before, dummy), b2 = clip(pair.second(), nAlong, before, dummy);
out.add(f2, f1, b1, b2);
}
// cap( out, after , along, profilePts, true );
// cap( out, before, nAlong, profilePts, false );
}
use of org.twak.utils.geom.Line3d in project chordatlas by twak.
the class Tube method clip.
private static Point3d clip(Point3d pt, Vector3d dir, Collection<LinearForm3D> after, List<LinearForm3D> hit) {
Point3d out = pt;
double bestScore = Double.MAX_VALUE;
Line3d line = Line3d.fromRay(pt, dir);
for (LinearForm3D l : after) {
if (l == null)
continue;
Point3d sec = l.collide(pt, dir);
if (sec == null)
continue;
double score = line.findPPram(sec);
if (score < bestScore) {
out = sec;
bestScore = score;
}
}
for (LinearForm3D l : after) {
if (l == null)
continue;
Point3d sec = l.collide(pt, dir);
if (sec != null) {
double score = line.findPPram(sec);
if (Math.abs(score - bestScore) < 0.00001)
hit.add(l);
}
}
return out;
}
use of org.twak.utils.geom.Line3d in project chordatlas by twak.
the class GreebleEdge method roowWallGreeble.
public static void roowWallGreeble(Output output, MeshBuilder roof, MeshBuilder wall) {
MultiMap<Point3d, SharedEdge> boundary = new MultiMap<>();
Set<SharedEdge> roofWallBoundary = new HashSet<>();
for (Face f1 : output.faces.values()) for (Loop<SharedEdge> sl : f1.edges) for (Loopable<SharedEdge> se : sl.loopableIterator()) {
Face f2 = se.get().getOther(f1);
if (isWall(f1) ^ isWall(f2)) {
boundary.put(se.get().getStart(f1), se.get());
roofWallBoundary.add(se.get());
}
}
for (SharedEdge se : roofWallBoundary) {
if (se.start.z < 1 || se.end.z < 1)
// something strange here...
continue;
Face f1 = se.left, f2 = se.right;
if (f1 == null || f2 == null)
continue;
EdgePoint bs = findAdjacent(se.start, se.end, boundary), be = findAdjacent(se.end, se.start, boundary);
if (bs != null && be != null) {
LinearForm3D cutS, cutE;
if (isOverhang(bs.se))
// between two angles
cutS = cut(bs.pt, se.start, se.end);
else
// flat at end
cutS = new LinearForm3D(LinearForm3D.linePerp(toXZ(se.end), toXZ(se.start)));
if (isOverhang(be.se))
cutE = cut(se.start, se.end, be.pt);
else
// flat at end
cutE = new LinearForm3D(LinearForm3D.linePerp(toXZ(se.start), toXZ(se.end)));
LinearForm3D right = new LinearForm3D(toXZ(f1.edge.getPlaneNormal()), toXZ(f1.edge.start)), left = new LinearForm3D(toXZ(f2.edge.getPlaneNormal()), toXZ(f2.edge.start));
Tube.tube(roof, Collections.singleton(cutS), Collections.singleton(cutE), new Line3d(toXZ(se.start), toXZ(se.end)), left, right, isOverhang(se) ? new OverhangCross() : new LipCross());
}
}
}
use of org.twak.utils.geom.Line3d in project chordatlas by twak.
the class GreebleEdge method roofGreeble.
public static boolean roofGreeble(Face f, MeshBuilder roof) {
boolean isWall = isWall(f);
for (Loop<SharedEdge> sl : f.edges) {
for (Loopable<SharedEdge> sel : sl.loopableIterator()) {
SharedEdge se = sel.get();
boolean otherIsWall = isWall(se.getOther(f));
if (!isWall && !otherIsWall) {
Face oF = se.getOther(f);
if (oF == null || order(f, oF) || f.edge.getPlaneNormal().angle(oF.edge.getPlaneNormal()) < 0.4)
continue;
List<LinearForm3D> start = new ArrayList(), end = new ArrayList<>();
{
SharedEdge fPrev = se.getAdjEdge(f, false), fNext = se.getAdjEdge(f, true), ofPrev = se.getAdjEdge(oF, false), ofNext = se.getAdjEdge(oF, true);
if (fNext == null || fPrev == null || ofNext == null || ofPrev == null)
continue;
double overHang = -0.03;
if (isWall(fNext.getOther(f)))
end.add(toLF(fNext.getOther(f), overHang));
else
end.add(roofTween(fNext, se, f));
if (isWall(ofPrev.getOther(oF)))
end.add(toLF(ofPrev.getOther(oF), overHang));
else
end.add(roofTween(se, ofPrev, oF));
if (isWall(fPrev.getOther(f)))
start.add(toLF(fPrev.getOther(f), overHang));
else
start.add(roofTween(se, fPrev, f));
if (isWall(ofNext.getOther(oF)))
start.add(toLF(ofNext.getOther(oF), overHang));
else
start.add(roofTween(ofNext, se, oF));
}
Point3d s = se.getStart(f), e = se.getEnd(f);
if (end.contains(null) || start.contains(null))
continue;
Tube.tube(roof, end, start, new Line3d(new Point3d(s.x, s.z, s.y), new Point3d(e.x, e.z, e.y)), toLF(f, 0), toLF(oF, 0), new CrossGen() {
@Override
public List<Point2d> gen(Vector2d left, Vector2d right) {
Vector2d l = new Vector2d(left);
l.normalize();
Vector2d lP = new Vector2d(l.y, -l.x);
Vector2d r = new Vector2d(right);
r.normalize();
Vector2d rP = new Vector2d(-r.y, r.x);
List<Point2d> out = new ArrayList();
double width = 0.15, height = 0.03;
Vector2d rn = new Vector2d(r);
rn.negate();
// height / Math.sin ( ( Math.PI - l.angle( rn ) ) /2 );
double cenOffset = 0.02;
Vector2d cen = new Vector2d(lP);
cen.add(rP);
cen.normalize();
for (double[] coords : new double[][] { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, -width }, { 0, 0, 0, height, -width }, { 0, 0, cenOffset, 0, 0 }, { -width, height, 0, 0, 0 }, { -width, 0, 0, 0, 0 } }) {
Point2d tmp = new Point2d(l), tmp2;
tmp.scale(coords[0]);
tmp2 = new Point2d(lP);
tmp2.scale(coords[1]);
tmp.add(tmp2);
tmp2 = new Point2d(cen);
tmp2.scale(coords[2]);
tmp.add(tmp2);
tmp2 = new Point2d(rP);
tmp2.scale(coords[3]);
tmp.add(tmp2);
tmp2 = new Point2d(r);
tmp2.scale(coords[4]);
tmp.add(tmp2);
out.add(tmp);
}
return out;
}
});
}
}
}
return true;
}
use of org.twak.utils.geom.Line3d in project chordatlas by twak.
the class GISGen method initGML.
public void initGML() {
Closer<Point3d> closer = new Closer<>();
LoopL<Point3d> polies = null;
try {
polies = GMLReader.readGML3d(Tweed.toWorkspace(new File(gmlFile)), DefaultGeocentricCRS.CARTESIAN, CRS.decode(crs));
} catch (NoSuchAuthorityCodeException e) {
e.printStackTrace();
return;
} catch (FactoryException e) {
e.printStackTrace();
return;
}
Optional<Gen> hg = tweed.frame.gens(HeightGen.class).stream().findAny();
if (hg.isPresent())
for (Loop<Point3d> poly : polies) {
if (poly instanceof SuperLoop) {
SuperLoop sl = ((SuperLoop) poly);
sl.properties.putAll(((HeightGen) hg.get()).getProperties((String) sl.properties.get("name")));
}
}
for (Loop<Point3d> poly : polies) {
List<Point3d> points = new ArrayList();
for (Pair<Point3d, Point3d> pair : poly.pairs()) {
TweedSettings.settings.toOrigin.transform(pair.first());
pair.first().y = 0;
points.add(pair.first());
lines.add(new Line3d(pair.first(), pair.second()));
}
if (TweedSettings.settings.flipFootprints)
poly.reverse();
closer.add(points.toArray(new Point3d[points.size()]));
}
createBlocks(closer, polies);
}
Aggregations