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.GeoLine; import org.geogebra.common.kernel.geos.GeoSegment; import org.geogebra.common.kernel.prover.polynomial.PPolynomial; import org.geogebra.common.kernel.prover.polynomial.PVariable; /** * Decides if the lines are concurrent. Can be embedded into the Prove command * to work symbolically. * * @author Simon Weitzhofer 18th April 2012 * @author Zoltan Kovacs <zoltan@geogebra.org> */ public class AlgoAreConcurrent extends AlgoElement implements SymbolicParametersAlgo, SymbolicParametersBotanaAlgoAre { private GeoLine inputLine1, inputLine2, inputLine3; // input private GeoBoolean outputBoolean; // output private PPolynomial[] polynomials; private PPolynomial[][] botanaPolynomials; /** * Creates a new AlgoAreConcurrent function * * @param cons * the Construction * @param inputLine1 * the first line * @param inputLine2 * the second line * @param inputLine3 * the third line */ public AlgoAreConcurrent(final Construction cons, final GeoLine inputLine1, final GeoLine inputLine2, final GeoLine inputLine3) { super(cons); this.inputLine1 = inputLine1; this.inputLine2 = inputLine2; this.inputLine3 = inputLine3; outputBoolean = new GeoBoolean(cons); setInputOutput(); compute(); } /** * Creates a new AlgoAreConcurrent function * * @param cons * the Construction * @param label * the label for the AlgoAreConcurrent object * @param inputLine1 * the first line * @param inputLine2 * the second line * @param inputLine3 * the third line */ public AlgoAreConcurrent(final Construction cons, final String label, final GeoLine inputLine1, final GeoLine inputLine2, final GeoLine inputLine3) { this(cons, inputLine1, inputLine2, inputLine3); outputBoolean.setLabel(label); } @Override public Commands getClassName() { return Commands.AreConcurrent; } @Override protected void setInputOutput() { input = new GeoElement[3]; input[0] = inputLine1; input[1] = inputLine2; input[2] = inputLine3; super.setOutputLength(1); super.setOutput(0, outputBoolean); setDependencies(); // done by AlgoElement } /** * Returns the result of the test * * @return true if the three lines are concurrent i.e. they intersect in a * common point, false otherwise */ public GeoBoolean getResult() { return outputBoolean; } @Override public final void compute() { outputBoolean.setValue( GeoLine.concurrent(inputLine1, inputLine2, inputLine3)); } @Override public SymbolicParameters getSymbolicParameters() { return new SymbolicParameters(this); } @Override public void getFreeVariables(HashSet<PVariable> variables) throws NoSymbolicParametersException { if ((inputLine1 instanceof GeoSegment) || (inputLine2 instanceof GeoSegment) || (inputLine3 instanceof GeoSegment)) { throw new NoSymbolicParametersException(); } if (inputLine1 != null && inputLine2 != null && inputLine3 != null) { inputLine1.getFreeVariables(variables); inputLine2.getFreeVariables(variables); inputLine3.getFreeVariables(variables); return; } throw new NoSymbolicParametersException(); } @Override public int[] getDegrees() throws NoSymbolicParametersException { if ((inputLine1 instanceof GeoSegment) || (inputLine2 instanceof GeoSegment) || (inputLine3 instanceof GeoSegment)) { throw new NoSymbolicParametersException(); } if (inputLine1 != null && inputLine2 != null && inputLine3 != null) { int[] degree1 = inputLine1.getDegrees(); int[] degree2 = inputLine2.getDegrees(); int[] degree3 = inputLine3.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 ((inputLine1 instanceof GeoSegment) || (inputLine2 instanceof GeoSegment) || (inputLine3 instanceof GeoSegment)) { throw new NoSymbolicParametersException(); } if (inputLine1 != null && inputLine2 != null && inputLine3 != null) { BigInteger[] coords1 = inputLine1.getExactCoordinates(values); BigInteger[] coords2 = inputLine2.getExactCoordinates(values); BigInteger[] coords3 = inputLine3.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 ((inputLine1 instanceof GeoSegment) || (inputLine2 instanceof GeoSegment) || (inputLine3 instanceof GeoSegment)) { throw new NoSymbolicParametersException(); } if (inputLine1 != null && inputLine2 != null && inputLine3 != null) { PPolynomial[] coords1 = inputLine1.getPolynomials(); PPolynomial[] coords2 = inputLine2.getPolynomials(); PPolynomial[] coords3 = inputLine3.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 (inputLine1 != null && inputLine2 != null && inputLine3 != null) { PVariable[][] v = new PVariable[3][4]; v[0] = inputLine1.getBotanaVars(inputLine1); v[1] = inputLine2.getBotanaVars(inputLine2); v[2] = inputLine3.getBotanaVars(inputLine3); PVariable[] nv = new PVariable[2]; // new point for collinearity nv[0] = new PVariable(kernel); nv[1] = new PVariable(kernel); // We need three collinearities with an extra point. botanaPolynomials = new PPolynomial[1][3]; for (int i = 0; i < 3; ++i) { botanaPolynomials[0][i] = PPolynomial.collinear(v[i][0], v[i][1], v[i][2], v[i][3], nv[0], nv[1]); } return botanaPolynomials; } throw new NoSymbolicParametersException(); } }