use of javax.vecmath.Point2d in project chordatlas by twak.
the class Prof method parameterize.
public static // all profs from a single profile-edge are in the same 2D space, with strange x-origin
Prof parameterize(// all profs from a single profile-edge are in the same 2D space, with strange x-origin
List<Prof> in) {
// double toProfileEdge;
// {
// Prof eg = in.iterator().next();
// Point3d p = Pointz.to3( profileEdge.start );
// toProfileEdge = eg.to2d( p ).x;
// }
double avgMinY = in.stream().filter(p -> p != null).mapToDouble(p -> p.get(0).y).average().getAsDouble();
Set<Line> lines = new HashSet<>();
for (Prof p : in) for (int i = 1; i < p.size(); i++) lines.add(new Line(p.get(i - 1), p.get(i)));
SliceParameters P = new SliceParameters(5);
P.FL_REGRESS = true;
P.FL_BINS = 20;
// double A = 0.4; // simple = 0.4
// double B = 0.1; // simple = 1;
// simple = 0.4
double A = 0.2;
// simple = 0.1;
double B = 0.3;
// simple = 0.1; rotate threshold, radians
double C = 0.1;
double firstFloorHeight = 2;
P.MIN_LINES = Math.max(1, in.size() * A);
lines = new FindLines(lines, P) {
protected double nextAngle(Set<Line> remaining, int iteration) {
double delta = Math.PI / P.FL_BINS;
// angle bin
Bin<Line> aBin = new Bin(-Math.PI - delta, Math.PI + delta, P.FL_BINS * 2, true);
for (Line l : remaining) {
double len = l.length();
double angle = l.aTan2();
aBin.add(angle, len, l);
}
// return MUtils.PI2;
if (iteration < 1 && aBin.getWeight(Mathz.PI2) >= 10)
return Mathz.PI2;
int aBinI = aBin.maxI();
return aBin.val(aBinI);
}
protected double getTolNearLine(Point2d p) {
return P.FL_NEAR_LINE * (p.y < avgMinY + firstFloorHeight ? 5 : B);
}
protected double getTolNearLine2(Point2d p) {
return P.FL_NEAR_LINE_2 * (p.y < avgMinY + firstFloorHeight ? 10 : B);
}
protected double getTolRemoveAngle(Line l) {
return l.start.y < avgMinY + firstFloorHeight ? Math.PI * 0.5 : Math.PI * 0.2;
}
}.result.all;
List<Line> llines = // is rubbish
lines.stream().filter(l -> l.lengthSquared() > 0.001).filter(// is floor polygon
l -> l.end.y > avgMinY + 1 || Math.abs(l.start.y - l.end.y) > 0.1).collect(Collectors.toList());
Prof clean = new Prof(in.get(in.size() / 2));
clean.clear();
if (llines.isEmpty()) {
clean.add(new Point2d(0, 0));
clean.add(new Point2d(0, 1));
return clean;
}
for (int i = 0; i < llines.size(); i++) {
Line l = llines.get(i);
double angle = l.aTan2();
if (angle < Mathz.PI2 + C && angle > Mathz.PI2 - C)
llines.set(i, FindLines.rotateToAngle(l, l.fromPPram(0.5), Mathz.PI2));
}
// llines.stream().filter( l -> l.start.y > l.end.y ).forEach( l -> l.reverseLocal() );
Collections.sort(llines, new Comparator<Line>() {
public int compare(Line o1, Line o2) {
return Double.compare(o1.fromPPram(0.2).y, o2.fromPPram(0.2).y);
}
});
// for (Line l : llines)
// PaintThing.debug( new Color(170,0,255), 2f, new Line( l.start.x+5, -l.start.y, l.end.x+5, -l.end.y ) );
Line lastL = null;
Point2d lastP = new Point2d(0, -Double.MAX_VALUE);
for (Line l : llines) {
// if (c >= 6)
// continue;
// if ( c== 5)
// System.out.println("here");
// c++;
Point2d mid = l.fromPPram(0.5);
if (!(lastL != null && !lastL.isOnLeft(mid) || (lastP.y == -Double.MAX_VALUE || (mid.y >= lastP.y - 0.5 && mid.x <= lastP.x + 0.5))))
continue;
boolean startAbove = l.start.y >= lastP.y && l.start.x <= lastP.x, endAbove = l.end.y >= lastP.y && l.end.x <= lastP.x;
if (l.end.y < l.start.y)
l.end.y = l.start.y;
if (startAbove && endAbove) {
// okay
} else {
if (lastL != null && l.start.distanceSquared(lastP) < 9) {
Point2d sec = lastL.intersects(l, false);
if (sec != null && sec.distanceSquared(lastP) < 9 && sec.x <= lastL.start.x && sec.y >= lastL.start.y) {
clean.remove(clean.size() - 1);
clean.add(sec);
lastP = sec;
l.start = sec;
} else if (l.start.x < lastP.x) {
sec = new LinearForm(new Vector2d(1, 0)).findC(l.start).intersect(new LinearForm(lastL));
if (sec != null && sec.distanceSquared(lastP) < 9) {
clean.remove(clean.size() - 1);
clean.add(sec);
lastP = sec;
}
}
}
if (l.start.x > lastP.x + 0.01 || l.end.x > lastP.x + 0.01) {
Point2d sec = new LinearForm(new Vector2d(0, 1)).findC(new Point2d(lastP.x, 0)).intersect(new LinearForm(l));
if (sec != null && sec.distanceSquared(lastP) < 9 && sec.distanceSquared(l.start) < 9) {
if (l.start.x > lastP.x)
l.start = sec;
else
l.end = sec;
}
}
}
if (lastL != null && l.start.distanceSquared(lastP) < 4) {
Point2d sec = lastL.intersects(l, false);
if (sec != null && (sec.distanceSquared(lastP) < 4 || Math.abs(sec.y - lastP.y) < 1) && sec.x <= lastL.start.x && sec.y >= lastL.start.y) {
clean.remove(clean.size() - 1);
clean.add(sec);
lastP = sec;
l.start = sec;
} else if (l.start.x < lastP.x) {
sec = new LinearForm(new Vector2d(1, 0)).findC(l.start).intersect(new LinearForm(lastL));
if (sec != null && (sec.distanceSquared(lastP) < 4 || Math.abs(sec.y - lastP.y) < 1)) {
clean.remove(clean.size() - 1);
clean.add(sec);
lastP = sec;
// l.start = sec;
}
}
}
if (lastP.y - l.end.y < 3 && l.end.x - lastP.x < 3) {
for (Point2d pt : l.points()) {
pt.x = Math.min(pt.x, lastP.x);
pt.y = Math.max(pt.y, lastP.y);
}
if (!l.start.equals(l.end))
for (Point2d pt : l.points()) {
// if (c == 2)
// PaintThing.debug.put(1, new Point2d ( pt.x, -pt.y ) );
pt = new Point2d(pt);
pt.x = Math.min(pt.x, lastP.x);
pt.y = Mathz.max(0, pt.y, lastP.y);
if (clean.isEmpty() && pt.y > 0.2) {
clean.add(new Point2d(pt.x, 0));
}
if (lastP != null && pt.distanceSquared(lastP) > 0.02) {
clean.add(pt);
}
lastP = clean.get(clean.size() - 1);
if (clean.size() >= 3) {
Point2d a = clean.get(clean.size() - 1), b = clean.get(clean.size() - 2), c = clean.get(clean.size() - 3);
if (Math.abs(Mathz.area(c, b, a)) < 0.1 || Mathz.absAngleBetween(a, b, c) < 0.1)
clean.remove(clean.size() - 2);
}
}
}
if (clean.size() >= 2)
lastL = new Line(clean.get(clean.size() - 2), clean.get(clean.size() - 1));
}
return clean;
}
use of javax.vecmath.Point2d in project chordatlas by twak.
the class Prof method findProfileLines.
/**
* We find an initial base offset. Then we cluster the start point of all
* (clean) profiles. If any are a good distance from the initial base, we
* add those as their own profile lines.
*
* The original line is offset by the remaiing data.
*/
public static List<SuperLine> findProfileLines(Collection<Prof> profiles, Line3d line) {
List<SuperLine> out = new ArrayList();
// PaintThing.debug.clear();
SuperLine superLine = new SuperLine(line.start.x, line.start.z, line.end.x, line.end.z);
double outLen = superLine.length();
double min = Double.MAX_VALUE, max = -Double.MAX_VALUE;
Cache<Prof, Double> vLength = new Cache<Prof, Double>() {
@Override
public Double create(Prof i) {
return i.verticalLength(0.5);
}
};
double vLen = profiles.stream().mapToDouble(p -> vLength.get(p)).sum();
boolean useVertical = vLen / profiles.size() > 1;
class Wrapper implements Clusterable {
double[] pt;
public Wrapper(Point2d pt) {
this.pt = new double[] { pt.x, pt.y };
}
@Override
public double[] getPoint() {
return pt;
}
}
List<Wrapper> toCluster = new ArrayList();
List<Double> baseLineOffset = new ArrayList();
for (Prof p : profiles) {
if (// vLen / (5*profiles.size()))
useVertical && vLength.get(p) < 1)
continue;
Prof clean = p.parameterize();
Point2d pt = clean.get(0);
Point3d pt3 = clean.to3d(pt);
double ppram = superLine.findPPram(new Point2d(pt3.x, pt3.z));
baseLineOffset.add(pt.x);
toCluster.add(new Wrapper(new Point2d(pt.x, ppram * outLen)));
min = Math.min(min, ppram);
max = Math.max(max, ppram);
}
if (min == max || toCluster.isEmpty())
return out;
if (true) {
baseLineOffset.sort(Double::compareTo);
double modeBaselineOffset = baseLineOffset.get(baseLineOffset.size() / 2);
DBSCANClusterer<Wrapper> cr = new DBSCANClusterer<>(1.5, 0);
List<Cluster<Wrapper>> results = cr.cluster(toCluster);
Iterator<Cluster<Wrapper>> cit = results.iterator();
while (cit.hasNext()) {
Cluster<Wrapper> cw = cit.next();
if (cw.getPoints().size() < 2 / TweedSettings.settings.profileHSampleDist) {
cit.remove();
double cMeanY = cw.getPoints().stream().mapToDouble(x -> x.pt[1]).average().getAsDouble();
double bestDist = Double.MAX_VALUE;
Cluster<Wrapper> bestWrapper = null;
for (Cluster<Wrapper> near : results) {
double meanY = near.getPoints().stream().mapToDouble(x -> x.pt[1]).average().getAsDouble();
double dist = Math.abs(meanY - cMeanY);
if (dist < bestDist) {
bestDist = dist;
bestWrapper = near;
}
}
if (bestWrapper != null)
bestWrapper.getPoints().addAll(cw.getPoints());
}
}
{
baseLineOffset.clear();
int c = 0;
for (Cluster<Wrapper> cw : results) {
double[] minMax = cw.getPoints().stream().map(p -> new double[] { p.pt[1] }).collect(new InAxDoubleArray());
double[] offsetA = cw.getPoints().stream().mapToDouble(p -> p.pt[0]).sorted().toArray();
double offset = offsetA[offsetA.length / 2];
if (offset - modeBaselineOffset < 1) {
for (Wrapper w : cw.getPoints()) baseLineOffset.add(w.pt[0]);
continue;
}
SuperLine sl = new SuperLine(superLine.fromPPram(minMax[0] / outLen), superLine.fromPPram(minMax[1] / outLen));
sl.moveLeft(offset);
out.add(sl);
List<Point2d> pts = cw.getPoints().stream().map(w -> new Point2d(w.pt[0], w.pt[1])).collect(Collectors.toList());
PaintThing.debug(Rainbow.getColour(c++), 1, pts);
}
}
}
Point2d nStart = superLine.fromPPram(min), nEnd = superLine.fromPPram(max);
superLine.start = nStart;
superLine.end = nEnd;
baseLineOffset.sort(Double::compare);
if (!baseLineOffset.isEmpty())
superLine.moveLeft(baseLineOffset.get(baseLineOffset.size() / 2));
out.add(0, superLine);
return out;
}
use of javax.vecmath.Point2d in project chordatlas by twak.
the class Prof method findRoofLine.
public Point2d findRoofLine() {
double nonVertRun = 0;
Line up = new Line(0, 0, 0, 1);
Point2d runStart = null;
for (Pair<Point2d, Point2d> line : new ConsecutivePairs<>(this, false)) {
Line l = new Line(line.first(), line.second());
double angle = l.absAngle(up);
if (angle > Math.PI / 6 && angle < Math.PI) {
if (nonVertRun == 0)
runStart = l.start;
nonVertRun += l.length();
} else {
if (nonVertRun > 2 && runStart != null)
return runStart;
nonVertRun = 0;
}
}
return runStart == null ? get(size() - 1) : runStart;
}
use of javax.vecmath.Point2d in project chordatlas by twak.
the class Prof method retarget.
public static Prof retarget(Prof p, SuperLine profileLine) {
Line3d l = new Line3d(Pointz.to3(profileLine));
Prof out = buildProfile(new Line3d(Pointz.to3(profileLine)), l.closestPointOn(p.to3d(p.get(0)), false));
for (Point2d p2 : p) out.add(p.to3d(p2));
return out;
}
use of javax.vecmath.Point2d in project chordatlas by twak.
the class Prof method createCap.
public void createCap(double height) {
{
Line last = new Line(get(size() - 2), get(size() - 1));
if (last.start.y == last.end.y && last.end.y < height)
return;
}
for (int i = 0; i < size() - 1; i++) {
Line l = new Line(get(i), get(i + 1));
if (l.start.y > height) {
remove(i);
i--;
continue;
} else if (l.end.y > height) {
l.end.x = l.xAtY(height);
l.end.y = height;
}
}
Point2d end = get(size() - 1);
if (end.y != height) {
end.x = new Line(get(size() - 2), get(size() - 1)).xAtY(height);
end.y = height;
}
add(new Point2d(end.x - 1, height));
}
Aggregations