/*
* PolynomialCoreNotNorm.java
*
* Created on September 4, 2002, 6:15 AM
*/
package hep.aida.ref.function;
import jas.hist.Handle;
import java.awt.Cursor;
import org.freehep.util.images.ImageHandler;
/**
*
* @author serbo
*/
/**
* Not normalised Polynomial (Pn) distribution in the form:
* f = p0 + p1*x + p2*x*x + ... , has n+1 parameters
*/
public class PolynomialCoreNotNorm extends FunctionCore {
protected boolean providesNormalization;
private double[] tmpVar = new double[1];
public PolynomialCoreNotNorm(int dim, int nPar) {
super(dim, nPar);
setTitle("PolynomialCoreNotNorm::P" + nPar);
providesNormalization = false;
}
public PolynomialCoreNotNorm(int dim, int nPar, double[] pVal) {
super(dim, nPar, pVal);
setTitle("PolynomialCoreNotNorm::P" + nPar);
providesNormalization = false;
}
public PolynomialCoreNotNorm(String str) {
super(1, getDimension(str));
setTitle("PolynomialCoreNotNorm::"+str);
providesNormalization = false;
}
public PolynomialCoreNotNorm(String str, double[] pVal) {
super(1, getDimension(str), pVal);
setTitle("PolynomialCoreNotNorm::"+str);
providesNormalization = false;
}
// Value of the function WITHOUT Normalization factor (as if N=1)
public double functionValue(double[] var) {
double val = 0;
for (int i=1; i<numberOfParameters; i++) { val += p[i]*Math.pow(var[0], i); }
return val+p[0];
}
// Each concrete FunctionCore has to implement those methods that deal with Gradients and Normalization
public boolean providesGradient() { return true; }
public double[] gradient(double[] var) {
double[] tmp = new double[] {0.};
if (numberOfParameters == 1) return tmp;
double val = p[1];
for (int i=2; i<numberOfParameters; i++) { val += i*p[i]*Math.pow(var[0], i-1); }
tmp[0] = val;
return tmp;
}
public boolean providesParameterGradient() { return true; }
public double[] parameterGradient(double[] var) {
double[] tmp = new double[numberOfParameters];
tmp[0] = 1;
for (int i=1; i<numberOfParameters; i++) {tmp[i] = Math.pow(var[0], i); }
return tmp;
}
public boolean providesNormalization() { return providesNormalization; }
public double normalizationAmplitude(double[] xMin, double[] xMax) {
throw new UnsupportedOperationException(title() + " ***** Can not calculate normalization for a not normalized function");
}
public static int getDimension(String str) {
if(!str.toLowerCase().startsWith("p"))
throw new IllegalArgumentException("Polynomial Function Qualifier must start with \"P\"");
return (1 + Integer.parseInt(str.substring(1)));
}
public Handle[] getHandles(double xLow, double xHigh, double yLow, double yHigh)
// using notation f(x) = ax^2 + bx + c
{
final double xmin = xLow;
final double xmax = xHigh;
final double ymin = yLow;
final double ymax = yHigh;
final int order = numberOfParameters() - 1;
/*
* copying these parameters over to instance
* variables makes them accessible to the
* anonymous class definitions below
*/
Handle[] result = null;
if ( order == 0 ) {
result = new Handle[1];
/* there will be one handle that can move the function up and down only */
result[0] = new Handle() {
public void moveTo(double x, double y) {
p[0] = y;
notifyCoreChanged();
}
public double getY() {
return p[0];
}
public double getX() {
return (xmax + xmin) / 2.0;
}
public Cursor cursor() {
return ImageHandler.getBestCursor("resizeNSCursor.png",PolynomialCoreNotNorm.class,0,0);
}
};
}
else if ( order == 1 ) {
result = new Handle[2];
double x0 = (ymax-p[0])/p[1];
if ( x0 < xmin ) x0 = xmin;
if ( x0 > xmax ) x0 = xmax;
double x1 = (ymin-p[0])/p[1];
if ( x1 < xmin ) x1 = xmin;
if ( x1 > xmax ) x1 = xmax;
final double xm = (x0+x1)/2;
final double ym = p[1]*xm + p[0];
result[0] = new InPlotHandle(xmin, xmax, ymin, ymax) {
double tmpx = Double.NaN;
public void moveTo(double x, double y) {
tmpx = x;
// p[1] = (xm-y)/(xm-x);
p[0] = y - p[1]*x;
if ( ! isInPlot( x, y ) )
tmpx = Double.NaN;
notifyCoreChanged();
}
public double getY() {
return p[1]*getX()+p[0];
}
public double getX() {
if ( Double.isNaN( tmpx ) ) {
calculateIntersections();
tmpx = 0.8*x0()+0.2*x1();
}
return tmpx;
}
public Cursor cursor() {
return ImageHandler.getBestCursor("moveCursor.png",PolynomialCoreNotNorm.class,0,0);
}
};
result[1] = new InPlotHandle(xmin, xmax, ymin, ymax) {
double tmpx = Double.NaN;
public void moveTo(double x, double y) {
tmpx = x;
double yh = mirrorHandle().getY();
double xh = mirrorHandle().getX();
if ( xh != x )
p[1] = (yh-y)/(xh-x);
p[0] = y - p[1]*x;
if ( ! isInPlot( x, y ) )
tmpx = Double.NaN;
notifyCoreChanged();
}
public double getY() {
return p[1]*getX()+p[0];
}
public double getX() {
if ( Double.isNaN( tmpx ) ) {
calculateIntersections();
tmpx = 0.2*x0()+0.8*x1();
}
return tmpx;
}
public Cursor cursor() {
return ImageHandler.getBestCursor("rotateCursor.png",PolynomialCoreNotNorm.class,0,0);
}
};
( (MirrorHandle) result[1] ).setMirrorHandle( (MirrorHandle) result[0] );
}
else if ( order == 2 ) {
result = new Handle[2];
result[0] = new Handle() {
// this handle is the vertex of the parabola
public void moveTo(double x, double y) {
p[1] = -2.0 * p[2] * x;
p[0] = y - p[2] * x * x - p[1] * x;
notifyCoreChanged();
}
public double getX() {
return -p[1] / (2 * p[2]);
}
public double getY() {
tmpVar[0] = getX();
return functionValue( tmpVar );
}
public Cursor cursor() {
return ImageHandler.getBestCursor("moveCursor.png",PolynomialCoreNotNorm.class,0,0);
}
};
result[1] = new Handle() {
public void moveTo(double x, double y) {
final double xVertex = -p[1] / (2.0 * p[2]);
tmpVar[0] = xVertex;
final double yVertex = functionValue( tmpVar );
p[2] = (y - yVertex) / Math.pow(x - xVertex, 2);
p[1] = -2.0 * p[2] * xVertex;
p[0] = y - (p[2] * x * x) - (p[1] * x);
notifyCoreChanged();
}
public double getY() {
tmpVar[0] = getX();
return functionValue( tmpVar );
}
public double getX() {
final double xVertex = -p[1] / (2 * p[2]);
final double xMiddle = (xmax - xmin) / 2.0;
if (xVertex > xMiddle && xVertex < xmax)
return ( (xVertex - xmin) / 2.0 ) + xmin;
else if (xVertex <= xMiddle && xVertex > xmin)
return xmax - ( (xmax - xVertex) / 2.0 );
else
return xMiddle;
}
public Cursor cursor() {
return ImageHandler.getBestCursor("resizeNSCursor.png",PolynomialCoreNotNorm.class,0,0);
}
};
}
return result;
}
private abstract class MirrorHandle extends Handle {
private MirrorHandle h = null;
void setMirrorHandle( MirrorHandle h ) {
this.h = h;
}
MirrorHandle mirrorHandle() {
return h;
}
boolean hasMirrorHandle() {
return h == null ? false : true;
}
}
private abstract class InPlotHandle extends MirrorHandle {
double x0, y0, x1, y1;
double xmin, xmax, ymin, ymax;
InPlotHandle( double xmin, double xmax, double ymin, double ymax ) {
super();
this.xmin = xmin;
this.xmax = xmax;
this.ymin = ymin;
this.ymax = ymax;
calculateIntersections();
}
boolean isInPlot(double x, double y) {
if ( x > xmax || x < xmin )
return false;
if ( y > ymax || y < ymin )
return false;
return true;
}
void calculateIntersections() {
x0 = xmin;
y0 = p[1]*x0+p[0];
if ( y0 > ymax )
y0 = ymax;
if ( y0 < ymin )
y0 = ymin;
if ( p[1] != 0 )
x0 = ( y0 - p[0] )/p[1];
x1 = xmax;
y1 = p[1]*x1+p[0];
if ( y1 > ymax )
y1 = ymax;
if ( y1 < ymin )
y1 = ymin;
if ( p[1] != 0 )
x1 = ( y1 - p[0] )/p[1];
}
double x0() {
return x0;
}
double x1() {
return x1;
}
double y0() {
return y0;
}
double y1() {
return y1;
}
}
}