1 /* 2 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.javafx.experiments.utils3d.geom.transform; 34 35 import com.javafx.experiments.utils3d.geom.*; 36 37 /** 38 * 39 */ 40 public abstract class BaseTransform implements CanTransformVec3d { 41 public static final BaseTransform IDENTITY_TRANSFORM = new Identity(); 42 43 public static enum Degree { 44 IDENTITY, 45 TRANSLATE_2D, 46 AFFINE_2D, 47 TRANSLATE_3D, 48 AFFINE_3D, 49 } 50 51 /* 52 * This constant is only useful for a cached type field. 53 * It indicates that the type has been decached and must be recalculated. 54 */ 55 protected static final int TYPE_UNKNOWN = -1; 56 57 /** 58 * This constant indicates that the transform defined by this object 59 * is an identity transform. 60 * An identity transform is one in which the output coordinates are 61 * always the same as the input coordinates. 62 * If this transform is anything other than the identity transform, 63 * the type will either be the constant GENERAL_TRANSFORM or a 64 * combination of the appropriate flag bits for the various coordinate 65 * conversions that this transform performs. 66 * @see #TYPE_TRANSLATION 67 * @see #TYPE_UNIFORM_SCALE 68 * @see #TYPE_GENERAL_SCALE 69 * @see #TYPE_FLIP 70 * @see #TYPE_QUADRANT_ROTATION 71 * @see #TYPE_GENERAL_ROTATION 72 * @see #TYPE_GENERAL_TRANSFORM 73 * @see #getType 74 */ 75 public static final int TYPE_IDENTITY = 0; 76 77 /** 78 * This flag bit indicates that the transform defined by this object 79 * performs a translation in addition to the conversions indicated 80 * by other flag bits. 81 * A translation moves the coordinates by a constant amount in x 82 * and y without changing the length or angle of vectors. 83 * @see #TYPE_IDENTITY 84 * @see #TYPE_UNIFORM_SCALE 85 * @see #TYPE_GENERAL_SCALE 86 * @see #TYPE_FLIP 87 * @see #TYPE_QUADRANT_ROTATION 88 * @see #TYPE_GENERAL_ROTATION 89 * @see #TYPE_GENERAL_TRANSFORM 90 * @see #getType 91 */ 92 public static final int TYPE_TRANSLATION = 1; 93 94 /** 95 * This flag bit indicates that the transform defined by this object 96 * performs a uniform scale in addition to the conversions indicated 97 * by other flag bits. 98 * A uniform scale multiplies the length of vectors by the same amount 99 * in both the x and y directions without changing the angle between 100 * vectors. 101 * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag. 102 * @see #TYPE_IDENTITY 103 * @see #TYPE_TRANSLATION 104 * @see #TYPE_GENERAL_SCALE 105 * @see #TYPE_FLIP 106 * @see #TYPE_QUADRANT_ROTATION 107 * @see #TYPE_GENERAL_ROTATION 108 * @see #TYPE_GENERAL_TRANSFORM 109 * @see #getType 110 */ 111 public static final int TYPE_UNIFORM_SCALE = 2; 112 113 /** 114 * This flag bit indicates that the transform defined by this object 115 * performs a general scale in addition to the conversions indicated 116 * by other flag bits. 117 * A general scale multiplies the length of vectors by different 118 * amounts in the x and y directions without changing the angle 119 * between perpendicular vectors. 120 * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag. 121 * @see #TYPE_IDENTITY 122 * @see #TYPE_TRANSLATION 123 * @see #TYPE_UNIFORM_SCALE 124 * @see #TYPE_FLIP 125 * @see #TYPE_QUADRANT_ROTATION 126 * @see #TYPE_GENERAL_ROTATION 127 * @see #TYPE_GENERAL_TRANSFORM 128 * @see #getType 129 */ 130 public static final int TYPE_GENERAL_SCALE = 4; 131 132 /** 133 * This constant is a bit mask for any of the scale flag bits. 134 * @see #TYPE_UNIFORM_SCALE 135 * @see #TYPE_GENERAL_SCALE 136 */ 137 public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE | 138 TYPE_GENERAL_SCALE); 139 140 /** 141 * This flag bit indicates that the transform defined by this object 142 * performs a mirror image flip about some axis which changes the 143 * normally right handed coordinate system into a left handed 144 * system in addition to the conversions indicated by other flag bits. 145 * A right handed coordinate system is one where the positive X 146 * axis rotates counterclockwise to overlay the positive Y axis 147 * similar to the direction that the fingers on your right hand 148 * curl when you stare end on at your thumb. 149 * A left handed coordinate system is one where the positive X 150 * axis rotates clockwise to overlay the positive Y axis similar 151 * to the direction that the fingers on your left hand curl. 152 * There is no mathematical way to determine the angle of the 153 * original flipping or mirroring transformation since all angles 154 * of flip are identical given an appropriate adjusting rotation. 155 * @see #TYPE_IDENTITY 156 * @see #TYPE_TRANSLATION 157 * @see #TYPE_UNIFORM_SCALE 158 * @see #TYPE_GENERAL_SCALE 159 * @see #TYPE_QUADRANT_ROTATION 160 * @see #TYPE_GENERAL_ROTATION 161 * @see #TYPE_GENERAL_TRANSFORM 162 * @see #getType 163 */ 164 public static final int TYPE_FLIP = 64; 165 /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public 166 * circulation and the flag bits could no longer be conveniently 167 * renumbered without introducing binary incompatibility in outside 168 * code. 169 */ 170 171 /** 172 * This flag bit indicates that the transform defined by this object 173 * performs a quadrant rotation by some multiple of 90 degrees in 174 * addition to the conversions indicated by other flag bits. 175 * A rotation changes the angles of vectors by the same amount 176 * regardless of the original direction of the vector and without 177 * changing the length of the vector. 178 * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag. 179 * @see #TYPE_IDENTITY 180 * @see #TYPE_TRANSLATION 181 * @see #TYPE_UNIFORM_SCALE 182 * @see #TYPE_GENERAL_SCALE 183 * @see #TYPE_FLIP 184 * @see #TYPE_GENERAL_ROTATION 185 * @see #TYPE_GENERAL_TRANSFORM 186 * @see #getType 187 */ 188 public static final int TYPE_QUADRANT_ROTATION = 8; 189 190 /** 191 * This flag bit indicates that the transform defined by this object 192 * performs a rotation by an arbitrary angle in addition to the 193 * conversions indicated by other flag bits. 194 * A rotation changes the angles of vectors by the same amount 195 * regardless of the original direction of the vector and without 196 * changing the length of the vector. 197 * This flag bit is mutually exclusive with the 198 * TYPE_QUADRANT_ROTATION flag. 199 * @see #TYPE_IDENTITY 200 * @see #TYPE_TRANSLATION 201 * @see #TYPE_UNIFORM_SCALE 202 * @see #TYPE_GENERAL_SCALE 203 * @see #TYPE_FLIP 204 * @see #TYPE_QUADRANT_ROTATION 205 * @see #TYPE_GENERAL_TRANSFORM 206 * @see #getType 207 */ 208 public static final int TYPE_GENERAL_ROTATION = 16; 209 210 /** 211 * This constant is a bit mask for any of the rotation flag bits. 212 * @see #TYPE_QUADRANT_ROTATION 213 * @see #TYPE_GENERAL_ROTATION 214 */ 215 public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION | 216 TYPE_GENERAL_ROTATION); 217 218 /** 219 * This constant indicates that the transform defined by this object 220 * performs an arbitrary conversion of the input coordinates. 221 * If this transform can be classified by any of the above constants, 222 * the type will either be the constant TYPE_IDENTITY or a 223 * combination of the appropriate flag bits for the various coordinate 224 * conversions that this transform performs. 225 * @see #TYPE_IDENTITY 226 * @see #TYPE_TRANSLATION 227 * @see #TYPE_UNIFORM_SCALE 228 * @see #TYPE_GENERAL_SCALE 229 * @see #TYPE_FLIP 230 * @see #TYPE_QUADRANT_ROTATION 231 * @see #TYPE_GENERAL_ROTATION 232 * @see #getType 233 */ 234 public static final int TYPE_GENERAL_TRANSFORM = 32; 235 236 public static final int TYPE_AFFINE2D_MASK = 237 (TYPE_TRANSLATION | 238 TYPE_UNIFORM_SCALE | 239 TYPE_GENERAL_SCALE | 240 TYPE_QUADRANT_ROTATION | 241 TYPE_GENERAL_ROTATION | 242 TYPE_GENERAL_TRANSFORM | 243 TYPE_FLIP); 244 245 public static final int TYPE_AFFINE_3D = 128; 246 247 /* 248 * Convenience method used internally to throw exceptions when 249 * an operation of degree higher than AFFINE_2D is attempted. 250 */ 251 static void degreeError(Degree maxSupported) { 252 throw new InternalError("does not support higher than "+ 253 maxSupported+" operations"); 254 } 255 256 public static BaseTransform getInstance(BaseTransform tx) { 257 if (tx.isIdentity()) { 258 return IDENTITY_TRANSFORM; 259 } else if (tx.isTranslateOrIdentity()) { 260 return new Translate2D(tx); 261 } else if (tx.is2D()) { 262 return new Affine2D(tx); 263 } 264 return new Affine3D(tx); 265 } 266 267 public static BaseTransform getInstance(double mxx, double mxy, double mxz, double mxt, 268 double myx, double myy, double myz, double myt, 269 double mzx, double mzy, double mzz, double mzt) 270 { 271 if (mxz == 0.0 && myz == 0.0 && 272 mzx == 0.0 && mzy == 0.0 && mzz == 1.0 && mzt == 0.0) 273 { 274 return getInstance(mxx, myx, mxy, myy, mxt, myt); 275 } else { 276 return new Affine3D(mxx, mxy, mxz, mxt, 277 myx, myy, myz, myt, 278 mzx, mzy, mzz, mzt); 279 } 280 } 281 282 public static BaseTransform getInstance(double mxx, double myx, 283 double mxy, double myy, 284 double mxt, double myt) 285 { 286 if (mxx == 1.0 && myx == 0.0 && mxy == 0.0 && myy == 1.0) { 287 return getTranslateInstance(mxt, myt); 288 } else { 289 return new Affine2D(mxx, myx, mxy, myy, mxt, myt); 290 } 291 } 292 293 public static BaseTransform getTranslateInstance(double mxt, double myt) { 294 if (mxt == 0.0 && myt == 0.0) { 295 return IDENTITY_TRANSFORM; 296 } else { 297 return new Translate2D(mxt, myt); 298 } 299 } 300 301 public static BaseTransform getScaleInstance(double mxx, double myy) { 302 return getInstance(mxx, 0, 0, myy, 0, 0); 303 } 304 305 public static BaseTransform getRotateInstance(double theta, double x, double y) { 306 Affine2D a = new Affine2D(); 307 a.setToRotation(theta, x, y); 308 return a; 309 } 310 311 public abstract Degree getDegree(); 312 313 /** 314 * Retrieves the flag bits describing the conversion properties of 315 * this transform. 316 * The return value is either one of the constants TYPE_IDENTITY 317 * or TYPE_GENERAL_TRANSFORM, or a combination of the 318 * appriopriate flag bits. 319 * A valid combination of flag bits is an exclusive OR operation 320 * that can combine 321 * the TYPE_TRANSLATION flag bit 322 * in addition to either of the 323 * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits 324 * as well as either of the 325 * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits. 326 * @return the OR combination of any of the indicated flags that 327 * apply to this transform 328 * @see #TYPE_IDENTITY 329 * @see #TYPE_TRANSLATION 330 * @see #TYPE_UNIFORM_SCALE 331 * @see #TYPE_GENERAL_SCALE 332 * @see #TYPE_QUADRANT_ROTATION 333 * @see #TYPE_GENERAL_ROTATION 334 * @see #TYPE_GENERAL_TRANSFORM 335 */ 336 public abstract int getType(); 337 338 public abstract boolean isIdentity(); 339 public abstract boolean isTranslateOrIdentity(); 340 public abstract boolean is2D(); 341 342 public abstract double getDeterminant(); 343 344 public double getMxx() { return 1.0; } 345 public double getMxy() { return 0.0; } 346 public double getMxz() { return 0.0; } 347 public double getMxt() { return 0.0; } 348 public double getMyx() { return 0.0; } 349 public double getMyy() { return 1.0; } 350 public double getMyz() { return 0.0; } 351 public double getMyt() { return 0.0; } 352 public double getMzx() { return 0.0; } 353 public double getMzy() { return 0.0; } 354 public double getMzz() { return 1.0; } 355 public double getMzt() { return 0.0; } 356 357 public abstract Point2D transform(Point2D src, Point2D dst); 358 public abstract Point2D inverseTransform(Point2D src, Point2D dst) 359 throws NoninvertibleTransformException; 360 public abstract Vec3d transform(Vec3d src, Vec3d dst); 361 public abstract Vec3d deltaTransform(Vec3d src, Vec3d dst); 362 public abstract Vec3d inverseTransform(Vec3d src, Vec3d dst) 363 throws NoninvertibleTransformException; 364 public abstract Vec3d inverseDeltaTransform(Vec3d src, Vec3d dst) 365 throws NoninvertibleTransformException; 366 367 public abstract void transform(float[] srcPts, int srcOff, 368 float[] dstPts, int dstOff, 369 int numPts); 370 public abstract void transform(double[] srcPts, int srcOff, 371 double[] dstPts, int dstOff, 372 int numPts); 373 public abstract void transform(float[] srcPts, int srcOff, 374 double[] dstPts, int dstOff, 375 int numPts); 376 public abstract void transform(double[] srcPts, int srcOff, 377 float[] dstPts, int dstOff, 378 int numPts); 379 public abstract void deltaTransform(float[] srcPts, int srcOff, 380 float[] dstPts, int dstOff, 381 int numPts); 382 public abstract void deltaTransform(double[] srcPts, int srcOff, 383 double[] dstPts, int dstOff, 384 int numPts); 385 public abstract void inverseTransform(float[] srcPts, int srcOff, 386 float[] dstPts, int dstOff, 387 int numPts) 388 throws NoninvertibleTransformException; 389 public abstract void inverseDeltaTransform(float[] srcPts, int srcOff, 390 float[] dstPts, int dstOff, 391 int numPts) 392 throws NoninvertibleTransformException; 393 public abstract void inverseTransform(double[] srcPts, int srcOff, 394 double[] dstPts, int dstOff, 395 int numPts) 396 throws NoninvertibleTransformException; 397 398 public abstract BaseBounds transform(BaseBounds bounds, BaseBounds result); 399 public abstract void transform(Rectangle rect, Rectangle result); 400 public abstract BaseBounds inverseTransform(BaseBounds bounds, BaseBounds result) 401 throws NoninvertibleTransformException; 402 public abstract void inverseTransform(Rectangle rect, Rectangle result) 403 throws NoninvertibleTransformException; 404 405 public abstract void setToIdentity(); 406 public abstract void setTransform(BaseTransform xform); 407 408 /** 409 * This function inverts the {@code BaseTransform} in place. All 410 * current implementations can support their own inverted form, and 411 * that should likely remain true in the future as well. 412 */ 413 public abstract void invert() throws NoninvertibleTransformException; 414 415 /** 416 * This function is only guaranteed to succeed if the transform is 417 * of degree AFFINE2D or less and the matrix 418 * parameters specified came from this same instance. In practice, 419 * they will also tend to succeed if they specify a transform of 420 * Degree less than or equal to the Degree of this instance as well, 421 * but the intent of this method is to restore the transform that 422 * had been read out of this transform into local variables. 423 */ 424 public abstract void restoreTransform(double mxx, double myx, 425 double mxy, double myy, 426 double mxt, double myt); 427 428 /** 429 * This function is only guaranteed to succeed if the matrix 430 * parameters specified came from this same instance. In practice, 431 * they will also tend to succeed if they specify a transform of 432 * Degree less than or equal to the Degree of this instance as well, 433 * but the intent of this method is to restore the transform that 434 * had been read out of this transform into local variables. 435 */ 436 public abstract void restoreTransform(double mxx, double mxy, double mxz, double mxt, 437 double myx, double myy, double myz, double myt, 438 double mzx, double mzy, double mzz, double mzt); 439 440 public abstract BaseTransform deriveWithTranslation(double mxt, double myt); 441 public abstract BaseTransform deriveWithTranslation(double mxt, double myt, double mzt); 442 public abstract BaseTransform deriveWithScale(double mxx, double myy, double mzz); 443 public abstract BaseTransform deriveWithRotation(double theta, double axisX, double axisY, double axisZ); 444 public abstract BaseTransform deriveWithPreTranslation(double mxt, double myt); 445 public abstract BaseTransform deriveWithConcatenation(double mxx, double myx, 446 double mxy, double myy, 447 double mxt, double myt); 448 public abstract BaseTransform deriveWithConcatenation( 449 double mxx, double mxy, double mxz, double mxt, 450 double myx, double myy, double myz, double myt, 451 double mzx, double mzy, double mzz, double mzt); 452 public abstract BaseTransform deriveWithPreConcatenation(BaseTransform transform); 453 public abstract BaseTransform deriveWithConcatenation(BaseTransform tx); 454 public abstract BaseTransform deriveWithNewTransform(BaseTransform tx); 455 456 /** 457 * This function always returns a new object, unless the transform 458 * is an identity transform in which case it might return the 459 * {@code Identity} singleton. 460 * @return a new transform representing the inverse of this transform. 461 */ 462 public abstract BaseTransform createInverse() 463 throws NoninvertibleTransformException; 464 465 public abstract BaseTransform copy(); 466 467 /** 468 * Returns the hashcode for this transform. 469 * @return a hash code for this transform. 470 */ 471 @Override 472 public int hashCode() { 473 if (isIdentity()) return 0; 474 long bits = 0; 475 bits = bits * 31 + Double.doubleToLongBits(getMzz()); 476 bits = bits * 31 + Double.doubleToLongBits(getMzy()); 477 bits = bits * 31 + Double.doubleToLongBits(getMzx()); 478 bits = bits * 31 + Double.doubleToLongBits(getMyz()); 479 bits = bits * 31 + Double.doubleToLongBits(getMxz()); 480 bits = bits * 31 + Double.doubleToLongBits(getMyy()); 481 bits = bits * 31 + Double.doubleToLongBits(getMyx()); 482 bits = bits * 31 + Double.doubleToLongBits(getMxy()); 483 bits = bits * 31 + Double.doubleToLongBits(getMxx()); 484 bits = bits * 31 + Double.doubleToLongBits(getMzt()); 485 bits = bits * 31 + Double.doubleToLongBits(getMyt()); 486 bits = bits * 31 + Double.doubleToLongBits(getMxt()); 487 return (((int) bits) ^ ((int) (bits >> 32))); 488 } 489 490 /** 491 * Returns <code>true</code> if this <code>BaseTransform</code> 492 * represents the same coordinate transform as the specified 493 * argument. 494 * @param obj the <code>Object</code> to test for equality with this 495 * <code>BaseTransform</code> 496 * @return <code>true</code> if <code>obj</code> equals this 497 * <code>BaseTransform</code> object; <code>false</code> otherwise. 498 */ 499 @Override 500 public boolean equals(Object obj) { 501 if (!(obj instanceof BaseTransform)) { 502 return false; 503 } 504 505 BaseTransform a = (BaseTransform) obj; 506 507 return (getMxx() == a.getMxx() && 508 getMxy() == a.getMxy() && 509 getMxz() == a.getMxz() && 510 getMxt() == a.getMxt() && 511 getMyx() == a.getMyx() && 512 getMyy() == a.getMyy() && 513 getMyz() == a.getMyz() && 514 getMyt() == a.getMyt() && 515 getMzx() == a.getMzx() && 516 getMzy() == a.getMzy() && 517 getMzz() == a.getMzz() && 518 getMzt() == a.getMzt()); 519 } 520 521 static Point2D makePoint(Point2D src, Point2D dst) { 522 if (dst == null) { 523 dst = new Point2D(); 524 } 525 return dst; 526 } 527 528 static final double EPSILON_ABSOLUTE = 1.0e-5; 529 530 public static boolean almostZero(double a) { 531 return ((a < EPSILON_ABSOLUTE) && (a > -EPSILON_ABSOLUTE)); 532 } 533 534 /** 535 * Returns the matrix elements and degree of this transform as a string. 536 * @return the matrix elements and degree of this transform 537 */ 538 @Override 539 public String toString() { 540 return "Matrix: degree " + getDegree() + "\n" + 541 getMxx() + ", " + getMxy() + ", " + getMxz() + ", " + getMxt() + "\n" + 542 getMyx() + ", " + getMyy() + ", " + getMyz() + ", " + getMyt() + "\n" + 543 getMzx() + ", " + getMzy() + ", " + getMzz() + ", " + getMzt() + "\n"; 544 } 545 }