/* 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. */ /* * AlgoSimpleRootsPolynomial.java * * Created on 28.07.2010, 13:20 */ package org.geogebra.common.kernel.implicit; import java.util.ArrayList; import java.util.List; import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.algos.AlgoRoots; import org.geogebra.common.kernel.algos.AlgoSimpleRootsPolynomial; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoFunction; import org.geogebra.common.kernel.geos.GeoLine; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.util.debug.Log; /** * Algorithm to intersect Implicit polynomials with either lines or polynomials */ public class AlgoIntersectImplicitpolyParametric extends AlgoSimpleRootsPolynomial { private PolynomialFunction tx; private PolynomialFunction ty; private GeoImplicit p; private GeoLine l; private GeoFunction f; private GeoPoint[] tangentPoints; /** * To compute intersection of polynomial and line * * @param c * construction * @param p * polynomial * @param l * line */ public AlgoIntersectImplicitpolyParametric(Construction c, GeoImplicit p, GeoLine l) { super(c, p.toGeoElement(), l); this.p = p; this.l = l; compute(); } /** * To compute intersection of polynomial and function * * @param c * construction * @param p * polynomial * @param f * function */ public AlgoIntersectImplicitpolyParametric(Construction c, GeoImplicit p, GeoFunction f) { super(c, p.toGeoElement(), f); this.p = p; this.f = f; compute(); } @Override protected double getYValue(double t) { return ty.value(t); } @Override protected double getXValue(double t) { return tx.value(t); } @Override public void compute() { if (!p.isDefined()) { return; } double maxT; double minT; if (f != null) { if (!f.isDefined()) { return; } if (!f.isPolynomialFunction(false) || p.getCoeff() == null) { computeNonPoly(f); return; } tx = new PolynomialFunction(new double[] { 0, 1 }); // x=t ty = new PolynomialFunction(f.getFunction() .getNumericPolynomialDerivative(0, false).getCoeffs()); // y=f(t) maxT = f.getMaxParameter(); minT = f.getMinParameter(); } else if (l != null) { if (!l.isDefined()) { points.adjustOutputSize(0); return; } if (p.getCoeff() == null) { computeNonPoly(l.getGeoFunction()); return; } // get parametrisation of line double startP[] = new double[2]; l.getInhomPointOnLine(startP); tx = new PolynomialFunction(new double[] { startP[0], l.getY() }); // x=p1+t*r1 ty = new PolynomialFunction(new double[] { startP[1], -l.getX() }); // y=p2+t*r2 maxT = l.getMaxParameter(); minT = l.getMinParameter(); if (l.getParentAlgorithm() instanceof AlgoTangentImplicitpoly) { tangentPoints = ((AlgoTangentImplicitpoly) l .getParentAlgorithm()).getTangentPoints(); } } else { return; } PolynomialFunction sum = null; PolynomialFunction zs = null; // Insert x and y (univariat)polynomials via the Horner-scheme double[][] coeff = p.getCoeff(); if (coeff != null) { for (int i = coeff.length - 1; i >= 0; i--) { zs = new PolynomialFunction( new double[] { coeff[i][coeff[i].length - 1] }); for (int j = coeff[i].length - 2; j >= 0; j--) { zs = zs.multiply(ty).add(new PolynomialFunction( new double[] { coeff[i][j] }));// y*zs+coeff[i][j]; } if (sum == null) { sum = zs; } else { sum = sum.multiply(tx).add(zs);// sum*x+zs; } } } if (sum == null) { Log.debug("problem in AlgoIntersectImplicitpolyParametric"); return; } setRootsPolynomialWithinRange(sum, minT, maxT); mergeWithTangentPoints(); } private void computeNonPoly(GeoFunction fun) { GeoFunction paramEquation = new GeoFunction(cons, p, null, fun); AlgoRoots algo = new AlgoRoots(cons, paramEquation, new GeoNumeric(cons, fun.getMinParameter()), new GeoNumeric(cons, fun.getMaxParameter())); cons.removeFromConstructionList(algo); GeoPoint[] rootPoints = algo.getRootPoints(); List<double[]> valPairs = new ArrayList<double[]>(); for (int i = 0; i < rootPoints.length; i++) { double t = rootPoints[i].getX(); valPairs.add(new double[] { t, fun.value(t) }); } setPoints(valPairs); } private void mergeWithTangentPoints() { if (tangentPoints == null || tangentPoints.length == 0) { return; } // assumption: tangent points are far apart from each other such that // dist(tangent1,tangent2) > epsilon. boolean addTangent[] = new boolean[tangentPoints.length]; int orgSize = points.size(); while (!points.getElement(orgSize - 1).isDefined()) { --orgSize; } int newSize = orgSize; double EPS2 = Kernel.STANDARD_PRECISION; // TODO: have a better guess of // the error for (int i = 0; i < tangentPoints.length; ++i) { if (tangentPoints[i].getIncidenceList() != null && tangentPoints[i].getIncidenceList().contains(l)) { addTangent[i] = true; for (int j = 0; j < orgSize; ++j) { if (points.getElement(j) .distanceSqr(tangentPoints[i]) < EPS2) { if (addTangent[i]) { points.getElement(j).setUndefined(); --newSize; } else { addTangent[i] = false; points.getElement(i).setCoords(tangentPoints[j]); } } } if (addTangent[i]) { ++newSize; } } else { addTangent[i] = false; } } int definedCount = 0; for (int i = 0; i < orgSize; ++i) { if (points.getElement(i).isDefined()) { if (definedCount != i) { points.getElement(definedCount) .setCoords(points.getElement(i)); } ++definedCount; } } points.adjustOutputSize(newSize); for (int i = 0; i < tangentPoints.length; ++i) { if (addTangent[i]) { points.getElement(definedCount++).setCoords(tangentPoints[i]); } } if (setLabels) { points.updateLabels(); } } @Override public Commands getClassName() { return Commands.Intersect; } @Override public int getRelatedModeID() { return EuclidianConstants.MODE_INTERSECT; } }