Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.transform;
027
028import javafx.beans.property.DoubleProperty;
029import javafx.beans.property.DoublePropertyBase;
030
031import com.sun.javafx.geom.transform.Affine3D;
032import javafx.geometry.Point2D;
033import javafx.geometry.Point3D;
034
035
036/**
037 * This class represents an {@code Affine} object that shears coordinates
038 * by the specified multipliers. The matrix representing the shearing
039 * transformation is as follows:
040 * <pre>
041 *      [   1   x   0   -x*pivotY ]
042 *      [   y   1   0   -y*pivotX ]
043 *      [   0   0   1   0   ]
044 * </pre>
045 *
046 * <p>
047 * For example:
048 * <pre><code>
049 * Text text = new Text("Using Shear for pseudo-italic font");
050 * text.setX(20);
051 * text.setY(50);
052 * text.setFont(new Font(20));
053 *
054 * text.getTransforms().add(new Shear(-0.35, 0));
055 * </code></pre>
056 * </p>
057 */
058public class Shear extends Transform {
059    
060    /**
061     * Creates a default Shear (identity).
062     */
063    public Shear() {
064    }
065
066    /**
067     * Creates a new instance of Shear.
068     * @param x the multiplier by which coordinates are shifted in the direction
069     * of the positive X axis as a factor of their Y coordinate
070     * @param y the multiplier by which coordinates are shifted in the direction
071     * of the positive Y axis as a factor of their X coordinate
072     */
073    public Shear(double x, double y) {
074        setX(x);
075        setY(y);
076    }
077
078    /**
079     * Creates a new instance of Shear with pivot.
080     * @param x the multiplier by which coordinates are shifted in the direction
081     * of the positive X axis as a factor of their Y coordinate
082     * @param y the multiplier by which coordinates are shifted in the direction
083     * of the positive Y axis as a factor of their X coordinate
084     * @param pivotX the X coordinate of the shear pivot point
085     * @param pivotY the Y coordinate of the shear pivot point
086     */
087    public Shear(double x, double y, double pivotX, double pivotY) {
088        setX(x);
089        setY(y);
090        setPivotX(pivotX);
091        setPivotY(pivotY);
092    }
093
094    /**
095     * Defines the multiplier by which coordinates are shifted in the direction
096     * of the positive X axis as a factor of their Y coordinate. Typical values
097     * are in the range -1 to 1, exclusive.
098     *
099     * @defaultValue 0.0
100     */
101    private DoubleProperty x;
102
103
104    public final void setX(double value) {
105        xProperty().set(value);
106    }
107
108    public final double getX() {
109        return x == null ? 0.0 : x.get();
110    }
111
112    public final DoubleProperty xProperty() {
113        if (x == null) {
114            x = new DoublePropertyBase() {
115
116                @Override
117                public void invalidated() {
118                    transformChanged();
119                }
120
121                @Override
122                public Object getBean() {
123                    return Shear.this;
124                }
125
126                @Override
127                public String getName() {
128                    return "x";
129                }
130            };
131        }
132        return x;
133    }
134
135    /**
136     * Defines the multiplier by which coordinates are shifted in the direction
137     * of the positive Y axis as a factor of their X coordinate. Typical values
138     * are in the range -1 to 1, exclusive.
139     *
140     * @defaultValue 0.0
141     */
142    private DoubleProperty y;
143
144
145    public final void setY(double value) {
146        yProperty().set(value);
147    }
148
149    public final double getY() {
150        return y == null ? 0.0 : y.get();
151    }
152
153    public final DoubleProperty yProperty() {
154        if (y == null) {
155            y = new DoublePropertyBase() {
156
157                @Override
158                public void invalidated() {
159                    transformChanged();
160                }
161
162                @Override
163                public Object getBean() {
164                    return Shear.this;
165                }
166
167                @Override
168                public String getName() {
169                    return "y";
170                }
171            };
172        }
173        return y;
174    }
175
176    /**
177     * Defines the X coordinate of the shear pivot point.
178     */
179    private DoubleProperty pivotX;
180
181
182    public final void setPivotX(double value) {
183        pivotXProperty().set(value);
184    }
185
186    public final double getPivotX() {
187        return pivotX == null ? 0.0 : pivotX.get();
188    }
189
190    public final DoubleProperty pivotXProperty() {
191        if (pivotX == null) {
192            pivotX = new DoublePropertyBase() {
193
194                @Override
195                public void invalidated() {
196                    transformChanged();
197                }
198
199                @Override
200                public Object getBean() {
201                    return Shear.this;
202                }
203
204                @Override
205                public String getName() {
206                    return "pivotX";
207                }
208            };
209        }
210        return pivotX;
211    }
212
213    /**
214     * Defines the Y coordinate of the shear pivot point.
215     */
216    private DoubleProperty pivotY;
217
218
219    public final void setPivotY(double value) {
220        pivotYProperty().set(value);
221    }
222
223    public final double getPivotY() {
224        return pivotY == null ? 0.0 : pivotY.get();
225    }
226
227    public final DoubleProperty pivotYProperty() {
228        if (pivotY == null) {
229            pivotY = new DoublePropertyBase() {
230
231                @Override
232                public void invalidated() {
233                    transformChanged();
234                }
235
236                @Override
237                public Object getBean() {
238                    return Shear.this;
239                }
240
241                @Override
242                public String getName() {
243                    return "pivotY";
244                }
245            };
246        }
247        return pivotY;
248    }
249
250    /* *************************************************************************
251     *                                                                         *
252     *                         Element getters                                 *
253     *                                                                         *
254     **************************************************************************/
255
256    @Override
257    public double getMxy() {
258        return getX();
259    }
260
261    @Override
262    public double getMyx() {
263        return getY();
264    }
265
266    @Override
267    public double getTx() {
268        return -getX() * getPivotY();
269    }
270
271    @Override
272    public double getTy() {
273        return -getY() * getPivotX();
274    }
275
276    /* *************************************************************************
277     *                                                                         *
278     *                           State getters                                 *
279     *                                                                         *
280     **************************************************************************/
281
282    @Override
283    boolean computeIs2D() {
284        return true;
285    }
286
287    @Override
288    boolean computeIsIdentity() {
289        return getX() == 0.0 && getY() == 0.0;
290    }
291
292    /* *************************************************************************
293     *                                                                         *
294     *                           Array getters                                 *
295     *                                                                         *
296     **************************************************************************/
297
298    @Override
299    void fill2DArray(double[] array) {
300        final double sx = getX();
301        final double sy = getY();
302
303        array[0] = 1.0;
304        array[1] = sx;
305        array[2] = -sx * getPivotY();
306        array[3] = sy;
307        array[4] = 1.0;
308        array[5] = -sy * getPivotX();
309    }
310
311    @Override
312    void fill3DArray(double[] array) {
313        final double sx = getX();
314        final double sy = getY();
315
316        array[0] = 1.0;
317        array[1] = sx;
318        array[2] = 0.0;
319        array[3] = -sx * getPivotY();
320        array[4] = sy;
321        array[5] = 1.0;
322        array[6] = 0.0;
323        array[7] = -sy * getPivotX();
324        array[8] = 0.0;
325        array[9] = 0.0;
326        array[10] = 1.0;
327        array[11] = 0.0;
328    }
329
330    /* *************************************************************************
331     *                                                                         *
332     *                         Transform creators                              *
333     *                                                                         *
334     **************************************************************************/
335
336    @Override
337    public Transform createConcatenation(Transform transform) {
338
339        if (transform instanceof Affine) {
340            Affine a = (Affine) transform.clone();
341            a.prepend(this);
342            return a;
343        }
344
345        final double sx = getX();
346        final double sy = getY();
347
348        final double txx = transform.getMxx();
349        final double txy = transform.getMxy();
350        final double txz = transform.getMxz();
351        final double ttx = transform.getTx();
352        final double tyx = transform.getMyx();
353        final double tyy = transform.getMyy();
354        final double tyz = transform.getMyz();
355        final double tty = transform.getTy();
356        return new Affine(
357                txx + sx * tyx,
358                txy + sx * tyy,
359                txz + sx * tyz,
360                ttx + sx * tty - sx * getPivotY(),
361                sy * txx + tyx,
362                sy * txy + tyy,
363                sy * txz + tyz,
364                sy * ttx + tty - sy * getPivotX(),
365                transform.getMzx(),
366                transform.getMzy(),
367                transform.getMzz(),
368                transform.getTz());
369    }
370
371    @Override
372    public Transform createInverse() {
373        final double sx = getX();
374        final double sy = getY();
375
376        if (sy == 0.0) {
377            return new Shear(-sx, 0.0, 0.0, getPivotY());
378        }
379
380        if (sx == 0.0) {
381            return new Shear(0.0, -sy, getPivotX(), 0.0);
382        }
383
384        final double px = getPivotX();
385        final double py = getPivotY();
386        final double coef = 1.0 / (1.0 - sx * sy);
387
388        return new Affine(
389                coef,       -sx * coef,         0, sx * (py - sy * px) * coef,
390                -sy * coef, 1 + sx * sy * coef, 0, sy * px + sy * (sx * sy * px - sx * py) * coef,
391                0,          0,                  1, 0);
392    }
393
394    @Override
395    public Shear clone() {
396        return new Shear(getX(), getY(), getPivotX(), getPivotY());
397    }
398
399    /* *************************************************************************
400     *                                                                         *
401     *                     Transform, Inverse Transform                        *
402     *                                                                         *
403     **************************************************************************/
404
405    @Override
406    public Point2D transform(double x, double y) {
407        final double mxy = getX();
408        final double myx = getY();
409
410        return new Point2D(
411            x + mxy * y - mxy * getPivotY(),
412            myx * x + y - myx * getPivotX());
413    }
414
415    @Override
416    public Point3D transform(double x, double y, double z) {
417        final double mxy = getX();
418        final double myx = getY();
419
420        return new Point3D(
421            x + mxy * y - mxy * getPivotY(),
422            myx * x + y - myx * getPivotX(),
423            z);
424    }
425
426    @Override
427    void transform2DPointsImpl(double[] srcPts, int srcOff,
428            double[] dstPts, int dstOff, int numPts) {
429        final double xy = getX();
430        final double yx = getY();
431        final double px = getPivotX();
432        final double py = getPivotY();
433
434        while (--numPts >= 0) {
435            final double x = srcPts[srcOff++];
436            final double y = srcPts[srcOff++];
437
438            dstPts[dstOff++] = x + xy * y - xy * py;
439            dstPts[dstOff++] = yx * x + y - yx * px;
440        }
441    }
442
443    @Override
444    void transform3DPointsImpl(double[] srcPts, int srcOff,
445            double[] dstPts, int dstOff, int numPts) {
446        final double xy = getX();
447        final double yx = getY();
448        final double px = getPivotX();
449        final double py = getPivotY();
450
451        while (--numPts >= 0) {
452            final double x = srcPts[srcOff++];
453            final double y = srcPts[srcOff++];
454
455            dstPts[dstOff++] = x + xy * y - xy * py;
456            dstPts[dstOff++] = yx * x + y - yx * px;
457            dstPts[dstOff++] = srcPts[srcOff++];
458        }
459    }
460
461    @Override
462    public Point2D deltaTransform(double x, double y) {
463
464        return new Point2D(
465            x + getX() * y,
466            getY() * x + y);
467    }
468
469    @Override
470    public Point3D deltaTransform(double x, double y, double z) {
471        return new Point3D(
472            x + getX() * y,
473            getY() * x + y,
474            z);
475    }
476
477
478    @Override
479    public Point2D inverseTransform(double x, double y)
480            throws NonInvertibleTransformException {
481        final double sx = getX();
482        final double sy = getY();
483
484        if (sy == 0.0) {
485            final double mxy = -getX();
486
487            return new Point2D(
488                x + mxy * y - mxy * getPivotY(),
489                y);
490        }
491
492        if (sx == 0.0) {
493            final double myx = -getY();
494
495            return new Point2D(
496                x,
497                myx * x + y - myx * getPivotX());
498        }
499
500        return super.inverseTransform(x, y);
501    }
502
503    @Override
504    public Point3D inverseTransform(double x, double y, double z)
505            throws NonInvertibleTransformException {
506        final double sx = getX();
507        final double sy = getY();
508
509        if (sy == 0.0) {
510            final double mxy = -getX();
511
512            return new Point3D(
513                x + mxy * y - mxy * getPivotY(),
514                y,
515                z);
516        }
517
518        if (sx == 0.0) {
519            final double myx = -getY();
520
521            return new Point3D(
522                x,
523                myx * x + y - myx * getPivotX(),
524                z);
525        }
526
527        return super.inverseTransform(x, y, z);
528    }
529
530    @Override
531    void inverseTransform2DPointsImpl(double[] srcPts, int srcOff,
532            double[] dstPts, int dstOff, int numPts)
533            throws NonInvertibleTransformException {
534
535        final double px = getPivotX();
536        final double py = getPivotY();
537
538        final double sx = getX();
539        final double sy = getY();
540
541        if (sy == 0.0) {
542            final double xy = -sx;
543
544            while (--numPts >= 0) {
545                final double x = srcPts[srcOff++];
546                final double y = srcPts[srcOff++];
547
548                dstPts[dstOff++] = x + xy * y - xy * py;
549                dstPts[dstOff++] = y;
550            }
551            return;
552        }
553
554        if (sx == 0.0) {
555            final double yx = -sy;
556
557            while (--numPts >= 0) {
558                final double x = srcPts[srcOff++];
559                final double y = srcPts[srcOff++];
560
561                dstPts[dstOff++] = x;
562                dstPts[dstOff++] = yx * x + y - yx * px;
563            }
564            return;
565        }
566
567        super.inverseTransform2DPointsImpl(srcPts, srcOff, dstPts, dstOff, numPts);
568    }
569
570    @Override
571    void inverseTransform3DPointsImpl(double[] srcPts, int srcOff,
572            double[] dstPts, int dstOff, int numPts) 
573            throws NonInvertibleTransformException{
574        
575        final double px = getPivotX();
576        final double py = getPivotY();
577
578        final double sx = getX();
579        final double sy = getY();
580
581        if (sy == 0.0) {
582            final double xy = -sx;
583
584            while (--numPts >= 0) {
585                final double x = srcPts[srcOff++];
586                final double y = srcPts[srcOff++];
587
588                dstPts[dstOff++] = x + xy * y - xy * py;
589                dstPts[dstOff++] = y;
590                dstPts[dstOff++] = srcPts[srcOff++];
591            }
592            return;
593        }
594
595        if (sx == 0.0) {
596            final double yx = -sy;
597
598            while (--numPts >= 0) {
599                final double x = srcPts[srcOff++];
600                final double y = srcPts[srcOff++];
601
602                dstPts[dstOff++] = x;
603                dstPts[dstOff++] = yx * x + y - yx * px;
604                dstPts[dstOff++] = srcPts[srcOff++];
605            }
606            return;
607        }
608
609        super.inverseTransform3DPointsImpl(srcPts, srcOff, dstPts, dstOff, numPts);
610    }
611
612    @Override
613    public Point2D inverseDeltaTransform(double x, double y)
614            throws NonInvertibleTransformException {
615        final double sx = getX();
616        final double sy = getY();
617
618        if (sy == 0.0) {
619            return new Point2D(
620                x - getX() * y,
621                y);
622        }
623
624        if (sx == 0.0) {
625            return new Point2D(
626                x,
627                -getY() * x + y);
628        }
629
630        return super.inverseDeltaTransform(x, y);
631    }
632
633    @Override
634    public Point3D inverseDeltaTransform(double x, double y, double z)
635            throws NonInvertibleTransformException {
636        final double sx = getX();
637        final double sy = getY();
638
639        if (sy == 0.0) {
640            return new Point3D(
641                x - getX() * y,
642                y,
643                z);
644        }
645
646        if (sx == 0.0) {
647            return new Point3D(
648                x,
649                -getY() * x + y,
650                z);
651        }
652
653        return super.inverseDeltaTransform(x, y, z);
654    }
655
656    /* *************************************************************************
657     *                                                                         *
658     *                               Other API                                 *
659     *                                                                         *
660     **************************************************************************/
661
662    /**
663     * Returns a string representation of this {@code Shear} object.
664     * @return a string representation of this {@code Shear} object.
665     */
666    @Override
667    public String toString() {
668        final StringBuilder sb = new StringBuilder("Shear [");
669
670        sb.append("x=").append(getX());
671        sb.append(", y=").append(getY());
672        sb.append(", pivotX=").append(getPivotX());
673        sb.append(", pivotY=").append(getPivotY());
674
675        return sb.append("]").toString();
676    }
677
678    /* *************************************************************************
679     *                                                                         *
680     *                    Internal implementation stuff                        *
681     *                                                                         *
682     **************************************************************************/
683
684    /**
685     * @treatAsPrivate implementation detail
686     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
687     */
688    @Deprecated
689    @Override
690    public void impl_apply(final Affine3D trans) {
691        if (getPivotX() != 0 || getPivotY() != 0) {
692            trans.translate(getPivotX(), getPivotY());
693            trans.shear(getX(), getY());
694            trans.translate(-getPivotX(), -getPivotY());
695        } else {
696            trans.shear(getX(), getY());
697        }
698    }
699
700    @Override
701    void validate() {
702        getX(); getPivotX();
703        getY(); getPivotY();
704    }
705
706    @Override
707    void appendTo(Affine a) {
708        a.appendShear(getX(), getY(), getPivotX(), getPivotY());
709    }
710
711    @Override
712    void prependTo(Affine a) {
713        a.prependShear(getX(), getY(), getPivotX(), getPivotY());
714    }
715}