This commit contains the following changes:
final
modifier to static methods. We don't know why those modifier has been added
since it is useless for static methods. This change has been reverted in SIS/Geotk.EPS
variable by a method argument in the round
method.
While a trivial change, we will nevertheless omit that method from SIS since the rounding operation on an affine
transform is pretty hard to define anyway.isIdentity(AffineTransform tr, double tolerance)
method. That method will be omitted in SIS.Command line:
svn diff --extensions "--unified --ignore-space-change --ignore-all-space --ignore-eol-style" -r24484:24485 https://svn.osgeo.org/geotools/trunk/modules/library/referencing/src/main/java/org/geotools/referencing/operation/matrix/XAffineTransform.java
Revision 24484 | Revision 24485 |
---|---|
*/ public abstract class XAffineTransform extends AffineTransform { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 5215291166450556451L; |
*/ public abstract class XAffineTransform extends AffineTransform { /** * Redefines {@link #isIdentity()} default behaviour from {@link AffineTransform} * in order to keep into account roundings errors. * * <p> * For example if we have the following affine transnform * * 1.0000000000000000001 0 0 * 0 0.999999999999999999999 0 * 0 0 1 * * I would say that is pretty hard to state that is not the identity. * * <P> * Keep in mind that the original check is pretty simple, see below here: * * return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY)); * * * @param tr {@link AffineTransform} to be checked for identity. * @param tolerance to use when checking for identity. * return <code>true</code> id this tranformation is *close* enough to the * indentity, <code>false</code> otherwise. * @since 2.3.1 */ public final static boolean isIdentity(final AffineTransform tr,double tolerance) { tolerance=Math.abs(tolerance); boolean isIdentity=tr.isIdentity(); if(!isIdentity){ //get scale final double scale=getScale(tr); if(Math.abs(scale-1)>tolerance) return false; //rotation final double rotation =XAffineTransform.getRotation(tr); if(Math.abs(rotation)>tolerance) return false; //translations final double transX=tr.getTranslateX(); if(Math.abs(transX)>tolerance) return false; final double transY=tr.getTranslateY(); if(Math.abs(transY)>tolerance) return false; //shear final double shearX=tr.getShearX(); if(Math.abs(shearX)>tolerance) return false; final double shearY=tr.getShearY(); if(Math.abs(shearY)>tolerance) return false; //scale NOT SURE WE NEED THIS final double scaleX=tr.getScaleX(); if(Math.abs(scaleX-1)>tolerance) return false; final double scaleY=tr.getScaleY(); if(Math.abs(scaleY-1)>tolerance) return false; return true; //// // // Proposed replacement less performace though // //// // final AffineTransform clonedTransformation=(AffineTransform) tr.clone(); // XAffineTransform.round(clonedTransformation, tolerance); // if(clonedTransformation.isIdentity()) // return true; } return isIdentity; } /** * Check whether or not this {@link XAffineTransform} is te identity by * using the provided <code>tolerance</code>. * * * @param tolerance to use for this check. * @return true if the check succeeds, faflse otherwise. * @since 2.3.1 */ public boolean isIdentity(double tolerance) { return isIdentity(this, tolerance); } /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 5215291166450556451L; |
/**
* Tolerance value for floating point comparisons.
*/
private static final double EPS = 1E-6;
/**
* Constructs a new {@code XAffineTransform} that is a |
/**
* Tolerance value for floating point comparisons.
*/
public static final double EPS = 1E-6;
/**
* Constructs a new {@code XAffineTransform} that is a |
*
* @return The direct transform of the {@code bounds} rectangle.
*/
public static Rectangle2D transform(final AffineTransform transform,
final Rectangle2D bounds,
final Rectangle2D dest)
{ |
*
* @return The direct transform of the {@code bounds} rectangle.
*/
public final static Rectangle2D transform(final AffineTransform transform,
final Rectangle2D bounds,
final Rectangle2D dest)
{ |
* @return The inverse transform of the {@code bounds} rectangle.
* @throws NoninvertibleTransformException if the affine transform can't be inverted.
*/
public static Rectangle2D inverseTransform(final AffineTransform transform,
final Rectangle2D bounds,
final Rectangle2D dest)
throws NoninvertibleTransformException |
* @return The inverse transform of the {@code bounds} rectangle.
* @throws NoninvertibleTransformException if the affine transform can't be inverted.
*/
public final static Rectangle2D inverseTransform(final AffineTransform transform,
final Rectangle2D bounds,
final Rectangle2D dest)
throws NoninvertibleTransformException |
* @return The inverse transform of the {@code source} point.
* @throws NoninvertibleTransformException if the affine transform can't be inverted.
*/
public static Point2D inverseDeltaTransform(final AffineTransform transform,
final Point2D source,
final Point2D dest)
throws NoninvertibleTransformException |
* @return The inverse transform of the {@code source} point.
* @throws NoninvertibleTransformException if the affine transform can't be inverted.
*/
public final static Point2D inverseDeltaTransform(final AffineTransform transform,
final Point2D source,
final Point2D dest)
throws NoninvertibleTransformException |
* preserved, {@code -1} if the transform seems to swap axis to the (<var>y</var>,
* <var>x</var>) axis order, or {@code 0} if this method can not make a decision.
*/
public static int getSwapXY(final AffineTransform tr) {
final int flip = getFlip(tr);
if (flip != 0) {
final double scaleX = getScaleX0(tr); |
* preserved, {@code -1} if the transform seems to swap axis to the (<var>y</var>,
* <var>x</var>) axis order, or {@code 0} if this method can not make a decision.
*/
public final static int getSwapXY(final AffineTransform tr) {
final int flip = getFlip(tr);
if (flip != 0) {
final double scaleX = getScaleX0(tr); |
* @return An estimation of the rotation angle in radians, or {@link Double#NaN NaN}
* if the angle can not be estimated.
*/
public static double getRotation(final AffineTransform tr) {
final int flip = getFlip(tr);
if (flip != 0) {
final double scaleX = getScaleX0(tr); |
* @return An estimation of the rotation angle in radians, or {@link Double#NaN NaN}
* if the angle can not be estimated.
*/
public final static double getRotation(final AffineTransform tr) {
final int flip = getFlip(tr);
if (flip != 0) {
final double scaleX = getScaleX0(tr); |
* boolean flipped = (tr.{@linkplain #getType() getType()} & {@linkplain #TYPE_FLIP}) != 0;
* </code></blockquote>
*/
public static int getFlip(final AffineTransform tr) {
final int scaleX = XMath.sgn(tr.getScaleX());
final int scaleY = XMath.sgn(tr.getScaleY());
final int shearX = XMath.sgn(tr.getShearX()); |
* boolean flipped = (tr.{@linkplain #getType() getType()} & {@linkplain #TYPE_FLIP}) != 0;
* </code></blockquote>
*/
public final static int getFlip(final AffineTransform tr) {
final int scaleX = XMath.sgn(tr.getScaleX());
final int scaleY = XMath.sgn(tr.getScaleY());
final int shearX = XMath.sgn(tr.getShearX()); |
* effect of eventual flip and rotation. This factor is calculated by
* <IMG src="{@docRoot}/org/geotools/display/canvas/doc-files/scaleX0.png">.
*/
public static double getScaleX0(final AffineTransform tr) {
return XMath.hypot(tr.getScaleX(), tr.getShearX());
} |
* effect of eventual flip and rotation. This factor is calculated by
* <IMG src="{@docRoot}/org/geotools/display/canvas/doc-files/scaleX0.png">.
*/
public final static double getScaleX0(final AffineTransform tr) {
return XMath.hypot(tr.getScaleX(), tr.getShearX());
} |
* effect of eventual flip and rotation. This factor is calculated by
* <IMG src="{@docRoot}/org/geotools/display/canvas/doc-files/scaleY0.png">.
*/
public static double getScaleY0(final AffineTransform tr) {
return XMath.hypot(tr.getScaleY(), tr.getShearY());
} |
* effect of eventual flip and rotation. This factor is calculated by
* <IMG src="{@docRoot}/org/geotools/display/canvas/doc-files/scaleY0.png">.
*/
public final static double getScaleY0(final AffineTransform tr) {
return XMath.hypot(tr.getScaleY(), tr.getShearY());
} |
* The way to compute such a "global" scale is somewhat arbitrary and may change
* in a future version.
*/
public static double getScale(final AffineTransform tr) {
return 0.5 * (getScaleX0(tr) + getScaleY0(tr));
} |
* The way to compute such a "global" scale is somewhat arbitrary and may change
* in a future version.
*/
public final static double getScale(final AffineTransform tr) {
return 0.5 * (getScaleX0(tr) + getScaleY0(tr));
} |
* @return Affine transform of a zoom which leaves the
* (<var>x</var>,<var>y</var>) coordinate unchanged.
*/
public static AffineTransform getScaleInstance(final double sx, final double sy,
final double x, final double y) {
return new AffineTransform(sx, 0, 0, sy, (1-sx)*x, (1-sy)*y);
} |
* @return Affine transform of a zoom which leaves the
* (<var>x</var>,<var>y</var>) coordinate unchanged.
*/
public final static AffineTransform getScaleInstance(final double sx, final double sy,
final double x, final double y) {
return new AffineTransform(sx, 0, 0, sy, (1-sx)*x, (1-sy)*y);
} |
* nearest whole numbers. This rounding up is useful, for example, for * speeding up image displays. Above all, it is efficient when we know that * a matrix has a chance of being close to the similarity matrix. */ public static void round(final AffineTransform tr) { double r; final double m00, m01, m10, m11; if (Math.abs((m00 = Math.rint(r = tr.getScaleX())) - r) <= EPS && Math.abs((m01 = Math.rint(r = tr.getShearX())) - r) <= EPS && Math.abs((m11 = Math.rint(r = tr.getScaleY())) - r) <= EPS && Math.abs((m10 = Math.rint(r = tr.getShearY())) - r) <= EPS) { if ((m00!=0 || m01!=0) && (m10!=0 || m11!=0)) { double m02=Math.rint(r=tr.getTranslateX()); if (!(Math.abs(m02-r)<=EPS)) m02=r; double m12=Math.rint(r=tr.getTranslateY()); if (!(Math.abs(m12-r)<=EPS)) m12=r; tr.setTransform(m00, m10, m01, m11, m02, m12); } } |
* nearest whole numbers. This rounding up is useful, for example, for * speeding up image displays. Above all, it is efficient when we know that * a matrix has a chance of being close to the similarity matrix. * * <p> * It is crucial to note that this method uses a default rounding threshold * whose value is hedl by the field {@link #EPS} which is {@value #EPS}. */ public final static void round(final AffineTransform tr) { round(tr,EPS); } /** * Checks whether the matrix coefficients are close to whole numbers. * If this is the case, these coefficients will be rounded up to the * nearest whole numbers. This rounding up is useful, for example, for * speeding up image displays. Above all, it is efficient when we know that * a matrix has a chance of being close to the similarity matrix. */ public final static void round(final AffineTransform tr,final double CUSTOM_EPS) { double r; final double m00, m01, m10, m11; if (Math.abs((m00 = Math.rint(r = tr.getScaleX())) - r) <= CUSTOM_EPS && Math.abs((m01 = Math.rint(r = tr.getShearX())) - r) <= CUSTOM_EPS && Math.abs((m11 = Math.rint(r = tr.getScaleY())) - r) <= CUSTOM_EPS && Math.abs((m10 = Math.rint(r = tr.getShearY())) - r) <= CUSTOM_EPS) { if ((m00!=0 || m01!=0) && (m10!=0 || m11!=0)) { double m02=Math.rint(r=tr.getTranslateX()); if (!(Math.abs(m02-r)<=CUSTOM_EPS)) m02=r; double m12=Math.rint(r=tr.getTranslateY()); if (!(Math.abs(m12-r)<=CUSTOM_EPS)) m12=r; tr.setTransform(m00, m10, m01, m11, m02, m12); } } |