package org.geogebra.common.kernel.advanced; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.arithmetic.FunctionVariable; 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.geos.GeoFunctionNVar; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.kernelND.GeoPointND; /** * @author michael * * http://en.wikipedia.org/wiki/Gaussian_curvature * http://emp.byui.edu/BrownD * /Mathematics/Calculus-Rn-Rm/Gaussian-curvature.pdf * * test-cases z=x^2+y^2, k=4/(1+4x^2+4y^2)^2 z=x^2-y^2, * k=-4/(1+4x^2+4y^2)^2 z=x^3+y^3, k=-36x y / (1 + 9x^4 + 9y^4)^2 * z=sqrt(1-x^2-y^2), k=1 (sphere) z=a x + b y, k=0 (plane!) */ public class AlgoCurvatureSurface extends AlgoElement { private GeoPointND A; // input private GeoFunctionNVar f; private GeoFunctionNVar fx, fxx, fy, fyy, fxy; // partial derivatives private GeoNumeric n; // output private AlgoDerivative algoCASfx, algoCASfxx, algoCASfy, algoCASfyy, algoCASfxy; @SuppressWarnings("javadoc") public AlgoCurvatureSurface(Construction cons, String label, GeoPointND A, GeoFunctionNVar f) { this(cons, A, f); if (label != null) { n.setLabel(label); } } @SuppressWarnings("javadoc") AlgoCurvatureSurface(Construction cons, GeoPointND A, GeoFunctionNVar f) { super(cons); this.A = A; this.f = f; n = new GeoNumeric(cons); FunctionVariable[] vars = f.getFunctionVariables(); if (vars.length != 2) { return; } GeoNumeric x = new GeoNumeric(cons); // x.setLocalVariableLabel("x"); x.setLocalVariableLabel(vars[0].getSetVarString()); GeoNumeric y = new GeoNumeric(cons); // y.setLocalVariableLabel("y"); y.setLocalVariableLabel(vars[1].getSetVarString()); GeoNumeric one = new GeoNumeric(cons, 1); EvalInfo info = new EvalInfo(false); // First derivative of function f algoCASfx = new AlgoDerivative(cons, f, x, one, false, info); cons.removeFromConstructionList(algoCASfx); this.fx = (GeoFunctionNVar) algoCASfx.getResult(); // Second derivative of function f algoCASfxx = new AlgoDerivative(cons, fx, x, one, false, info); cons.removeFromConstructionList(algoCASfxx); this.fxx = (GeoFunctionNVar) algoCASfxx.getResult(); // First derivative of function f algoCASfy = new AlgoDerivative(cons, f, y, one, false, info); cons.removeFromConstructionList(algoCASfy); this.fy = (GeoFunctionNVar) algoCASfy.getResult(); // Second derivative of function f algoCASfyy = new AlgoDerivative(cons, fy, y, one, false, info); cons.removeFromConstructionList(algoCASfyy); this.fyy = (GeoFunctionNVar) algoCASfyy.getResult(); // Second derivative of function f algoCASfxy = new AlgoDerivative(cons, fx, y, one, false, info); cons.removeFromConstructionList(algoCASfxy); this.fxy = (GeoFunctionNVar) algoCASfxy.getResult(); // Log.debug("x' = "+ fx.toString(StringTemplate.defaultTemplate)); // Log.debug("x'' = "+ fxx.toString(StringTemplate.defaultTemplate)); // Log.debug("y' = "+ fy.toString(StringTemplate.defaultTemplate)); // Log.debug("y'' = "+ fyy.toString(StringTemplate.defaultTemplate)); // Log.debug("fxy = "+ fxy.toString(StringTemplate.defaultTemplate)); setInputOutput(); compute(); } @Override public Commands getClassName() { return Commands.Curvature; } // for AlgoElement @Override protected void setInputOutput() { input = new GeoElement[2]; input[0] = (GeoElement) A; input[1] = f; super.setOutputLength(1); super.setOutput(0, n); setDependencies(); // done by AlgoElement } /** * @return result */ public GeoNumeric getResult() { return n; } @Override public final void compute() { if (!A.isFinite() || fx == null || fxx == null || fy == null || fyy == null || fxy == null) { n.setUndefined(); return; } double x = A.getInhomX(); double y = A.getInhomY(); // don't need z, take point vertically above if not on surface double[] xy = { x, y }; double fxEval = fx.evaluate(xy); double fyEval = fy.evaluate(xy); double fxxEval = fxx.evaluate(xy); double fyyEval = fyy.evaluate(xy); double fxyEval = fxy.evaluate(xy); double top = (fxxEval * fyyEval - fxyEval * fxyEval); double bottomSqrt = 1 + fxEval * fxEval + fyEval * fyEval; double k = top / (bottomSqrt * bottomSqrt); n.setValue(k); } @Override public void remove() { if (removed) { return; } super.remove(); ((GeoElement) A).removeAlgorithm(algoCASfx); f.removeAlgorithm(algoCASfx); ((GeoElement) A).removeAlgorithm(algoCASfxx); f.removeAlgorithm(algoCASfxx); ((GeoElement) A).removeAlgorithm(algoCASfy); f.removeAlgorithm(algoCASfy); ((GeoElement) A).removeAlgorithm(algoCASfyy); f.removeAlgorithm(algoCASfyy); ((GeoElement) A).removeAlgorithm(algoCASfxy); f.removeAlgorithm(algoCASfxy); } }