/* * 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 */