/* 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. */ /* * AlgoAngularBisector.java * * Created on 26. Oktober 2001 */ package org.geogebra.common.kernel.algos; 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.geos.GeoVec3D; import org.geogebra.common.kernel.geos.GeoVector; 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; import org.geogebra.common.util.MyMath; /** * * @author Markus */ public class AlgoAngularBisectorPoints extends AlgoElement implements SymbolicParametersBotanaAlgo { private GeoPoint A, B, C; // input private GeoLine bisector; // output // temp private GeoLine g, h; private GeoVector wv; // direction of line bisector private PPolynomial[] botanaPolynomials; private PVariable[] botanaVars; /** * Creates new AlgoLineBisector * * @param cons * @param label * @param A * @param B * @param C */ public AlgoAngularBisectorPoints(Construction cons, String label, GeoPoint A, GeoPoint B, GeoPoint C) { super(cons); this.A = A; this.B = B; this.C = C; bisector = new GeoLine(cons); bisector.setStartPoint(B); setInputOutput(); // for AlgoElement g = new GeoLine(cons); h = new GeoLine(cons); wv = new GeoVector(cons); wv.setCoords(0, 0, 0); // compute bisector of angle(A, B, C) compute(); bisector.setLabel(label); } @Override public Commands getClassName() { return Commands.AngularBisector; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_ANGULAR_BISECTOR; } // for AlgoElement @Override protected void setInputOutput() { input = new GeoElement[3]; input[0] = A; input[1] = B; input[2] = C; setOutputLength(1); setOutput(0, bisector); setDependencies(); // done by AlgoElement } public GeoLine getLine() { return bisector; } // Made public for LocusEqu public GeoPoint getA() { return A; } // Made public for LocusEqu public GeoPoint getB() { return B; } // Made public for LocusEqu public GeoPoint getC() { return C; } @Override public final void compute() { boolean infiniteB = B.isInfinite(); // compute lines g = B v A, h = B v C GeoVec3D.cross(B, A, g); GeoVec3D.cross(B, C, h); // (gx, gy) is direction of g = B v A double gx = g.y; double gy = -g.x; double lenG = MyMath.length(gx, gy); gx /= lenG; gy /= lenG; // (hx, hy) is direction of h = B v C double hx = h.y; double hy = -h.x; double lenH = MyMath.length(hx, hy); hx /= lenH; hy /= lenH; // set direction vector of bisector: (wx, wy) double wx, wy; if (infiniteB) { // if B is at infinity then g and h are parallel // and the bisector line has same direction as g (and h) wx = gx; wy = gy; // calc z value of line in the middle of g, h bisector.z = (g.z / lenG + h.z / lenH) / 2.0; // CONTINUITY handling if (kernel.isContinuous()) { // init old direction vector if (bisector.isDefined()) { wv.x = bisector.y; wv.y = -bisector.x; } // check orientation: take smallest change!!! if (wv.x * wx + wv.y * wy >= 0) { wv.x = wx; wv.y = wy; } else { // angle > 180degrees, change orientation wv.x = -wx; wv.y = -wy; bisector.z = -bisector.z; } } else { wv.x = wx; wv.y = wy; } // set direction vector bisector.x = -wv.y; bisector.y = wv.x; } // standard case: B is not at infinity else { // calc direction vector (wx, wy) of angular bisector // check if angle between vectors is > 90 degrees double ip = gx * hx + gy * hy; if (ip >= 0.0) { // angle < 90 degrees // standard case wx = gx + hx; wy = gy + hy; } else { // ip <= 0.0, angle > 90 degrees // BC - BA is a normalvector of the bisector wx = hy - gy; wy = gx - hx; // if angle > 180 degree change orientation of direction // det(g,h) < 0 if (gx * hy < gy * hx) { wx = -wx; wy = -wy; } } // make (wx, wy) a unit vector double length = MyMath.length(wx, wy); wx /= length; wy /= length; // CONTINUITY handling if (kernel.isContinuous()) { // init old direction vector if (bisector.isDefined()) { wv.x = bisector.y; wv.y = -bisector.x; } // check orientation: take smallest change compared to old // direction vector wv !!! if (wv.x * wx + wv.y * wy >= 0) { wv.x = wx; wv.y = wy; } else { // angle > 180 degrees, change orientation wv.x = -wx; wv.y = -wy; } } else { wv.x = wx; wv.y = wy; } // set bisector bisector.x = -wv.y; bisector.y = wv.x; bisector.z = -(B.inhomX * bisector.x + B.inhomY * bisector.y); } // Application.debug("bisector = (" + bisector.x + ", " + bisector.y + // ", " + bisector.z + ")\n"); } @Override final public String toString(StringTemplate tpl) { // Michael Borcherds 2008-03-30 // simplified to allow better Chinese translation return getLoc().getPlain("AngleBisectorOfABC", A.getLabel(tpl), B.getLabel(tpl), C.getLabel(tpl)); } @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 && C != null) { PVariable[] vA = A.getBotanaVars(A); PVariable[] vB = C.getBotanaVars(C); PVariable[] vC = B.getBotanaVars(B); if (botanaVars == null) { botanaVars = new PVariable[4]; // M botanaVars[0] = new PVariable(kernel); botanaVars[1] = new PVariable(kernel); // A botanaVars[2] = vC[0]; botanaVars[3] = vC[1]; } /* * // Computation borrowed from OpenGeoProver. // Maybe there is an * error somewhere (it does not work properly). * * botanaPolynomials = new Polynomial[1]; * * Polynomial a1 = new Polynomial(vA[0]); Polynomial a2 = new * Polynomial(vA[1]); Polynomial b1 = new Polynomial(vB[0]); * Polynomial b2 = new Polynomial(vB[1]); Polynomial c1 = new * Polynomial(vC[0]); Polynomial c2 = new Polynomial(vC[1]); * Polynomial m1 = new Polynomial(botanaVars[0]); Polynomial m2 = * new Polynomial(botanaVars[1]); * * // ((yM - yC)(xA - xC) - (yA - yC)(xM - xC)) Polynomial * nominator1 = (m2.subtract(c2)) * .multiply(a1.subtract(c1)).subtract( * (a2.subtract(c2)).multiply(m1.subtract(c1))); * * // ((xA - xC)(xM - xC) + (yA - yC)(yM - yC)) Polynomial * denominator1 = (a1.subtract(c1)) * .multiply(m1.subtract(c1)).add((a2 * .subtract(c2)).multiply(m2.subtract(c2))); * * // ((yB - yM)(xC - xM) - (yC - yM)(xB - xM)) Polynomial * nominator2 = * (b2.subtract(m2)).multiply(c1.subtract(m1)).subtract( * (c2.subtract(m2)).multiply(b1.subtract(m1))); * * // ((xC - xM)(xB - xM) + (yC - yM)(yB - yM)) Polynomial * denominator2 = * (c1.subtract(m1)).multiply(b1.subtract(m1)).add((c2 * .subtract(m2)).multiply(b2.subtract(m2))); * * // nominator1 * denominator2 = denominator1 * nominator2 * botanaPolynomials[0] = * nominator1.multiply(denominator2).subtract( * denominator1.multiply(nominator2)); */ // Here we use the scalar product formula, see // https://dev.geogebra.org/trac/wiki/TheoremProvingPlanning#Anglebisectortheorem. // Maybe this method is not the fastest or the most useful one. // incenter1.ggb still gives false for this formula. botanaPolynomials = new PPolynomial[2]; PPolynomial a1 = new PPolynomial(vA[0]); PPolynomial a2 = new PPolynomial(vA[1]); PPolynomial b1 = new PPolynomial(vB[0]); PPolynomial b2 = new PPolynomial(vB[1]); PPolynomial c1 = new PPolynomial(vC[0]); PPolynomial c2 = new PPolynomial(vC[1]); PPolynomial m1 = new PPolynomial(botanaVars[0]); // d1 PPolynomial m2 = new PPolynomial(botanaVars[1]); // d2 // A,M,B collinear (needed for easing computations) botanaPolynomials[0] = PPolynomial.collinear(vA[0], vA[1], vB[0], vB[1], botanaVars[0], botanaVars[1]); // (b1-c1)*(c1-d1) PPolynomial p1 = b1.subtract(c1).multiply(c1.subtract(m1)); // (b2-c2)*(c2-d2) PPolynomial p2 = b2.subtract(c2).multiply(c2.subtract(m2)); // (a1-c1)^2+(a2-c2)^2 PPolynomial p3 = (PPolynomial.sqr(a1.subtract(c1))) .add(PPolynomial.sqr(a2.subtract(c2))); // (a1-c1)*(c1-d1) PPolynomial p4 = a1.subtract(c1).multiply(c1.subtract(m1)); // (a2-c2)*(c2-d2) PPolynomial p5 = a2.subtract(c2).multiply(c2.subtract(m2)); // (b1-c1)^2+(b2-c2)^2 PPolynomial p6 = PPolynomial.sqr(b1.subtract(c1)) .add(PPolynomial.sqr(b2.subtract(c2))); // ((b1-c1)*(c1-d1)+(b2-c2)*(c2-d2))^2*((a1-c1)^2+(a2-c2)^2) // -((a1-c1)*(c1-d1)+(a2-c2)*(c2-d2))^2*((b1-c1)^2+(b2-c2)^2) botanaPolynomials[1] = PPolynomial.sqr((p1.add(p2))).multiply(p3) .subtract(PPolynomial.sqr(p4.add(p5)).multiply(p6)); /* * // Another method. //Maybe there is an error somewhere (it does * not work properly). * * Polynomial m_1 = new Polynomial(botanaVars[2]); Polynomial m_2 = * new Polynomial(botanaVars[3]); * * Polynomial a_1 = b2.subtract(a2); Polynomial b_1 = * a1.subtract(b1); Polynomial c_1 = * (a1.multiply(b2)).subtract(b1.multiply(a2)); Polynomial a_2 = * c2.subtract(a2); Polynomial b_2 = a1.subtract(c1); Polynomial c_2 * = (a1.multiply(c2)).subtract(c1.multiply(a2)); * * botanaPolynomials[0] = a_1.add(a_2).add(a2).subtract(m2); * botanaPolynomials[1] = b_1.add(b_2).add(m1).subtract(a1); * botanaPolynomials[2] = c_1.add(c_2).add(m1.multiply(a2)) * .subtract(a1.multiply(m2)); botanaPolynomials[3] = * a1.add(b_1).add(b_2).subtract(m_1); botanaPolynomials[4] = * a2.subtract(a_1).subtract(a_2).subtract(m_2); */ return botanaPolynomials; } throw new NoSymbolicParametersException(); } }