package org.geogebra.common.geogebra3D.kernel3D.algos; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoConic3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3DLimited; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoQuadric3DPart; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.Transform; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.AlgoRadius; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.kernelND.GeoPointND; /** * Algo for cylinder between two end points and given radius. * * @author mathieu * */ public abstract class AlgoQuadricLimitedPointPointRadius extends AlgoElement3D {// implements // AlgoTransformable // { // input private GeoPointND origin, secondPoint; private NumberValue radius; // output private GeoQuadric3DPart side; protected GeoConic3D bottom; protected GeoConic3D top; private GeoQuadric3DLimited quadric; private AlgoQuadricSide algoSide; private AlgoQuadricEnds algoEnds; public AlgoQuadricLimitedPointPointRadius(Construction c, String[] labels, GeoPointND origin, GeoPointND secondPoint, NumberValue r, int type) { super(c); this.origin = origin; this.secondPoint = secondPoint; this.radius = r; quadric = new GeoQuadric3DLimited(c);// ,origin,secondPoint); quadric.setType(type); input = new GeoElement[] { (GeoElement) origin, (GeoElement) secondPoint, (GeoElement) r }; ((GeoElement) origin).addAlgorithm(this); ((GeoElement) secondPoint).addAlgorithm(this); ((GeoElement) r).addAlgorithm(this); // parent of output quadric.setParentAlgorithm(this); cons.addToAlgorithmList(this); setQuadric(); algoSide = new AlgoQuadricSide(cons, quadric, true, null); cons.removeFromConstructionList(algoSide); side = (GeoQuadric3DPart) algoSide.getQuadric(); side.setParentAlgorithm(this); quadric.setSide(side); algoEnds = createEnds(); bottom.setParentAlgorithm(this); top.setParentAlgorithm(this); quadric.setBottomTop(bottom, top); // output = new GeoElement[] {quadric,bottom,top,side}; setOutput(); quadric.initLabelsIncludingBottom(labels); quadric.updatePartsVisualStyle(); // force update for side update(); } /** * sets the output */ abstract protected void setOutput(); abstract protected AlgoQuadricEnds createEnds(); final private void computeHelpers() { // side must be done before ends (for midpoint) algoSide.compute(); algoEnds.compute(); } private boolean setQuadric() { // check end points if (!((GeoElement) origin).isDefined() || origin.isInfinite() || !((GeoElement) secondPoint).isDefined() || secondPoint.isInfinite() || !radius.isDefined()) { getQuadric().setUndefined(); return false; } Coords o = origin.getInhomCoordsInD3(); Coords o2 = secondPoint.getInhomCoordsInD3(); Coords d = o2.sub(o); if (d.equalsForKernel(0, Kernel.STANDARD_PRECISION)) { getQuadric().setUndefined(); return false; } double r = radius.getDouble(); d.calcNorm(); double altitude = d.getNorm(); quadric.setDefined(); setQuadric(o, o2, d.mul(1 / altitude), r, 0, altitude); return true; } @Override public void compute() { if (!setQuadric()) { bottom.setUndefined(); top.setUndefined(); side.setUndefined(); return; } computeHelpers(); quadric.calcVolume(); } abstract protected void setQuadric(Coords o1, Coords o2, Coords d, double r, double min, double max); public GeoQuadric3DLimited getQuadric() { return quadric; } // ////////////////////// // ALGOTRANSFORMABLE // ////////////////////// /** * * @param labels * transformed labels * @param p1 * transformed first point * @param p2 * transformed second point * @param r * transformed radius * @return new algo for transformed inputs */ protected abstract AlgoElement getTransformedAlgo(String[] labels, GeoPointND p1, GeoPointND p2, GeoNumeric r); public GeoElement[] getTransformedOutput(Transform t) { GeoPointND p1 = (GeoPointND) t.transform((GeoElement) origin, Transform.transformedGeoLabel((GeoElement) origin))[0]; GeoPointND p2 = (GeoPointND) t.transform((GeoElement) secondPoint, Transform.transformedGeoLabel((GeoElement) secondPoint))[0]; Transform.setVisualStyleForTransformations((GeoElement) origin, (GeoElement) p1); Transform.setVisualStyleForTransformations((GeoElement) secondPoint, (GeoElement) p2); GeoNumeric r = (new AlgoRadius(this.cons, null, getQuadric().getBottom())).getRadius(); r.setAuxiliaryObject(true); GeoElement[] output = getOutput(); String[] labels = new String[output.length]; for (int i = 0; i < output.length; i++) { labels[i] = Transform.transformedGeoLabel(output[i]); } AlgoElement algo = getTransformedAlgo(labels, p1, p2, r); GeoElement[] ret = algo.getOutput(); for (int i = 0; i < ret.length; i++) { Transform.setVisualStyleForTransformations(output[i], ret[i]); } algo.update(); return ret; } // @Override // public void update() { // // if (stopUpdateCascade) { // return; // } // // compute(); // quadric.update(); // // if (!getQuadric().isLabelSet()) { // geo is in sequence/list : update // // bottom, top and side // getQuadric().getBottom().getParentAlgorithm().update(); // getQuadric().getTop().getParentAlgorithm().update(); // getQuadric().getSide().getParentAlgorithm().update(); // } // // } }