/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
/*
Fix the following methods: inverseTransform, createInverse
*/
package org.opensourcephysics.numerics;
/**
* Title: InvertibleFunction
* Description: An invertible function of one variable.
*/
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
/**
* Class description
*
*/
public final class FunctionTransform extends AffineTransform {
double m00;
double m10 = 1; // identity transform by default
double m01 = 1;
double m11;
double m02;
double m12;
double[] flatmatrix = new double[6];
InvertibleFunction xFunction;
InvertibleFunction yFunction;
boolean applyXFunction = false;
boolean applyYFunction = false;
/**
* Constructor FunctionTransform
*/
public FunctionTransform() {
super();
}
/**
* Constructor FunctionTransform
* @param m00
* @param m10
* @param m01
* @param m11
* @param m02
* @param m12
*/
public FunctionTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
super(m00, m10, m01, m11, m02, m12);
this.m00 = m00;
this.m10 = m10;
this.m01 = m01;
this.m11 = m11;
this.m02 = m02;
this.m12 = m12;
}
/*
Sets the x function to the specified parameter.
@param x the new x function. Can not be null.
*/
public void setXFunction(InvertibleFunction x) {
if(x==null) {
throw new NullPointerException("x function can not be null."); //$NON-NLS-1$
}
xFunction = x;
}
/*
Sets the y function to the specified parameter.
@param y the new y function. Can not be null.
*/
public void setYFunction(InvertibleFunction y) {
if(y==null) {
throw new NullPointerException("y function can not be null."); //$NON-NLS-1$
}
yFunction = y;
}
/*
sets whether this FunctionTransform applies the x function
*/
public void setApplyXFunction(boolean b) {
applyXFunction = b;
}
/*
sets whether this FunctionTransform applies the y function
*/
public void setApplyYFunction(boolean b) {
applyYFunction = b;
}
public void translate(double tx, double ty) {
super.translate(tx, ty);
updateMatrix();
}
public void rotate(double theta) {
super.rotate(theta);
updateMatrix();
}
public void rotate(double theta, double x, double y) {
super.rotate(theta, x, y);
updateMatrix();
}
public void scale(double sx, double sy) {
super.scale(sx, sy);
updateMatrix();
}
public void shear(double shx, double shy) {
super.shear(shx, shy);
updateMatrix();
}
public void setToIdentity() {
super.setToIdentity();
updateMatrix();
}
public void setToTranslation(double tx, double ty) {
super.setToTranslation(tx, ty);
updateMatrix();
}
public void setToRotation(double theta) {
super.setToRotation(theta);
updateMatrix();
}
public void setToRotation(double theta, double x, double y) {
super.setToRotation(theta, x, y);
updateMatrix();
}
public void setToScale(double sx, double sy) {
super.setToScale(sx, sy);
updateMatrix();
}
public void setToShear(double shx, double shy) {
super.setToShear(shx, shy);
updateMatrix();
}
public void setTransform(AffineTransform Tx) {
super.setTransform(Tx);
updateMatrix();
}
public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
super.setTransform(m00, m10, m01, m11, m02, m12);
updateMatrix();
}
/*
Concatenates this FunctionTransform with the given AffineTransform as specified in AffineTransform. Note-The if specified parameter is a FunctionTransform, the function is ignored.
*/
public void concatenate(AffineTransform Tx) {
super.concatenate(Tx);
updateMatrix();
}
/*
Pre-concatenates this FunctionTransform with the given AffineTransform as specified in AffineTransform. Note-The if specified parameter is a FunctionTransform, the function is ignored.
*/
public void preConcatenate(AffineTransform Tx) {
super.preConcatenate(Tx);
updateMatrix();
}
public AffineTransform createInverse() throws NoninvertibleTransformException { // FIX_ME
AffineTransform at = super.createInverse();
FunctionTransform ft = new FunctionTransform();
ft.setTransform(at);
final InvertibleFunction xFunction = new InvertibleFunction() {
public double evaluate(double x) {
return FunctionTransform.this.xFunction.getInverse(x);
}
public double getInverse(double y) {
return FunctionTransform.this.xFunction.evaluate(y);
}
};
final InvertibleFunction yFunction = new InvertibleFunction() {
public double evaluate(double x) {
return FunctionTransform.this.yFunction.getInverse(x);
}
public double getInverse(double y) {
return FunctionTransform.this.yFunction.evaluate(y);
}
};
ft.setXFunction(xFunction);
ft.setYFunction(yFunction);
return ft;
}
public Point2D transform(Point2D ptSrc, Point2D ptDst) {
if(ptDst==null) {
if(ptSrc instanceof Point2D.Double) {
ptDst = new Point2D.Double();
} else {
ptDst = new Point2D.Float();
}
}
// Copy source coords into local variables in case src == dst
double x = ptSrc.getX();
double y = ptSrc.getY();
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
ptDst.setLocation(x*m00+y*m01+m02, x*m10+y*m11+m12);
return ptDst;
}
public void transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst, int dstOff, int numPts) {
while(--numPts>=0) {
// Copy source coords into local variables in case src == dst
Point2D src = ptSrc[srcOff++];
double x = src.getX();
double y = src.getY();
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
Point2D dst = ptDst[dstOff++];
if(dst==null) {
if(src instanceof Point2D.Double) {
dst = new Point2D.Double();
} else {
dst = new Point2D.Float();
}
ptDst[dstOff-1] = dst;
}
dst.setLocation(x*m00+y*m01+m02, x*m10+y*m11+m12);
}
}
public void transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts) {
double M00;
double M01;
double M02;
double M10;
double M11;
double M12; // For caching
if((dstPts==srcPts)&&(dstOff>srcOff)&&(dstOff<srcOff+numPts*2)) {
// If the arrays overlap partially with the destination higher
// than the source and we transform the coordinates normally
// we would overwrite some of the later source coordinates
// with results of previous transformations.
// To get around this we use arraycopy to copy the points
// to their final destination with correct overwrite
// handling and then transform them in place in the new
// safer location.
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts*2);
// srcPts = dstPts; // They are known to be equal.
srcOff = dstOff;
}
M00 = m00;
M01 = m01;
M02 = m02;
M10 = m10;
M11 = m11;
M12 = m12;
while(--numPts>=0) {
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
// W. Christian
// Java 1.3 bug in Windows VM
// the following two lines may cause a crash while drawing shapes if |dstPts| is very large
dstPts[dstOff++] = (float) (M00*x+M01*y+M02);
dstPts[dstOff++] = (float) (M10*x+M11*y+M12);
}
}
public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts) {
double M00;
double M01;
double M02;
double M10;
double M11;
double M12; // For caching
if((dstPts==srcPts)&&(dstOff>srcOff)&&(dstOff<srcOff+numPts*2)) {
// If the arrays overlap partially with the destination higher
// than the source and we transform the coordinates normally
// we would overwrite some of the later source coordinates
// with results of previous transformations.
// To get around this we use arraycopy to copy the points
// to their final destination with correct overwrite
// handling and then transform them in place in the new
// safer location.
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts*2);
// srcPts = dstPts; // They are known to be equal.
srcOff = dstOff;
}
M00 = m00;
M01 = m01;
M02 = m02;
M10 = m10;
M11 = m11;
M12 = m12;
while(--numPts>=0) {
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
// W. Christian
// Java 1.3 bug in Windows VM
// the following two lines may cause a crash while drawing shapes if |dstPts| is very large
dstPts[dstOff++] = M00*x+M01*y+M02;
dstPts[dstOff++] = M10*x+M11*y+M12;
}
}
public void transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts) {
double M00;
double M01;
double M02;
double M10;
double M11;
double M12; // For caching
M00 = m00;
M01 = m01;
M02 = m02;
M10 = m10;
M11 = m11;
M12 = m12;
while(--numPts>=0) {
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
// W. Christian
// Java 1.3 bug in Windows VM
// the following two lines may cause a crash while drawing shapes if |dstPts| is very large
dstPts[dstOff++] = M00*x+M01*y+M02;
dstPts[dstOff++] = M10*x+M11*y+M12;
}
}
public void transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts) {
double M00;
double M01;
double M02;
double M10;
double M11;
double M12; // For caching
M00 = m00;
M01 = m01;
M02 = m02;
M10 = m10;
M11 = m11;
M12 = m12;
while(--numPts>=0) {
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
// W. Christian
// Java 1.3 bug in Windows VM
// the following two lines cause a crash while drawing shapes if |dstPts| is very large
dstPts[dstOff++] = (float) (M00*x+M01*y+M02);
dstPts[dstOff++] = (float) (M10*x+M11*y+M12);
}
}
public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) throws NoninvertibleTransformException { // FIX_ME
if(ptDst==null) {
if(ptSrc instanceof Point2D.Double) {
ptDst = new Point2D.Double();
} else {
ptDst = new Point2D.Float();
}
}
//FIX ME
return ptDst;
}
public void inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts) // FIX_ME
throws NoninvertibleTransformException {
if((dstPts==srcPts)&&(dstOff>srcOff)&&(dstOff<srcOff+numPts*2)) {
// If the arrays overlap partially with the destination higher
// than the source and we transform the coordinates normally
// we would overwrite some of the later source coordinates
// with results of previous transformations.
// To get around this we use arraycopy to copy the points
// to their final destination with correct overwrite
// handling and then transform them in place in the new
// safer location.
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts*2);
// srcPts = dstPts; // They are known to be equal.
srcOff = dstOff;
}
double det = m00*m11-m01*m10;
if(Math.abs(det)<=Double.MIN_VALUE) {
throw new NoninvertibleTransformException("Determinant is "+det); //$NON-NLS-1$
}
// newx = M00 * x + M01 * y + M02;
/*
dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
while(--numPts >= 0) {
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
if(applyXFunction) {
x = xFunction.getInverse(x);
}
if(applyYFunction) {
y = yFunction.getInverse(y);
}
double div = m00
(x-m02)/m00
z = M00 * x + M01 * y + M02;
x * m11 - y * m01) / M00 * M11 - M01 * M10
x -=- m02;
x/m01
x/m00
y -= m12;
ptDst.setLocation(x / m00, y / m11);
dstPts[dstOff++] = M00 * x + M01 * y + M02;
dstPts[dstOff++] = M10 * x + M11 * y + M12;
}
*/
}
public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
if(ptDst==null) {
if(ptSrc instanceof Point2D.Double) {
ptDst = new Point2D.Double();
} else {
ptDst = new Point2D.Float();
}
}
// Copy source coords into local variables in case src == dst
double x = ptSrc.getX();
double y = ptSrc.getY();
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
ptDst.setLocation(x*m00+y*m01, x*m10+y*m11);
return ptDst;
}
public void deltaTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts) {
double M00;
double M01;
double M10;
double M11; // For caching
if((dstPts==srcPts)&&(dstOff>srcOff)&&(dstOff<srcOff+numPts*2)) {
// If the arrays overlap partially with the destination higher
// than the source and we transform the coordinates normally
// we would overwrite some of the later source coordinates
// with results of previous transformations.
// To get around this we use arraycopy to copy the points
// to their final destination with correct overwrite
// handling and then transform them in place in the new
// safer location.
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts*2);
// srcPts = dstPts; // They are known to be equal.
srcOff = dstOff;
}
M00 = m00;
M01 = m01;
M10 = m10;
M11 = m11;
while(--numPts>=0) {
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
if(applyXFunction) {
x = xFunction.evaluate(x);
}
if(applyYFunction) {
y = yFunction.evaluate(y);
}
dstPts[dstOff++] = x*M00+y*M01;
dstPts[dstOff++] = x*M10+y*M11;
}
}
public boolean equals(Object obj) {
if(obj instanceof FunctionTransform) {
FunctionTransform a = (FunctionTransform) obj;
double[] matrix = new double[6];
a.getMatrix(matrix);
if((m00==matrix[0])&&(m01==matrix[1])&&(m02==matrix[2])&&(m10==matrix[3])&&(m11==matrix[4])&&(m12==matrix[5])) {
if((applyXFunction==a.applyXFunction)&&(applyYFunction==a.applyYFunction)) {
return(xFunction.getClass()==a.xFunction.getClass())&&(yFunction.getClass()==a.yFunction.getClass());
}
}
} else if(obj instanceof AffineTransform) {
if(!applyXFunction&&!applyYFunction) {
return super.equals(obj);
}
}
return false;
}
private void updateMatrix() {
getMatrix(flatmatrix);
m00 = flatmatrix[0];
m10 = flatmatrix[1];
m01 = flatmatrix[2];
m11 = flatmatrix[3];
m02 = flatmatrix[4];
m12 = flatmatrix[5];
}
}
/*
* Open Source Physics software is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License (GPL) as
* published by the Free Software Foundation; either version 2 of the License,
* or(at your option) any later version.
* Code that uses any portion of the code in the org.opensourcephysics package
* or any subpackage (subdirectory) of this package must must also be be released
* under the GNU GPL license.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
* or view the license online at http://www.gnu.org/copyleft/gpl.html
*
* Copyright (c) 2007 The Open Source Physics project
* http://www.opensourcephysics.org
*/