/*
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.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.CoordSys;
import org.geogebra.common.kernel.Matrix.Coords;
import org.geogebra.common.kernel.algos.AlgoIntersectLineConic;
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.GeoConicPartND;
/**
*
* @author mathieu
*
*/
public abstract class AlgoIntersectConic3D extends AlgoIntersect3D {
protected GeoElement firstGeo; // input
protected GeoConicND c; // input
protected GeoPoint3D[] P; // output
private GeoPoint3D[] D;
/** 2d description of g when included in conic coord sys */
private GeoLine g2d;
/** 2d points created by using AlgoIntersectLineConic.intersectLineConic */
private GeoPoint[] points2d;
/**
*
* @param cons
* @param c
*/
AlgoIntersectConic3D(Construction cons) {
super(cons);
p2d = new Coords(3);
// helper algo
g2d = new GeoLine(cons);
points2d = new GeoPoint[2];
for (int i = 0; i < 2; i++) {
points2d[i] = new GeoPoint(cons);
}
}
AlgoIntersectConic3D(Construction cons, GeoElement firstGeo, GeoConicND c) {
this(cons);
this.firstGeo = firstGeo;
this.c = c;
P = new GeoPoint3D[2];
D = new GeoPoint3D[2];
for (int i = 0; i < 2; i++) {
P[i] = new GeoPoint3D(cons);
D[i] = new GeoPoint3D(cons);
}
setInputOutput(); // for AlgoElement
compute();
}
// for AlgoElement
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = firstGeo;
input[1] = c;
setOutput(P);
noUndefinedPointsInAlgebraView();
setDependencies(); // done by AlgoElement
}
@Override
public final GeoPoint3D[] getIntersectionPoints() {
return P;
}
@Override
protected GeoPoint3D[] getLastDefinedIntersectionPoints() {
return D;
}
/**
*
* @return conic input
*/
GeoConicND getConic() {
return c;
}
@Override
public final String toString(StringTemplate tpl) {
return getLoc().getPlain("IntersectionPointOfAB", c.getLabel(tpl),
firstGeo.getLabel(tpl));
}
/**
*
* @return start point for first geo
*/
protected abstract Coords getFirstGeoStartInhomCoords();
/**
*
* @return direction for first geo
*/
protected abstract Coords getFirstGeoDirectionInD3();
/**
*
* @param p
* point coords
* @return true if coords are in the first geo as limited path
*/
protected abstract boolean getFirstGeoRespectLimitedPath(Coords p);
@Override
public void compute() {
intersect(c, P);
}
private Coords p2d;
/**
* calc intersection points with the conic
*
* @param c
* conic
* @param P
* points
*/
protected final void intersect(GeoConicND c, GeoPoint3D[] P) {
CoordSys cs = c.getCoordSys();
Coords o = getFirstGeoStartInhomCoords();
Coords d = getFirstGeoDirectionInD3();
// project line on conic coord sys
Coords dp = cs.getNormalProjection(d)[1];
if (!Kernel.isZero(dp.getZ())) { // line intersect conic coord sys
Coords globalCoords = new Coords(4);
Coords inPlaneCoords = new Coords(4);
o.projectPlaneThruV(cs.getMatrixOrthonormal(), d, globalCoords,
inPlaneCoords);
p2d.setX(inPlaneCoords.getX());
p2d.setY(inPlaneCoords.getY());
p2d.setZ(inPlaneCoords.getW());
// check if intersect point is on conic
if (c.isOnFullConic(p2d, Kernel.MIN_PRECISION)
&& getFirstGeoRespectLimitedPath(globalCoords)) {
P[0].setCoords(globalCoords, false);
} else {
setPointsUndefined();
}
} else {// line parallel to conic coord sys
Coords op = cs.getNormalProjection(o)[1];
if (!Kernel.isZero(op.getZ())) {// line not included
setPointsUndefined(); // TODO infinite points ?
} else {// line included
g2d.setCoords(dp.getY(), -dp.getX(),
-dp.getY() * op.getX() + dp.getX() * op.getY());
intersectLineIncluded(c, P, cs, g2d);
}
}
}
/**
* intersect with line included
*
* @param c
* conic
* @param P
* points
* @param cs
* conic coord sys
* @param g
* line
*/
protected void intersectLineIncluded(GeoConicND c, GeoPoint3D[] P,
CoordSys cs, GeoLine g) {
AlgoIntersectLineConic.intersectLineConic(g, c, points2d,
Kernel.STANDARD_PRECISION);
// Application.debug(points2d[0]+"\n"+points2d[1]);
P[0].setCoords(cs.getPoint(points2d[0].x, points2d[0].y), false);
checkIsOnFirstGeo(P[0]);
checkIsOnConicPart(c, points2d[0], P[0]);
P[1].setCoords(cs.getPoint(points2d[1].x, points2d[1].y), false);
checkIsOnFirstGeo(P[1]);
checkIsOnConicPart(c, points2d[1], P[1]);
}
private Coords tmpCoords;
private void checkIsOnConicPart(GeoConicND c, GeoPoint point,
GeoPoint3D p3d) {
if (c.isGeoConicPart()) {
if (!p3d.isDefined()) {
return;
}
if (tmpCoords == null) {
tmpCoords = new Coords(3);
tmpCoords.setZ(1);
}
tmpCoords.setX(point.x);
tmpCoords.setY(point.y);
if (!((GeoConicPartND) c).getParameters().isOnPath(tmpCoords)) {
p3d.setUndefined();
}
}
}
/**
* if p is really on first geo
*
* @param p
* point
*/
protected abstract void checkIsOnFirstGeo(GeoPoint3D p);
private void setPointsUndefined() {
for (int i = 0; i < 2; i++) {
P[i].setUndefined();
}
}
/**
* Returns the index in output[] of the intersection point that is closest
* to the coordinates (xRW, yRW) TODO: move to an interface
*/
/*
* int getClosestPointIndex(double xRW, double yRW, CoordMatrix4x4 mat) {
* GeoPoint3D[] P = getIntersectionPoints(); double x, y, lengthSqr, mindist
* = Double.POSITIVE_INFINITY; int minIndex = 0; for (int i = 0; i <
* P.length; i++) { Coords toSceneInhomCoords =
* mat.mul(P[i].getCoords().getCoordsLast1()).getInhomCoords(); x =
* (toSceneInhomCoords.getX() - xRW); y = (toSceneInhomCoords.getY() - yRW);
* lengthSqr = x * x + y * y; if (lengthSqr < mindist) { mindist =
* lengthSqr; minIndex = i; } }
*
* return minIndex; }
*/
@Override
public final void initForNearToRelationship() {
// TODO
}
/**
*
* @return first geo
*/
protected GeoElement getFirtGeo() {
return firstGeo;
}
/*
*
* @param i index (0 or 1)
*
* @return i-th 2D point last computed
*
* public GeoPoint getPoint2D(int i){ return points2d[i]; }
*/
}