/*
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.util.Arrays;
import org.geogebra.common.euclidian.EuclidianViewInterfaceCommon;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoPoint;
/**
* Abstract class with all the label methods needed to update labels of commands
* on functions, where the command returns a varying number of GeoPoints. This
* is to avoid a lot of duplicated label-updating code. Most of the code is
* copied from AlgoRootsPolynomial. (Where it might be eliminated later...)
*
* @author Hans-Petter Ulven
* @version 06.03.11
*
*/
public abstract class AlgoGeoPointsFunction extends AlgoElement {
protected GeoFunction f; // For calculation of y-values
protected GeoPoint[] points; // output in subcclass
private String[] labels;
private boolean initLabels;
protected boolean setLabels = false;
// remove? double[] curXValues = new double[30]; // current x-values
protected GeoNumberValue left; // input
protected GeoNumberValue right; // input
protected boolean intervalDefinedByEV = false;
/**
* Computes all roots of f
*/
public AlgoGeoPointsFunction(Construction cons, String[] labels,
boolean setLabels, GeoFunction f) {
super(cons);
this.labels = labels;
this.setLabels = setLabels; // In subclass:
// !cons.isSuppressLabelsActive();
this.f = f;
// make sure root points is not null
int number = labels == null ? 1 : Math.max(1, labels.length);
points = new GeoPoint[0];
initPoints(number);
initLabels = true;
// setInputOutput, compute(), show at least one point: must be done in
// subclass.
}// Constructor
public AlgoGeoPointsFunction(Construction cons, GeoFunction f) {
super(cons);
this.f = f;
// make sure root points is not null
int number = 1;
points = new GeoPoint[0];
initPoints(number);
// setInputOutput, compute(), show at least one point: must be done in
// subclass.
}// Constructor
/**
* The given labels will be used for the resulting points.
*/
public void setLabels(String[] labels) {
this.labels = labels;
setLabels = true;
// make sure that there are at least as many
// points as labels
if (labels != null) {
initPoints(labels.length);
}
update();
}// setLabels(String[])
public GeoPoint[] getPoints() {
return points;
}// getPoints()
// Show at least one root point in algebra view
// Copied from AlgoRootsPolynomial...
protected final void showOneRootInAlgebraView() {
if (!points[0].isDefined()) {
points[0].setCoords(0, 0, 1);
points[0].update();
points[0].setUndefined();
points[0].update();
} // if list not defined
}// showOneRootInAlgebraView()
protected final static void removeDuplicates(double[] tab) {
Arrays.sort(tab);
int maxIndex = 0;
double max = tab[0];
for (int i = 1; i < tab.length; i++) {
if ((tab[i] - max) > Kernel.MIN_PRECISION) {
max = tab[i];
maxIndex++;
tab[maxIndex] = max;
} // if greater
} // for
}// removeDuplicates(double[])
// roots array and number of roots
protected final void setPoints(double[] curXValues, int number) {
initPoints(number);
// now set the new values of the roots
for (int i = 0; i < number; i++) {
points[i].setCoords(curXValues[i], yAt(curXValues[i]), // yValFunction.evaluate(curXValues[i]),
1.0);
// Application.debug(" " + rootPoints[i]);
} // for
// all other roots are undefined
for (int i = number; i < points.length; i++) {
points[i].setUndefined();
} //
if (setLabels) {
updateLabels(number);
}
noUndefinedPointsInAlgebraView(points); // **** experiment****
}// setPoints(double[],n)
protected double yAt(double d) {
return f.value(d);
}
// number is the number of current roots
protected void updateLabels(int number) {
if (initLabels) {
GeoElement.setLabels(labels, points);
initLabels = false;
} else {
for (int i = 0; i < number; i++) {
// check labeling
if (!points[i].isLabelSet()) {
// use user specified label if we have one
String newLabel = (labels != null && i < labels.length)
? labels[i] : null;
points[i].setLabel(newLabel);
} // if
} // for
} // if
// all other roots are undefined
for (int i = number; i < points.length; i++) {
points[i].setUndefined(); // Points[i].setAlgebraVisible(false);
} // for
}// updateLabels(n)
protected void noUndefinedPointsInAlgebraView(GeoPoint[] gpts) {
for (int i = 1; i < gpts.length; i++) {
gpts[i].showUndefinedInAlgebraView(false);
} // for
}// noUndefinedPointsInAlgebraView(GeoPoint[])
/**
* Removes only one single output element if possible. If this is not
* possible the whole algorithm is removed.
*/
@Override
public void remove(GeoElement output) {
// only single undefined points may be removed
for (int i = 0; i < points.length; i++) {
if (points[i] == output && !points[i].isDefined()) {
removePoint(i);
// make sure that the function is removed after the last
// undefined point was removed
if (points.length == 0) {
super.remove();
}
return;
} // if
} // for
// if we get here removing output was not possible
// so we remove the whole algorithm
super.remove();
}// remove(GeoElement)
protected void initPoints(int number) {
// make sure that there are enough points
if (points.length < number) {
GeoPoint[] temp = new GeoPoint[number];
for (int i = 0; i < points.length; i++) {
temp[i] = points[i];
temp[i].setCoords(0, 0, 1); // init as defined
}
for (int i = points.length; i < temp.length; i++) {
temp[i] = new GeoPoint(cons);
temp[i].setCoords(0, 0, 1); // init as defined
temp[i].setParentAlgorithm(this);
}
points = temp;
super.setOutput(points);
} // if
}// initPoints(n)
protected void removePoint(int pos) {
points[pos].doRemove();
// build new rootPoints array without the removed point
GeoPoint[] temp = new GeoPoint[points.length - 1];
int i;
for (i = 0; i < pos; i++) {
temp[i] = points[i];
}
for (i = pos + 1; i < points.length; i++) {
temp[i - 1] = points[i];
}
points = temp;
}// removePoint(int pos)
protected void updateInterval() {
EuclidianViewInterfaceCommon ev = this.kernel.getApplication()
.getActiveEuclidianView();
left = ev.getXminObject();
right = ev.getXmaxObject();
setInputOutput();
}
@Override
protected int getInputLengthForXML() {
if (intervalDefinedByEV) {
return 1;
}
return super.getInputLengthForXML();
}
}// class AlgoGeoPontsFunction