/* 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.geogebra3D.kernel3D.algos; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoCurveCartesian3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoLine3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.algos.AlgoPointOnPath; import org.geogebra.common.kernel.arithmetic.ExpressionNode; import org.geogebra.common.kernel.arithmetic.ExpressionValue; import org.geogebra.common.kernel.cas.AlgoDerivative; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.commands.EvalInfo; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.plugin.Operation; /** * @author Victor Franco Espino * @version 11-02-2007 * * tangent to Curve f in point P: (b'(t), -a'(t), * a'(t)*b(t)-a(t)*b'(t)) */ public class AlgoTangentCurve3D extends AlgoLinePoint { private GeoPointND P; // input private GeoCurveCartesian3D f, df; // input f private GeoLine3D tangent; // output private GeoPointND T; private boolean pointOnCurve; private boolean pointOnCurveSpecial; private ExpressionValue pointOnCurveSpecialParam; private AlgoDerivative algo; /** * @param cons * construction * @param label * label for output * @param P * point on function * @param f * curve */ public AlgoTangentCurve3D(Construction cons, String label, GeoPointND P, GeoCurveCartesian3D f) { super(cons); tangent = new GeoLine3D(cons); this.P = P; initialize(f); setInputOutput(); // for AlgoElement compute(); tangent.setLabel(label); update(); } /** * @param f1 * cartesian curve (input) */ public void initialize(GeoCurveCartesian3D f1) { this.f = f1; // check if P is defined as a point of the curve's graph pointOnCurve = false; if (P.getParentAlgorithm() instanceof AlgoPointOnPath) { AlgoPointOnPath algoPOP = (AlgoPointOnPath) P.getParentAlgorithm(); pointOnCurve = algoPOP.getPath() == f; } else if (P.getParentAlgorithm() instanceof AlgoDependentPoint3D) { // special code for curve(t) AlgoDependentPoint3D algoDP = (AlgoDependentPoint3D) P .getParentAlgorithm(); ExpressionNode en = algoDP.getExpression(); if (en.getOperation() == Operation.VEC_FUNCTION && en.getLeft().unwrap() == f) { pointOnCurveSpecial = true; pointOnCurveSpecialParam = en.getRight().unwrap(); } } if (pointOnCurve || pointOnCurveSpecial) { T = P; } else { T = new GeoPoint3D(cons); } tangent.setStartPoint(T); EvalInfo info = new EvalInfo(false); // First derivative of curve f algo = new AlgoDerivative(cons, f, true, info); this.df = (GeoCurveCartesian3D) algo.getResult(); cons.removeFromConstructionList(algo); } @Override public Commands getClassName() { return Commands.Tangent; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_TANGENTS; } // for AlgoElement @Override protected void setInputOutput() { input = new GeoElement[2]; input[0] = (GeoElement) P; input[1] = f; setOutputLength(1); setOutput(0, tangent); setDependencies(); // done by AlgoElement } /** * @return resulting tangent */ public GeoLine3D getTangent() { return tangent; } /** * @return input curve */ GeoCurveCartesian3D getCurve() { return f; } @Override public GeoLine3D getLine() { return tangent; } private Coords direction = new Coords(0, 0, 0, 1); @Override protected GeoPointND getPoint() { return T; } private double feval[] = new double[3]; private double dfeval[] = new double[3]; @Override protected Coords getDirection() { if (!(f.isDefined() && P.isDefined())) { direction.setX(Double.NaN); direction.setY(Double.NaN); direction.setZ(Double.NaN); return direction; } // first derivative if (df == null || !df.isDefined()) { direction.setX(Double.NaN); direction.setY(Double.NaN); direction.setZ(Double.NaN); return direction; } // calc the tangent; double tvalue; if (pointOnCurve) { tvalue = P.getPathParameter().t; } else if (pointOnCurveSpecialParam != null) { tvalue = pointOnCurveSpecialParam.evaluateDouble(); } else { tvalue = f.getClosestParameter(P, f.getMinParameter()); } df.evaluateCurve(tvalue, dfeval); direction.setX(dfeval[0]); direction.setY(dfeval[1]); direction.setZ(dfeval[2]); if (!pointOnCurve && !pointOnCurveSpecial) { f.evaluateCurve(tvalue, feval); T.setCoords(feval[0], feval[1], feval[2], 1.0); } return direction; } @Override public String toString(StringTemplate tpl) { return getLoc().getPlain("TangentToAatB", f.getLabel(tpl), P.getLabel(tpl)); } }