package org.geogebra.common.geogebra3D.kernel3D.implicit3D; import org.geogebra.common.geogebra3D.kernel3D.algos.AlgoElement3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPlane3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3D; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.algos.Algos; import org.geogebra.common.kernel.algos.GetCommand; import org.geogebra.common.kernel.arithmetic.Equation; import org.geogebra.common.kernel.arithmetic.ExpressionValue; import org.geogebra.common.kernel.arithmetic.Polynomial; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.implicit.GeoImplicit; import org.geogebra.common.kernel.kernelND.GeoElementND; /** * Dependent implicit surface * * @author Shamshad Alam * */ public class AlgoDependentImplicitSurface extends AlgoElement3D { private Equation equation; private GeoElement geoElem; private ExpressionValue[] ev = new ExpressionValue[10]; /** * * @param c * construction * @param equ * equation */ public AlgoDependentImplicitSurface(Construction c, Equation equ) { super(c, false); equation = equ; c.addToConstructionList(this, false); switch (equ.preferredDegree()) { // linear equation -> LINE case 1: geoElem = new GeoPlane3D(c); break; // quadratic equation -> CONIC case 2: geoElem = new GeoQuadric3D(c); break; default: geoElem = new GeoImplicitSurface(c); } geoElem.setDefinition(equ.wrap()); setInputOutput(); // for AlgoElement compute(true); } @Override protected void setInputOutput() { if (input == null) { input = equation.getGeoElementVariables(); } if (getOutputLength() == 0) { setOutputLength(1); } setOutput(0, geoElem); setDependencies(); } @Override public void compute() { compute(false); } @Override public GetCommand getClassName() { return Algos.Expression; } private void compute(boolean first) { if (!first && (equation.hasVariableDegree() || equation.isFunctionDependent())) { equation.resetFlags(); equation.initEquation(); } int degree = equation.preferredDegree(); if (!equation.isPolynomial()) { degree = 3; } switch (degree) { // linear equation -> LINE case 1: if (geoElem instanceof GeoPlane3D) { setPlane(); } else { if (geoElem.hasChildren()) { geoElem.setUndefined(); } else { replaceGeoElement(new GeoPlane3D(getConstruction())); setPlane(); } } break; // quadratic equation -> CONIC case 2: if (geoElem instanceof GeoQuadric3D) { setQuadric(); } else { if (geoElem.hasChildren()) { geoElem.setUndefined(); } else { replaceGeoElement(new GeoQuadric3D(getConstruction())); setQuadric(); } } break; default: if (geoElem instanceof GeoImplicit) { ((GeoImplicitSurface) geoElem).updateSurface(); } else { if (geoElem.hasChildren()) { geoElem.setUndefined(); } else { replaceGeoElement( new GeoImplicitSurface(getConstruction())); ((GeoImplicitSurface) geoElem).fromEquation(equation); } } } } private void setQuadric() { double[] coeffs = new double[10]; Polynomial lhs = equation.getNormalForm(); ev[0] = lhs.getCoefficient("xx"); ev[1] = lhs.getCoefficient("yy"); ev[2] = lhs.getCoefficient("zz"); ev[3] = lhs.getConstantCoefficient(); // further will be divided by 2 ev[4] = lhs.getCoefficient("xy"); ev[5] = lhs.getCoefficient("xz"); ev[6] = lhs.getCoefficient("yz"); ev[7] = lhs.getCoefficient("x"); ev[8] = lhs.getCoefficient("y"); ev[9] = lhs.getCoefficient("z"); for (int i = 0; i < 4; i++) { coeffs[i] = ev[i].evaluateDouble(); } for (int i = 4; i < 10; i++) { coeffs[i] = ev[i].evaluateDouble() / 2; } ((GeoQuadric3D) geoElem).setMatrix(coeffs); } private void setPlane() { Polynomial lhs = equation.getNormalForm(); ev[0] = lhs.getCoefficient("x"); ev[1] = lhs.getCoefficient("y"); ev[2] = lhs.getCoefficient("z"); ev[3] = lhs.getCoefficient(""); ((GeoPlane3D) geoElem).setEquation(ev[0].evaluateDouble(), ev[1].evaluateDouble(), ev[2].evaluateDouble(), ev[3].evaluateDouble()); } private void replaceGeoElement(GeoElementND newElem) { String label = geoElem.getLabelSimple(); newElem.toGeoElement().setVisualStyle(geoElem); geoElem.doRemove(); geoElem = newElem.toGeoElement(); setInputOutput(); geoElem.setLabel(label); } /** * * @return {@link GeoImplicitSurface} */ public GeoElement getGeo() { return geoElem; } /** * * @return {@link Equation} */ public Equation getEquation() { return equation; } @Override public final String toString(StringTemplate tpl) { return equation.toString(tpl); } @Override protected String toExpString(StringTemplate tpl) { return geoElem.getLabel(tpl) + ": " + equation.toString(tpl); } }