/* 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. */ /* * AlgoJoinPointsSegment * * Created on 21. August 2003 */ package org.geogebra.common.geogebra3D.kernel3D.algos; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoConic3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoConicSection; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPlane3D; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D; 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.PathNormalizer; import org.geogebra.common.kernel.PathParameter; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.kernelND.GeoConicND; import org.geogebra.common.kernel.kernelND.GeoConicNDConstants; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.kernel.kernelND.GeoQuadricND; /** * * @author mathieu * * */ public class AlgoIntersectPlaneQuadricLimited extends AlgoIntersectPlaneQuadric { private AlgoIntersectPlaneConic algoBottom, algoTop; private GeoPoint3D[] bottomP, topP; /** * Creates new AlgoIntersectLinePlane * * @param cons * the construction * @param plane * plane * @param quadric * quadric */ AlgoIntersectPlaneQuadricLimited(Construction cons, GeoPlane3D plane, GeoQuadricND quadric) { super(cons, plane, quadric); } /** * Creates new AlgoIntersectLinePlane * * @param cons * the construction * @param label * name of conic * @param plane * plane * @param quadric * quadric */ AlgoIntersectPlaneQuadricLimited(Construction cons, String label, GeoPlane3D plane, GeoQuadricND quadric) { this(cons, plane, quadric); conic.setLabel(label); /* * //labels String conicLabel = null; String[] bottomLabels = null; * String[] topLabels = null; if (labels!=null){ conicLabel = labels[0]; * if (labels.length>2){ bottomLabels = new String[2]; bottomLabels[0] = * labels[1]; bottomLabels[1] = labels[2]; if (labels.length>4){ * topLabels = new String[2]; topLabels[0] = labels[3]; topLabels[1] = * labels[4]; } * * } } * * conic.setLabel(conicLabel); GeoElement.setLabels(bottomLabels, * bottomP); GeoElement.setLabels(topLabels, topP); */ } @Override protected GeoConic3D newConic(Construction cons) { return new GeoConicSection(cons, true); } @Override protected void end() { // algo for intersect points with bottom and top algoBottom = new AlgoIntersectPlaneConic(cons); algoTop = new AlgoIntersectPlaneConic(cons); cons.removeFromConstructionList(algoBottom); cons.removeFromConstructionList(algoTop); bottomP = new GeoPoint3D[2]; for (int i = 0; i < 2; i++) { bottomP[i] = new GeoPoint3D(cons); } topP = new GeoPoint3D[2]; for (int i = 0; i < 2; i++) { topP[i] = new GeoPoint3D(cons); } super.end(); } // ///////////////////////////////////////////// // COMPUTE /** * * @return bottom of the quadric as a conic */ protected GeoConicND getBottom() { return ((GeoQuadric3DLimited) quadric).getBottom(); } /** * * @return top of the quadric as a conic */ protected GeoConicND getTop() { return ((GeoQuadric3DLimited) quadric).getTop(); } /** * * @return side of the quadric as a surface */ protected GeoQuadric3DPart getSide() { return ((GeoQuadric3DLimited) quadric).getSide(); } @Override public void compute() { super.compute(); // set part points double[] bottomParameters = setPartPoints(algoBottom, getBottom(), bottomP); double[] topParameters = setPartPoints(algoTop, getTop(), topP); /* * Log.debug(bottomParameters[0]+","+ bottomParameters[1]+","+ * topParameters[0]+","+ topParameters[1]); */ switch (conic.getType()) { case GeoConicNDConstants.CONIC_CIRCLE: case GeoConicNDConstants.CONIC_ELLIPSE: // if some parameters are NaN, force to be in topParameters if (Double.isNaN(bottomParameters[0])) { bottomParameters[0] = topParameters[0]; bottomParameters[1] = topParameters[1]; // bottomP[0] = topP[0]; topParameters[0] = Double.NaN; } // check if top parameters are equal : then no hole for top if (Kernel.isEqual(topParameters[0], topParameters[1])) { topParameters[0] = Double.NaN; } // if topParameters are NaN, and not bottomParameters, // set twice the "middle" parameter for topParameters to check the // order // Log.debug(topParameters[0]+","+bottomParameters[0]); if (Double.isNaN(topParameters[0])) { if (!Double.isNaN(bottomParameters[0])) { // if parameters are equal, no hole if (Kernel.isEqual(bottomParameters[0], bottomParameters[1])) { if (planeOutsideAxis()) { // just single point setSinglePoint(bottomP[0], topP[0]); } else { // no hole bottomParameters[0] = Double.NaN; } } else { // calc "midpoint" on conic double midParameter = (bottomParameters[0] + bottomParameters[1]) / 2; PathParameter pp = new PathParameter(midParameter); Coords P = new Coords(3); conic.pathChangedWithoutCheck(P, pp, false); P = conic.getPoint(P.getX(), P.getY(), new Coords(4)); // check if "midpoint" is on quadric side // Log.debug("\n"+P+"\n"+ql.getSide().isInRegion(P)); if (getSide().isInRegion(P)) { // set "midpoint" topParameters[0] = midParameter; } else { // set symetric "midpoint" topParameters[0] = midParameter + Math.PI; if (midParameter < 0) { topParameters[0] = midParameter + Math.PI; } else { topParameters[0] = midParameter - Math.PI; } } topParameters[1] = topParameters[0]; } } else { // no intersection : check if the plane is not totally // outside the quadric if (planeOutsideAxis()) { conic.setUndefined(); return; } } } break; case GeoConicNDConstants.CONIC_HYPERBOLA: case GeoConicNDConstants.CONIC_PARABOLA: if (Double.isNaN(bottomParameters[0])) { if (Double.isNaN(topParameters[0])) { // no intersection with // ends of the quadric : // hyperbola is // completely outside conic.setUndefined(); } else if (Kernel.isEqual(topParameters[0], topParameters[1])) { // single // point setSinglePoint(topP[0], topP[1]); } } else if (Kernel.isEqual(bottomParameters[0], bottomParameters[1])) { // single // point setSinglePoint(bottomP[0], bottomP[1]); } break; } // set parameters to conic GeoConicSection cp = (GeoConicSection) conic; /* * App.error(bottomParameters[0]+","+ bottomParameters[1]+","+ * topParameters[0]+","+ topParameters[1]); */ // Log.debug("\n"+bottomP[0]+"\n"+bottomP[1]+"\n"+topP[0]+"\n"+topP[1]); /* * Log.debug(PathNormalizer.infFunction(bottomParameters[0])+","+ * PathNormalizer.infFunction(topParameters[0])+","+ * PathNormalizer.infFunction(bottomParameters[1]-2)+","+ * PathNormalizer.infFunction(topParameters[1]-2)); */ cp.setParameters(bottomParameters[0], bottomParameters[1], topParameters[0], topParameters[1]); } protected double getBottomParameter() { return ((GeoQuadric3DLimited) quadric).getBottomParameter(); } protected double getTopParameter() { return ((GeoQuadric3DLimited) quadric).getTopParameter(); } private Coords tmpCoords; private boolean planeOutsideAxis() { if (tmpCoords == null) { tmpCoords = new Coords(4); } // calc parameter (on quadric axis) of the intersection point between // plane and quadrix axis quadric.getMidpoint3D().projectPlaneThruVInPlaneCoords( plane.getCoordSys().getMatrixOrthonormal(), quadric.getEigenvec3D(2), tmpCoords); double parameter = -tmpCoords.getZ(); // check if parameter is between quadric min and max double min = getBottomParameter(); double max = getTopParameter(); if (min > max) { double m = min; min = max; max = m; } // check if min > parameter if (Kernel.isGreater(min, parameter)) { // check if parameter is close to min in comparison to max - min if (Kernel.isEpsilonToX(min - parameter, max - min)) { return false; } return true; } // check if max < parameter if (Kernel.isGreater(parameter, max)) { // check if parameter is close to max in comparison to max - min if (Kernel.isEpsilonToX(parameter - max, max - min)) { return false; } return true; } // min < parameter < max return false; } /** * set conic as single point at p1 location if p1 is define, else at p2 * location * * @param p1 * first point * @param p2 * second point */ private void setSinglePoint(GeoPointND p1, GeoPointND p2) { if (p1.isDefined()) { conic.setSinglePoint(p1); } else { conic.setSinglePoint(p2); } } private double[] setPartPoints(AlgoIntersectPlaneConic algo, GeoConicND c, GeoPoint3D[] points) { // check if c is point or undefined if (// c==null // || !c.isDefined() || c.getType() == GeoConicNDConstants.CONIC_EMPTY // || c.getType()==GeoConicNDConstants.CONIC_SINGLE_POINT ) { return new double[] { Double.NaN, Double.NaN }; } // calc points algo.intersect(plane, c, points); // Log.debug(points[0].isDefined()); if (!points[0].isDefined()) { return new double[] { Double.NaN, Double.NaN }; } Coords c0 = points[0].getCoordsInD2(conic.getCoordSys()); Coords c1 = points[1].getCoordsInD2(conic.getCoordSys()); double[] ret = new double[2]; if (c0.equalsForKernel(c1) && conic .getType() == GeoConicNDConstants.CONIC_INTERSECTING_LINES) { // force compute parameter for the two liness PathParameter pp = new PathParameter(); conic.lines[0].doPointChanged(c0, pp); ret[0] = PathNormalizer.inverseInfFunction(pp.getT()); conic.lines[1].doPointChanged(c1, pp); ret[1] = PathNormalizer.inverseInfFunction(pp.getT()) + 2; } else { // get parameters to limit the conic PathParameter pp = new PathParameter(); conic.pointChanged(c0, pp, false); ret[0] = pp.getT(); conic.pointChanged(c1, pp, false); ret[1] = pp.getT(); } return ret; } /** * * @param index * index (0 or 1) * @return last bottom point computed */ public GeoPoint3D getBottomPoint(int index) { return bottomP[index]; } /** * * @param index * index (0 or 1) * @return last top point computed */ public GeoPoint3D getTopPoint(int index) { return topP[index]; } }