/* 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. */ /* * AlgoTangentLine.java * * Created on 30. August 2001, 21:37 */ package org.geogebra.common.geogebra3D.kernel3D.algos; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.geogebra3D.kernel3D.geos.GeoPoint3D; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.Matrix.CoordMatrix; import org.geogebra.common.kernel.Matrix.CoordMatrixUtil; import org.geogebra.common.kernel.Matrix.CoordSys; import org.geogebra.common.kernel.Matrix.Coords; import org.geogebra.common.kernel.algos.AlgoIntersectConics; import org.geogebra.common.kernel.algos.AlgoIntersectLineConic; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoConic; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoLine; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.kernelND.GeoConicND; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.kernel.kernelND.GeoQuadricND; /** * * @author Markus */ public class AlgoIntersectConics3D extends AlgoIntersect3D { private GeoConicND A; private GeoQuadricND B; // input private GeoPoint3D[] P, D; // output /** 2d line description of intersection of the two coord sys when exists */ private GeoLine l2d; /** 2d conic description of A and B when B included in A coord sys */ private GeoConic A2d, B2d; /** 2d points created by using AlgoIntersectLineConic.intersectLineConic */ private GeoPoint[] points2d; /** 2d intersect conics helper algo */ private AlgoIntersectConics algo2d; private AlgoIntersectPlaneQuadric algoPlane; /** matrix so that (x y 0 z) = AUGMENT_DIM * (x y z) */ final static private CoordMatrix AUGMENT_DIM = new CoordMatrix(4, 3, new double[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }); /** matrix so that (x y z) = REDUCE_DIM * (x y 0 z) */ final static private CoordMatrix REDUCE_DIM = AUGMENT_DIM.transposeCopy(); /** * * @param cons * @param label * @param A * @param B */ AlgoIntersectConics3D(Construction cons, String label, GeoConicND A, GeoConicND B) { this(cons, A, B); GeoElement.setLabels(label, P); } /** * * @param cons * @param labels * @param A * @param B */ AlgoIntersectConics3D(Construction cons, String[] labels, GeoConicND A, GeoConicND B) { this(cons, A, B); GeoElement.setLabels(labels, P); } @Override public Commands getClassName() { return Commands.Intersect; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_INTERSECT; } /** * * @param cons * construction */ AlgoIntersectConics3D(Construction cons) { super(cons); // helper algo l2d = new GeoLine(cons); A2d = new GeoConic(cons); B2d = new GeoConic(cons); algo2d = new AlgoIntersectConics(cons, false); points2d = new GeoPoint[4]; } /** * * @param cons * construction * @param A * first conic * @param B * second conic */ AlgoIntersectConics3D(Construction cons, GeoConicND A, GeoQuadricND B) { this(cons); P = new GeoPoint3D[4]; D = new GeoPoint3D[4]; for (int i = 0; i < 4; i++) { P[i] = new GeoPoint3D(cons); D[i] = new GeoPoint3D(cons); points2d[i] = new GeoPoint(cons); } this.A = A; this.B = B; setInputOutput(); // for AlgoElement compute(); } // for AlgoElement @Override public void setInputOutput() { input = new GeoElement[2]; input[0] = A; input[1] = B; setOutput(P); noUndefinedPointsInAlgebraView(); setDependencies(); // done by AlgoElement } @Override public final GeoPoint3D[] getIntersectionPoints() { return P; } @Override protected GeoPoint3D[] getLastDefinedIntersectionPoints() { return D; } @Override protected void setCoords(GeoPointND destination, GeoPointND source) { destination.setCoords(source.getCoordsInD3(), false); } @Override public final String toString(StringTemplate tpl) { return getLoc().getPlain("IntersectionPointOfAB", A.getLabel(tpl), B.getLabel(tpl)); } @Override public void compute() { if (B.isGeoConic()) { intersectConics3D(A, (GeoConicND) B, P); } else { if (algoPlane == null) { algoPlane = new AlgoIntersectPlaneQuadric(cons, A, B, false); algoPlane.compute(); } intersectSamePlane(A, algoPlane.getConic(), P); // TODO limited quadric } } /** * calc intersection points between A, B * * @param A * first conic * @param B * second conic * @param P * intersection points */ public final void intersectConics3D(GeoConicND A, GeoConicND B, GeoPoint3D[] P) { if (!A.isDefined() || !B.isDefined()) { setPointsUndefined(P); return; } CoordSys csA = A.getCoordSys(); CoordSys csB = B.getCoordSys(); // check if coord sys are incident Coords cross = csA.getNormal().crossProduct(csB.getNormal()); if (!cross.equalsForKernel(0, Kernel.MIN_PRECISION)) { // not same plane Coords[] intersection = CoordMatrixUtil.intersectPlanes( A.getCoordSys().getMatrixOrthonormal(), B.getCoordSys().getMatrixOrthonormal()); Coords op = csA.getNormalProjection(intersection[0])[1]; Coords dp = csA.getNormalProjection(intersection[1])[1]; l2d.setCoords(dp.getY(), -dp.getX(), -dp.getY() * op.getX() + dp.getX() * op.getY()); AlgoIntersectLineConic.intersectLineConic(l2d, A, points2d, Kernel.STANDARD_PRECISION); // Application.debug(points2d[0]+"\n"+points2d[1]); P[0].setCoords(csA.getPoint(points2d[0].x, points2d[0].y), false); checkIsOnConic(B, P[0]); P[1].setCoords(csA.getPoint(points2d[1].x, points2d[1].y), false); checkIsOnConic(B, P[1]); if (!P[0].isDefined() && P[1].isDefined()) { P[0].setCoords(P[1].getCoords(), false); P[1].setUndefined(); } P[2].setUndefined(); P[3].setUndefined(); } else { // parallel plane Coords op = csA.getNormalProjection(csB.getOrigin())[1]; if (!Kernel.isZero(op.getZ())) {// coord sys strictly parallel setPointsUndefined(P); // TODO infinite points ? } else {// coord sys included intersectSamePlane(A, B, P); } } } private void intersectSamePlane(GeoConicND A, GeoConicND B, GeoPoint3D[] P) { CoordSys csA = A.getCoordSys(); CoordSys csB = B.getCoordSys(); setPointsUndefined(P); CoordMatrix BtoA = REDUCE_DIM.mul(csB.getMatrixOrthonormal().inverse() .mul(csA.getMatrixOrthonormal())).mul(AUGMENT_DIM); // Log.debug("\nBtoA=\n"+BtoA); CoordMatrix sB = B.getSymetricMatrix(); CoordMatrix sBinA = BtoA.transposeCopy().mul(sB).mul(BtoA); // Log.debug(/*"\ncsA=\n"+csA.getMatrixOrthonormal()+"\ncsB=\n"+csB.getMatrixOrthonormal()+*/"\nsym=\n"+sB+"\ninA\n"+sBinA); A2d.setMatrix(A.getMatrix()); B2d.setMatrix(sBinA); // Log.debug(sBinA.get(1,1)+","+B2d.matrix[0]+""); algo2d.intersectConics(A2d, B2d, points2d); for (int i = 0; i < 4; i++) { P[i].setCoords(csA.getPoint(points2d[i].x, points2d[i].y), false); } } private static void checkIsOnConic(GeoConicND B, GeoPoint3D p) { if (!p.isDefined()) { return; } Coords pp = B.getCoordSys().getNormalProjection(p.getCoords())[1]; Coords pp2d = new Coords(3); pp2d.setX(pp.getX()); pp2d.setY(pp.getY()); pp2d.setZ(pp.getW()); if (!B.isOnFullConic(pp2d, Kernel.MIN_PRECISION)) { p.setUndefined(); } } private static void setPointsUndefined(GeoPoint3D[] P) { for (int i = 0; i < 4; i++) { P[i].setUndefined(); } } @Override public final void initForNearToRelationship() { // TODO } }