public AlgoLocus(Construction cons, String label, GeoPoint2 Q, GeoPoint2 P) { super(cons); this.movingPoint = P; this.locusPoint = Q; path = P.getPath(); pathMover = path.createPathMover(); QstartPos = new GeoPoint2(cons); PstartPos = new GeoPoint2(cons); init(); updateScreenBorders(); locus = new GeoLocus(cons); setInputOutput(); // for AlgoElement cons.registerEuclidianViewCE(this); compute(); // we may have created a starting point for the path now // make sure that the movingPoint in the main construction // uses the correct path parameter for it path.pointChanged(P); locus.setLabel(label); }
private void insertPoint(double x, double y, boolean lineTo) { pointCount++; // Application.debug("insertPoint: " + x + ", " + y + ", lineto: " + lineTo); locus.insertPoint(x, y, lineTo); lastX = x; lastY = y; lastFarAway = isFarAway(lastX, lastY); }
private void buildLocusMacroConstruction(TreeSet<ConstructionElement> locusConsElements) { // build macro construction macroKernel = new MacroKernel((Kernel) kernel); macroKernel.setGlobalVariableLookup(true); // tell the macro construction about reserved names: // these names will not be looked up in the parent // construction Iterator<ConstructionElement> it = locusConsElements.iterator(); while (it.hasNext()) { ConstructionElement ce = it.next(); if (ce.isGeoElement()) { GeoElement geo = (GeoElement) ce; macroKernel.addReservedLabel(geo.getLabel()); } } try { // get XML for macro construction of P -> Q String locusConsXML = Macro.buildMacroXML((Kernel) kernel, locusConsElements); macroKernel.loadXML(locusConsXML); // get the copies of P and Q from the macro kernel Pcopy = (GeoPoint2) macroKernel.lookupLabel(movingPoint.label); Pcopy.setFixed(false); Pcopy.setPath(movingPoint.getPath()); Qcopy = (GeoPoint2) macroKernel.lookupLabel(locusPoint.label); macroCons = macroKernel.getConstruction(); /* // make sure that the references to e.g. start/end point of a segment are not // changed later on. This is achieved by setting isMacroOutput to true it = macroCons.getGeoElementsIterator(); while (it.hasNext()) { GeoElement geo = (GeoElement) it.next(); geo.isAlgoMacroOutput = true; } Pcopy.isAlgoMacroOutput = false; */ } catch (Exception e) { e.printStackTrace(); locus.setUndefined(); macroCons = null; } // //Application.debug("P: " + P + ", kernel class: " + P.kernel.getClass()); // Application.debug("Pcopy: " + Pcopy + ", kernel class: " + Pcopy.kernel.getClass()); // //Application.debug("P == Pcopy: " + (P == Pcopy)); // //Application.debug("Q: " + Q + ", kernel class: " + Q.kernel.getClass()); // Application.debug("Qcopy: " + Qcopy + ", kernel class: " + Qcopy.kernel.getClass()); // //Application.debug("Q == Qcopy: " + (Q == Qcopy)); }
// compute locus line @Override public final void compute() { if (!movingPoint.isDefined() || macroCons == null || !path.toGeoElement().isDefined()) { locus.setUndefined(); return; } locus.clearPoints(); clearCache(); pointCount = 0; useCache = 0; countUpdates = 0; lastX = Double.MAX_VALUE; lastY = Double.MAX_VALUE; maxTimeExceeded = false; foundDefined = false; boolean prevQcopyDefined = false; int max_runs; // continuous kernel? continuous = kernel.isContinuous(); macroKernel.setContinuous(continuous); // update macro construction with current values of global vars resetMacroConstruction(); macroCons.updateConstruction(); // use current position of movingPoint to start Pcopy pathMover.init(Pcopy); if (continuous) { // continous constructions may need several parameter run throughs // to draw all parts of the locus max_runs = GeoLocus.MAX_PATH_RUNS; } else { max_runs = 1; } // update Pcopy to compute Qcopy pcopyUpdateCascade(); prevQcopyDefined = Qcopy.isDefined() && !Qcopy.isInfinite(); // move Pcopy along the path // do this until Qcopy comes back to its start position // for continuous constructions // this may require several runs of Pcopy along the whole path int runs = 1; int MAX_LOOPS = 2 * PathMover.MAX_POINTS; int whileLoops = 0; do { boolean finishedRun = false; while (!finishedRun && !maxTimeExceeded && pointCount <= PathMover.MAX_POINTS && whileLoops <= MAX_LOOPS) { whileLoops++; // lineTo may be false due to a parameter jump // i.e. param in [0,1] gets bigger than 1 and thus jumps to 0 boolean parameterJump = !pathMover.getNext(Pcopy); boolean stepChanged = false; // update construction pcopyUpdateCascade(); // Qcopy DEFINED if (Qcopy.isDefined() && !Qcopy.isInfinite()) { // STANDARD CASE: no parameter jump if (!parameterJump) { // make steps smaller until distance ok to connect with last point while (Qcopy.isDefined() && !Qcopy.isInfinite() && !distanceOK(Qcopy) && !maxTimeExceeded) { // go back and try smaller step boolean smallerStep = pathMover.smallerStep(); if (!smallerStep) break; stepChanged = true; pathMover.stepBack(); pathMover.getNext(Pcopy); // update construction pcopyUpdateCascade(); } if (Qcopy.isDefined() && !Qcopy.isInfinite()) { // draw point insertPoint(Qcopy.inhomX, Qcopy.inhomY, distanceSmall(Qcopy)); prevQcopyDefined = true; } } // PARAMETER jump: !lineTo else { // draw point insertPoint(Qcopy.inhomX, Qcopy.inhomY, distanceSmall(Qcopy)); prevQcopyDefined = true; } } // Qcopy NOT DEFINED else { // check if we moved from defined to undefined case: // step back and try with smaller step if (prevQcopyDefined && !parameterJump) { pathMover.stepBack(); // set smallest step if (!pathMover.smallerStep()) { prevQcopyDefined = false; } else stepChanged = true; } // add better undefined case support for continuous curves // maybe change orientation of path mover } // if we didn't decrease the step width increase it if (!stepChanged) { pathMover.biggerStep(); } // end of run: the next step would pass the start position if (!pathMover.hasNext()) { if (distanceSmall(QstartPos)) { // draw line back to first point when it's close enough insertPoint(QstartPos.inhomX, QstartPos.inhomY, true); finishedRun = true; } else { // decrease step until another step is possible while (!pathMover.hasNext() && pathMover.smallerStep()) ; // no smaller step possible: run finished if (!pathMover.hasNext()) finishedRun = true; } } } // calculating the steps took too long, so we stopped somewhere if (maxTimeExceeded) { System.err.println("AlgoLocus: max time exceeded"); return; } else { // make sure that Pcopy is back at startPos now // look at Qcopy at startPos Pcopy.set((GeoElement) PstartPos); pcopyUpdateCascade(); if (Qcopy.inhomX != lastX || Qcopy.inhomY != lastY) insertPoint(Qcopy.inhomX, Qcopy.inhomY, distanceSmall(Qcopy)); // Application.debug("run: " + runs); // Application.debug("pointCount: " + pointCount); // Application.debug(" startPos: " + QstartPos); // Application.debug(" Qcopy: " + Qcopy); // we are finished with all runs // if we got back to the start position of Qcopy // AND if the direction of moving along the path // is positive like in the beginning if (pathMover.hasPositiveOrientation()) { kernel.setMinPrecision(); boolean equal = QstartPos.isEqual(Qcopy); kernel.resetPrecision(); if (equal) break; } } pathMover.resetStartParameter(); runs++; } while (runs < max_runs); // set defined/undefined locus.setDefined(foundDefined); // System.out.println(" first point: " + locus.getMyPointList().get(0)); // ArrayList list = locus.getMyPointList(); // for (int i=list.size()-10; i < list.size()-1; i++) { // System.out.println(" point: " + list.get(i)); // } // System.out.println(" last point: " + locus.getMyPointList().get(pointCount-1)); // Application.debug("LOCUS COMPUTE updateCascades: " + countUpdates + ", cache used: " + // useCache); }