package org.geogebra.common.kernel.prover;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Path;
import org.geogebra.common.kernel.algos.AlgoElement;
import org.geogebra.common.kernel.algos.AlgoPointOnPath;
import org.geogebra.common.kernel.algos.SymbolicParametersBotanaAlgo;
import org.geogebra.common.kernel.algos.SymbolicParametersBotanaAlgoAre;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoBoolean;
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.prover.polynomial.PPolynomial;
import org.geogebra.common.kernel.prover.polynomial.PVariable;
/**
* Decides if the point lies on a path. Currently only point/line check is
* implemented. TODO: consider adding this as a command (and add a numerical
* check in compute()). Then embedding into the Prove/ProveDetails commands will
* give symbolic functionality automatically.
*
* @author Zoltan Kovacs <zoltan@geogebra.org>
*/
public class AlgoIsOnPath extends AlgoElement
implements SymbolicParametersBotanaAlgoAre {
private GeoPoint inputPoint;
private Path inputPath;
private GeoBoolean outputBoolean; // output
private PPolynomial[][] botanaPolynomials;
private PVariable[] botanaVars;
/**
* Creates a new AlgoIsOnPath function
*
* @param cons
* the Construction
* @param inputPoint
* the point
* @param inputPath
* the line
*/
public AlgoIsOnPath(final Construction cons, final GeoPoint inputPoint,
final Path inputPath) {
super(cons);
this.inputPoint = inputPoint;
this.inputPath = inputPath;
outputBoolean = new GeoBoolean(cons);
setInputOutput();
compute();
}
@Override
public Commands getClassName() {
// TODO: change this
// return Commands.IsOnPath;
return null;
}
@Override
protected void setInputOutput() {
input = new GeoElement[2];
input[0] = inputPoint;
input[1] = (GeoElement) inputPath;
super.setOutputLength(1);
super.setOutput(0, outputBoolean);
setDependencies(); // done by AlgoElement
}
/**
* Returns the result of the test
*
* @return true if the three points lie on one line, false otherwise
*/
public GeoBoolean getResult() {
return outputBoolean;
}
@Override
public final void compute() {
// TODO: implement this
outputBoolean.setUndefined();
}
/**
* @return botana vars
*/
public PVariable[] getBotanaVars() {
return botanaVars;
}
@Override
public PPolynomial[][] getBotanaPolynomials()
throws NoSymbolicParametersException {
if (botanaPolynomials != null) {
return botanaPolynomials;
}
if (inputPoint != null && inputPath != null) {
if (inputPath instanceof GeoLine) {
PVariable[] fv1 = inputPoint.getBotanaVars(inputPoint);
PVariable[] fv2 = ((GeoLine) inputPath)
.getBotanaVars(inputPath);
botanaPolynomials = new PPolynomial[1][1];
botanaPolynomials[0][0] = PPolynomial.collinear(fv1[0], fv1[1],
fv2[0], fv2[1], fv2[2], fv2[3]);
return botanaPolynomials;
} else if (inputPath instanceof GeoConic) {
return getPolynomialsConic();
}
}
throw new NoSymbolicParametersException();
}
private PPolynomial[][] getPolynomialsConic()
throws NoSymbolicParametersException {
if (((GeoConic) inputPath).isCircle()) {
PVariable[] fv1 = inputPoint.getBotanaVars(inputPoint);
PVariable[] fv2 = ((GeoConic) inputPath).getBotanaVars(inputPath);
botanaPolynomials = new PPolynomial[1][1];
botanaPolynomials[0][0] = PPolynomial.equidistant(fv1[0], fv1[1],
fv2[0], fv2[1], fv2[2], fv2[3]);
return botanaPolynomials;
}
if (((GeoConic) inputPath).isParabola()) {
if (botanaVars == null) {
botanaVars = new PVariable[2];
// T - projection of P to directrix
botanaVars[0] = new PVariable(kernel);
botanaVars[1] = new PVariable(kernel);
}
PVariable[] fv1 = inputPoint.getBotanaVars(inputPoint);
PVariable[] fv2 = ((GeoConic) inputPath).getBotanaVars(inputPath);
botanaPolynomials = new PPolynomial[1][3];
// |FP| = |PT|
botanaPolynomials[0][0] = PPolynomial.equidistant(fv2[8], fv2[9],
fv1[0], fv1[1], botanaVars[0], botanaVars[1]);
// A,T,B collinear
botanaPolynomials[0][1] = PPolynomial.collinear(fv2[4], fv2[5],
botanaVars[0], botanaVars[1], fv2[6], fv2[7]);
// PT orthogonal AB
botanaPolynomials[0][2] = PPolynomial.perpendicular(fv1[0], fv1[1],
botanaVars[0], botanaVars[1], fv2[4], fv2[5], fv2[6],
fv2[7]);
return botanaPolynomials;
}
if (((GeoConic) inputPath).isEllipse()
|| ((GeoConic) inputPath).isHyperbola()) {
if (botanaVars == null
&& ((GeoElement) inputPoint).getParentAlgorithm() != null) {
botanaVars = new PVariable[4];
botanaVars = ((SymbolicParametersBotanaAlgo) ((GeoElement) inputPoint)
.getParentAlgorithm()).getBotanaVars(inputPoint);
}
// botana variables of input point
PVariable[] fv1 = inputPoint.getBotanaVars(inputPoint);
// botana variables of input path
PVariable[] fv2 = ((GeoConic) inputPath).getBotanaVars(inputPath);
botanaPolynomials = new PPolynomial[1][3];
PPolynomial e_1 = new PPolynomial();
PPolynomial e_2 = new PPolynomial();
AlgoElement algoParent = ((GeoElement) inputPoint)
.getParentAlgorithm();
// case input point is point on ellipse/hyperbola
if (algoParent instanceof AlgoPointOnPath
&& (((GeoConic) ((AlgoPointOnPath) algoParent).getPath())
.isEllipse() || ((GeoConic) ((AlgoPointOnPath) algoParent)
.getPath()).isHyperbola())) {
e_1 = new PPolynomial(botanaVars[2]);
e_2 = new PPolynomial(botanaVars[3]);
}
// case input point is point from ellipses definition
else if (fv1[0].equals(fv2[10]) && fv1[1].equals(fv2[11])) {
e_1 = new PPolynomial(fv2[2]);
e_2 = new PPolynomial(fv2[3]);
} else {
e_1 = new PPolynomial(new PVariable(kernel));
e_2 = new PPolynomial(new PVariable(kernel));
}
PPolynomial d1 = new PPolynomial(fv2[2]);
PPolynomial d2 = new PPolynomial(fv2[3]);
// d1+d2 = e1'+e2'
botanaPolynomials[0][0] = d1.add(d2).subtract(e_1).subtract(e_2);
// e1'^2=Polynomial.sqrDistance(a1,a2,p1,p2)
botanaPolynomials[0][1] = PPolynomial.sqrDistance(fv2[6], fv2[7],
fv1[0], fv1[1]).subtract(e_1.multiply(e_1));
// e2'^2=Polynomial.sqrDistance(b1,b2,p1,p2)
botanaPolynomials[0][2] = PPolynomial.sqrDistance(fv2[8], fv2[9],
fv1[0], fv1[1]).subtract(e_2.multiply(e_2));
return botanaPolynomials;
}
throw new NoSymbolicParametersException();
}
}