1 /*
   2  * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.transform;
  27 
  28 import javafx.beans.property.DoubleProperty;
  29 import javafx.beans.property.DoublePropertyBase;
  30 
  31 import com.sun.javafx.geom.transform.Affine3D;
  32 import com.sun.javafx.geom.transform.BaseTransform;
  33 import javafx.geometry.Point2D;
  34 import javafx.geometry.Point3D;
  35 
  36 
  37 /**
  38  * This class represents an {@code Affine} object that translates coordinates
  39  * by the specified factors. The matrix representing the translating
  40  * transformation by distances {@code x}, {@code y} and {@code z} is as follows:
  41  * <pre>
  42  *              [   1   0   0   x   ]
  43  *              [   0   1   0   y   ]
  44  *              [   0   0   1   z   ]
  45  * </pre>
  46  * @since JavaFX 2.0
  47  */
  48 
  49 public class Translate extends Transform {
  50 
  51     /**
  52      * Creates a default Translate (identity).
  53      */
  54     public Translate() {
  55     }
  56 
  57     /**
  58      * Creates a two-dimensional Translate.
  59      * @param x the distance by which coordinates are translated in the
  60      * X axis direction
  61      * @param y the distance by which coordinates are translated in the
  62      * Y axis direction
  63      */
  64     public Translate(double x, double y) {
  65         setX(x);
  66         setY(y);
  67     }
  68 
  69     /**
  70      * Creates a three-dimensional Translate.
  71      * @param x the distance by which coordinates are translated in the
  72      * X axis direction
  73      * @param y the distance by which coordinates are translated in the
  74      * Y axis direction
  75      * @param z the distance by which coordinates are translated in the
  76      * Z axis direction
  77      */
  78     public Translate(double x, double y, double z) {
  79         this(x, y);
  80         setZ(z);
  81     }
  82 
  83     /**
  84      * Defines the distance by which coordinates are translated in the
  85      * X axis direction
  86      */
  87     private DoubleProperty x;
  88 
  89 
  90     public final void setX(double value) {
  91         xProperty().set(value);
  92     }
  93 
  94     public final double getX() {
  95         return x == null ? 0.0 : x.get();
  96     }
  97 
  98     public final DoubleProperty xProperty() {
  99         if (x == null) {
 100             x = new DoublePropertyBase() {
 101 
 102                 @Override
 103                 public void invalidated() {
 104                     transformChanged();
 105                 }
 106 
 107                 @Override
 108                 public Object getBean() {
 109                     return Translate.this;
 110                 }
 111 
 112                 @Override
 113                 public String getName() {
 114                     return "x";
 115                 }
 116             };
 117         }
 118         return x;
 119     }
 120 
 121     /**
 122      * Defines the distance by which coordinates are translated in the
 123      * Y axis direction
 124      */
 125     private DoubleProperty y;
 126 
 127 
 128     public final void setY(double value) {
 129         yProperty().set(value);
 130     }
 131 
 132     public final double getY() {
 133         return y == null ? 0.0 : y.get();
 134     }
 135 
 136     public final DoubleProperty yProperty() {
 137         if (y == null) {
 138             y = new DoublePropertyBase() {
 139 
 140                 @Override
 141                 public void invalidated() {
 142                     transformChanged();
 143                 }
 144 
 145                 @Override
 146                 public Object getBean() {
 147                     return Translate.this;
 148                 }
 149 
 150                 @Override
 151                 public String getName() {
 152                     return "y";
 153                 }
 154             };
 155         }
 156         return y;
 157     }
 158 
 159     /**
 160      * Defines the distance by which coordinates are translated in the
 161      * Z axis direction
 162      */
 163     private DoubleProperty z;
 164 
 165 
 166     public final void setZ(double value) {
 167         zProperty().set(value);
 168     }
 169 
 170     public final double getZ() {
 171         return z == null ? 0.0 : z.get();
 172     }
 173 
 174     public final DoubleProperty zProperty() {
 175         if (z == null) {
 176             z = new DoublePropertyBase() {
 177 
 178                 @Override
 179                 public void invalidated() {
 180                     transformChanged();
 181                 }
 182 
 183                 @Override
 184                 public Object getBean() {
 185                     return Translate.this;
 186                 }
 187 
 188                 @Override
 189                 public String getName() {
 190                     return "z";
 191                 }
 192             };
 193         }
 194         return z;
 195     }
 196 
 197     /* *************************************************************************
 198      *                                                                         *
 199      *                         Element getters                                 *
 200      *                                                                         *
 201      **************************************************************************/
 202 
 203     @Override
 204     public double getTx() {
 205         return getX();
 206     }
 207 
 208     @Override
 209     public double getTy() {
 210         return getY();
 211     }
 212 
 213     @Override
 214     public double getTz() {
 215         return getZ();
 216     }
 217 
 218     /* *************************************************************************
 219      *                                                                         *
 220      *                           State getters                                 *
 221      *                                                                         *
 222      **************************************************************************/
 223 
 224     @Override
 225     boolean computeIs2D() {
 226         return getZ() == 0.0;
 227     }
 228 
 229     @Override
 230     boolean computeIsIdentity() {
 231         return getX() == 0.0 && getY() == 0.0 && getZ() == 0.0;
 232     }
 233 
 234     /* *************************************************************************
 235      *                                                                         *
 236      *                           Array getters                                 *
 237      *                                                                         *
 238      **************************************************************************/
 239 
 240     @Override
 241     void fill2DArray(double[] array) {
 242         array[0] = 1.0;
 243         array[1] = 0.0;
 244         array[2] = getX();
 245         array[3] = 0.0;
 246         array[4] = 1.0;
 247         array[5] = getY();
 248     }
 249 
 250     @Override
 251     void fill3DArray(double[] array) {
 252         array[0] = 1.0;
 253         array[1] = 0.0;
 254         array[2] = 0.0;
 255         array[3] = getX();
 256         array[4] = 0.0;
 257         array[5] = 1.0;
 258         array[6] = 0.0;
 259         array[7] = getY();
 260         array[8] = 0.0;
 261         array[9] = 0.0;
 262         array[10] = 1.0;
 263         array[11] = getZ();
 264     }
 265 
 266     /* *************************************************************************
 267      *                                                                         *
 268      *                         Transform creators                              *
 269      *                                                                         *
 270      **************************************************************************/
 271 
 272     @Override
 273     public Transform createConcatenation(Transform transform) {
 274         if (transform instanceof Translate) {
 275             final Translate t = (Translate) transform;
 276             return new Translate(
 277                     getX() + t.getX(),
 278                     getY() + t.getY(),
 279                     getZ() + t.getZ());
 280         }
 281 
 282         if (transform instanceof Scale) {
 283             final Scale s = (Scale) transform;
 284 
 285             final double sx = s.getX();
 286             final double sy = s.getY();
 287             final double sz = s.getZ();
 288 
 289             final double tx = getX();
 290             final double ty = getY();
 291             final double tz = getZ();
 292 
 293             if ((tx == 0.0 || sx != 1.0) &&
 294                     (ty == 0.0 || sy != 1.0) &&
 295                     (tz == 0.0 || sz != 1.0)) {
 296                 return new Scale(
 297                         sx, sy, sz,
 298                         s.getPivotX() + (sx == 1.0 ? 0 : tx / (1.0 - sx)),
 299                         s.getPivotY() + (sy == 1.0 ? 0 : ty / (1.0 - sy)),
 300                         s.getPivotZ() + (sz == 1.0 ? 0 : tz / (1.0 - sz)));
 301             }
 302         }
 303 
 304         if (transform instanceof Affine) {
 305             Affine a = (Affine) transform.clone();
 306             a.prepend(this);
 307             return a;
 308         }
 309 
 310         final double txx = transform.getMxx();
 311         final double txy = transform.getMxy();
 312         final double txz = transform.getMxz();
 313         final double ttx = transform.getTx();
 314         final double tyx = transform.getMyx();
 315         final double tyy = transform.getMyy();
 316         final double tyz = transform.getMyz();
 317         final double tty = transform.getTy();
 318         final double tzx = transform.getMzx();
 319         final double tzy = transform.getMzy();
 320         final double tzz = transform.getMzz();
 321         final double ttz = transform.getTz();
 322         return new Affine(
 323                 txx, txy, txz, ttx + getX(),
 324                 tyx, tyy, tyz, tty + getY(),
 325                 tzx, tzy, tzz, ttz + getZ());
 326     }
 327 
 328     @Override
 329     public Translate createInverse() {
 330         return new Translate(-getX(), -getY(), -getZ());
 331     }
 332 
 333     @Override
 334     public Translate clone() {
 335         return new Translate(getX(), getY(), getZ());
 336     }
 337 
 338     /* *************************************************************************
 339      *                                                                         *
 340      *                     Transform, Inverse Transform                        *
 341      *                                                                         *
 342      **************************************************************************/
 343 
 344     @Override
 345     public Point2D transform(double x, double y) {
 346         ensureCanTransform2DPoint();
 347         return new Point2D(
 348                 x + getX(),
 349                 y + getY());
 350     }
 351 
 352     @Override
 353     public Point3D transform(double x, double y, double z) {
 354         return new Point3D(
 355                 x + getX(),
 356                 y + getY(),
 357                 z + getZ());
 358     }
 359 
 360     @Override
 361     void transform2DPointsImpl(double[] srcPts, int srcOff,
 362             double[] dstPts, int dstOff, int numPts) {
 363         final double tx = getX();
 364         final double ty = getY();
 365 
 366         while (--numPts >= 0) {
 367             final double x = srcPts[srcOff++];
 368             final double y = srcPts[srcOff++];
 369 
 370             dstPts[dstOff++] = x + tx;
 371             dstPts[dstOff++] = y + ty;
 372         }
 373     }
 374 
 375     @Override
 376     void transform3DPointsImpl(double[] srcPts, int srcOff,
 377             double[] dstPts, int dstOff, int numPts) {
 378 
 379         final double tx = getX();
 380         final double ty = getY();
 381         final double tz = getZ();
 382 
 383         while (--numPts >= 0) {
 384             final double x = srcPts[srcOff++];
 385             final double y = srcPts[srcOff++];
 386             final double z = srcPts[srcOff++];
 387 
 388             dstPts[dstOff++] = x + tx;
 389             dstPts[dstOff++] = y + ty;
 390             dstPts[dstOff++] = z + tz;
 391         }
 392     }
 393 
 394     @Override
 395     public Point2D deltaTransform(double x, double y) {
 396         ensureCanTransform2DPoint();
 397         return new Point2D(x, y);
 398     }
 399 
 400     @Override
 401     public Point2D deltaTransform(Point2D point) {
 402         if (point == null) {
 403             throw new NullPointerException();
 404         }
 405         ensureCanTransform2DPoint();
 406         return point;
 407     }
 408 
 409     @Override
 410     public Point3D deltaTransform(double x, double y, double z) {
 411         return new Point3D(x, y, z);
 412     }
 413 
 414     @Override
 415     public Point3D deltaTransform(Point3D point) {
 416         if (point == null) {
 417             throw new NullPointerException();
 418         }
 419         return point;
 420     }
 421 
 422     @Override
 423     public Point2D inverseTransform(double x, double y) {
 424         ensureCanTransform2DPoint();
 425         return new Point2D(
 426                 x - getX(),
 427                 y - getY());
 428     }
 429 
 430     @Override
 431     public Point3D inverseTransform(double x, double y, double z) {
 432         return new Point3D(
 433                 x - getX(),
 434                 y - getY(),
 435                 z - getZ());
 436     }
 437 
 438     @Override
 439     void inverseTransform2DPointsImpl(double[] srcPts, int srcOff,
 440             double[] dstPts, int dstOff, int numPts) {
 441         final double tx = getX();
 442         final double ty = getY();
 443 
 444         while (--numPts >= 0) {
 445             dstPts[dstOff++] = srcPts[srcOff++] - tx;
 446             dstPts[dstOff++] = srcPts[srcOff++] - ty;
 447         }
 448     }
 449 
 450     @Override
 451     void inverseTransform3DPointsImpl(double[] srcPts, int srcOff,
 452             double[] dstPts, int dstOff, int numPts) {
 453 
 454         final double tx = getX();
 455         final double ty = getY();
 456         final double tz = getZ();
 457 
 458         while (--numPts >= 0) {
 459             dstPts[dstOff++] = srcPts[srcOff++] - tx;
 460             dstPts[dstOff++] = srcPts[srcOff++] - ty;
 461             dstPts[dstOff++] = srcPts[srcOff++] - tz;
 462         }
 463     }
 464 
 465     @Override
 466     public Point2D inverseDeltaTransform(double x, double y) {
 467         ensureCanTransform2DPoint();
 468         return new Point2D(x, y);
 469     }
 470 
 471     @Override
 472     public Point2D inverseDeltaTransform(Point2D point) {
 473         if (point == null) {
 474             throw new NullPointerException();
 475         }
 476         ensureCanTransform2DPoint();
 477         return point;
 478     }
 479 
 480     @Override
 481     public Point3D inverseDeltaTransform(double x, double y, double z) {
 482         return new Point3D(x, y, z);
 483     }
 484 
 485     @Override
 486     public Point3D inverseDeltaTransform(Point3D point) {
 487         if (point == null) {
 488             throw new NullPointerException();
 489         }
 490         return point;
 491     }
 492 
 493     /* *************************************************************************
 494      *                                                                         *
 495      *                               Other API                                 *
 496      *                                                                         *
 497      **************************************************************************/
 498 
 499     /**
 500      * Returns a string representation of this {@code Translate} object.
 501      * @return a string representation of this {@code Translate} object.
 502      */
 503     @Override
 504     public String toString() {
 505         final StringBuilder sb = new StringBuilder("Translate [");
 506 
 507         sb.append("x=").append(getX());
 508         sb.append(", y=").append(getY());
 509         sb.append(", z=").append(getZ());
 510 
 511         return sb.append("]").toString();
 512     }
 513 
 514     /* *************************************************************************
 515      *                                                                         *
 516      *                    Internal implementation stuff                        *
 517      *                                                                         *
 518      **************************************************************************/
 519 
 520     @Override
 521     void apply(final Affine3D trans) {
 522         trans.translate(getX(), getY(), getZ());
 523     }
 524 
 525     @Override
 526     BaseTransform derive(final BaseTransform trans) {
 527         return trans.deriveWithTranslation(getX(), getY(), getZ());
 528     }
 529 
 530     @Override
 531     void validate() {
 532         getX();
 533         getY();
 534         getZ();
 535     }
 536 
 537     @Override
 538     void appendTo(Affine a) {
 539         a.appendTranslation(getTx(), getTy(), getTz());
 540     }
 541 
 542     @Override
 543     void prependTo(Affine a) {
 544         a.prependTranslation(getTx(), getTy(), getTz());
 545     }
 546 }