/** * Convert array of hyperbolas to hyperbolas with single connected range * * @param h1 * @return */ public static Hyperbola[] singlify(Hyperbola[] h1) { DArray e = new DArray(); for (int i = 0; i < h1.length; i++) { Hyperbola hi = h1[i]; if (hi.visSeg.size() == 1) { e.add(hi); } else { for (int j = 0; j < hi.visSeg.size(); j += 2) { double t0 = hi.visSeg.getDouble(j + 0); double t1 = hi.visSeg.getDouble(j + 1); Hyperbola h = new Hyperbola(hi); h.visSeg.clear(); h.visSeg.addDouble(t0); h.visSeg.addDouble(t1); e.add(h); } } } return (Hyperbola[]) e.toArray(Hyperbola.class); }
/** * Calc possible hull from a set of polygons * * @param polySet set of polygons * @param first first polygon to include * @param last last polygon to include * @return polygon containing possible hull */ private static EdPolygon calcPHullRange(EdPolygon[] polySet, int first, int last) { final boolean db = true; int len = last + 1 - first; if (len == 1) return polySet[first]; if (len > 2) { if (db && T.update()) { DArray a = new DArray(); for (int i = first; i <= last; i++) a.add(polySet[i]); T.msg("calc possible hull of multiple polygons" + T.show(a, MyColor.cRED, STRK_THICK, -1)); } int n = len / 2; return calcPHull( calcPHullRange(polySet, first, first + n - 1), calcPHullRange(polySet, first + n, last)); } return calcPHull(polySet[first], polySet[first + 1]); }
/** * Find intersections of hyperbolic arm with a line. * * @param s0 : first point on line * @param s1 : second point on line * @param ipts : intersection points returned here */ public DArray findLineIntersect(FPoint2 s0, FPoint2 s1, DArray ipts) { if (ipts == null) ipts = new DArray(); ipts.clear(); // transform both line points to curve space FPoint2 c0 = toCurveSpace(s0, null), c1 = toCurveSpace(s1, null); double a = c0.x, b = c0.y, c = c1.x, d = c1.y; double e = d - b; double f = c - a; double D = f * f - B * e * e; double E = 2 * a * f - 2 * b * B * e; double F = a * a - A - B * b * b; Polyn q = new Polyn(D, E, F); DArray roots = new DArray(); q.solve(roots); for (int i = 0; i < roots.size(); i++) { double k = roots.getDouble(i); FPoint2 pt = // ipts.add( new FPoint2(s0.x + (s1.x - s0.x) * k, s0.y + (s1.y - s0.y) * k); // ); // Make sure this point is actually on the arm. FPoint2 cpt = toCurveSpace(pt, null); if (cpt.x < 0) { continue; } ipts.add(pt); } return ipts; }
/** * Find intersections of hyperbolic arm with an axes-aligned line segment. Arm must intersect * segment, not its underlying (infinite) line. The intersection points are sorted into increasing * parameter values w.r.t. the arm. * * @param s0 : start of line segment * @param s1 : end of line segment * @param ipts : intersection points returned here * @param reverseOrder : if true, points are sorted by decreasing parameter values * @param dbFlag : true to print debug information */ public void findOrthogonalIntersect( FPoint2 s0, FPoint2 s1, DArray ipts, boolean reverseOrder, boolean dbFlag) { final boolean db = true && dbFlag; if (db) { System.out.println( "findOrthogonalIntersect " + s0 + " -> " + s1 + " rev:" + Tools.f(reverseOrder)); } // Determine whether this is a vertical or horizontal line segment. boolean vert = (Math.abs(s1.y - s0.y) > Math.abs(s1.x - s0.x)); if (db) { System.out.println(" vert=" + Tools.f(vert)); } // Find the quadratic to solve. Polyn p; PlaneCurve cv = getCurve(); if (vert) { p = cv.solveForX(s0.x); } else { p = cv.solveForY(s0.y); } DArray lst = new DArray(); p.solve(lst); if (db) { System.out.println(" curve=" + cv.toString(true)); System.out.println(" polyn=" + p.toString(true)); System.out.println(" roots=" + Tools.d(lst)); } // Sort points, discarding those not on line segment, // and those not on the correct arm. ipts.clear(); for (int i = 0; i < lst.size(); i++) { double ta = lst.getDouble(i); FPoint2 pt; if (vert) { pt = new FPoint2(s0.x, ta); } else { pt = new FPoint2(ta, s0.y); } if (db) { System.out.println(" position on arm for ta=" + ta + " is " + pt); } double t = MyMath.positionOnSegment(pt, s0, s1); if (db) { System.out.println(" pt=" + pt + " t=" + t); } if (t < 0 || t > 1) { if (db) { System.out.println(" not on segment, skipping"); } continue; } FPoint2 cpt = toCurveSpace(pt, null); if (db) { System.out.println(" curveSpace=" + cpt); } if (cpt.x < 0) { if (db) { System.out.println(" skipping..."); } continue; } double t1 = calcParameter(pt); int j = 0; while (true) { if (j == ipts.size()) { break; } double t2 = calcParameter(ipts.getFPoint2(j)); if (!reverseOrder) { if (t1 < t2) { break; } } else if (t1 > t2) { break; } j++; } ipts.add(j, pt); } if (db) { System.out.println(" ipts=" + Tools.d(ipts)); } }
/** * Find intersections between two hyperbolas * * @param a Hyperbola * @param b Hyperbola * @param iPts where to store intersection points; null to construct */ public static DArray findIntersections(Hyperbola a, Hyperbola b, DArray iPts) { final boolean db = false; if (iPts == null) iPts = new DArray(); iPts.clear(); final DArray jPts = new DArray(); // a.initClipIfNec(); // b.initClipIfNec(); if (db) { System.out.println( "finding intersections between:\n" + a.toString(true) + "\n" + b.toString(true)); } PlaneCurve.findIntersect(a.getCurve(), b.getCurve(), jPts); // filter out false intersections if (db) { System.out.println("prefilter # intersections= " + jPts.size()); } FPoint2 ptc = new FPoint2(); for (int i = 0; i < jPts.size(); i++) { FPoint2 pt = jPts.getFPoint2(i); // make sure calculated intersect point is actually on both arms { FPoint2 data = a.calcParameterAndDistance(pt); if (data.y > .001) continue; data = b.calcParameterAndDistance(pt); if (data.y > .001) continue; } if (!a.isLine()) { // put in curve space to verify it's to the right of the y axis a.toCurveSpace(pt, ptc); if (db) { System.out.println("Filter " + i + " in curveA= " + ptc); } if (ptc.x <= 0) { if (db) { System.out.println(" < 0"); } continue; } } if (!b.isLine()) { b.toCurveSpace(pt, ptc); if (db) { System.out.println(" in curveB= " + ptc); } if (ptc.x <= 0) { if (db) { System.out.println(" < 0"); } continue; } } if (db) { System.out.println(" adding " + pt); } iPts.add(pt); } return iPts; }
private static void OLDexpandHull( PtEntry convHullEntry, PtEntry aHull, PtEntry bHull, boolean ccw) { boolean db__OLD = C.vb(DB_HULLEXPAND); if (db__OLD && T.update()) T.msg("expandHull" + T.show(convHullEntry) + " ccw=" + ccw); PtEntry[] opp = new PtEntry[2]; opp[0] = aHull; opp[1] = bHull; PtEntry old____hEnt = convHullEntry; boolean advanced = false; do { if (old____hEnt != convHullEntry) advanced = true; inf.update(); if (old____hEnt.source() == null) { if (db__OLD && T.update()) T.msg("expandHull, source unknown, guaranteed not convex" + T.show(old____hEnt)); old____hEnt = old____hEnt.next(ccw); continue; } int w = (old____hEnt.source() == opp[0].source()) ? 1 : 0; PtEntry oppEnt = opp[w]; boolean isTangent = !COper3.right(old____hEnt, oppEnt, oppEnt.next(true), ccw) && !COper3.right(old____hEnt, oppEnt, oppEnt.prev(true), ccw); if (!isTangent) { if (db__OLD && T.update()) T.msg( "expandHull, advance tangent line" + T.show(oppEnt.toPolygon(), MyColor.cDARKGRAY, -1, MARK_X) + T.show(old____hEnt) + tl(old____hEnt, oppEnt)); opp[w] = oppEnt.next(ccw); continue; } if (COper3.left(old____hEnt, oppEnt, old____hEnt.next(ccw), ccw) && COper3.left(old____hEnt, oppEnt, old____hEnt.prev(ccw), ccw)) { DArray dispPts = new DArray(); // delete points until cross tangent line PtEntry next = old____hEnt.next(ccw); while (true) { PtEntry prev = next; dispPts.add(prev); next = prev.delete(ccw); inf.update(); if (COper3.right(old____hEnt, oppEnt, next, ccw)) { FPoint2 cross = MyMath.linesIntersection(old____hEnt, oppEnt, prev, next, null); old____hEnt = old____hEnt.insert(new PtEntry(cross), ccw); if (db__OLD && T.update()) T.msg( "expandHull, clipped to shadow region" + tl(old____hEnt, oppEnt) + T.show(old____hEnt) + T.show(dispPts)); break; } } } else { if (db__OLD && T.update()) T.msg( "expandHull, not dipping into shadow region" + T.show(old____hEnt.next(ccw)) + tl(old____hEnt, oppEnt)); } old____hEnt = old____hEnt.next(ccw); } while (!advanced || old____hEnt != convHullEntry); }
/** * Apply hull expansion procedure * * @param convHullEntry an entry of the hull (should be on the convex hull, so it is not deleted * or replaced and is still valid for subsequent calls) * @param aHull entry on convex hull of polygon A * @param bHull entry on convex hull of polygon B * @param ccw true to move in ccw direction, else cw */ private static void expandHull(PtEntry convHullEntry, PtEntry aHull, PtEntry bHull, boolean ccw) { if (C.vb(OLDMETHOD)) { OLDexpandHull(convHullEntry, aHull, bHull, ccw); return; } boolean db = C.vb(DB_HULLEXPAND); if (db && T.update()) T.msg("expandHull" + T.show(convHullEntry) + " ccw=" + ccw); // tangent points for A, B PtEntry[] tangentPoints = new PtEntry[2]; tangentPoints[0] = aHull; tangentPoints[1] = bHull; PtEntry hEnt = convHullEntry; do { inf.update(); // calculate tangent ray R PtEntry tangentPt = null; while (true) { int tanIndex = (hEnt.source() == tangentPoints[0].source()) ? 1 : 0; tangentPt = tangentPoints[tanIndex]; if (!COper3.right(hEnt, tangentPt, tangentPt.next(true), ccw) && !COper3.right(hEnt, tangentPt, tangentPt.prev(true), ccw)) break; tangentPt = tangentPt.next(ccw); if (db && T.update()) T.msg( "expandHull, advance tangent line" + T.show(tangentPt.toPolygon(), MyColor.cDARKGRAY, -1, MARK_DISC) + T.show(hEnt) + tl(hEnt, tangentPt)); tangentPoints[tanIndex] = tangentPt; } if (COper3.left(hEnt, tangentPt, hEnt.next(ccw), ccw)) { DArray dispPts = new DArray(); // delete points until cross tangent line PtEntry next = hEnt.next(ccw); while (true) { PtEntry prev = next; dispPts.add(prev); next = prev.delete(ccw); if (COper3.right(hEnt, tangentPt, next, ccw)) { FPoint2 cross = MyMath.linesIntersection(hEnt, tangentPt, prev, next, null); hEnt = hEnt.insert(new PtEntry(cross), ccw); if (db && T.update()) T.msg( "expandHull, clipped to shadow region" + tl(hEnt, tangentPt) + T.show(hEnt) + T.show(dispPts)); break; } } } else { if (db && T.update()) T.msg( "expandHull, not dipping into shadow region" + T.show(hEnt.next(ccw)) + tl(hEnt, tangentPt)); } while (true) { hEnt = hEnt.next(ccw); if (COper3.left(hEnt.prev(ccw), hEnt, hEnt.next(ccw), ccw)) break; if (db && T.update()) T.msg("skipping reflex vertex" + T.show(hEnt)); } } while (hEnt != convHullEntry); }