/** * Clip out a section of the arm, using internal parameter values * * @param c0 : start of section to clip out * @param c1 : end of section to clip out; if < c0, c0 & c1 are swapped */ private void clip0(double c0, double c1) { final boolean db = false; if (c0 > c1) { double t = c0; c0 = c1; c1 = t; } // array to store new clip elements in DArray nc = new DArray(); if (db) { System.out.println("clip " + Tools.f(c0) + "..." + Tools.f(c1)); } for (int i = 0; i < visSeg.size(); i += 2) { double t0 = visSeg.getDouble(i), t1 = visSeg.getDouble(i + 1); if (db) { System.out.println(" seg " + i + " " + Tools.f(t0) + "..." + Tools.f(t1)); } // if this seg is outside clip region, leave intact (add it) if (t0 >= c1 || t1 <= c0) { nc.addDouble(t0); nc.addDouble(t1); continue; } if (t0 >= c0 && t1 <= c1) { if (db) { System.out.println(" clipping entire segment"); } // remove entire segment, by skipping it continue; } // add unclipped portion if (t0 < c0) { nc.addDouble(t0); nc.addDouble(c0); } if (t1 > c1) { nc.addDouble(c1); nc.addDouble(t1); } } visSeg = nc; if (db) { System.out.println(" after clipping:" + visSeg); } }
/** * Determine closest point on hyperbolic arm to a point pt * * @param pt : point * @return t value for closest point; not necessarily within clipped range */ public double closestPointTo(FPoint2 pt) { final boolean db = false; pt = toCurveSpace(pt, null); double U = B + 1; double V = -pt.y; double W = B * pt.x; Polyn p = new Polyn( // B * U * U, // 2 * B * U * V, // B * V * V + A * U * U - W * W, // 2 * A * U * V, // A * V * V // ); if (db) Streams.out.println("closestPointTo, pt=" + pt + "\n" + p); double ret = 0; try { DArray r = new DArray(); if (Math.abs(p.c(0)) < 1e-5) r.addDouble(0); else p.solve(r); if (r.isEmpty()) { throw new FPError("can't find closest point, poly=\n" + p); } double bestDist = 0; for (int i = 0; i < r.size(); i++) { double t = r.getDouble(i); FPoint2 apt = calcPoint(t); double dist = apt.distance(pt); if (i == 0 || dist < bestDist) { bestDist = dist; ret = t; } } } catch (FPError e) { Tools.warn("caught FPError"); // Streams.out.println("caught:\n" + e); ret = (this.minParameter() + this.maxParameter()) * .5; } return ret; }
/** * 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]); }
/** * Build an array of <? extends {@link solver.variables.Variable}>. </br>WARNING: array's indice * are from 1 to n. * * @param name name of the array of variables.</br> Each variable is named like {@code name}_i. * @param type {@link parser.flatzinc.ast.declaration.DArray} object. * @param earr array of {@link parser.flatzinc.ast.expression.Expression} * @param map * @param solver */ private static void buildWithDArray( String name, DArray type, Expression expression, EArray earr, THashMap<String, Object> map, Solver solver) { final DInt2 index = (DInt2) type.getIndex(0); // no need to get lowB, it is always 1 (see specification of FZN for more informations) final int size = index.getUpp(); final Declaration what = type.getWhat(); switch (what.typeOf) { case BOOL: final BoolVar[] bs = new BoolVar[size]; for (int i = 0; i < size; i++) { bs[i] = earr.getWhat_i(i).boolVarValue(solver); } map.put(name, bs); break; case INT: case INT2: case INTN: final IntVar[] vs = new IntVar[size]; for (int i = 0; i < size; i++) { vs[i] = earr.getWhat_i(i).intVarValue(solver); } map.put(name, vs); break; case SET: // final SetVariable[] svs = new SetVariable[size]; // for (int i = 0; i < size; i++) { // svs[i] = earr.getWhat_i(i).setVarValue(); // } // map.put(name, svs); Exit.log("SET VAR"); break; default: break; } }
/** * 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); }
/** * 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)); } }
public void render(Color c, int stroke, int markType) { final boolean db = false; // Get array of visible segments. If no such array exists, // use default. DArray vseg = visSeg; boolean dashed = false; // if (step == 0) { double step = renderStep(); // } // vp V = TestBed.view(); if (db) Streams.out.println(" step=" + step); // plot each visible segment for (int seg = 0; seg < vseg.size(); seg += 2) { double t0 = vseg.getDouble(seg + 0), t1 = vseg.getDouble(seg + 1); t0 = MyMath.clamp(t0, -500.0, 500.0); t1 = MyMath.clamp(t1, -500.0, 500.0); // render() expects external parameters. double s0 = toExt(t0), s1 = toExt(t1); if (s0 > s1) { double tmp = s0; s0 = s1; s1 = tmp; } FPoint2 p0 = calcPoint(s0), p1 = calcPoint(s1); if (db) Streams.out.println(" p0=" + p0 + ", p1=" + p1); if (isLine() && !dashed) { V.drawLine(p0, p1); } else { /* if (Math.abs(s0) >= 500 ||Math.abs(s1) >= 500) System.out.println("Rendering "+t0+" to "+t1+" step "+step); */ if (dashed) V.pushStroke(Globals.STRK_RUBBERBAND); { // int count = 0; boolean first = true; for (double t = t0; ; t += step) { // , count++) { boolean last = (t >= t1); if (last) { t = t1; } calcPointInternal(t, p1); if (!p1.isValid()) { if (last) { break; } continue; } if (db) { System.out.println(" calcPt " + Tools.f(toExt(t)) + " = " + p1.x + "," + p1.y); } if (!first) { V.drawLine(p0, p1); if (false) { Tools.warn("highlighting int"); V.mark(p0); } } if (last) { break; } p0.setLocation(p1); first = false; } } if (dashed) V.popStroke(); } } }
/** * 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; }
/** * Constructor * * @param f1 FPoint2 * @param f2 FPoint2 * @param pt FPoint2, or null for bisector */ private void construct(FPoint2 f1, FPoint2 f2, FPoint2 pt) { // userData[LEFT] = new DArray(); // userData[RIGHT] =new DArray(); final boolean db = false; if (db) { System.out.println("Hyperbola constructor\n f1=" + f1 + "\n f2=" + f2 + "\n pt=" + pt); } boolean bisector = (pt == null); initializeVisibleSegments(); // if point on arm is closer to f2 than f1, swap f1 & f2. if (!bisector && FPoint2.distanceSquared(f1, pt) > FPoint2.distanceSquared(f2, pt)) { flipped = true; } this.foci[RIGHT] = new FPoint2(f1); this.foci[LEFT] = new FPoint2(f2); if (!bisector) { this.pt = new FPoint2(pt); } double fociDist = FPoint2.distance(f1, f2); if (fociDist == 0) { throw new FPError("Hyperbola foci are same point"); } c = fociDist * .5; // calculate the translation of the hyperbola away from // standard position. FPoint2 rFocus = getFocus(0), lFocus = getFocus(1); origin = new FPoint2(.5 * (rFocus.x + lFocus.x), .5 * (rFocus.y + lFocus.y)); // calculate the angle of rotation of the hyperbola away // from the standard position. double theta = Math.atan2(rFocus.y - lFocus.y, rFocus.x - lFocus.x); Matrix fromCenterInW = Matrix.getTranslate(origin, true); Matrix rotToE = Matrix.getRotate(-theta); toE2 = rotToE; Matrix.mult(toE2, fromCenterInW, toE2); // calculate inverse toW2 = toE2.invert(null); // Matrix toCenterInW = Matrix.translationMatrix(origin, false); // Matrix rotToW = Matrix.getRotate2D(theta); // // toW2 = toCenterInW; // Matrix.mult(toW2, rotToW, toW2); // Tools.warn("just invert matrix here"); // if (bisector) { valid = true; } else { // get the arm point in hyperbola space. FPoint2 workPt = toE2.apply(pt, null); double xs = workPt.x * workPt.x; double cs = c * c; Polyn q = new Polyn(1, -(cs + xs + workPt.y * workPt.y), cs * xs); if (db) { System.out.println("a2 quadratic:\n" + q); } final DArray qsoln = new DArray(); q.solve(qsoln); if (db) { Streams.out.println(qsoln); } double val = q.c(1) * -.5; int ql = qsoln.size(); if (ql >= 1) { val = qsoln.getDouble(0); } // choose the root that is less than c*c. if (ql == 2) { if (val > qsoln.getDouble(1)) { val = qsoln.getDouble(1); if (db) { System.out.println(" two roots, choosing smaller."); } } } if (db) { System.out.println(" root chosen=" + val); } a = Polyn.sqrt(val); A = a * a; B = A / (c * c - A); } valid = true; if (db) { System.out.println(" ==> " + this); } }
private static void test_dds() { System.out.println("DDS test:"); DataDDS table = new DataDDS(new ServerVersion(2, 16)); table.setName("test_table"); // add variables to it DUInt32 myUInt = new DUInt32("myUInt"); myUInt.setValue(42); table.addVariable(myUInt); // note that arrays and lists take their name from the addVariable method DArray myArray = new DArray(); myArray.addVariable(new DByte("myArray")); myArray.appendDim(10, "dummy"); myArray.setLength(10); BytePrimitiveVector bpv = (BytePrimitiveVector) myArray.getPrimitiveVector(); for (int i = 0; i < 10; i++) bpv.setValue(i, (byte) (i * 10)); table.addVariable(myArray); DList myList = new DList(); myList.addVariable(new DURL("myList")); myList.setLength(10); BaseTypePrimitiveVector btpv = (BaseTypePrimitiveVector) myList.getPrimitiveVector(); for (int i = 0; i < 10; i++) { DURL testURL = new DURL(); testURL.setValue("http://" + i); btpv.setValue(i, testURL); } table.addVariable(myList); DStructure myStructure = new DStructure("myStructure"); DFloat64 structFloat = new DFloat64("structFloat"); structFloat.setValue(42.0); myStructure.addVariable(structFloat); DString structString = new DString("structString"); structString.setValue("test value"); myStructure.addVariable(structString); table.addVariable(myStructure); DGrid myGrid = new DGrid("myGrid"); DArray gridArray = (DArray) myArray.clone(); gridArray.setName("gridArray"); myGrid.addVariable(gridArray, DGrid.ARRAY); DArray gridMap = new DArray(); gridMap.addVariable(new DInt32("gridMap")); gridMap.appendDim(10, "dummy"); gridMap.setLength(10); Int32PrimitiveVector ipv = (Int32PrimitiveVector) gridMap.getPrimitiveVector(); for (int i = 0; i < 10; i++) ipv.setValue(i, i * 10); myGrid.addVariable(gridMap, DGrid.MAPS); table.addVariable(myGrid); // this is the one case where two DODS variables can have the same name: // each row should have the same exact variables (name doesn't matter) DSequence mySequence = new DSequence("mySequence"); mySequence.addVariable(new DInt32("seqInt32")); mySequence.addVariable(new DString("seqString")); Vector seqRow = new Vector(); // a row of the sequence DInt32 seqVar1 = new DInt32("seqInt32"); seqVar1.setValue(1); seqRow.addElement(seqVar1); DString seqVar2 = new DString("seqString"); seqVar2.setValue("string"); seqRow.addElement(seqVar2); mySequence.addRow(seqRow); seqRow = new Vector(); // add a second row seqVar1 = new DInt32("seqInt32"); seqVar1.setValue(3); seqRow.addElement(seqVar1); seqVar2 = new DString("seqString"); seqVar2.setValue("another string"); seqRow.addElement(seqVar2); mySequence.addRow(seqRow); table.addVariable(mySequence); try { table.checkSemantics(); System.out.println("DDS passed semantic check"); } catch (BadSemanticsException e) { System.out.println("DDS failed semantic check:\n" + e); } try { table.checkSemantics(true); System.out.println("DDS passed full semantic check"); } catch (BadSemanticsException e) { System.out.println("DDS failed full semantic check:\n" + e); } // print the declarations System.out.println("declarations:"); table.print(System.out); // print the data System.out.println("\nData:"); table.printVal(System.out); System.out.println(); // and read it programmatically try { int testValue1 = ((DUInt32) table.getVariable("myUInt")).getValue(); System.out.println("myUInt = " + testValue1); byte testValue2 = ((BytePrimitiveVector) ((DArray) table.getVariable("myArray")).getPrimitiveVector()) .getValue(5); System.out.println("myArray[5] = " + testValue2); String testValue3 = ((DString) ((BaseTypePrimitiveVector) ((DList) table.getVariable("myList")).getPrimitiveVector()) .getValue(5)) .getValue(); System.out.println("myList[5] = " + testValue3); double testValue4 = ((DFloat64) ((DStructure) table.getVariable("myStructure")).getVariable("structFloat")) .getValue(); System.out.println("myStructure.structFloat = " + testValue4); int testValue5 = ((Int32PrimitiveVector) ((DArray) ((DGrid) table.getVariable("myGrid")).getVariable("gridMap")) .getPrimitiveVector()) .getValue(5); System.out.println("myGrid.gridMap[5] = " + testValue5); String testValue7 = ((DString) ((DSequence) table.getVariable("mySequence")).getVariable(0, "seqString")) .getValue(); System.out.println("mySequence[0].seqString = " + testValue7); } catch (NoSuchVariableException e) { System.out.println("Error getting variable:\n" + e); } System.out.println(); DataDDS table2 = (DataDDS) table.clone(); // test Cloneable interface try { table2.checkSemantics(); System.out.println("DDS passed semantic check"); } catch (BadSemanticsException e) { System.out.println("DDS failed semantic check:\n" + e); } try { table2.checkSemantics(true); System.out.println("DDS passed full semantic check"); } catch (BadSemanticsException e) { System.out.println("DDS failed full semantic check:\n" + e); } // print the declarations and data System.out.println("clone declarations:"); table2.print(System.out); System.out.println("\nData:"); table2.printVal(System.out); System.out.println(); // add some values to the original table DInt32 myNewInt = new DInt32("myNewInt"); myNewInt.setValue(420); table.addVariable(myNewInt); // verify that they aren't in the cloned table try { DInt32 testInt = (DInt32) table2.getVariable("myNewInt"); System.out.println("Error: value from table in table2"); } catch (NoSuchVariableException e) { System.out.println("Variable cloning looks good"); } }
/** * Build an array of <? extends {@link solver.variables.Variable}>. </br>WARNING: array's indice * are from 1 to n. * * @param name name of the array of variables.</br> Each variable is named like {@code name}_i. * @param type {@link parser.flatzinc.ast.declaration.DArray} object. * @param map * @param solver */ private static void buildWithDArray( String name, DArray type, Expression expression, THashMap<String, Object> map, Solver solver) { final DInt2 index = (DInt2) type.getIndex(0); // no need to get lowB, it is always 1 (see specification of FZN for more informations) final int size = index.getUpp(); final Declaration what = type.getWhat(); final IntVar[] vs; switch (what.typeOf) { case BOOL: BoolVar[] bs = new BoolVar[size]; if (expression == null) { for (int i = 1; i <= size; i++) { bs[i - 1] = buildWithBool(name + '_' + i, expression, map, solver); } } else if (expression.getTypeOf().equals(Expression.EType.ARR)) { EArray array = (EArray) expression; // build the array for (int i = 0; i < size; i++) { bs[i] = array.getWhat_i(i).boolVarValue(solver); } } map.put(name, bs); break; case INT: vs = new IntVar[size]; if (expression == null) { for (int i = 1; i <= size; i++) { vs[i - 1] = buildWithInt(name + '_' + i, null, map, solver); } } else if (expression.getTypeOf().equals(Expression.EType.ARR)) { buildFromIntArray(vs, (EArray) expression, size, solver); } map.put(name, vs); break; case INT2: vs = new IntVar[size]; if (expression == null) { for (int i = 1; i <= size; i++) { vs[i - 1] = buildWithInt2(name + '_' + i, (DInt2) what, expression, map, solver); } } else if (expression.getTypeOf().equals(Expression.EType.ARR)) { buildFromIntArray(vs, (EArray) expression, size, solver); } map.put(name, vs); break; case INTN: vs = new IntVar[size]; if (expression == null) { for (int i = 1; i <= size; i++) { vs[i - 1] = buildWithManyInt(name + '_' + i, (DManyInt) what, expression, map, solver); } } else if (expression.getTypeOf().equals(Expression.EType.ARR)) { buildFromIntArray(vs, (EArray) expression, size, solver); } map.put(name, vs); break; case SET: // final SetVariable[] svs = new SetVariable[size]; // for (int i = 1; i <= size; i++) { // svs[i - 1] = buildWithSet(name + '_' + i, (DSet) what, map); // } // map.put(name, svs); Exit.log("SET VAR"); break; default: break; } }
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); }