package org.geogebra.common.kernel.prover; import java.math.BigInteger; import java.util.HashMap; import java.util.HashSet; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.algos.SymbolicParameters; import org.geogebra.common.kernel.algos.SymbolicParametersAlgo; 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.GeoElement; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.kernel.kernelND.GeoPointND; import org.geogebra.common.kernel.prover.polynomial.PPolynomial; import org.geogebra.common.kernel.prover.polynomial.PVariable; /** * Decides if the points are collinear. Can be embedded into the Prove command * to work symbolically. * * @author Simon Weitzhofer 18th April 2012 * @author Zoltan Kovacs <zoltan@geogebra.org> */ public class AlgoAreCollinear extends AlgoElement implements SymbolicParametersAlgo, SymbolicParametersBotanaAlgoAre { private GeoPointND inputPoint1, inputPoint2, inputPoint3; // input private GeoBoolean outputBoolean; // output private PPolynomial[] polynomials; private PPolynomial[][] botanaPolynomials; /** * Creates a new AlgoAreCollinear function * * @param cons * the Construction * @param inputPoint1 * the first point * @param inputPoint2 * the second point * @param inputPoint3 * the third point */ public AlgoAreCollinear(final Construction cons, final GeoPointND inputPoint1, final GeoPointND inputPoint2, final GeoPointND inputPoint3) { super(cons); this.inputPoint1 = inputPoint1; this.inputPoint2 = inputPoint2; this.inputPoint3 = inputPoint3; outputBoolean = new GeoBoolean(cons); setInputOutput(); compute(); } @Override public Commands getClassName() { return Commands.AreCollinear; } @Override protected void setInputOutput() { input = new GeoElement[3]; input[0] = inputPoint1.toGeoElement(); input[1] = inputPoint2.toGeoElement(); input[2] = inputPoint3.toGeoElement(); 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() { outputBoolean.setValue( GeoPoint.collinearND(inputPoint1, inputPoint2, inputPoint3)); } @Override public SymbolicParameters getSymbolicParameters() { return new SymbolicParameters(this); } @Override public void getFreeVariables(HashSet<PVariable> variables) throws NoSymbolicParametersException { if (getInputPoint1() != null && getInputPoint2() != null && getInputPoint3() != null) { getInputPoint1().getFreeVariables(variables); getInputPoint2().getFreeVariables(variables); getInputPoint3().getFreeVariables(variables); return; } throw new NoSymbolicParametersException(); } @Override public int[] getDegrees() throws NoSymbolicParametersException { if (getInputPoint1() != null && getInputPoint2() != null && getInputPoint3() != null) { int[] degree1 = getInputPoint1().getDegrees(); int[] degree2 = getInputPoint2().getDegrees(); int[] degree3 = getInputPoint3().getDegrees(); int[] result = new int[1]; result[0] = Math.max(degree1[0] + degree2[1] + degree3[2], Math.max( degree2[0] + degree3[1] + degree1[2], Math.max(degree3[0] + degree1[1] + degree2[2], Math.max( degree3[0] + degree2[1] + degree1[2], Math.max( degree2[0] + degree1[1] + degree3[2], degree1[0] + degree3[1] + degree2[2]))))); return result; } throw new NoSymbolicParametersException(); } @Override public BigInteger[] getExactCoordinates( final HashMap<PVariable, BigInteger> values) throws NoSymbolicParametersException { if (getInputPoint1() != null && getInputPoint2() != null && getInputPoint3() != null) { BigInteger[] coords1 = getInputPoint1().getExactCoordinates(values); BigInteger[] coords2 = getInputPoint2().getExactCoordinates(values); BigInteger[] coords3 = getInputPoint3().getExactCoordinates(values); BigInteger[] coords = new BigInteger[1]; coords[0] = coords1[0].multiply(coords2[1]).multiply(coords3[2]) .add(coords2[0].multiply(coords3[1]).multiply(coords1[2])) .add(coords3[0].multiply(coords1[1]).multiply(coords2[2])) .subtract( coords3[0].multiply(coords2[1]).multiply(coords1[2]) .add(coords2[0].multiply(coords1[1]) .multiply(coords3[2])) .add(coords1[0].multiply(coords3[1]) .multiply(coords2[2]))); return coords; } throw new NoSymbolicParametersException(); } @Override public PPolynomial[] getPolynomials() throws NoSymbolicParametersException { if (polynomials != null) { return polynomials; } if (getInputPoint1() != null && getInputPoint2() != null && getInputPoint3() != null) { PPolynomial[] coords1 = getInputPoint1().getPolynomials(); PPolynomial[] coords2 = getInputPoint2().getPolynomials(); PPolynomial[] coords3 = getInputPoint3().getPolynomials(); polynomials = new PPolynomial[1]; polynomials[0] = coords1[0].multiply(coords2[1]) .multiply(coords3[2]) .add(coords2[0].multiply(coords3[1]).multiply(coords1[2])) .add(coords3[0].multiply(coords1[1]).multiply(coords2[2])) .subtract( coords3[0].multiply(coords2[1]).multiply(coords1[2]) .add(coords2[0].multiply(coords1[1]) .multiply(coords3[2])) .add(coords1[0].multiply(coords3[1]) .multiply(coords2[2]))); return polynomials; } throw new NoSymbolicParametersException(); } @Override public PPolynomial[][] getBotanaPolynomials() throws NoSymbolicParametersException { if (botanaPolynomials != null) { return botanaPolynomials; } if (getInputPoint1() != null && getInputPoint2() != null && getInputPoint3() != null) { PVariable[] fv1 = getInputPoint1().getBotanaVars(getInputPoint1()); PVariable[] fv2 = getInputPoint2().getBotanaVars(getInputPoint2()); PVariable[] fv3 = getInputPoint3().getBotanaVars(getInputPoint3()); botanaPolynomials = new PPolynomial[1][1]; botanaPolynomials[0][0] = PPolynomial.collinear(fv1[0], fv1[1], fv2[0], fv2[1], fv3[0], fv3[1]); return botanaPolynomials; } throw new NoSymbolicParametersException(); } private GeoPoint getInputPoint1() { return (GeoPoint) inputPoint1; } private GeoPoint getInputPoint2() { return (GeoPoint) inputPoint2; } private GeoPoint getInputPoint3() { return (GeoPoint) inputPoint3; } }