/* 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. */ package org.geogebra.common.kernel.algos; import java.math.BigInteger; import java.util.HashMap; import java.util.HashSet; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.StringTemplate; import org.geogebra.common.kernel.commands.Commands; 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.GeoElementND; import org.geogebra.common.kernel.prover.NoSymbolicParametersException; import org.geogebra.common.kernel.prover.polynomial.PPolynomial; import org.geogebra.common.kernel.prover.polynomial.PVariable; public class AlgoLineBisector extends AlgoElement implements SymbolicParametersAlgo, SymbolicParametersBotanaAlgo { private GeoPoint A, B; // input private GeoLine g; // output // temp private GeoPoint midPoint; private PPolynomial[] polynomials; private PPolynomial[] botanaPolynomials; private PVariable[] botanaVars; /** Creates new AlgoLineBisector */ public AlgoLineBisector(Construction cons, String label, GeoPoint A, GeoPoint B) { super(cons); this.A = A; this.B = B; g = new GeoLine(cons); midPoint = new GeoPoint(cons); g.setStartPoint(midPoint); setInputOutput(); // for AlgoElement // compute bisector of A, B compute(); g.setLabel(label); } @Override public Commands getClassName() { return Commands.LineBisector; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_LINE_BISECTOR; } // for AlgoElement @Override protected void setInputOutput() { input = new GeoElement[2]; input[0] = A; input[1] = B; super.setOutputLength(1); super.setOutput(0, g); setDependencies(); // done by AlgoElement } public GeoLine getLine() { return g; } // Made public for LocusEqu public GeoPoint getA() { return A; } // Made public for LocusEqu public GeoPoint getB() { return B; } // Made public for LocusEqu public GeoPoint getMidPoint() { return midPoint; } // line through P normal to v @Override public final void compute() { // get inhomogenous coords double ax = A.inhomX; double ay = A.inhomY; double bx = B.inhomX; double by = B.inhomY; // comput line g.x = ax - bx; g.y = ay - by; midPoint.setCoords((ax + bx), (ay + by), 2.0); g.z = -(midPoint.x * g.x + midPoint.y * g.y) / 2.0; } @Override public SymbolicParameters getSymbolicParameters() { return new SymbolicParameters(this); } @Override public void getFreeVariables(HashSet<PVariable> variables) throws NoSymbolicParametersException { if (A != null && B != null) { A.getFreeVariables(variables); B.getFreeVariables(variables); return; } throw new NoSymbolicParametersException(); } @Override public int[] getDegrees() throws NoSymbolicParametersException { if (A != null && B != null) { int[] degree1 = A.getDegrees(); int[] degree2 = B.getDegrees(); int[] result = new int[3]; result[0] = Math.max(degree1[0] + degree1[2] + 2 * degree2[2], 2 * degree1[2] + degree2[0] + degree2[2]); result[1] = Math.max(degree1[1] + degree1[2] + 2 * degree2[2], 2 * degree1[2] + degree2[1] + degree2[2]); result[2] = 2 * Math.max( Math.max(degree1[2] + degree2[0], degree1[2] + degree2[1]), Math.max(degree1[0] + degree2[2], degree1[1] + degree2[2])); return result; } throw new NoSymbolicParametersException(); } @Override public BigInteger[] getExactCoordinates( HashMap<PVariable, BigInteger> values) throws NoSymbolicParametersException { if (A != null && B != null) { BigInteger[] coords1 = A.getExactCoordinates(values); BigInteger[] coords2 = B.getExactCoordinates(values); BigInteger[] result = new BigInteger[3]; // 2 az bz (-az bx + ax bz) result[0] = BigInteger.valueOf(2).multiply(coords1[2]) .multiply(coords2[2]) .multiply(coords1[0].multiply(coords2[2]) .subtract(coords2[0].multiply(coords1[2]))); // 2 az bz (-az by + ay bz) result[1] = BigInteger.valueOf(2).multiply(coords1[2]) .multiply(coords2[2]) .multiply(coords1[1].multiply(coords2[2]) .subtract(coords2[1].multiply(coords1[2]))); // (az bx - ax bz) (az bx + ax bz) - (-az by + ay bz) (az by + ay // bz) result[2] = coords1[2].multiply(coords2[0]) .subtract(coords1[0].multiply(coords2[2])) .multiply(coords1[2].multiply(coords2[0]) .add(coords1[0].multiply(coords2[2]))) .subtract(coords1[1].multiply(coords2[2]) .subtract(coords1[2].multiply(coords2[1])) .multiply(coords1[1].multiply(coords2[2]) .add(coords1[2].multiply(coords2[1])))); return result; } throw new NoSymbolicParametersException(); } @Override public PPolynomial[] getPolynomials() throws NoSymbolicParametersException { if (polynomials != null) { return polynomials; } if (A != null && B != null) { PPolynomial[] coords1 = A.getPolynomials(); PPolynomial[] coords2 = B.getPolynomials(); polynomials = new PPolynomial[3]; // 2 az bz (-az bx + ax bz) polynomials[0] = (new PPolynomial(2)).multiply(coords1[2]) .multiply(coords2[2]) .multiply(coords1[0].multiply(coords2[2]) .subtract(coords2[0].multiply(coords1[2]))); // 2 az bz (-az by + ay bz) polynomials[1] = (new PPolynomial(2)).multiply(coords1[2]) .multiply(coords2[2]) .multiply(coords1[1].multiply(coords2[2]) .subtract(coords2[1].multiply(coords1[2]))); // (az bx - ax bz) (az bx + ax bz) - (-az by + ay bz) (az by + ay // bz) polynomials[2] = coords1[2].multiply(coords2[0]) .subtract(coords1[0].multiply(coords2[2])) .multiply(coords1[2].multiply(coords2[0]) .add(coords1[0].multiply(coords2[2]))) .subtract(coords1[1].multiply(coords2[2]) .subtract(coords1[2].multiply(coords2[1])) .multiply(coords1[1].multiply(coords2[2]) .add(coords1[2].multiply(coords2[1])))); return polynomials; } throw new NoSymbolicParametersException(); } @Override public PVariable[] getBotanaVars(GeoElementND geo) { return botanaVars; } @Override public PPolynomial[] getBotanaPolynomials(GeoElementND geo) throws NoSymbolicParametersException { if (botanaPolynomials != null) { return botanaPolynomials; } if (A != null && B != null) { PVariable[] vA = A.getBotanaVars(A); PVariable[] vB = B.getBotanaVars(B); if (botanaVars == null) { botanaVars = new PVariable[4]; // storing 4 new variables (C, D) botanaVars[0] = new PVariable(kernel); botanaVars[1] = new PVariable(kernel); botanaVars[2] = new PVariable(kernel); botanaVars[3] = new PVariable(kernel); } botanaPolynomials = SymbolicParameters .botanaPolynomialsLineBisector(vA[0], vA[1], vB[0], vB[1], botanaVars); return botanaPolynomials; } throw new NoSymbolicParametersException(); } // /////////////////////////////// // TRICKS FOR XOY PLANE // /////////////////////////////// @Override protected int getInputLengthForXML() { return getInputLengthForXMLMayNeedXOYPlane(); } @Override protected int getInputLengthForCommandDescription() { return getInputLengthForCommandDescriptionMayNeedXOYPlane(); } @Override public GeoElementND getInput(int i) { return getInputMaybeXOYPlane(i); } @Override final public String toString(StringTemplate tpl) { return getLoc().getPlain("LineBisectorOfA", A.getLabel(tpl) + B.getLabel(tpl)); } }