/*
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 27.07.2010, 17:41
*/
package org.geogebra.common.kernel.algos;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.math3.analysis.polynomials.PolynomialFunction;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.EquationSolverInterface;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.commands.Commands;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoPoint;
public abstract class AlgoSimpleRootsPolynomial extends AlgoIntersect {
protected boolean setLabels;
protected EquationSolverInterface eqnSolver;
protected GeoElement[] geos;
protected OutputHandler<GeoPoint> points;
public AlgoSimpleRootsPolynomial(Construction c) {
super(c);
eqnSolver = cons.getKernel().getEquationSolver();
points = new OutputHandler<GeoPoint>(new elementFactory<GeoPoint>() {
@Override
public GeoPoint newElement() {
GeoPoint p = new GeoPoint(cons);
// p.setCoords(0, 0, 1);
p.setUndefined();
p.setParentAlgorithm(AlgoSimpleRootsPolynomial.this);
return p;
}
});
}
public AlgoSimpleRootsPolynomial(Construction c, GeoElement... geos) {
this(c);
this.geos = new GeoElement[geos.length];
for (int i = 0; i < geos.length; i++) {
this.geos[i] = geos[i];
}
setInputOutput();
}
/**
* @param pf
* assigns a PolynomialFunction to this Algorithm which roots
* lead to one or more output Points
*/
public void setRootsPolynomial(PolynomialFunction pf) {
doCalc(pf);
}
public void setRootsPolynomialWithinRange(PolynomialFunction pf, double min,
double max) {
doCalc(pf, min, max);
}
@Override
public GeoPoint[] getIntersectionPoints() {
return points.getOutput(new GeoPoint[0]);
}
@Override
protected GeoPoint[] getLastDefinedIntersectionPoints() {
return null;
}
@Override
protected void setInputOutput() {
input = geos;
setDependencies();
}
/**
* @param roots
* array with the coefficients of the polynomial<br/>
* the roots of the polynomial are assigned to the first n
* elements of <b>roots</b>
* @param eqnSolver
* @return number of distinct roots
*/
public static int getRoots(double[] roots,
EquationSolverInterface eqnSolver) {
int nrRealRoots = eqnSolver.polynomialRoots(roots, false);
// StringBuilder sb=new StringBuilder();
// for (int i=0;i<nrRealRoots;i++){
// if (i>0)
// sb.append(',');
// sb.append(roots[i]);
// }
// Application.debug("roots->"+sb);
if (nrRealRoots > 1) {
int c = 0;
Arrays.sort(roots, 0, nrRealRoots);
double last = roots[0];
for (int i = 1; i < nrRealRoots; i++) {
if (roots[i] - last <= Kernel.MIN_PRECISION) {
c++;
} else {
last = roots[i];
if (c > 0) {
roots[i - c] = roots[i];
}
}
}
nrRealRoots -= c;
}
return nrRealRoots;
}
protected void doCalc(PolynomialFunction rootsPoly) {
double roots[] = rootsPoly.getCoefficients();
int nrRealRoots = 0;
if (roots.length > 1) {
nrRealRoots = getRoots(roots, eqnSolver);
}
makePoints(roots, nrRealRoots);
}
protected void doCalc(PolynomialFunction rootsPoly, double min,
double max) {
double roots[] = rootsPoly.getCoefficients();
int nrRealRoots = 0;
if (roots.length > 1) {
nrRealRoots = getRoots(roots, eqnSolver);
}
for (int i = 0; i < nrRealRoots; ++i) {
if (Kernel.isGreater(roots[i], max, Kernel.STANDARD_PRECISION)
|| Kernel.isGreater(min, roots[i],
Kernel.STANDARD_PRECISION)) {
roots[i] = Double.NaN;
}
}
makePoints(roots, nrRealRoots);
}
private static double distancePairSq(double[] p1, double[] p2) {
return (p1[0] - p2[0]) * (p1[0] - p2[0])
+ (p1[1] - p2[1]) * (p1[1] - p2[1]);
}
private void makePoints(double[] roots, int nrRealRoots) {
List<double[]> valPairs = new ArrayList<double[]>();
int len;
for (int i = 0; i < nrRealRoots; i++) {
len = getNrPoints(roots[i]);
for (int j = 0; j < len; j++) {
double[] pair = getXYPair(roots[i], j);
for (int k = 0; k < valPairs.size(); k++) {
if (distancePairSq(pair,
valPairs.get(k)) < Kernel.STANDARD_PRECISION) {
pair = null;
break;
}
}
if (pair != null) {
valPairs.add(pair);
}
}
}
setPoints(valPairs);
}
public void setLabels(String[] labels) {
points.setLabels(labels);
update();
}
protected void setPoints(List<double[]> valPairs) {
points.adjustOutputSize(valPairs.size());
for (int i = 0; i < valPairs.size(); i++) {
points.getElement(i).setCoords(valPairs.get(i)[0],
valPairs.get(i)[1], 1);
}
if (setLabels) {
points.updateLabels();
}
}
/**
* @param t
* root of PolynomialFunction
* @return number of corresponding outputPoints
*/
protected int getNrPoints(double t) {
return 1;
}
/**
* @param t
* root of PolynomialFunction
* @param idx
* @return Y-value corresponding to t and idx.
*/
protected double getYValue(double t, int idx) {
return getYValue(t);
}
/**
* @param t
* root of PolynomialFunction
* @return the corresponding Y-value
*/
protected abstract double getYValue(double t);
/**
* @param t
* root of PolynomialFunction
* @return the corresponding X-value
*/
protected double getXValue(double t) {
return t;
}
/**
* @param t
* root of PolynomialFunction
* @param idx
* @return X-value corresponding to t and idx.
*/
protected double getXValue(double t, int idx) {
return getXValue(t);
}
protected double[] getXYPair(double t, int idx) {
return new double[] { getXValue(t, idx), getYValue(t, idx) };
}
@Override
public Commands getClassName() {
return Commands.Roots;
}
}