/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package org.geogebra.common.kernel.algos; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.arithmetic.Function; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoFunction; import org.geogebra.common.kernel.geos.GeoLine; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.kernelND.GeoPointND; /** * Finds intersection points of two polynomials (using the roots of their * difference) * * @author Markus Hohenwarter */ public class AlgoIntersectFunctionLineNewton extends AlgoRootNewton { private GeoFunction f; // input private GeoLine line; // input private GeoPoint startPoint, rootPoint; private GeoPointND tangentPoint; private Function diffFunction; private boolean isDefinedAsTangent; public AlgoIntersectFunctionLineNewton(Construction cons, String label, GeoFunction f, GeoLine line, GeoPoint startPoint) { this(cons, f, line, startPoint); rootPoint.setLabel(label); addIncidence(); } public AlgoIntersectFunctionLineNewton(Construction cons, GeoFunction f, GeoLine line, GeoPoint startPoint) { super(cons); this.f = f; this.line = line; this.startPoint = startPoint; if (line.getParentAlgorithm() instanceof TangentAlgo) { TangentAlgo algo = (TangentAlgo) line.getParentAlgorithm(); tangentPoint = algo.getTangentPoint(f, line); isDefinedAsTangent = (tangentPoint != null); } if (!isDefinedAsTangent) { diffFunction = new Function(kernel); } // output rootPoint = new GeoPoint(cons); setInputOutput(); // for AlgoElement compute(); } /** * @author Tam * * for special cases of e.g. AlgoIntersectLineConic */ private void addIncidence() { rootPoint.addIncidence(f, false); rootPoint.addIncidence(line, false); } @Override public Commands getClassName() { return Commands.Intersect; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_INTERSECT; } // for AlgoElement @Override protected void setInputOutput() { input = new GeoElement[3]; input[0] = f; input[1] = line; input[2] = startPoint; super.setOutputLength(1); super.setOutput(0, rootPoint); setDependencies(); } @Override public final void compute() { if (!(f.isDefined() && line.isDefined() && startPoint.isDefined())) { rootPoint.setUndefined(); return; } if (isDefinedAsTangent) { rootPoint.setCoordsFromPoint(tangentPoint); return; } double x; // check for vertical line a*x + c = 0: intersection at x=-c/a if (Kernel.isZero(line.y)) { x = -line.z / line.x; } // standard case else { // get difference f - line Function.difference(f.getFunction(startPoint.inhomX), line, diffFunction); x = calcRoot(diffFunction, startPoint.inhomX); } if (Double.isNaN(x)) { rootPoint.setUndefined(); return; } double y = f.value(x); rootPoint.setCoords(x, y, 1.0); // check if the intersection point really is on the line // this is important for segments and rays if (!line.isIntersectionPointIncident(rootPoint, Kernel.MIN_PRECISION)) { rootPoint.setUndefined(); return; } // if we got here we have a new valid rootPoint // in order to make dynamic moving of the intersecting objects // a little bit more stable, we try to be clever here: // let's take the new rootPoints position as the next starting point // for Newton's method. // Note: we should only do this if the starting point is not labeled, // i.e. not visible on screen (and was probably created by clicking // on an intersection) if (!startPoint.isLabelSet() && startPoint.isIndependent() && rootPoint.isDefined()) { startPoint.setCoords(rootPoint); } } public GeoPoint getIntersectionPoint() { return rootPoint; } @Override final public String toString(StringTemplate tpl) { // Michael Borcherds 2008-03-31 // simplified to allow better translation return getLoc().getPlain("IntersectionPointOfABWithInitialValueC", input[0].getLabel(tpl), input[1].getLabel(tpl), startPoint.getLabel(tpl)); } }