1 /*
   2  * Copyright (c) 2012, 2014, 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 test.javafx.scene.transform;
  27 
  28 import java.util.Arrays;
  29 import java.util.Collection;
  30 import javafx.beans.InvalidationListener;
  31 import javafx.beans.Observable;
  32 import javafx.beans.value.ChangeListener;
  33 import javafx.beans.value.ObservableValue;
  34 import javafx.event.EventHandler;
  35 import javafx.geometry.BoundingBox;
  36 import javafx.geometry.Bounds;
  37 import javafx.geometry.Point2D;
  38 import javafx.geometry.Point3D;
  39 import com.sun.javafx.scene.transform.TransformUtils;
  40 import javafx.scene.transform.Affine;
  41 import javafx.scene.transform.MatrixType;
  42 import javafx.scene.transform.NonInvertibleTransformException;
  43 import javafx.scene.transform.Rotate;
  44 import javafx.scene.transform.Scale;
  45 import javafx.scene.transform.Shear;
  46 import javafx.scene.transform.Transform;
  47 import javafx.scene.transform.TransformChangedEvent;
  48 import javafx.scene.transform.TransformShim;
  49 import javafx.scene.transform.Translate;
  50 import test.com.sun.javafx.test.TransformHelper;
  51 import org.junit.Test;
  52 import org.junit.runner.RunWith;
  53 import org.junit.runners.Parameterized;
  54 import org.junit.runners.Parameterized.Parameters;
  55 
  56 import static org.junit.Assert.*;
  57 
  58 @RunWith(Parameterized.class)
  59 public class TransformOperationsTest {
  60     private static final Affine affine_identity = new Affine();
  61     private static final Affine affine_translate_only = new Affine(0, 0, 2,
  62                                                                    0, 0, 3);
  63     private static final Affine affine_translate = new Affine(1, 0, 2,
  64                                                               0, 1, 3);
  65     private static final Affine affine_scale = new Affine(4, 0, 0,
  66                                                           0, 5, 0);
  67     private static final Affine affine_sc_tr = new Affine(6, 0, 8,
  68                                                           0, 7, 9);
  69     private static final Affine affine_shear = new Affine( 0, 10, 0,
  70                                                           11,  0, 0);
  71     private static final Affine affine_sh_tr = new Affine( 0, 12, 14,
  72                                                           13,  0, 15);
  73     private static final Affine affine_sh_sc_simple = new Affine( 1, 18, 0,
  74                                                                  19,  1, 0);
  75     private static final Affine affine_sh_sc = new Affine(16, 18, 0,
  76                                                           19, 17, 0);
  77     private static final Affine affine_sh_sc_tr = new Affine(20, 21, 22,
  78                                                              23, 24, 25);
  79     private static final Affine affine_3d_tr = new Affine(1, 0, 0, 0,
  80                                                     0, 1, 0, 0,
  81                                                     0, 0, 1, 30);
  82     private static final Affine affine_3d_sc = new Affine(1, 0, 0, 0,
  83                                                     0, 1, 0, 0,
  84                                                     0, 0, 3, 0);
  85     private static final Affine affine_3d_sc_tr = new Affine(1, 0, 0, 0,
  86                                                        0, 1, 0, 0,
  87                                                        0, 0, 3, 30);
  88     private static final Affine affine_3d_sc2_tr3 = new Affine(1, 0, 0, 0,
  89                                                          0, 3, 0, 0,
  90                                                          0, 0, 1, 30);
  91     private static final Affine affine_3d_sc3_tr2 = new Affine(1, 0, 0, 25,
  92                                                          0, 1, 0, 0,
  93                                                          0, 0, 3, 0);
  94     private static final Affine affine_3d_withShear = new Affine(1, 5, 0, 0,
  95                                                            0, 1, 0, 0,
  96                                                            0, 0, 3, 30);
  97     private static final Affine affine_3d_only3d = new Affine( 1,  0, 20, 0,
  98                                                          0,  1, 30, 0,
  99                                                         11, 12, 13, 0);
 100     private static final Affine affine_3d_translate_only = new Affine(0, 0, 0, 10,
 101                                                                        0, 0, 0, 20,
 102                                                                        0, 0, 0, 30);
 103     private static final Affine affine_3d_complex = new Affine( 7,  3,  4,  5,
 104                                                           6,  7,  5,  9,
 105                                                          10, 11, 12, 13);
 106     private static final Affine affine_3d_complex_noninvertible =
 107                                                      new Affine( 2,  3,  4,  5,
 108                                                                  6,  7,  8,  9,
 109                                                                 10, 11, 12, 13);
 110     private static final Affine affine_empty = new Affine(0, 0, 0, 0,
 111                                                           0, 0, 0, 0,
 112                                                           0, 0, 0, 0);
 113     private static final Affine affine_emptyZ = new Affine(1, 0, 0, 0,
 114                                                            0, 1, 0, 0,
 115                                                            0, 0, 0, 0);
 116     private static final Affine affine_emptyXY = new Affine(0, 0, 0, 0,
 117                                                             0, 0, 0, 0,
 118                                                             0, 0, 1, 0);
 119     private static final Affine affine_nonInv_translate_x = new Affine(0, 0, 2,
 120                                                                        0, 0, 0);
 121     private static final Affine affine_nonInv_translate_y = new Affine(0, 0, 0,
 122                                                                        0, 0, 4);
 123     private static final Affine affine_nonInv_translate_z = new Affine(0, 0, 0, 0,
 124                                                                        0, 0, 0, 0,
 125                                                                        0, 0, 0, 4);
 126     private static final Affine affine_nonInv_scale_x = new Affine(2, 0, 0,
 127                                                           0, 0, 0);
 128     private static final Affine affine_nonInv_scale_y = new Affine(0, 0, 0,
 129                                                           0, 2, 0);
 130     private static final Affine affine_nonInv_scale_xy = new Affine(2, 0, 0, 0,
 131                                                                     0, 2, 0, 0,
 132                                                                     0, 0, 0, 0);
 133     private static final Affine affine_nonInv_scale_z = new Affine(0, 0, 0, 0,
 134                                                                     0, 0, 0, 0,
 135                                                                     0, 0, 4, 0);
 136     private static final Affine affine_nonInv_shear_x = new Affine(0, 3, 0,
 137                                                           0, 0, 0);
 138     private static final Affine affine_nonInv_shear_y = new Affine(0, 0, 0,
 139                                                           3, 0, 0);
 140     private static final Affine affine_nonInv_sh_tr_x = new Affine(0, 3, 4,
 141                                                           0, 0, 0);
 142     private static final Affine affine_nonInv_sh_tr_y = new Affine(0, 0, 0,
 143                                                           3, 0, 4);
 144     private static final Affine affine_nonInv_sh_sc_tr = new Affine(0, 0, 0,
 145                                                              2, 3, 4);
 146     private static final Affine affine_nonInv_sh_sc = new Affine(0, 0, 0,
 147                                                           2, 3, 0);
 148     private static final Affine affine_nonInv_sh_tr = new Affine(0, 0, 0,
 149                                                           2, 0, 5);
 150     private static final Affine affine_nonInv_sc_tr = new Affine(0, 0, 0,
 151                                                           0, 6, 5);
 152     private static final Affine affine_nonInv_sc_tr_x = new Affine(2, 0, 4,
 153                                                           0, 0, 0);
 154     private static final Affine affine_nonInv_sc_tr_y = new Affine(0, 0, 0,
 155                                                           0, 2, 7);
 156     private static final Translate translate2d = new Translate(120, 225);
 157     private static final Translate translate3d = new Translate(120, 225, 346);
 158     private static final Translate translate3d_only = new Translate(0, 0, 346);
 159     private static final Translate noTranslate = new Translate(0, 0);
 160     private static final Scale scale2d = new Scale(0.5, 2.5, 35, 46);
 161     private static final Scale scale2d_x = new Scale(1.0, 2.5, 35, 46);
 162     private static final Scale scale2d_y = new Scale(0.5, 1.0, 35, 46);
 163     private static final Scale scale3d = new Scale(0.5, 2.5, 3.6, 35, 46, 55);
 164     private static final Scale scale3dOnly = new Scale(1.0, 1.0, 3.6);
 165     private static final Scale scale2dNoPivot = new Scale(0.5, 2.5);
 166     private static final Scale scale2dUslessPivots = new Scale(0.5, 1.0, 0.0, 45);
 167     private static final Scale scale2dPivot3d = new Scale(0.5, 2.5, 1.0, 35, 46, 52);
 168     private static final Scale scale3dNoPivot = new Scale(0.5, 2.5, 3.6);
 169     private static final Scale noScale = new Scale(1, 1);
 170     private static final Scale nonInvertible3dScale = new Scale(0.0, 2.5, 3.6, 35, 46, 55);
 171     private static final Scale nonInvertible2dScale = new Scale(1.3, 0.0, 35, 45);
 172     private static final Shear shear = new Shear(3.2, 4.3, 75, 84);
 173     private static final Shear shearX = new Shear(3.2, 0, 75, 84);
 174     private static final Shear shearY = new Shear(0, 4.3, 75, 84);
 175     private static final Shear shearNoPivot = new Shear(3.5, 4.3);
 176     private static final Shear noShear = new Shear(0, 0, 75, 84);
 177     private static final Rotate simpleRotate3d = new Rotate(97.5, Rotate.Y_AXIS);
 178     private static final Rotate rotate2d = new Rotate(97.5, 123, 456);
 179     private static final Rotate rotate3d = new Rotate(97.5, 33, 44, 55, new Point3D(66, 77, 88));
 180     private static final Rotate rotate3d2d = new Rotate(97.5, 33, 44, 55, new Point3D(0, 0, 10));
 181     private static final Rotate rotateZeroAxis = new Rotate(97.5, 33, 44, 55, new Point3D(0, 0, 0));
 182     private static final Rotate rotate3dUpsideDown2d = new Rotate(97.5, 33, 44, 55, new Point3D(0, 0, -10));
 183     private static final Rotate rotate2dNoPivot = new Rotate(97.5);
 184     private static final Rotate rotate3dNoPivot = new Rotate(97.5, new Point3D(66, 77, 88));
 185     private static final Rotate rotate2dPivot3d = new Rotate(97.5, 125, 126, 127, Rotate.Z_AXIS);
 186     private static final Rotate noRotate = new Rotate(0, Rotate.Y_AXIS);
 187     private static final Transform immutable_identity =
 188             TransformHelper.immutableTransform(1, 0, 0, 0, 1, 0);
 189     private static final Transform immutable_translate_only =
 190             TransformHelper.immutableTransform(0, 0, 2, 0, 0, 3);
 191     private static final Transform immutable_translate =
 192             TransformHelper.immutableTransform(1, 0, 2, 0, 1, 3);
 193     private static final Transform immutable_scale =
 194             TransformHelper.immutableTransform(4, 0, 0, 0, 5, 0);
 195     private static final Transform immutable_sc_tr =
 196             TransformHelper.immutableTransform(6, 0, 8, 0, 7, 9);
 197     private static final Transform immutable_shear =
 198             TransformHelper.immutableTransform( 0, 10, 0, 11,  0, 0);
 199     private static final Transform immutable_sh_tr =
 200             TransformHelper.immutableTransform( 0, 12, 14, 13,  0, 15);
 201     private static final Transform immutable_sh_sc_simple =
 202             TransformHelper.immutableTransform( 1, 18, 0, 19,  1, 0);
 203     private static final Transform immutable_sh_sc =
 204             TransformHelper.immutableTransform(16, 18, 0, 19, 17, 0);
 205     private static final Transform immutable_sh_sc_tr =
 206             TransformHelper.immutableTransform(20, 21, 22, 23, 24, 25);
 207     private static final Transform immutable_3d_tr =
 208             TransformUtils.immutableTransform(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 30);
 209     private static final Transform immutable_3d_sc =
 210             TransformUtils.immutableTransform(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 0);
 211     private static final Transform immutable_3d_sc_tr =
 212             TransformUtils.immutableTransform(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 30);
 213     private static final Transform immutable_3d_sc2_tr3 =
 214             TransformUtils.immutableTransform(1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 30);
 215     private static final Transform immutable_3d_sc3_tr2 =
 216             TransformUtils.immutableTransform(1, 0, 0, 25, 0, 1, 0, 0, 0, 0, 3, 0);
 217     private static final Transform immutable_3d_withShear =
 218             TransformUtils.immutableTransform(1, 5, 0, 0, 0, 1, 0, 0, 0, 0, 3, 30);
 219     private static final Transform immutable_3d_only3d =
 220             TransformUtils.immutableTransform(1, 0, 20, 0, 0, 1, 30, 0, 11, 12, 13, 0);
 221     private static final Transform immutable_3d_translate_only =
 222             TransformUtils.immutableTransform(0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30);
 223     private static final Transform immutable_3d_complex =
 224             TransformUtils.immutableTransform(7, 3, 4, 5, 5, 7, 8, 9, 10, 11, 12, 13);
 225     private static final Transform immutable_3d_complex_noninvertible =
 226             TransformUtils.immutableTransform(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
 227     private static final Transform immutable_empty =
 228             TransformUtils.immutableTransform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 229     private static final Transform immutable_emptyZ =
 230             TransformUtils.immutableTransform(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
 231     private static final Transform immutable_emptyXY =
 232             TransformUtils.immutableTransform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
 233     private static final Transform immutable_nonInv_translate_x =
 234             TransformHelper.immutableTransform(0, 0, 2, 0, 0, 0);
 235     private static final Transform immutable_nonInv_translate_y =
 236             TransformHelper.immutableTransform(0, 0, 0, 0, 0, 4);
 237     private static final Transform immutable_nonInv_translate_z =
 238             TransformUtils.immutableTransform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4);
 239     private static final Transform immutable_nonInv_scale_x =
 240             TransformHelper.immutableTransform(2, 0, 0, 0, 0, 0);
 241     private static final Transform immutable_nonInv_scale_y =
 242             TransformHelper.immutableTransform(0, 0, 0, 0, 2, 0);
 243     private static final Transform immutable_nonInv_scale_xy =
 244             TransformUtils.immutableTransform(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0);
 245     private static final Transform immutable_nonInv_scale_z =
 246             TransformUtils.immutableTransform(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0);
 247     private static final Transform immutable_nonInv_shear_x =
 248             TransformHelper.immutableTransform(0, 3, 0, 0, 0, 0);
 249     private static final Transform immutable_nonInv_shear_y =
 250             TransformHelper.immutableTransform(0, 0, 0, 3, 0, 0);
 251     private static final Transform immutable_nonInv_sh_tr_x =
 252             TransformHelper.immutableTransform(0, 3, 4, 0, 0, 0);
 253     private static final Transform immutable_nonInv_sh_tr_y =
 254             TransformHelper.immutableTransform(0, 0, 0, 3, 0, 4);
 255     private static final Transform immutable_nonInv_sh_sc_tr =
 256             TransformHelper.immutableTransform(0, 0, 0, 2, 3, 4);
 257     private static final Transform immutable_nonInv_sh_sc =
 258             TransformHelper.immutableTransform(0, 0, 0, 2, 3, 0);
 259     private static final Transform immutable_nonInv_sh_tr =
 260             TransformHelper.immutableTransform(0, 0, 0, 2, 0, 5);
 261     private static final Transform immutable_nonInv_sc_tr =
 262             TransformHelper.immutableTransform(0, 0, 0, 0, 6, 5);
 263     private static final Transform immutable_nonInv_sc_tr_x =
 264             TransformHelper.immutableTransform(2, 0, 4, 0, 0, 0);
 265     private static final Transform immutable_nonInv_sc_tr_y =
 266             TransformHelper.immutableTransform(0, 0, 0, 0, 2, 7);
 267     private static final Transform raw_arbitrary_nonInvertible =
 268             TransformHelper.rawTransform( 5,  6,  7,  8,
 269                                          10, 11, 12, 13,
 270                                          15, 16, 17, 18);
 271     private static final Transform raw_arbitrary =
 272             TransformHelper.rawTransform( 5,  6, 13,  8,
 273                                          10,  4, 12, 13,
 274                                          15, 16, 26, 18);
 275     private static final Transform raw_empty =
 276             TransformHelper.rawTransform(0, 0, 0, 0,
 277                                          0, 0, 0, 0,
 278                                          0, 0, 0, 0);
 279     private static final Transform raw_emptyZ =
 280             TransformHelper.rawTransform(1, 0, 0, 0,
 281                                          0, 1, 0, 0,
 282                                          0, 0, 0, 0);
 283     private static final Transform raw_emptyXY =
 284             TransformHelper.rawTransform(0, 0, 0, 0,
 285                                          0, 0, 0, 0,
 286                                          0, 0, 1, 0);
 287 
 288     private boolean listenerCalled;
 289     private int eventCounter;
 290 
 291     //BEWARE: used also in AffineOperationsTest
 292     @Parameters
 293     public static Collection getParams() {
 294         return Arrays.asList(new Object[][] {
 295             { affine_identity, true, Affine.class },            //  0
 296             { affine_translate, true, Affine.class },           //  1
 297             { affine_translate_only, true, Affine.class },      //  2
 298             { affine_scale, true, Affine.class },               //  3
 299             { affine_sc_tr, true, Affine.class },               //  4
 300             { affine_shear, true, Affine.class },               //  5
 301             { affine_sh_tr, true, Affine.class },               //  6
 302             { affine_sh_sc_simple, true, Affine.class },        //  7
 303             { affine_sh_sc, true, Affine.class },               //  8
 304             { affine_sh_sc_tr, true, Affine.class },            //  9
 305             { affine_3d_tr, false, Affine.class },              // 10
 306             { affine_3d_sc, false, Affine.class },              // 11
 307             { affine_3d_sc_tr, false, Affine.class },           // 12
 308             { affine_3d_sc2_tr3, false, Affine.class },         // 13
 309             { affine_3d_sc3_tr2, false, Affine.class },         // 14
 310             { affine_3d_withShear, false, Affine.class },       // 15
 311             { affine_3d_only3d, false, Affine.class },          // 16
 312             { affine_3d_translate_only, false, null },          // 17
 313             { affine_3d_complex, false, Affine.class },         // 18
 314             { affine_3d_complex_noninvertible, false, null },   // 19
 315             { affine_empty, false, null },                      // 20
 316             { affine_emptyZ, false, null },                     // 21
 317             { affine_emptyXY, true, null },                     // 22
 318             { affine_nonInv_translate_x, true, null },          // 23
 319             { affine_nonInv_translate_y, true, null },          // 24
 320             { affine_nonInv_translate_z, false, null },         // 25
 321             { affine_nonInv_scale_x, true, null },              // 26
 322             { affine_nonInv_scale_y, true, null },              // 27
 323             { affine_nonInv_scale_xy, false, null },            // 28
 324             { affine_nonInv_scale_z, false, null },             // 29
 325             { affine_nonInv_shear_x, true, null },              // 30
 326             { affine_nonInv_shear_y, true, null },              // 31
 327             { affine_nonInv_sh_tr_x, true, null },              // 32
 328             { affine_nonInv_sh_tr_y, true, null },              // 33
 329             { affine_nonInv_sh_sc_tr, true, null },             // 34
 330             { affine_nonInv_sh_sc, true, null },                // 35
 331             { affine_nonInv_sh_tr, true, null },                // 36
 332             { affine_nonInv_sc_tr, true, null },                // 37
 333             { affine_nonInv_sc_tr_x, true, null },              // 38
 334             { affine_nonInv_sc_tr_y, true, null },              // 39
 335             { translate2d, true, Translate.class },             // 40
 336             { translate3d, false, Translate.class },            // 41
 337             { translate3d_only, false, Translate.class },       // 42
 338             { noTranslate, true, Translate.class },             // 43
 339             { scale2d, true, Scale.class },                     // 44
 340             { scale2d_x, true, Scale.class },                   // 45
 341             { scale2d_y, true, Scale.class },                   // 46
 342             { scale3d, false, Scale.class },                    // 47
 343             { scale3dOnly, false, Scale.class },                // 48
 344             { scale2dNoPivot, true, Scale.class },              // 49
 345             { scale2dUslessPivots, true, Scale.class },         // 50
 346             { scale3dNoPivot, false, Scale.class },             // 51
 347             { scale2dPivot3d, true, Scale.class },              // 52
 348             { noScale, true, Scale.class },                     // 53
 349             { nonInvertible2dScale, true, null },               // 54
 350             { nonInvertible3dScale, false, null },              // 55
 351             { shear, true, Affine.class },                      // 56
 352             { shearX, true, Shear.class },                      // 57
 353             { shearY, true, Shear.class },                      // 58
 354             { shearNoPivot, true, Affine.class },               // 59
 355             { noShear, true, Shear.class },                     // 60
 356             { simpleRotate3d, false, Rotate.class},             // 61
 357             { rotate2d, true, Rotate.class },                   // 62
 358             { rotate3d, false, Rotate.class },                  // 63
 359             { rotate3d2d, true, Rotate.class },                 // 64
 360             { rotate3dUpsideDown2d, true, Rotate.class },       // 65
 361             { rotateZeroAxis, true, Rotate.class },             // 66
 362             { rotate2dNoPivot, true, Rotate.class },            // 67
 363             { rotate3dNoPivot, false, Rotate.class },           // 68
 364             { rotate2dPivot3d, true, Rotate.class },            // 69
 365             { noRotate, true, Rotate.class },                   // 70
 366             { immutable_identity, true, Affine.class },         // 71
 367             { immutable_translate, true, Affine.class },        // 72
 368             { immutable_translate_only, true, Affine.class },   // 73
 369             { immutable_scale, true, Affine.class },            // 74
 370             { immutable_sc_tr, true, Affine.class },            // 75
 371             { immutable_shear, true, Affine.class },            // 76
 372             { immutable_sh_tr, true, Affine.class },            // 77
 373             { immutable_sh_sc_simple, true, Affine.class },     // 78
 374             { immutable_sh_sc, true, Affine.class },            // 79
 375             { immutable_sh_sc_tr, true, Affine.class },         // 80
 376             { immutable_3d_tr, false, Affine.class },           // 81
 377             { immutable_3d_sc, false, Affine.class },           // 82
 378             { immutable_3d_sc_tr, false, Affine.class },        // 83
 379             { immutable_3d_sc2_tr3, false, Affine.class },      // 84
 380             { immutable_3d_sc3_tr2, false, Affine.class },      // 85
 381             { immutable_3d_withShear, false, Affine.class },    // 86
 382             { immutable_3d_only3d, false, Affine.class },       // 87
 383             { immutable_3d_translate_only, false, null },       // 88
 384             { immutable_3d_complex, false, Affine.class },      // 89
 385             { immutable_3d_complex_noninvertible, false, null },// 90
 386             { immutable_empty, false, null },                   // 91
 387             { immutable_emptyZ, false, null },                  // 92
 388             { immutable_emptyXY, true, null },                  // 93
 389             { immutable_nonInv_translate_x, true, null },       // 94
 390             { immutable_nonInv_translate_y, true, null },       // 95
 391             { immutable_nonInv_translate_z, false, null },      // 96
 392             { immutable_nonInv_scale_x, true, null },           // 97
 393             { immutable_nonInv_scale_y, true, null },           // 98
 394             { immutable_nonInv_scale_xy, false, null },         // 99
 395             { immutable_nonInv_scale_z, false, null },          //100
 396             { immutable_nonInv_shear_x, true, null },           //101
 397             { immutable_nonInv_shear_y, true, null },           //102
 398             { immutable_nonInv_sh_tr_x, true, null },           //103
 399             { immutable_nonInv_sh_tr_y, true, null },           //104
 400             { immutable_nonInv_sh_sc_tr, true, null },          //105
 401             { immutable_nonInv_sh_sc, true, null },             //106
 402             { immutable_nonInv_sh_tr, true, null },             //107
 403             { immutable_nonInv_sc_tr, true, null },             //108
 404             { immutable_nonInv_sc_tr_x, true, null },           //109
 405             { immutable_nonInv_sc_tr_y, true, null },           //110
 406             { raw_arbitrary, false, Affine.class },             //111
 407             { raw_arbitrary_nonInvertible, false, null },       //112
 408             { raw_empty, false, null },                         //113
 409             { raw_emptyZ, false, null },                        //114
 410             { raw_emptyXY, true, null },                        //115
 411         });
 412     }
 413 
 414     private Transform t;
 415     private Transform it;
 416     private boolean is2d, isIdentity;
 417     private boolean isInvertible;
 418     private Class inverseType;
 419 
 420     public TransformOperationsTest(Transform t, boolean twoDee, Class inverseType) {
 421         this.t = t;
 422         this.is2d = twoDee;
 423         this.isIdentity =
 424                (t.getMxx() == 1 && t.getMxy() == 0 && t.getMxz() == 0 && t.getTx() == 0
 425              && t.getMyx() == 0 && t.getMyy() == 1 && t.getMyz() == 0 && t.getTy() == 0
 426              && t.getMzx() == 0 && t.getMzy() == 0 && t.getMzz() == 1 && t.getTz() == 0);
 427 
 428         this.it = null;
 429         this.inverseType = inverseType;
 430         this.isInvertible = (TransformHelper.determinant(t) != 0);
 431         if (isInvertible) {
 432             try {
 433                 it = TransformHelper.invert(t);
 434             } catch (NonInvertibleTransformException e) {
 435                 // error in test
 436                 throw new RuntimeException("Test is wrong, it must be invertible");
 437             }
 438         } else {
 439             // to avoid non-null checks everywhere
 440             it = new Affine();
 441         }
 442     }
 443 
 444     @Test
 445     public void testClone() {
 446         final double mxx = t.getMxx();
 447         final double mxy = t.getMxy();
 448         final double mxz = t.getMxz();
 449         final double tx = t.getTx();
 450         final double myx = t.getMyx();
 451         final double myy = t.getMyy();
 452         final double myz = t.getMyz();
 453         final double ty = t.getTy();
 454         final double mzx = t.getMzx();
 455         final double mzy = t.getMzy();
 456         final double mzz = t.getMzz();
 457         final double tz = t.getTz();
 458 
 459         Transform clone = t.clone();
 460 
 461         TransformHelper.assertMatrix(clone,
 462                 mxx, mxy, mxz, tx, myx, myy, myz, ty, mzx, mzy, mzz, tz);
 463 
 464         if (!TransformHelper.modify(clone, 42)) {
 465             // cannot modify, nothing else to test
 466             return;
 467         }
 468 
 469         TransformHelper.assertMatrixDiffers(clone,
 470                 mxx, mxy, mxz, tx, myx, myy, myz, ty, mzx, mzy, mzz, tz);
 471 
 472         TransformHelper.assertMatrix(t,
 473                 mxx, mxy, mxz, tx, myx, myy, myz, ty, mzx, mzy, mzz, tz);
 474     }
 475 
 476     private Class getExpectedConcatenationClass(Transform t1, Transform t2) {
 477         Class c1 = t1.getClass();
 478         Class c2 = t2.getClass();
 479 
 480         if (c1 == Translate.class && c2 == Translate.class) {
 481             return Translate.class;
 482         }
 483 
 484         if (c1 == Translate.class && c2 == Scale.class) {
 485             Translate t = (Translate) t1;
 486             Scale s = (Scale) t2;
 487 
 488             if ((t.getX() == 0.0 || s.getX() != 1.0) &&
 489                     (t.getY() == 0.0 || s.getY() != 1.0) &&
 490                     (t.getZ() == 0.0 || s.getZ() != 1.0)) {
 491                 return Scale.class;
 492             }
 493         }
 494 
 495         if (c1 == Scale.class && c2 == Translate.class) {
 496             Scale s = (Scale) t1;
 497             Translate tr = (Translate) t2;
 498 
 499             if ((tr.getX() == 0.0 || (s.getX() != 1.0 && s.getX() != 0.0)) &&
 500                     (tr.getY() == 0.0 || (s.getY() != 1.0 && s.getY() != 0.0)) &&
 501                     (tr.getZ() == 0.0 || (s.getZ() != 1.0 && s.getY() != 0.0))) {
 502                 return Scale.class;
 503             }
 504         }
 505 
 506         if (c1 == Scale.class && c2 == Scale.class) {
 507             Scale s1 = (Scale) t1;
 508             Scale s2 = (Scale) t2;
 509 
 510             if (s1.getPivotX() == s2.getPivotX() &&
 511                     s1.getPivotY() == s2.getPivotY() &&
 512                     s1.getPivotZ() == s2.getPivotZ()) {
 513                 return Scale.class;
 514             }
 515         }
 516 
 517         if (c1 == Rotate.class && c2 == Rotate.class) {
 518             Rotate r1 = (Rotate) t1;
 519             Rotate r2 = (Rotate) t2;
 520             if (r1.getAxis().normalize().equals(r2.getAxis().normalize()) &&
 521                     r1.getPivotX() == r2.getPivotX() &&
 522                     r1.getPivotY() == r2.getPivotY() &&
 523                     r1.getPivotZ() == r2.getPivotZ()) {
 524                 return Rotate.class;
 525             }
 526         }
 527 
 528         return Affine.class;
 529     }
 530 
 531     @Test
 532     public void testCreateConcatenation() {
 533         int counter = 0;
 534         for (Object o : TransformOperationsTest.getParams()) {
 535             Object[] arr = (Object[]) o;
 536             Transform other = (Transform) arr[0];
 537 
 538             Transform res = TransformHelper.concatenate(t, other);
 539             Transform conc = t.createConcatenation(other);
 540 
 541             TransformHelper.assertMatrix("Concatenating with #" + counter,
 542                     conc, res);
 543             assertSame("Concatenating with #" + counter,
 544                     getExpectedConcatenationClass(t, other),
 545                     conc.getClass());
 546             counter++;
 547         }
 548     }
 549 
 550     @Test(expected=NullPointerException.class)
 551     public void testCreateConcatenationNullTransform() {
 552         t.createConcatenation(null);
 553     }
 554 
 555     @Test
 556     public void testCreateInverse() {
 557         Transform res = null;
 558         try {
 559             res = t.createInverse();
 560         } catch(NonInvertibleTransformException e) {
 561             if (isInvertible) {
 562                 e.printStackTrace();
 563                 fail("NonInvertibleTransformException thrown for invertible transform");
 564             } else {
 565                 // ok
 566                 return;
 567             }
 568         }
 569 
 570         if (!isInvertible) {
 571             fail("Should have thrown NonInvertibleTransformException");
 572         }
 573 
 574         assertNotNull(res);
 575         assertSame(inverseType, res.getClass());
 576         TransformHelper.assertMatrix(res, it);
 577     }
 578 
 579     @Test
 580     public void createInverseShouldUpdateCache() {
 581         Transform ct = t.clone();
 582         Transform res = null;
 583         boolean canInvert = isInvertible;
 584         try {
 585             res = ct.createInverse();
 586         } catch(NonInvertibleTransformException e) {
 587             if (canInvert) {
 588                 e.printStackTrace();
 589                 fail("NonInvertibleTransformException thrown for invertible transform");
 590             } else {
 591                 // ok
 592                 return;
 593             }
 594         }
 595 
 596         if (!canInvert) {
 597             fail("Should have thrown NonInvertibleTransformException");
 598         }
 599 
 600         assertNotNull(res);
 601         assertSame(inverseType, res.getClass());
 602         TransformHelper.assertMatrix(res, it);
 603 
 604         // modify the matrix to check the cache keeps up
 605 
 606         TransformHelper.modify(ct, 43);
 607         Transform inv = null;
 608         try {
 609             inv = TransformHelper.invert(ct);
 610             canInvert = true;
 611         } catch (NonInvertibleTransformException e) {
 612             canInvert = false;
 613         }
 614 
 615         try {
 616             res = ct.createInverse();
 617         } catch(NonInvertibleTransformException e) {
 618             if (canInvert) {
 619                 e.printStackTrace();
 620                 fail("NonInvertibleTransformException thrown for invertible transform");
 621             } else {
 622                 // ok
 623                 return;
 624             }
 625         }
 626 
 627         if (!isInvertible) {
 628             fail("Should have thrown NonInvertibleTransformException");
 629         }
 630 
 631         assertNotNull(res);
 632         TransformHelper.assertMatrix(res, inv);
 633 
 634         // emulate garbage collection of the cache to check it's renewed
 635         TransformShim.clearInverseCache(ct);
 636 
 637         try {
 638             res = ct.createInverse();
 639         } catch(NonInvertibleTransformException e) {
 640             if (canInvert) {
 641                 e.printStackTrace();
 642                 fail("NonInvertibleTransformException thrown for invertible transform");
 643             } else {
 644                 // ok
 645                 return;
 646             }
 647         }
 648 
 649         if (!isInvertible) {
 650             fail("Should have thrown NonInvertibleTransformException");
 651         }
 652 
 653         assertNotNull(res);
 654         TransformHelper.assertMatrix(res, inv);
 655     }
 656 
 657     @Test
 658     public void testTransformPoint3d() {
 659         Point3D p = new Point3D(12, -18, 30);
 660         Point3D expected = new Point3D(
 661             t.getMxx() * 12 - t.getMxy() * 18 + t.getMxz() * 30 + t.getTx(),
 662             t.getMyx() * 12 - t.getMyy() * 18 + t.getMyz() * 30 + t.getTy(),
 663             t.getMzx() * 12 - t.getMzy() * 18 + t.getMzz() * 30 + t.getTz());
 664 
 665 
 666         Point3D result = t.transform(p);
 667         assertEquals(expected.getX(), result.getX(), 0.00001);
 668         assertEquals(expected.getY(), result.getY(), 0.00001);
 669         assertEquals(expected.getZ(), result.getZ(), 0.00001);
 670 
 671         result = t.transform(12, -18, 30);
 672         assertEquals(expected.getX(), result.getX(), 0.00001);
 673         assertEquals(expected.getY(), result.getY(), 0.00001);
 674         assertEquals(expected.getZ(), result.getZ(), 0.00001);
 675     }
 676 
 677     @Test(expected=NullPointerException.class)
 678     public void testTransformNullPoint3D() {
 679         t.transform((Point3D) null);
 680     }
 681 
 682     @Test
 683     public void testTransformPoint2d() {
 684 
 685         Point2D p = new Point2D(12, -18);
 686         Point2D expected = new Point2D(
 687             t.getMxx() * 12 - t.getMxy() * 18 + t.getTx(),
 688             t.getMyx() * 12 - t.getMyy() * 18 + t.getTy());
 689 
 690         try {
 691             Point2D result = t.transform(p);
 692             if (!is2d) {
 693                 fail("Should have thrown ISE");
 694             }
 695             assertEquals(expected.getX(), result.getX(), 0.00001);
 696             assertEquals(expected.getY(), result.getY(), 0.00001);
 697         } catch (IllegalStateException e) {
 698             if (is2d) {
 699                 fail("Wrong exception thrown");
 700             }
 701         }
 702 
 703         try {
 704             Point2D result = t.transform(12, -18);
 705             if (!is2d) {
 706                 fail("Should have thrown ISE");
 707             }
 708             assertEquals(expected.getX(), result.getX(), 0.00001);
 709             assertEquals(expected.getY(), result.getY(), 0.00001);
 710         } catch (IllegalStateException e) {
 711             if (is2d) {
 712                 fail("Wrong exception thrown");
 713             }
 714         }
 715     }
 716 
 717     @Test(expected=NullPointerException.class)
 718     public void testTransformNullPoint2D() {
 719         t.transform((Point2D) null);
 720     }
 721 
 722     @Test
 723     public void testDeltaTransformPoint3d() {
 724         Point3D p = new Point3D(12, -18, 30);
 725         Point3D expected = new Point3D(
 726             t.getMxx() * 12 - t.getMxy() * 18 + t.getMxz() * 30,
 727             t.getMyx() * 12 - t.getMyy() * 18 + t.getMyz() * 30,
 728             t.getMzx() * 12 - t.getMzy() * 18 + t.getMzz() * 30);
 729 
 730 
 731         Point3D result = t.deltaTransform(p);
 732         assertEquals(expected.getX(), result.getX(), 0.00001);
 733         assertEquals(expected.getY(), result.getY(), 0.00001);
 734         assertEquals(expected.getZ(), result.getZ(), 0.00001);
 735 
 736         result = t.deltaTransform(12, -18, 30);
 737         assertEquals(expected.getX(), result.getX(), 0.00001);
 738         assertEquals(expected.getY(), result.getY(), 0.00001);
 739         assertEquals(expected.getZ(), result.getZ(), 0.00001);
 740     }
 741 
 742     @Test(expected=NullPointerException.class)
 743     public void testDeltaTransformNullPoint3D() {
 744         t.deltaTransform((Point3D) null);
 745     }
 746 
 747     @Test
 748     public void testDeltaTransformPoint2d() {
 749 
 750         Point2D p = new Point2D(12, -18);
 751         Point2D expected = new Point2D(
 752             t.getMxx() * 12 - t.getMxy() * 18,
 753             t.getMyx() * 12 - t.getMyy() * 18);
 754 
 755         try {
 756             Point2D result = t.deltaTransform(p);
 757             if (!is2d) {
 758                 fail("Should have thrown ISE");
 759             }
 760             assertEquals(expected.getX(), result.getX(), 0.00001);
 761             assertEquals(expected.getY(), result.getY(), 0.00001);
 762         } catch (IllegalStateException e) {
 763             if (is2d) {
 764                 fail("Wrong exception thrown");
 765             }
 766         }
 767 
 768         try {
 769             Point2D result = t.deltaTransform(12, -18);
 770             if (!is2d) {
 771                 fail("Should have thrown ISE");
 772             }
 773             assertEquals(expected.getX(), result.getX(), 0.00001);
 774             assertEquals(expected.getY(), result.getY(), 0.00001);
 775         } catch (IllegalStateException e) {
 776             if (is2d) {
 777                 fail("Wrong exception thrown");
 778             }
 779         }
 780     }
 781 
 782     @Test(expected=NullPointerException.class)
 783     public void testDeltaTransformNullPoint2D() {
 784         t.deltaTransform((Point2D) null);
 785     }
 786 
 787     @Test
 788     public void testTransformBounds() {
 789         Bounds result = t.transform(new BoundingBox(10, 11, 12, 13, 14, 15));
 790 
 791         Point3D[] points = new Point3D[] {
 792                 new Point3D(10, 11, 12),
 793                 new Point3D(10, 11, 27),
 794                 new Point3D(10, 25, 12),
 795                 new Point3D(10, 25, 27),
 796                 new Point3D(23, 11, 12),
 797                 new Point3D(23, 11, 27),
 798                 new Point3D(23, 25, 12),
 799                 new Point3D(23, 25, 27),
 800         };
 801 
 802         Point3D expected1 = new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
 803         Point3D expected2 = new Point3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE);
 804 
 805         for (Point3D p : points) {
 806             Point3D tp = new Point3D(
 807                     t.getMxx() * p.getX() + t.getMxy() * p.getY() + t.getMxz() * p.getZ() + t.getTx(),
 808                     t.getMyx() * p.getX() + t.getMyy() * p.getY() + t.getMyz() * p.getZ() + t.getTy(),
 809                     t.getMzx() * p.getX() + t.getMzy() * p.getY() + t.getMzz() * p.getZ() + t.getTz());
 810             expected1 = new Point3D(Math.min(expected1.getX(), tp.getX()), Math.min(expected1.getY(), tp.getY()),
 811                     Math.min(expected1.getZ(), tp.getZ()));
 812             expected2 = new Point3D(Math.max(expected2.getX(), tp.getX()), Math.max(expected2.getY(), tp.getY()),
 813                     Math.max(expected2.getZ(), tp.getZ()));
 814 
 815         }
 816 
 817         assertEquals(expected1.getX(), result.getMinX(), 0.00001);
 818         assertEquals(expected1.getY(), result.getMinY(), 0.00001);
 819         assertEquals(expected1.getZ(), result.getMinZ(), 0.00001);
 820         assertEquals(expected2.getX(), result.getMaxX(), 0.00001);
 821         assertEquals(expected2.getY(), result.getMaxY(), 0.00001);
 822         assertEquals(expected2.getZ(), result.getMaxZ(), 0.00001);
 823     }
 824 
 825     @Test(expected=NullPointerException.class)
 826     public void testTransformNullBounds() {
 827         t.transform((Bounds) null);
 828     }
 829 
 830     @Test
 831     public void testTransform2DPoints() {
 832         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6 };
 833         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6 };
 834 
 835         Point2D expected1 = new Point2D(
 836             t.getMxx() * 3 + t.getMxy() * 4 + t.getTx(),
 837             t.getMyx() * 3 + t.getMyy() * 4 + t.getTy());
 838 
 839         Point2D expected2 = new Point2D(
 840             t.getMxx() * 5 + t.getMxy() * 6 + t.getTx(),
 841             t.getMyx() * 5 + t.getMyy() * 6 + t.getTy());
 842 
 843         try {
 844             t.transform2DPoints(srcPts, 3, dstPts, 1, 2);
 845             if (!is2d) {
 846                 fail("Should have thrown ISE");
 847             }
 848 
 849             assertEquals(1, dstPts[0], 0.00001);
 850             assertEquals(expected1.getX(), dstPts[1], 0.00001);
 851             assertEquals(expected1.getY(), dstPts[2], 0.00001);
 852             assertEquals(expected2.getX(), dstPts[3], 0.00001);
 853             assertEquals(expected2.getY(), dstPts[4], 0.00001);
 854             assertEquals(6, dstPts[5], 0.00001);
 855         } catch (IllegalStateException e) {
 856             if (is2d) {
 857                 fail("Wrong exception thrown");
 858             }
 859         }
 860     }
 861 
 862     @Test(expected=NullPointerException.class)
 863     public void testTransform2DPointsBothPtsNull() {
 864         t.transform2DPoints(null, 2, null, 0, 0);
 865     }
 866 
 867     @Test(expected=NullPointerException.class)
 868     public void testTransform2DPointsSrcPtsNull() {
 869         t.transform2DPoints(null, 2, new double[] { 1, 2 }, 0, 0);
 870     }
 871 
 872     @Test(expected=NullPointerException.class)
 873     public void testTransform2DPointsDstPtsNull() {
 874         t.transform2DPoints(new double[] { 1, 2, 3, 4 }, 2, null, 0, 0);
 875     }
 876 
 877     @Test
 878     public void testTransform2DPointsWithOverlap() {
 879         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
 880 
 881         Point2D expected1 = new Point2D(
 882             t.getMxx() * 2 + t.getMxy() * 3 + t.getTx(),
 883             t.getMyx() * 2 + t.getMyy() * 3 + t.getTy());
 884 
 885         Point2D expected2 = new Point2D(
 886             t.getMxx() * 4 + t.getMxy() * 5 + t.getTx(),
 887             t.getMyx() * 4 + t.getMyy() * 5 + t.getTy());
 888 
 889         try {
 890             t.transform2DPoints(srcPts, 2, srcPts, 4, 2);
 891             if (!is2d) {
 892                 fail("Should have thrown ISE");
 893             }
 894 
 895             assertEquals(0, srcPts[0], 0.00001);
 896             assertEquals(1, srcPts[1], 0.00001);
 897             assertEquals(2, srcPts[2], 0.00001);
 898             assertEquals(3, srcPts[3], 0.00001);
 899             assertEquals(expected1.getX(), srcPts[4], 0.00001);
 900             assertEquals(expected1.getY(), srcPts[5], 0.00001);
 901             assertEquals(expected2.getX(), srcPts[6], 0.00001);
 902             assertEquals(expected2.getY(), srcPts[7], 0.00001);
 903             assertEquals(8, srcPts[8], 0.00001);
 904         } catch (IllegalStateException e) {
 905             if (is2d) {
 906                 fail("Wrong exception thrown");
 907             }
 908         }
 909     }
 910 
 911     @Test(expected=IndexOutOfBoundsException.class)
 912     public void testTransform2DPointsSrcOut() {
 913         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
 914         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6 };
 915 
 916         try {
 917             t.transform2DPoints(srcPts, 3, dstPts, 0, 3);
 918         } catch (IllegalStateException e) {
 919             if (!is2d) {
 920                 throw new IndexOutOfBoundsException("expected result");
 921             }
 922         }
 923     }
 924 
 925     @Test(expected=IndexOutOfBoundsException.class)
 926     public void testTransform2DPointsDstOut() {
 927         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
 928         double[] dstPts = new double[] { 1 };
 929 
 930         try {
 931             t.transform2DPoints(srcPts, 1, dstPts, 0, 2);
 932         } catch (IllegalStateException e) {
 933             if (!is2d) {
 934                 throw new IndexOutOfBoundsException("expected result");
 935             }
 936         }
 937     }
 938 
 939     @Test
 940     public void testTransform3DPoints() {
 941         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
 942         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6, 7, 8 };
 943 
 944         Point3D expected1 = new Point3D(
 945             t.getMxx() * 3 + t.getMxy() * 4 + t.getMxz() * 5 + t.getTx(),
 946             t.getMyx() * 3 + t.getMyy() * 4 + t.getMyz() * 5 + t.getTy(),
 947             t.getMzx() * 3 + t.getMzy() * 4 + t.getMzz() * 5 + t.getTz());
 948 
 949         Point3D expected2 = new Point3D(
 950             t.getMxx() * 6 + t.getMxy() * 7 + t.getMxz() * 8 + t.getTx(),
 951             t.getMyx() * 6 + t.getMyy() * 7 + t.getMyz() * 8 + t.getTy(),
 952             t.getMzx() * 6 + t.getMzy() * 7 + t.getMzz() * 8 + t.getTz());
 953 
 954         t.transform3DPoints(srcPts, 3, dstPts, 1, 2);
 955 
 956         assertEquals(1, dstPts[0], 0.00001);
 957         assertEquals(expected1.getX(), dstPts[1], 0.00001);
 958         assertEquals(expected1.getY(), dstPts[2], 0.00001);
 959         assertEquals(expected1.getZ(), dstPts[3], 0.00001);
 960         assertEquals(expected2.getX(), dstPts[4], 0.00001);
 961         assertEquals(expected2.getY(), dstPts[5], 0.00001);
 962         assertEquals(expected2.getZ(), dstPts[6], 0.00001);
 963         assertEquals(8, dstPts[7], 0.00001);
 964     }
 965 
 966     @Test(expected=NullPointerException.class)
 967     public void testTransform3DPointsBothPtsNull() {
 968         t.transform3DPoints(null, 2, null, 0, 0);
 969     }
 970 
 971     @Test(expected=NullPointerException.class)
 972     public void testTransform3DPointsSrcPtsNull() {
 973         t.transform3DPoints(null, 2, new double[] { 1, 2, 3 }, 0, 0);
 974     }
 975 
 976     @Test(expected=NullPointerException.class)
 977     public void testTransform3DPointsDstPtsNull() {
 978         t.transform3DPoints(new double[] { 1, 2, 3, 4 }, 2, null, 0, 0);
 979     }
 980 
 981     @Test
 982     public void testTransform3DPointsWithOverlap() {
 983         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 984 
 985         Point3D expected1 = new Point3D(
 986             t.getMxx() * 2 + t.getMxy() * 3 + t.getMxz() * 4 + t.getTx(),
 987             t.getMyx() * 2 + t.getMyy() * 3 + t.getMyz() * 4 + t.getTy(),
 988             t.getMzx() * 2 + t.getMzy() * 3 + t.getMzz() * 4 + t.getTz());
 989 
 990         Point3D expected2 = new Point3D(
 991             t.getMxx() * 5 + t.getMxy() * 6 + t.getMxz() * 7 + t.getTx(),
 992             t.getMyx() * 5 + t.getMyy() * 6 + t.getMyz() * 7 + t.getTy(),
 993             t.getMzx() * 5 + t.getMzy() * 6 + t.getMzz() * 7 + t.getTz());
 994 
 995         t.transform3DPoints(srcPts, 2, srcPts, 3, 2);
 996 
 997         assertEquals(0, srcPts[0], 0.00001);
 998         assertEquals(1, srcPts[1], 0.00001);
 999         assertEquals(2, srcPts[2], 0.00001);
1000         assertEquals(expected1.getX(), srcPts[3], 0.00001);
1001         assertEquals(expected1.getY(), srcPts[4], 0.00001);
1002         assertEquals(expected1.getZ(), srcPts[5], 0.00001);
1003         assertEquals(expected2.getX(), srcPts[6], 0.00001);
1004         assertEquals(expected2.getY(), srcPts[7], 0.00001);
1005         assertEquals(expected2.getZ(), srcPts[8], 0.00001);
1006         assertEquals(9, srcPts[9], 0.00001);
1007     }
1008 
1009     @Test(expected=IndexOutOfBoundsException.class)
1010     public void testTransform3DPointsSrcOut() {
1011         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
1012         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6 };
1013 
1014         t.transform3DPoints(srcPts, 6, dstPts, 0, 1);
1015     }
1016 
1017     @Test(expected=IndexOutOfBoundsException.class)
1018     public void testTransform3DPointsDstOut() {
1019         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
1020         double[] dstPts = new double[] { 1 };
1021 
1022         t.transform3DPoints(srcPts, 1, dstPts, 0, 1);
1023     }
1024 
1025     @Test
1026     public void testInverseTransformPoint3d() throws Exception {
1027         Point3D p = new Point3D(12, -18, 30);
1028 
1029         Point3D expected = new Point3D(
1030             it.getMxx() * 12 - it.getMxy() * 18 + it.getMxz() * 30 + it.getTx(),
1031             it.getMyx() * 12 - it.getMyy() * 18 + it.getMyz() * 30 + it.getTy(),
1032             it.getMzx() * 12 - it.getMzy() * 18 + it.getMzz() * 30 + it.getTz());
1033 
1034         try {
1035             Point3D result = t.inverseTransform(p);
1036             if (!isInvertible) {
1037                 fail("Should have thrown NonInvertibleTransformException");
1038             }
1039             assertEquals(expected.getX(), result.getX(), 0.00001);
1040             assertEquals(expected.getY(), result.getY(), 0.00001);
1041             assertEquals(expected.getZ(), result.getZ(), 0.00001);
1042         } catch (NonInvertibleTransformException e) {
1043             if (isInvertible) {
1044                 fail("Wrong exception thrown");
1045             }
1046         }
1047 
1048         try {
1049             Point3D result = t.inverseTransform(12, -18, 30);
1050             if (!isInvertible) {
1051                 fail("Should have thrown NonInvertibleTransformException");
1052             }
1053             assertEquals(expected.getX(), result.getX(), 0.00001);
1054             assertEquals(expected.getY(), result.getY(), 0.00001);
1055             assertEquals(expected.getZ(), result.getZ(), 0.00001);
1056         } catch (NonInvertibleTransformException e) {
1057             if (isInvertible) {
1058                 fail("Wrong exception thrown");
1059             }
1060         }
1061     }
1062 
1063     @Test(expected=NullPointerException.class)
1064     public void testInverseTransformNullPoint3D()
1065             throws NonInvertibleTransformException {
1066         t.inverseTransform((Point3D) null);
1067     }
1068 
1069     @Test
1070     public void testInverseTransformPoint2d() throws Exception {
1071 
1072         Point2D p = new Point2D(12, -18);
1073         Point2D expected = new Point2D(
1074             it.getMxx() * 12 - it.getMxy() * 18 + it.getTx(),
1075             it.getMyx() * 12 - it.getMyy() * 18 + it.getTy());
1076 
1077         try {
1078             Point2D result = t.inverseTransform(p);
1079             if (!is2d) {
1080                 fail("Should have thrown ISE");
1081             }
1082             if (!isInvertible) {
1083                 fail("Should have thrown NonInvertibleTransformException");
1084             }
1085             assertEquals(expected.getX(), result.getX(), 0.00001);
1086             assertEquals(expected.getY(), result.getY(), 0.00001);
1087         } catch (IllegalStateException e) {
1088             if (is2d) {
1089                 fail("Wrong exception thrown");
1090             }
1091         } catch (NonInvertibleTransformException e) {
1092             if (isInvertible) {
1093                 fail("Wrong exception thrown");
1094             }
1095         }
1096 
1097         try {
1098             Point2D result = t.inverseTransform(12, -18);
1099             if (!is2d) {
1100                 fail("Should have thrown ISE");
1101             }
1102             if (!isInvertible) {
1103                 fail("Should have thrown NonInvertibleTransformException");
1104             }
1105             assertEquals(expected.getX(), result.getX(), 0.00001);
1106             assertEquals(expected.getY(), result.getY(), 0.00001);
1107         } catch (IllegalStateException e) {
1108             if (is2d) {
1109                 fail("Wrong exception thrown");
1110             }
1111         } catch (NonInvertibleTransformException e) {
1112             if (isInvertible) {
1113                 fail("Wrong exception thrown");
1114             }
1115         }
1116     }
1117 
1118     @Test(expected=NullPointerException.class)
1119     public void testInverseTransformNullPoint2D()
1120             throws NonInvertibleTransformException {
1121         t.inverseTransform((Point2D) null);
1122     }
1123 
1124     @Test
1125     public void testInverseDeltaTransformPoint3d() throws Exception {
1126         Point3D p = new Point3D(12, -18, 30);
1127         Point3D expected = new Point3D(
1128             it.getMxx() * 12 - it.getMxy() * 18 + it.getMxz() * 30,
1129             it.getMyx() * 12 - it.getMyy() * 18 + it.getMyz() * 30,
1130             it.getMzx() * 12 - it.getMzy() * 18 + it.getMzz() * 30);
1131 
1132         try {
1133             Point3D result = t.inverseDeltaTransform(p);
1134             if (!isInvertible) {
1135                 fail("Should have thrown NonInvertibleTransformException");
1136             }
1137             assertEquals(expected.getX(), result.getX(), 0.00001);
1138             assertEquals(expected.getY(), result.getY(), 0.00001);
1139             assertEquals(expected.getZ(), result.getZ(), 0.00001);
1140         } catch (NonInvertibleTransformException e) {
1141             if (isInvertible) {
1142                 fail("Wrong exception thrown");
1143             }
1144         }
1145 
1146         try {
1147             Point3D result = t.inverseDeltaTransform(12, -18, 30);
1148             if (!isInvertible) {
1149                 fail("Should have thrown NonInvertibleTransformException");
1150             }
1151             assertEquals(expected.getX(), result.getX(), 0.00001);
1152             assertEquals(expected.getY(), result.getY(), 0.00001);
1153             assertEquals(expected.getZ(), result.getZ(), 0.00001);
1154         } catch (NonInvertibleTransformException e) {
1155             if (isInvertible) {
1156                 fail("Wrong exception thrown");
1157             }
1158         }
1159     }
1160 
1161     @Test(expected=NullPointerException.class)
1162     public void testInverseDeltaTransformNullPoint3D()
1163             throws NonInvertibleTransformException {
1164         t.inverseDeltaTransform((Point3D) null);
1165     }
1166 
1167     @Test
1168     public void testInverseDeltaTransformPoint2d() throws Exception {
1169 
1170         Point2D p = new Point2D(12, -18);
1171         Point2D expected = new Point2D(
1172             it.getMxx() * 12 - it.getMxy() * 18,
1173             it.getMyx() * 12 - it.getMyy() * 18);
1174 
1175         try {
1176             Point2D result = t.inverseDeltaTransform(p);
1177             if (!is2d) {
1178                 fail("Should have thrown ISE");
1179             }
1180             if (!isInvertible) {
1181                 fail("Should have thrown NonInvertibleTransformException");
1182             }
1183             assertEquals(expected.getX(), result.getX(), 0.00001);
1184             assertEquals(expected.getY(), result.getY(), 0.00001);
1185         } catch (IllegalStateException e) {
1186             if (is2d) {
1187                 fail("Wrong exception thrown");
1188             }
1189         } catch (NonInvertibleTransformException e) {
1190             if (isInvertible) {
1191                 fail("Wrong exception thrown");
1192             }
1193         }
1194 
1195         try {
1196             Point2D result = t.inverseDeltaTransform(12, -18);
1197             if (!is2d) {
1198                 fail("Should have thrown ISE");
1199             }
1200             if (!isInvertible) {
1201                 fail("Should have thrown NonInvertibleTransformException");
1202             }
1203             assertEquals(expected.getX(), result.getX(), 0.00001);
1204             assertEquals(expected.getY(), result.getY(), 0.00001);
1205         } catch (IllegalStateException e) {
1206             if (is2d) {
1207                 fail("Wrong exception thrown");
1208             }
1209         } catch (NonInvertibleTransformException e) {
1210             if (isInvertible) {
1211                 fail("Wrong exception thrown");
1212             }
1213         }
1214     }
1215 
1216     @Test(expected=NullPointerException.class)
1217     public void testInverseDeltaTransformNullPoint2D()
1218             throws NonInvertibleTransformException {
1219         t.inverseDeltaTransform((Point2D) null);
1220     }
1221 
1222     @Test
1223     public void testInverseTransformBounds() throws Exception {
1224         Bounds result = null;
1225         try {
1226             result = t.inverseTransform(new BoundingBox(10, 11, 12, 13, 14, 15));
1227             if (!isInvertible) {
1228                 fail("Should have thrown NonInvertibleTransformException");
1229             }
1230 
1231             Point3D[] points = new Point3D[] {
1232                     new Point3D(10, 11, 12),
1233                     new Point3D(10, 11, 27),
1234                     new Point3D(10, 25, 12),
1235                     new Point3D(10, 25, 27),
1236                     new Point3D(23, 11, 12),
1237                     new Point3D(23, 11, 27),
1238                     new Point3D(23, 25, 12),
1239                     new Point3D(23, 25, 27),
1240             };
1241 
1242             Point3D expected1 = new Point3D(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
1243             Point3D expected2 = new Point3D(-Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE);
1244 
1245             for (Point3D p : points) {
1246                 Point3D tp = new Point3D(
1247                         it.getMxx() * p.getX() + it.getMxy() * p.getY() + it.getMxz() * p.getZ() + it.getTx(),
1248                         it.getMyx() * p.getX() + it.getMyy() * p.getY() + it.getMyz() * p.getZ() + it.getTy(),
1249                         it.getMzx() * p.getX() + it.getMzy() * p.getY() + it.getMzz() * p.getZ() + it.getTz());
1250                 expected1 = new Point3D(Math.min(expected1.getX(), tp.getX()), Math.min(expected1.getY(), tp.getY()),
1251                         Math.min(expected1.getZ(), tp.getZ()));
1252                 expected2 = new Point3D(Math.max(expected2.getX(), tp.getX()), Math.max(expected2.getY(), tp.getY()),
1253                         Math.max(expected2.getZ(), tp.getZ()));
1254 
1255             }
1256 
1257             assertEquals(expected1.getX(), result.getMinX(), 0.00001);
1258             assertEquals(expected1.getY(), result.getMinY(), 0.00001);
1259             assertEquals(expected1.getZ(), result.getMinZ(), 0.00001);
1260             assertEquals(expected2.getX(), result.getMaxX(), 0.00001);
1261             assertEquals(expected2.getY(), result.getMaxY(), 0.00001);
1262             assertEquals(expected2.getZ(), result.getMaxZ(), 0.00001);
1263 
1264         } catch (NonInvertibleTransformException e) {
1265             if (isInvertible) {
1266                 fail("Wrong exception thrown");
1267             }
1268             return;
1269         }
1270     }
1271 
1272     @Test(expected=NullPointerException.class)
1273     public void testInverseTransformNullBounds()
1274             throws NonInvertibleTransformException {
1275         t.inverseTransform((Bounds) null);
1276     }
1277 
1278     @Test
1279     public void testInverseTransform2DPoints() throws Exception {
1280         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6 };
1281         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6 };
1282 
1283         Point2D expected1 = new Point2D(
1284             it.getMxx() * 3 + it.getMxy() * 4 + it.getTx(),
1285             it.getMyx() * 3 + it.getMyy() * 4 + it.getTy());
1286 
1287         Point2D expected2 = new Point2D(
1288             it.getMxx() * 5 + it.getMxy() * 6 + it.getTx(),
1289             it.getMyx() * 5 + it.getMyy() * 6 + it.getTy());
1290 
1291         try {
1292             t.inverseTransform2DPoints(srcPts, 3, dstPts, 1, 2);
1293             if (!is2d) {
1294                 fail("Should have thrown ISE");
1295             }
1296             if (!isInvertible) {
1297                 fail("Should have thrown NonInvertibleTransformException");
1298             }
1299 
1300             assertEquals(1, dstPts[0], 0.00001);
1301             assertEquals(expected1.getX(), dstPts[1], 0.00001);
1302             assertEquals(expected1.getY(), dstPts[2], 0.00001);
1303             assertEquals(expected2.getX(), dstPts[3], 0.00001);
1304             assertEquals(expected2.getY(), dstPts[4], 0.00001);
1305             assertEquals(6, dstPts[5], 0.00001);
1306         } catch (IllegalStateException e) {
1307             if (is2d) {
1308                 fail("Wrong exception thrown");
1309             }
1310         } catch (NonInvertibleTransformException e) {
1311             if (isInvertible) {
1312                 fail("Wrong exception thrown");
1313             }
1314         }
1315     }
1316 
1317     @Test(expected=NullPointerException.class)
1318     public void testInverseTransform2DPointsBothPtsNull()
1319             throws NonInvertibleTransformException {
1320         t.inverseTransform2DPoints(null, 2, null, 0, 0);
1321     }
1322 
1323     @Test(expected=NullPointerException.class)
1324     public void testInverseTransform2DPointsSrcPtsNull()
1325             throws NonInvertibleTransformException {
1326         t.inverseTransform2DPoints(null, 2, new double[] { 1, 2, 3 }, 0, 0);
1327     }
1328 
1329     @Test(expected=NullPointerException.class)
1330     public void testInverseTransform2DPointsDstPtsNull()
1331             throws NonInvertibleTransformException {
1332         t.inverseTransform2DPoints(new double[] { 1, 2, 3, 4 }, 2, null, 0, 0);
1333     }
1334 
1335     @Test
1336     public void testInverseTransform2DPointsWithOverlap() throws Exception {
1337         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
1338 
1339         Point2D expected1 = new Point2D(
1340             it.getMxx() * 2 + it.getMxy() * 3 + it.getTx(),
1341             it.getMyx() * 2 + it.getMyy() * 3 + it.getTy());
1342 
1343         Point2D expected2 = new Point2D(
1344             it.getMxx() * 4 + it.getMxy() * 5 + it.getTx(),
1345             it.getMyx() * 4 + it.getMyy() * 5 + it.getTy());
1346 
1347         try {
1348             t.inverseTransform2DPoints(srcPts, 2, srcPts, 4, 2);
1349             if (!is2d) {
1350                 fail("Should have thrown ISE");
1351             }
1352             if (!isInvertible) {
1353                 fail("Should have thrown NonInvertibleTransformException");
1354             }
1355             assertEquals(0, srcPts[0], 0.00001);
1356             assertEquals(1, srcPts[1], 0.00001);
1357             assertEquals(2, srcPts[2], 0.00001);
1358             assertEquals(3, srcPts[3], 0.00001);
1359             assertEquals(expected1.getX(), srcPts[4], 0.00001);
1360             assertEquals(expected1.getY(), srcPts[5], 0.00001);
1361             assertEquals(expected2.getX(), srcPts[6], 0.00001);
1362             assertEquals(expected2.getY(), srcPts[7], 0.00001);
1363             assertEquals(8, srcPts[8], 0.00001);
1364         } catch (IllegalStateException e) {
1365             if (is2d) {
1366                 fail("Wrong exception thrown");
1367             }
1368         } catch (NonInvertibleTransformException e) {
1369             if (isInvertible) {
1370                 fail("Wrong exception thrown");
1371             }
1372         }
1373     }
1374 
1375     @Test(expected=IndexOutOfBoundsException.class)
1376     public void testInverseTransform2DPointsSrcOut() throws Exception {
1377         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
1378         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6 };
1379 
1380         try {
1381             t.inverseTransform2DPoints(srcPts, 3, dstPts, 0, 3);
1382         } catch (IllegalStateException e) {
1383             if (!is2d) {
1384                 throw new IndexOutOfBoundsException("expected result");
1385             }
1386         } catch (NonInvertibleTransformException e) {
1387             if (!isInvertible) {
1388                 throw new IndexOutOfBoundsException("expected result");
1389             }
1390         }
1391     }
1392 
1393     @Test(expected=IndexOutOfBoundsException.class)
1394     public void testInverseTransform2DPointsDstOut() throws Exception {
1395         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
1396         double[] dstPts = new double[] { 1 };
1397 
1398         try {
1399             t.inverseTransform2DPoints(srcPts, 1, dstPts, 0, 2);
1400         } catch (IllegalStateException e) {
1401             if (!is2d) {
1402                 throw new IndexOutOfBoundsException("expected result");
1403             }
1404         } catch (NonInvertibleTransformException e) {
1405             if (!isInvertible) {
1406                 throw new IndexOutOfBoundsException("expected result");
1407             }
1408         }
1409     }
1410 
1411     @Test
1412     public void testInverseTransform3DPoints() throws Exception {
1413         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
1414         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6, 7, 8 };
1415 
1416         Point3D expected1 = new Point3D(
1417             it.getMxx() * 3 + it.getMxy() * 4 + it.getMxz() * 5 + it.getTx(),
1418             it.getMyx() * 3 + it.getMyy() * 4 + it.getMyz() * 5 + it.getTy(),
1419             it.getMzx() * 3 + it.getMzy() * 4 + it.getMzz() * 5 + it.getTz());
1420 
1421         Point3D expected2 = new Point3D(
1422             it.getMxx() * 6 + it.getMxy() * 7 + it.getMxz() * 8 + it.getTx(),
1423             it.getMyx() * 6 + it.getMyy() * 7 + it.getMyz() * 8 + it.getTy(),
1424             it.getMzx() * 6 + it.getMzy() * 7 + it.getMzz() * 8 + it.getTz());
1425 
1426         try {
1427             t.inverseTransform3DPoints(srcPts, 3, dstPts, 1, 2);
1428             if (!isInvertible) {
1429                 fail("Should have thrown NonInvertibleTransformException");
1430             }
1431 
1432             assertEquals(1, dstPts[0], 0.00001);
1433             assertEquals(expected1.getX(), dstPts[1], 0.00001);
1434             assertEquals(expected1.getY(), dstPts[2], 0.00001);
1435             assertEquals(expected1.getZ(), dstPts[3], 0.00001);
1436             assertEquals(expected2.getX(), dstPts[4], 0.00001);
1437             assertEquals(expected2.getY(), dstPts[5], 0.00001);
1438             assertEquals(expected2.getZ(), dstPts[6], 0.00001);
1439             assertEquals(8, dstPts[7], 0.00001);
1440         } catch (NonInvertibleTransformException e) {
1441             if (isInvertible) {
1442                 fail("Wrong exception thrown");
1443             }
1444         }
1445     }
1446 
1447     @Test(expected=NullPointerException.class)
1448     public void testInverseTransform3DPointsBothPtsNull()
1449             throws NonInvertibleTransformException {
1450         t.inverseTransform3DPoints(null, 2, null, 0, 0);
1451     }
1452 
1453     @Test(expected=NullPointerException.class)
1454     public void testInverseTransform3DPointsSrcPtsNull()
1455             throws NonInvertibleTransformException {
1456         t.inverseTransform3DPoints(null, 2, new double[] { 1, 2, 3 }, 0, 0);
1457     }
1458 
1459     @Test(expected=NullPointerException.class)
1460     public void testInverseTransform3DPointsDstPtsNull()
1461             throws NonInvertibleTransformException {
1462         t.inverseTransform3DPoints(new double[] { 1, 2, 3, 4 }, 2, null, 0, 0);
1463     }
1464 
1465     @Test
1466     public void testInverseTransform3DPointsWithOverlap() throws Exception {
1467         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
1468 
1469         Point3D expected1 = new Point3D(
1470             it.getMxx() * 2 + it.getMxy() * 3 + it.getMxz() * 4 + it.getTx(),
1471             it.getMyx() * 2 + it.getMyy() * 3 + it.getMyz() * 4 + it.getTy(),
1472             it.getMzx() * 2 + it.getMzy() * 3 + it.getMzz() * 4 + it.getTz());
1473 
1474         Point3D expected2 = new Point3D(
1475             it.getMxx() * 5 + it.getMxy() * 6 + it.getMxz() * 7 + it.getTx(),
1476             it.getMyx() * 5 + it.getMyy() * 6 + it.getMyz() * 7 + it.getTy(),
1477             it.getMzx() * 5 + it.getMzy() * 6 + it.getMzz() * 7 + it.getTz());
1478 
1479         try {
1480             t.inverseTransform3DPoints(srcPts, 2, srcPts, 3, 2);
1481             if (!isInvertible) {
1482                 fail("Should have thrown NonInvertibleTransformException");
1483             }
1484 
1485             assertEquals(0, srcPts[0], 0.00001);
1486             assertEquals(1, srcPts[1], 0.00001);
1487             assertEquals(2, srcPts[2], 0.00001);
1488             assertEquals(expected1.getX(), srcPts[3], 0.00001);
1489             assertEquals(expected1.getY(), srcPts[4], 0.00001);
1490             assertEquals(expected1.getZ(), srcPts[5], 0.00001);
1491             assertEquals(expected2.getX(), srcPts[6], 0.00001);
1492             assertEquals(expected2.getY(), srcPts[7], 0.00001);
1493             assertEquals(expected2.getZ(), srcPts[8], 0.00001);
1494             assertEquals(9, srcPts[9], 0.00001);
1495         } catch (NonInvertibleTransformException e) {
1496             if (isInvertible) {
1497                 fail("Wrong exception thrown");
1498             }
1499         }
1500     }
1501 
1502     @Test(expected=IndexOutOfBoundsException.class)
1503     public void testInverseTransform3DPointsSrcOut() throws Exception {
1504         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
1505         double[] dstPts = new double[] { 1, 2, 3, 4, 5, 6 };
1506 
1507         try {
1508             t.inverseTransform3DPoints(srcPts, 6, dstPts, 0, 1);
1509         } catch (NonInvertibleTransformException e) {
1510             if (!isInvertible) {
1511                 throw new IndexOutOfBoundsException("expected result");
1512             }
1513         }
1514     }
1515 
1516     @Test(expected=IndexOutOfBoundsException.class)
1517     public void testInverseTransform3DPointsDstOut() throws Exception {
1518         double[] srcPts = new double[] { 0, 1, 2, 3, 4, 5, 6, 7 };
1519         double[] dstPts = new double[] { 1 };
1520 
1521         try {
1522             t.inverseTransform3DPoints(srcPts, 1, dstPts, 0, 1);
1523         } catch (NonInvertibleTransformException e) {
1524             if (!isInvertible) {
1525                 throw new IndexOutOfBoundsException("expected result");
1526             }
1527         }
1528     }
1529 
1530     @Test
1531     public void testDeterminant() {
1532         assertEquals(TransformHelper.determinant(t), t.determinant(), 0.00001);
1533     }
1534 
1535     @Test
1536     public void testIsType2D() {
1537         Transform clone = t.clone();
1538 
1539         if (is2d) {
1540             assertTrue(t.isType2D());
1541             if (TransformHelper.make3D(clone)) {
1542                 assertFalse(clone.isType2D());
1543             }
1544         } else {
1545             assertFalse(t.isType2D());
1546             if (TransformHelper.make2D(clone)) {
1547                 assertTrue(clone.isType2D());
1548             }
1549         }
1550     }
1551 
1552     @Test
1553     public void testType2DProperty() {
1554         Transform clone = t.clone();
1555 
1556         assertEquals("type2D", clone.type2DProperty().getName());
1557         assertSame(clone, clone.type2DProperty().getBean());
1558     }
1559 
1560     @Test
1561     public void testType2DPropertyGetter() {
1562         Transform clone = t.clone();
1563 
1564         if (is2d) {
1565             assertTrue(clone.type2DProperty().get());
1566             assertTrue(clone.isType2D());
1567             if (TransformHelper.make3D(clone)) {
1568                 assertFalse(clone.type2DProperty().get());
1569                 assertFalse(clone.isType2D());
1570             }
1571         } else {
1572             assertFalse(clone.type2DProperty().get());
1573             assertFalse(clone.isType2D());
1574             if (TransformHelper.make2D(clone)) {
1575                 assertTrue(clone.type2DProperty().get());
1576                 assertTrue(clone.isType2D());
1577             }
1578         }
1579     }
1580 
1581     @Test
1582     public void testType2DPropertyInvalidation() {
1583         final Transform clone = t.clone();
1584 
1585         InvalidationListener l =
1586                 valueModel -> {
1587                      if (is2d) {
1588                          assertFalse(clone.type2DProperty().get());
1589                      } else {
1590                          assertTrue(clone.type2DProperty().get());
1591                      }
1592                      listenerCalled = true;
1593                 };
1594 
1595         clone.type2DProperty().addListener(l);
1596 
1597         listenerCalled = false;
1598 
1599         if (is2d) {
1600             if (TransformHelper.make3D(clone)) {
1601                 assertTrue(listenerCalled);
1602             }
1603         } else {
1604             if (TransformHelper.make2D(clone)) {
1605                 assertTrue(listenerCalled);
1606             }
1607         }
1608 
1609         listenerCalled = false;
1610         clone.type2DProperty().removeListener(l);
1611 
1612         if (is2d) {
1613             TransformHelper.make2D(clone);
1614             assertFalse(listenerCalled);
1615         } else {
1616             TransformHelper.make3D(clone);
1617             assertFalse(listenerCalled);
1618         }
1619     }
1620 
1621     @Test
1622     public void testType2DPropertyChange() {
1623         final Transform clone = t.clone();
1624 
1625         ChangeListener<Boolean> l =
1626                 (observable, oldValue, newValue) -> {
1627 
1628                     if ((is2d && (eventCounter == 0 || eventCounter == 2))
1629                             || (!is2d && eventCounter == 1)) {
1630                         assertTrue(oldValue);
1631                         assertFalse(newValue);
1632                         assertFalse(clone.type2DProperty().get());
1633                     } else {
1634                         assertFalse(oldValue);
1635                         assertTrue(newValue);
1636                         assertTrue(clone.type2DProperty().get());
1637                     }
1638 
1639                     listenerCalled = true;
1640                     eventCounter++;
1641                 };
1642 
1643         clone.type2DProperty().addListener(l);
1644 
1645         listenerCalled = false;
1646         eventCounter = 0;
1647         TransformHelper.modify(clone, 42);
1648         assertFalse(listenerCalled);
1649 
1650         if (is2d) {
1651             if (TransformHelper.make3D(clone)) {
1652                 assertTrue(listenerCalled);
1653                 listenerCalled = false;
1654                 TransformHelper.make3D(clone);
1655                 assertFalse(listenerCalled);
1656                 TransformHelper.make2D(clone);
1657                 assertTrue(listenerCalled);
1658                 listenerCalled = false;
1659                 clone.type2DProperty().removeListener(l);
1660                 TransformHelper.make3D(clone);
1661                 assertFalse(listenerCalled);
1662             }
1663         } else {
1664             if (TransformHelper.make2D(clone)) {
1665                 assertTrue(listenerCalled);
1666                 listenerCalled = false;
1667                 TransformHelper.make2D(clone);
1668                 assertFalse(listenerCalled);
1669                 TransformHelper.make3D(clone);
1670                 assertTrue(listenerCalled);
1671                 listenerCalled = false;
1672                 clone.type2DProperty().removeListener(l);
1673                 TransformHelper.make2D(clone);
1674                 assertFalse(listenerCalled);
1675             }
1676         }
1677     }
1678 
1679     @Test
1680     public void testIsIdentity() {
1681         Transform clone = t.clone();
1682 
1683         if (isIdentity) {
1684             assertTrue(t.isIdentity());
1685             if (TransformHelper.modify(clone, 42)) {
1686                 assertFalse(clone.isIdentity());
1687             }
1688         } else {
1689             assertFalse(t.isIdentity());
1690             if (TransformHelper.makeIdentity(clone)) {
1691                 assertTrue(clone.isIdentity());
1692             }
1693         }
1694     }
1695 
1696     @Test
1697     public void testIdentityProperty() {
1698         Transform clone = t.clone();
1699 
1700         assertEquals("identity", clone.identityProperty().getName());
1701         assertSame(clone, clone.identityProperty().getBean());
1702     }
1703 
1704     @Test
1705     public void testIdentityPropertyGetter() {
1706         Transform clone = t.clone();
1707 
1708         if (isIdentity) {
1709             assertTrue(clone.identityProperty().get());
1710             assertTrue(clone.isIdentity());
1711             if (TransformHelper.modify(clone, 42)) {
1712                 assertFalse(clone.identityProperty().get());
1713                 assertFalse(clone.isIdentity());
1714             }
1715         } else {
1716             assertFalse(clone.identityProperty().get());
1717             assertFalse(clone.isIdentity());
1718             if (TransformHelper.makeIdentity(clone)) {
1719                 assertTrue(clone.identityProperty().get());
1720                 assertTrue(clone.isIdentity());
1721             }
1722         }
1723     }
1724 
1725     @Test
1726     public void testIdentityPropertyInvalidation() {
1727         final Transform clone = t.clone();
1728 
1729         InvalidationListener l =
1730                 valueModel -> {
1731                      if (isIdentity) {
1732                          if (!clone.identityProperty().get()) {
1733                             listenerCalled = true;
1734                          }
1735                      } else {
1736                          if (clone.identityProperty().get()) {
1737                             listenerCalled = true;
1738                          }
1739                      }
1740                 };
1741 
1742         clone.identityProperty().addListener(l);
1743 
1744         listenerCalled = false;
1745 
1746         if (isIdentity) {
1747             if (TransformHelper.modify(clone, 42)) {
1748                 assertTrue(listenerCalled);
1749             }
1750         } else {
1751             if (TransformHelper.makeIdentity(clone)) {
1752                 assertTrue(listenerCalled);
1753             }
1754         }
1755 
1756         listenerCalled = false;
1757         clone.identityProperty().removeListener(l);
1758 
1759         if (isIdentity) {
1760             TransformHelper.makeIdentity(clone);
1761             TransformHelper.modify(clone, 42);
1762             assertFalse(listenerCalled);
1763         } else {
1764             TransformHelper.modify(clone, 42);
1765             TransformHelper.makeIdentity(clone);
1766             assertFalse(listenerCalled);
1767         }
1768     }
1769 
1770     @Test
1771     public void testIdentityPropertyChange() {
1772         final Transform clone = t.clone();
1773 
1774         ChangeListener<Boolean> l =
1775                 (observable, oldValue, newValue) -> {
1776                     if (isIdentity) {
1777                         if (oldValue == true && newValue == false
1778                                 && clone.identityProperty().get() == false) {
1779                             listenerCalled = true;
1780                         }
1781                     } else {
1782                         if (oldValue == false && newValue == true
1783                                 && clone.identityProperty().get() == true) {
1784                             listenerCalled = true;
1785                         }
1786                     }
1787 
1788                 };
1789 
1790         clone.identityProperty().addListener(l);
1791 
1792         listenerCalled = false;
1793 
1794         if (isIdentity) {
1795             if (TransformHelper.modify(clone, 42)) {
1796                 assertTrue(listenerCalled);
1797                 listenerCalled = false;
1798                 TransformHelper.modify(clone, 43);
1799                 assertFalse(listenerCalled);
1800 
1801                 clone.identityProperty().removeListener(l);
1802                 TransformHelper.makeIdentity(clone);
1803                 TransformHelper.modify(clone, 42);
1804                 assertFalse(listenerCalled);
1805             }
1806         } else {
1807             TransformHelper.modify(clone, 42);
1808             assertFalse(listenerCalled);
1809             if (TransformHelper.makeIdentity(clone)) {
1810                 assertTrue(listenerCalled);
1811                 listenerCalled = false;
1812                 TransformHelper.makeIdentity(clone);
1813                 assertFalse(listenerCalled);
1814 
1815                 clone.identityProperty().removeListener(l);
1816                 TransformHelper.modify(clone, 42);
1817                 TransformHelper.makeIdentity(clone);
1818                 assertFalse(listenerCalled);
1819             }
1820         }
1821     }
1822 
1823     @Test
1824     public void testSimilarTo() {
1825         Transform clone = t.clone();
1826 
1827         assertTrue(t.similarTo(clone, new BoundingBox(-10000, -10000, 10000, 10000), 1e-10));
1828 
1829         if (TransformHelper.tinyModify(clone)) {
1830             assertTrue(t.similarTo(clone, new BoundingBox(0, 0, 1, 1), 5));
1831             if (is2d) {
1832                 assertTrue(t.similarTo(clone, new BoundingBox(0, 0, 0, 0.1, 0.1, 10000), 2));
1833             } else {
1834                 assertFalse(t.similarTo(clone, new BoundingBox(0, 0, 0, 0.1, 0.1, 10000), 2));
1835             }
1836             assertFalse(t.similarTo(clone, new BoundingBox(0, 0, 1000, 1000), 0.5));
1837 
1838             if (t instanceof Translate) {
1839                 assertTrue(t.similarTo(clone, new BoundingBox(0, 0, 1, 1), 4));
1840                 assertFalse(t.similarTo(clone, new BoundingBox(0, 0, 1, 1), 0.5));
1841             }
1842 
1843             if (t instanceof Scale) {
1844                 assertTrue(t.similarTo(clone, new BoundingBox(0, 0, 1, 1), 5));
1845                 assertFalse(t.similarTo(clone, new BoundingBox(0, 0, 1000, 1000), 5));
1846             }
1847 
1848         }
1849     }
1850 
1851     @Test(expected=NullPointerException.class)
1852     public void testSimilarToNullTransform() {
1853         t.similarTo(null, new BoundingBox(0, 0, 0, 1, 1, 1), 0);
1854     }
1855 
1856     @Test(expected=NullPointerException.class)
1857     public void testSimilarToNullRange() {
1858         t.similarTo(t, null, 0);
1859     }
1860 
1861     private void assertGetElement(MatrixType type, int row, int col,
1862             double expected, boolean iae, boolean iob) {
1863         double res = Double.MIN_VALUE;
1864 
1865         try {
1866             res = t.getElement(type, row, col);
1867         } catch (IllegalArgumentException e) {
1868             if (iae) {
1869                 // ok
1870                 return;
1871             }
1872         } catch (IndexOutOfBoundsException e) {
1873             if (iob) {
1874                 // ok
1875                 return;
1876             }
1877         }
1878 
1879         if (iae) {
1880             fail("Should have thrown IAE");
1881         }
1882         if (iob) {
1883             fail("Should have thrown IOB");
1884         }
1885 
1886         assertEquals(expected, res, 1e-100);
1887     }
1888 
1889     @Test
1890     public void testGetElement() {
1891         assertGetElement(MatrixType.MT_2D_2x3, 0, 0, t.getMxx(), !is2d, false);
1892         assertGetElement(MatrixType.MT_2D_2x3, 0, 1, t.getMxy(), !is2d, false);
1893         assertGetElement(MatrixType.MT_2D_2x3, 0, 2, t.getTx(), !is2d, false);
1894         assertGetElement(MatrixType.MT_2D_2x3, 1, 0, t.getMyx(), !is2d, false);
1895         assertGetElement(MatrixType.MT_2D_2x3, 1, 1, t.getMyy(), !is2d, false);
1896         assertGetElement(MatrixType.MT_2D_2x3, 1, 2, t.getTy(), !is2d, false);
1897         assertGetElement(MatrixType.MT_2D_2x3, -1, 0, 0, !is2d, true);
1898         assertGetElement(MatrixType.MT_2D_2x3, 2, 1, 0, !is2d, true);
1899         assertGetElement(MatrixType.MT_2D_2x3, 1, 3, 0, !is2d, true);
1900         assertGetElement(MatrixType.MT_2D_2x3, 1, -1, 0, !is2d, true);
1901         assertGetElement(MatrixType.MT_2D_3x3, 0, 0, t.getMxx(), !is2d, false);
1902         assertGetElement(MatrixType.MT_2D_3x3, 0, 1, t.getMxy(), !is2d, false);
1903         assertGetElement(MatrixType.MT_2D_3x3, 0, 2, t.getTx(), !is2d, false);
1904         assertGetElement(MatrixType.MT_2D_3x3, 1, 0, t.getMyx(), !is2d, false);
1905         assertGetElement(MatrixType.MT_2D_3x3, 1, 1, t.getMyy(), !is2d, false);
1906         assertGetElement(MatrixType.MT_2D_3x3, 1, 2, t.getTy(), !is2d, false);
1907         assertGetElement(MatrixType.MT_2D_3x3, 2, 0, 0, !is2d, false);
1908         assertGetElement(MatrixType.MT_2D_3x3, 2, 1, 0, !is2d, false);
1909         assertGetElement(MatrixType.MT_2D_3x3, 2, 2, 1, !is2d, false);
1910         assertGetElement(MatrixType.MT_2D_3x3, -1, 0, 0, !is2d, true);
1911         assertGetElement(MatrixType.MT_2D_3x3, 3, 1, 0, !is2d, true);
1912         assertGetElement(MatrixType.MT_2D_3x3, 1, 3, 0, !is2d, true);
1913         assertGetElement(MatrixType.MT_2D_3x3, 1, -1, 0, !is2d, true);
1914         assertGetElement(MatrixType.MT_3D_3x4, 0, 0, t.getMxx(), false, false);
1915         assertGetElement(MatrixType.MT_3D_3x4, 0, 1, t.getMxy(), false, false);
1916         assertGetElement(MatrixType.MT_3D_3x4, 0, 2, t.getMxz(), false, false);
1917         assertGetElement(MatrixType.MT_3D_3x4, 0, 3, t.getTx(), false, false);
1918         assertGetElement(MatrixType.MT_3D_3x4, 1, 0, t.getMyx(), false, false);
1919         assertGetElement(MatrixType.MT_3D_3x4, 1, 1, t.getMyy(), false, false);
1920         assertGetElement(MatrixType.MT_3D_3x4, 1, 2, t.getMyz(), false, false);
1921         assertGetElement(MatrixType.MT_3D_3x4, 1, 3, t.getTy(), false, false);
1922         assertGetElement(MatrixType.MT_3D_3x4, 2, 0, t.getMzx(), false, false);
1923         assertGetElement(MatrixType.MT_3D_3x4, 2, 1, t.getMzy(), false, false);
1924         assertGetElement(MatrixType.MT_3D_3x4, 2, 2, t.getMzz(), false, false);
1925         assertGetElement(MatrixType.MT_3D_3x4, 2, 3, t.getTz(), false, false);
1926         assertGetElement(MatrixType.MT_3D_3x4, -1, 0, 0, false, true);
1927         assertGetElement(MatrixType.MT_3D_3x4, 3, 1, 0, false, true);
1928         assertGetElement(MatrixType.MT_3D_3x4, 1, 4, 0, false, true);
1929         assertGetElement(MatrixType.MT_3D_3x4, 1, -1, 0, false, true);
1930         assertGetElement(MatrixType.MT_3D_4x4, 0, 0, t.getMxx(), false, false);
1931         assertGetElement(MatrixType.MT_3D_4x4, 0, 1, t.getMxy(), false, false);
1932         assertGetElement(MatrixType.MT_3D_4x4, 0, 2, t.getMxz(), false, false);
1933         assertGetElement(MatrixType.MT_3D_4x4, 0, 3, t.getTx(), false, false);
1934         assertGetElement(MatrixType.MT_3D_4x4, 1, 0, t.getMyx(), false, false);
1935         assertGetElement(MatrixType.MT_3D_4x4, 1, 1, t.getMyy(), false, false);
1936         assertGetElement(MatrixType.MT_3D_4x4, 1, 2, t.getMyz(), false, false);
1937         assertGetElement(MatrixType.MT_3D_4x4, 1, 3, t.getTy(), false, false);
1938         assertGetElement(MatrixType.MT_3D_4x4, 2, 0, t.getMzx(), false, false);
1939         assertGetElement(MatrixType.MT_3D_4x4, 2, 1, t.getMzy(), false, false);
1940         assertGetElement(MatrixType.MT_3D_4x4, 2, 2, t.getMzz(), false, false);
1941         assertGetElement(MatrixType.MT_3D_4x4, 2, 3, t.getTz(), false, false);
1942         assertGetElement(MatrixType.MT_3D_4x4, 3, 0, 0, false, false);
1943         assertGetElement(MatrixType.MT_3D_4x4, 3, 1, 0, false, false);
1944         assertGetElement(MatrixType.MT_3D_4x4, 3, 2, 0, false, false);
1945         assertGetElement(MatrixType.MT_3D_4x4, 3, 3, 1, false, false);
1946         assertGetElement(MatrixType.MT_3D_4x4, -1, 0, 0, false, true);
1947         assertGetElement(MatrixType.MT_3D_4x4, 4, 1, 0, false, true);
1948         assertGetElement(MatrixType.MT_3D_4x4, 1, 4, 0, false, true);
1949         assertGetElement(MatrixType.MT_3D_4x4, 1, -1, 0, false, true);
1950     }
1951 
1952     @Test(expected=NullPointerException.class)
1953     public void testGetElementNullType() {
1954         t.getElement(null, 0, 0);
1955     }
1956 
1957     private void assertArray(MatrixType type, double[] a, Transform t) {
1958         switch (type) {
1959             case MT_2D_3x3:
1960                 assertEquals(0, a[6], 1e-100);
1961                 assertEquals(0, a[7], 1e-100);
1962                 assertEquals(1, a[8], 1e-100);
1963                 // fallthrough
1964             case MT_2D_2x3:
1965                 assertEquals(t.getMxx(), a[0], 1e-100);
1966                 assertEquals(t.getMxy(), a[1], 1e-100);
1967                 assertEquals(t.getTx(),  a[2], 1e-100);
1968                 assertEquals(t.getMyx(), a[3], 1e-100);
1969                 assertEquals(t.getMyy(), a[4], 1e-100);
1970                 assertEquals(t.getTy(),  a[5], 1e-100);
1971                 break;
1972             case MT_3D_4x4:
1973                 assertEquals(0, a[12], 1e-100);
1974                 assertEquals(0, a[13], 1e-100);
1975                 assertEquals(0, a[14], 1e-100);
1976                 assertEquals(1, a[15], 1e-100);
1977                 // fallthrough
1978             case MT_3D_3x4:
1979                 assertEquals(t.getMxx(), a[0], 1e-100);
1980                 assertEquals(t.getMxy(), a[1], 1e-100);
1981                 assertEquals(t.getMxz(), a[2], 1e-100);
1982                 assertEquals(t.getTx(),  a[3], 1e-100);
1983                 assertEquals(t.getMyx(), a[4], 1e-100);
1984                 assertEquals(t.getMyy(), a[5], 1e-100);
1985                 assertEquals(t.getMyz(), a[6], 1e-100);
1986                 assertEquals(t.getTy(),  a[7], 1e-100);
1987                 assertEquals(t.getMzx(), a[8], 1e-100);
1988                 assertEquals(t.getMzy(), a[9], 1e-100);
1989                 assertEquals(t.getMzz(), a[10], 1e-100);
1990                 assertEquals(t.getTz(),  a[11], 1e-100);
1991                 break;
1992         }
1993     }
1994 
1995     private void assertToArray2D(MatrixType type, double[] tmp,
1996             boolean shouldPass, boolean shouldUse) {
1997         double[] a = null;
1998         try {
1999             if (shouldPass) {
2000                 a = t.toArray(type, tmp);
2001             } else {
2002                 a = t.toArray(type);
2003             }
2004         } catch (IllegalArgumentException e) {
2005             if (is2d) {
2006                 fail("Wrong exception thrown");
2007             }
2008             return;
2009         }
2010 
2011         if (!is2d) {
2012             fail("Should have thrown IAE");
2013         } else {
2014             assertNotNull(a);
2015             if (shouldUse) {
2016                 assertSame(tmp, a);
2017             }
2018             assertArray(type, a, t);
2019         }
2020     }
2021 
2022     private void assertToArray3D(MatrixType type, double[] tmp,
2023             boolean shouldPass, boolean shouldUse) {
2024         double[] a = null;
2025 
2026         if (shouldPass) {
2027             a = t.toArray(type, tmp);
2028         } else {
2029             a = t.toArray(type);
2030         }
2031 
2032         assertNotNull(a);
2033         if (shouldUse) {
2034             assertSame(tmp, a);
2035         }
2036         assertArray(type, a, t);
2037     }
2038 
2039     @Test
2040     public void testToArray() {
2041 
2042         assertToArray2D(MatrixType.MT_2D_2x3, null, false, false);
2043         assertToArray2D(MatrixType.MT_2D_2x3, null, true, false);
2044         assertToArray2D(MatrixType.MT_2D_2x3, new double[4], true, false);
2045         assertToArray2D(MatrixType.MT_2D_2x3, new double[6], true, true);
2046 
2047         assertToArray2D(MatrixType.MT_2D_3x3, null, false, false);
2048         assertToArray2D(MatrixType.MT_2D_3x3, null, true, false);
2049         assertToArray2D(MatrixType.MT_2D_3x3, new double[8], true, false);
2050         assertToArray2D(MatrixType.MT_2D_3x3, new double[9], true, true);
2051 
2052         assertToArray3D(MatrixType.MT_3D_3x4, null, false, false);
2053         assertToArray3D(MatrixType.MT_3D_3x4, null, true, false);
2054         assertToArray3D(MatrixType.MT_3D_3x4, new double[11], true, false);
2055         assertToArray3D(MatrixType.MT_3D_3x4, new double[12], true, true);
2056 
2057         assertToArray3D(MatrixType.MT_3D_4x4, null, false, false);
2058         assertToArray3D(MatrixType.MT_3D_4x4, null, true, false);
2059         assertToArray3D(MatrixType.MT_3D_4x4, new double[15], true, false);
2060         assertToArray3D(MatrixType.MT_3D_4x4, new double[16], true, true);
2061     }
2062 
2063     @Test(expected=NullPointerException.class)
2064     public void testToArrayNullType1() {
2065         t.toArray(null);
2066     }
2067 
2068     @Test(expected=NullPointerException.class)
2069     public void testToArrayNullType2() {
2070         t.toArray(null, new double[] {});
2071     }
2072 
2073     private void assertRow(MatrixType type, int row, double[] a, Transform t) {
2074         switch (type) {
2075             case MT_2D_3x3:
2076                 if (row == 2) {
2077                     assertEquals(0, a[0], 1e-100);
2078                     assertEquals(0, a[1], 1e-100);
2079                     assertEquals(1, a[2], 1e-100);
2080                     return;
2081                 }
2082                 // fallthrough
2083             case MT_2D_2x3:
2084                 if (row == 0) {
2085                     assertEquals(t.getMxx(), a[0], 1e-100);
2086                     assertEquals(t.getMxy(), a[1], 1e-100);
2087                     assertEquals(t.getTx(),  a[2], 1e-100);
2088                     return;
2089                 } else if (row == 1) {
2090                     assertEquals(t.getMyx(), a[0], 1e-100);
2091                     assertEquals(t.getMyy(), a[1], 1e-100);
2092                     assertEquals(t.getTy(),  a[2], 1e-100);
2093                     return;
2094                 }
2095                 break;
2096             case MT_3D_4x4:
2097                 if (row == 3) {
2098                     assertEquals(0, a[0], 1e-100);
2099                     assertEquals(0, a[1], 1e-100);
2100                     assertEquals(0, a[2], 1e-100);
2101                     assertEquals(1, a[3], 1e-100);
2102                     return;
2103                 }
2104                 // fallthrough
2105             case MT_3D_3x4:
2106                 if (row == 0) {
2107                     assertEquals(t.getMxx(), a[0], 1e-100);
2108                     assertEquals(t.getMxy(), a[1], 1e-100);
2109                     assertEquals(t.getMxz(), a[2], 1e-100);
2110                     assertEquals(t.getTx(),  a[3], 1e-100);
2111                     return;
2112                 } else if (row == 1) {
2113                     assertEquals(t.getMyx(), a[0], 1e-100);
2114                     assertEquals(t.getMyy(), a[1], 1e-100);
2115                     assertEquals(t.getMyz(), a[2], 1e-100);
2116                     assertEquals(t.getTy(),  a[3], 1e-100);
2117                     return;
2118                 } else if (row == 2) {
2119                     assertEquals(t.getMzx(), a[0], 1e-100);
2120                     assertEquals(t.getMzy(), a[1], 1e-100);
2121                     assertEquals(t.getMzz(), a[2], 1e-100);
2122                     assertEquals(t.getTz(),  a[3], 1e-100);
2123                     return;
2124                 }
2125                 break;
2126         }
2127 
2128         fail("Should have thrown IOB");
2129     }
2130 
2131     private void assertRow2D(MatrixType type, int row, double[] tmp,
2132             boolean shouldPass, boolean shouldUse, boolean iob) {
2133         double[] a = null;
2134         try {
2135             if (shouldPass) {
2136                 a = t.row(type, row, tmp);
2137             } else {
2138                 a = t.row(type, row);
2139             }
2140         } catch (IllegalArgumentException e) {
2141             if (is2d) {
2142                 fail("Wrong exception thrown");
2143             }
2144             return;
2145         } catch (IndexOutOfBoundsException e) {
2146             if (!iob) {
2147                 fail("Wrong exception thrown");
2148             }
2149             return;
2150         }
2151         if (!is2d) {
2152             fail("Should have thrown IAE");
2153         } else if (iob) {
2154             fail("Should have thrown IOB");
2155         } else {
2156             assertNotNull(a);
2157             if (shouldUse) {
2158                 assertSame(tmp, a);
2159             }
2160             assertRow(type, row, a, t);
2161         }
2162     }
2163 
2164     private void assertRow3D(MatrixType type, int row, double[] tmp,
2165             boolean shouldPass, boolean shouldUse, boolean iob) {
2166         double[] a = null;
2167         try {
2168             if (shouldPass) {
2169                 a = t.row(type, row, tmp);
2170             } else {
2171                 a = t.row(type, row);
2172             }
2173         } catch (IndexOutOfBoundsException e) {
2174             if (!iob) {
2175                 fail("Wrong exception thrown");
2176             }
2177             return;
2178         }
2179         if (iob) {
2180             fail("Should have thrown IOB");
2181         } else {
2182             assertNotNull(a);
2183             if (shouldUse) {
2184                 assertSame(tmp, a);
2185             }
2186             assertRow(type, row, a, t);
2187         }
2188     }
2189 
2190     @Test
2191     public void testRow() {
2192         assertRow2D(MatrixType.MT_2D_2x3, 0, null, false, false, false);
2193         assertRow2D(MatrixType.MT_2D_2x3, 0, null, true, false, false);
2194         assertRow2D(MatrixType.MT_2D_2x3, 0, new double[2], true, false, false);
2195         assertRow2D(MatrixType.MT_2D_2x3, 0, new double[3], true, true, false);
2196         assertRow2D(MatrixType.MT_2D_2x3, 1, null, false, false, false);
2197         assertRow2D(MatrixType.MT_2D_2x3, 1, null, true, false, false);
2198         assertRow2D(MatrixType.MT_2D_2x3, 1, new double[2], true, false, false);
2199         assertRow2D(MatrixType.MT_2D_2x3, 1, new double[3], true, true, false);
2200         assertRow2D(MatrixType.MT_2D_2x3, -1, null, true, false, true);
2201         assertRow2D(MatrixType.MT_2D_2x3, 2, null, false, false, true);
2202 
2203         assertRow2D(MatrixType.MT_2D_3x3, 0, null, false, false, false);
2204         assertRow2D(MatrixType.MT_2D_3x3, 0, null, true, false, false);
2205         assertRow2D(MatrixType.MT_2D_3x3, 0, new double[2], true, false, false);
2206         assertRow2D(MatrixType.MT_2D_3x3, 0, new double[3], true, true, false);
2207         assertRow2D(MatrixType.MT_2D_3x3, 1, null, false, false, false);
2208         assertRow2D(MatrixType.MT_2D_3x3, 1, null, true, false, false);
2209         assertRow2D(MatrixType.MT_2D_3x3, 1, new double[2], true, false, false);
2210         assertRow2D(MatrixType.MT_2D_3x3, 1, new double[3], true, true, false);
2211         assertRow2D(MatrixType.MT_2D_3x3, 2, null, false, false, false);
2212         assertRow2D(MatrixType.MT_2D_3x3, 2, null, true, false, false);
2213         assertRow2D(MatrixType.MT_2D_3x3, 2, new double[2], true, false, false);
2214         assertRow2D(MatrixType.MT_2D_3x3, 2, new double[3], true, true, false);
2215         assertRow2D(MatrixType.MT_2D_3x3, -1, null, true, false, true);
2216         assertRow2D(MatrixType.MT_2D_3x3, 3, null, false, false, true);
2217 
2218         assertRow3D(MatrixType.MT_3D_3x4, 0, null, false, false, false);
2219         assertRow3D(MatrixType.MT_3D_3x4, 0, null, true, false, false);
2220         assertRow3D(MatrixType.MT_3D_3x4, 0, new double[3], true, false, false);
2221         assertRow3D(MatrixType.MT_3D_3x4, 0, new double[4], true, true, false);
2222         assertRow3D(MatrixType.MT_3D_3x4, 1, null, false, false, false);
2223         assertRow3D(MatrixType.MT_3D_3x4, 1, null, true, false, false);
2224         assertRow3D(MatrixType.MT_3D_3x4, 1, new double[3], true, false, false);
2225         assertRow3D(MatrixType.MT_3D_3x4, 1, new double[4], true, true, false);
2226         assertRow3D(MatrixType.MT_3D_3x4, 2, null, false, false, false);
2227         assertRow3D(MatrixType.MT_3D_3x4, 2, null, true, false, false);
2228         assertRow3D(MatrixType.MT_3D_3x4, 2, new double[3], true, false, false);
2229         assertRow3D(MatrixType.MT_3D_3x4, 2, new double[4], true, true, false);
2230         assertRow3D(MatrixType.MT_3D_3x4, -1, null, true, false, true);
2231         assertRow3D(MatrixType.MT_3D_3x4, 3, null, false, false, true);
2232 
2233         assertRow3D(MatrixType.MT_3D_4x4, 0, null, false, false, false);
2234         assertRow3D(MatrixType.MT_3D_4x4, 0, null, true, false, false);
2235         assertRow3D(MatrixType.MT_3D_4x4, 0, new double[3], true, false, false);
2236         assertRow3D(MatrixType.MT_3D_4x4, 0, new double[4], true, true, false);
2237         assertRow3D(MatrixType.MT_3D_4x4, 1, null, false, false, false);
2238         assertRow3D(MatrixType.MT_3D_4x4, 1, null, true, false, false);
2239         assertRow3D(MatrixType.MT_3D_4x4, 1, new double[3], true, false, false);
2240         assertRow3D(MatrixType.MT_3D_4x4, 1, new double[4], true, true, false);
2241         assertRow3D(MatrixType.MT_3D_4x4, 2, null, false, false, false);
2242         assertRow3D(MatrixType.MT_3D_4x4, 2, null, true, false, false);
2243         assertRow3D(MatrixType.MT_3D_4x4, 2, new double[3], true, false, false);
2244         assertRow3D(MatrixType.MT_3D_4x4, 2, new double[4], true, true, false);
2245         assertRow3D(MatrixType.MT_3D_4x4, 3, null, false, false, false);
2246         assertRow3D(MatrixType.MT_3D_4x4, 3, null, true, false, false);
2247         assertRow3D(MatrixType.MT_3D_4x4, 3, new double[3], true, false, false);
2248         assertRow3D(MatrixType.MT_3D_4x4, 3, new double[4], true, true, false);
2249         assertRow3D(MatrixType.MT_3D_4x4, -1, null, true, false, true);
2250         assertRow3D(MatrixType.MT_3D_4x4, 4, null, false, false, true);
2251     }
2252 
2253     @Test(expected=NullPointerException.class)
2254     public void testRowNullType1() {
2255         t.row(null, 0);
2256     }
2257 
2258     @Test(expected=NullPointerException.class)
2259     public void testRowNullType2() {
2260         t.row(null, 0, new double[] {});
2261     }
2262 
2263     private void assertCol(MatrixType type, int col, double[] a, Transform t) {
2264         switch (type) {
2265             case MT_2D_2x3:
2266                 if (col == 0) {
2267                     assertEquals(t.getMxx(), a[0], 1e-100);
2268                     assertEquals(t.getMyx(), a[1], 1e-100);
2269                     return;
2270                 } else if (col == 1) {
2271                     assertEquals(t.getMxy(), a[0], 1e-100);
2272                     assertEquals(t.getMyy(), a[1], 1e-100);
2273                     return;
2274                 } else if (col == 2) {
2275                     assertEquals(t.getTx(), a[0], 1e-100);
2276                     assertEquals(t.getTy(), a[1], 1e-100);
2277                     return;
2278                 }
2279                 break;
2280             case MT_2D_3x3:
2281                 if (col == 0) {
2282                     assertEquals(t.getMxx(), a[0], 1e-100);
2283                     assertEquals(t.getMyx(), a[1], 1e-100);
2284                     assertEquals(0, a[2], 1e-100);
2285                     return;
2286                 } else if (col == 1) {
2287                     assertEquals(t.getMxy(), a[0], 1e-100);
2288                     assertEquals(t.getMyy(), a[1], 1e-100);
2289                     assertEquals(0, a[2], 1e-100);
2290                     return;
2291                 } else if (col == 2) {
2292                     assertEquals(t.getTx(), a[0], 1e-100);
2293                     assertEquals(t.getTy(), a[1], 1e-100);
2294                     assertEquals(1, a[2], 1e-100);
2295                     return;
2296                 }
2297                 break;
2298             case MT_3D_3x4:
2299                 if (col == 0) {
2300                     assertEquals(t.getMxx(), a[0], 1e-100);
2301                     assertEquals(t.getMyx(), a[1], 1e-100);
2302                     assertEquals(t.getMzx(), a[2], 1e-100);
2303                     return;
2304                 } else if (col == 1) {
2305                     assertEquals(t.getMxy(), a[0], 1e-100);
2306                     assertEquals(t.getMyy(), a[1], 1e-100);
2307                     assertEquals(t.getMzy(), a[2], 1e-100);
2308                     return;
2309                 } else if (col == 2) {
2310                     assertEquals(t.getMxz(), a[0], 1e-100);
2311                     assertEquals(t.getMyz(), a[1], 1e-100);
2312                     assertEquals(t.getMzz(), a[2], 1e-100);
2313                     return;
2314                 } else if (col == 3) {
2315                     assertEquals(t.getTx(), a[0], 1e-100);
2316                     assertEquals(t.getTy(), a[1], 1e-100);
2317                     assertEquals(t.getTz(), a[2], 1e-100);
2318                     return;
2319                 }
2320                 break;
2321             case MT_3D_4x4:
2322                 if (col == 0) {
2323                     assertEquals(t.getMxx(), a[0], 1e-100);
2324                     assertEquals(t.getMyx(), a[1], 1e-100);
2325                     assertEquals(t.getMzx(), a[2], 1e-100);
2326                     assertEquals(0, a[3], 1e-100);
2327                     return;
2328                 } else if (col == 1) {
2329                     assertEquals(t.getMxy(), a[0], 1e-100);
2330                     assertEquals(t.getMyy(), a[1], 1e-100);
2331                     assertEquals(t.getMzy(), a[2], 1e-100);
2332                     assertEquals(0, a[3], 1e-100);
2333                     return;
2334                 } else if (col == 2) {
2335                     assertEquals(t.getMxz(), a[0], 1e-100);
2336                     assertEquals(t.getMyz(), a[1], 1e-100);
2337                     assertEquals(t.getMzz(), a[2], 1e-100);
2338                     assertEquals(0, a[3], 1e-100);
2339                     return;
2340                 } else if (col == 3) {
2341                     assertEquals(t.getTx(), a[0], 1e-100);
2342                     assertEquals(t.getTy(), a[1], 1e-100);
2343                     assertEquals(t.getTz(), a[2], 1e-100);
2344                     assertEquals(1, a[3], 1e-100);
2345                     return;
2346                 }
2347                 break;
2348         }
2349 
2350         fail("Should have thrown IOB");
2351     }
2352 
2353     private void assertCol2D(MatrixType type, int col, double[] tmp,
2354             boolean shouldPass, boolean shouldUse, boolean iob) {
2355         double[] a = null;
2356         try {
2357             if (shouldPass) {
2358                 a = t.column(type, col, tmp);
2359             } else {
2360                 a = t.column(type, col);
2361             }
2362         } catch (IllegalArgumentException e) {
2363             if (is2d) {
2364                 fail("Wrong exception thrown");
2365             }
2366             return;
2367         } catch (IndexOutOfBoundsException e) {
2368             if (!iob) {
2369                 fail("Wrong exception thrown");
2370             }
2371             return;
2372         }
2373         if (!is2d) {
2374             fail("Should have thrown IAE");
2375         } else if (iob) {
2376             fail("Should have thrown IOB");
2377         } else {
2378             assertNotNull(a);
2379             if (shouldUse) {
2380                 assertSame(tmp, a);
2381             }
2382             assertCol(type, col, a, t);
2383         }
2384     }
2385 
2386     private void assertCol3D(MatrixType type, int col, double[] tmp,
2387             boolean shouldPass, boolean shouldUse, boolean iob) {
2388         double[] a = null;
2389         try {
2390             if (shouldPass) {
2391                 a = t.column(type, col, tmp);
2392             } else {
2393                 a = t.column(type, col);
2394             }
2395         } catch (IndexOutOfBoundsException e) {
2396             if (!iob) {
2397                 fail("Wrong exception thrown");
2398             }
2399             return;
2400         }
2401         if (iob) {
2402             fail("Should have thrown IOB");
2403         } else {
2404             assertNotNull(a);
2405             if (shouldUse) {
2406                 assertSame(tmp, a);
2407             }
2408             assertCol(type, col, a, t);
2409         }
2410     }
2411 
2412     @Test
2413     public void testColumn() {
2414         assertCol2D(MatrixType.MT_2D_2x3, 0, null, false, false, false);
2415         assertCol2D(MatrixType.MT_2D_2x3, 0, null, true, false, false);
2416         assertCol2D(MatrixType.MT_2D_2x3, 0, new double[1], true, false, false);
2417         assertCol2D(MatrixType.MT_2D_2x3, 0, new double[2], true, true, false);
2418         assertCol2D(MatrixType.MT_2D_2x3, 1, null, false, false, false);
2419         assertCol2D(MatrixType.MT_2D_2x3, 1, null, true, false, false);
2420         assertCol2D(MatrixType.MT_2D_2x3, 1, new double[1], true, false, false);
2421         assertCol2D(MatrixType.MT_2D_2x3, 1, new double[2], true, true, false);
2422         assertCol2D(MatrixType.MT_2D_2x3, 2, null, false, false, false);
2423         assertCol2D(MatrixType.MT_2D_2x3, 2, null, true, false, false);
2424         assertCol2D(MatrixType.MT_2D_2x3, 2, new double[1], true, false, false);
2425         assertCol2D(MatrixType.MT_2D_2x3, 2, new double[2], true, true, false);
2426         assertCol2D(MatrixType.MT_2D_2x3, -1, null, true, false, true);
2427         assertCol2D(MatrixType.MT_2D_2x3, 3, null, false, false, true);
2428 
2429         assertCol2D(MatrixType.MT_2D_3x3, 0, null, false, false, false);
2430         assertCol2D(MatrixType.MT_2D_3x3, 0, null, true, false, false);
2431         assertCol2D(MatrixType.MT_2D_3x3, 0, new double[2], true, false, false);
2432         assertCol2D(MatrixType.MT_2D_3x3, 0, new double[3], true, true, false);
2433         assertCol2D(MatrixType.MT_2D_3x3, 1, null, false, false, false);
2434         assertCol2D(MatrixType.MT_2D_3x3, 1, null, true, false, false);
2435         assertCol2D(MatrixType.MT_2D_3x3, 1, new double[2], true, false, false);
2436         assertCol2D(MatrixType.MT_2D_3x3, 1, new double[3], true, true, false);
2437         assertCol2D(MatrixType.MT_2D_3x3, 2, null, false, false, false);
2438         assertCol2D(MatrixType.MT_2D_3x3, 2, null, true, false, false);
2439         assertCol2D(MatrixType.MT_2D_3x3, 2, new double[2], true, false, false);
2440         assertCol2D(MatrixType.MT_2D_3x3, 2, new double[3], true, true, false);
2441         assertCol2D(MatrixType.MT_2D_3x3, -1, null, true, false, true);
2442         assertCol2D(MatrixType.MT_2D_3x3, 3, null, false, false, true);
2443 
2444         assertCol3D(MatrixType.MT_3D_3x4, 0, null, false, false, false);
2445         assertCol3D(MatrixType.MT_3D_3x4, 0, null, true, false, false);
2446         assertCol3D(MatrixType.MT_3D_3x4, 0, new double[2], true, false, false);
2447         assertCol3D(MatrixType.MT_3D_3x4, 0, new double[3], true, true, false);
2448         assertCol3D(MatrixType.MT_3D_3x4, 1, null, false, false, false);
2449         assertCol3D(MatrixType.MT_3D_3x4, 1, null, true, false, false);
2450         assertCol3D(MatrixType.MT_3D_3x4, 1, new double[2], true, false, false);
2451         assertCol3D(MatrixType.MT_3D_3x4, 1, new double[3], true, true, false);
2452         assertCol3D(MatrixType.MT_3D_3x4, 2, null, false, false, false);
2453         assertCol3D(MatrixType.MT_3D_3x4, 2, null, true, false, false);
2454         assertCol3D(MatrixType.MT_3D_3x4, 2, new double[2], true, false, false);
2455         assertCol3D(MatrixType.MT_3D_3x4, 2, new double[3], true, true, false);
2456         assertCol3D(MatrixType.MT_3D_3x4, 3, null, false, false, false);
2457         assertCol3D(MatrixType.MT_3D_3x4, 3, null, true, false, false);
2458         assertCol3D(MatrixType.MT_3D_3x4, 3, new double[2], true, false, false);
2459         assertCol3D(MatrixType.MT_3D_3x4, 3, new double[3], true, true, false);
2460         assertCol3D(MatrixType.MT_3D_3x4, -1, null, true, false, true);
2461         assertCol3D(MatrixType.MT_3D_3x4, 4, null, false, false, true);
2462 
2463         assertCol3D(MatrixType.MT_3D_4x4, 0, null, false, false, false);
2464         assertCol3D(MatrixType.MT_3D_4x4, 0, null, true, false, false);
2465         assertCol3D(MatrixType.MT_3D_4x4, 0, new double[3], true, false, false);
2466         assertCol3D(MatrixType.MT_3D_4x4, 0, new double[4], true, true, false);
2467         assertCol3D(MatrixType.MT_3D_4x4, 1, null, false, false, false);
2468         assertCol3D(MatrixType.MT_3D_4x4, 1, null, true, false, false);
2469         assertCol3D(MatrixType.MT_3D_4x4, 1, new double[3], true, false, false);
2470         assertCol3D(MatrixType.MT_3D_4x4, 1, new double[4], true, true, false);
2471         assertCol3D(MatrixType.MT_3D_4x4, 2, null, false, false, false);
2472         assertCol3D(MatrixType.MT_3D_4x4, 2, null, true, false, false);
2473         assertCol3D(MatrixType.MT_3D_4x4, 2, new double[3], true, false, false);
2474         assertCol3D(MatrixType.MT_3D_4x4, 2, new double[4], true, true, false);
2475         assertCol3D(MatrixType.MT_3D_4x4, 3, null, false, false, false);
2476         assertCol3D(MatrixType.MT_3D_4x4, 3, null, true, false, false);
2477         assertCol3D(MatrixType.MT_3D_4x4, 3, new double[3], true, false, false);
2478         assertCol3D(MatrixType.MT_3D_4x4, 3, new double[4], true, true, false);
2479         assertCol3D(MatrixType.MT_3D_4x4, -1, null, true, false, true);
2480         assertCol3D(MatrixType.MT_3D_4x4, 4, null, false, false, true);
2481     }
2482 
2483     @Test(expected=NullPointerException.class)
2484     public void testColumnNullType1() {
2485         t.column(null, 0);
2486     }
2487 
2488     @Test(expected=NullPointerException.class)
2489     public void testColumnNullType2() {
2490         t.column(null, 0, new double[] {});
2491     }
2492 
2493     @Test
2494     public void testSetOnTransformChanged() {
2495         Transform clone = t.clone();
2496 
2497         EventHandler<TransformChangedEvent> ontc =
2498                 event -> {
2499                     eventCounter++;
2500                 };
2501 
2502         assertSame(null, clone.getOnTransformChanged());
2503         clone.setOnTransformChanged(ontc);
2504         assertSame(ontc, clone.getOnTransformChanged());
2505 
2506         eventCounter = 0;
2507         if (TransformHelper.modify(clone, 42)) {
2508             if (t == rotateZeroAxis || t == noRotate) {
2509                 // needs two changes to be further usable
2510                 eventCounter--;
2511             }
2512             assertEquals(1, eventCounter);
2513             TransformHelper.modify(clone, 42);
2514             assertEquals(1, eventCounter);
2515             TransformHelper.modify(clone, 43);
2516             assertEquals(2, eventCounter);
2517 
2518             clone.setOnTransformChanged(null);
2519             assertNull(clone.getOnTransformChanged());
2520             TransformHelper.modify(clone, 44);
2521             assertEquals(2, eventCounter);
2522 
2523         } else {
2524             assertEquals(0, eventCounter);
2525         }
2526     }
2527 
2528     @Test
2529     public void testAddRemoveEventHandler() {
2530         Transform clone = t.clone();
2531 
2532         EventHandler<TransformChangedEvent> counting =
2533                 event -> {
2534                     eventCounter++;
2535                 };
2536 
2537         EventHandler<TransformChangedEvent> checking =
2538                 event -> {
2539                     listenerCalled = true;
2540                 };
2541 
2542         clone.addEventHandler(TransformChangedEvent.TRANSFORM_CHANGED, counting);
2543         clone.addEventHandler(TransformChangedEvent.TRANSFORM_CHANGED, checking);
2544 
2545         eventCounter = 0;
2546         listenerCalled = false;
2547         if (TransformHelper.modify(clone, 42)) {
2548             if (t == rotateZeroAxis || t == noRotate) {
2549                 // needs two changes to be further usable
2550                 eventCounter--;
2551             }
2552             assertEquals(1, eventCounter);
2553             assertTrue(listenerCalled);
2554 
2555             listenerCalled = false;
2556             TransformHelper.modify(clone, 42);
2557             assertEquals(1, eventCounter);
2558             assertFalse(listenerCalled);
2559 
2560             clone.removeEventHandler(TransformChangedEvent.TRANSFORM_CHANGED, checking);
2561 
2562             TransformHelper.modify(clone, 43);
2563             assertEquals(2, eventCounter);
2564             assertFalse(listenerCalled);
2565         } else {
2566             assertEquals(0, eventCounter);
2567         }
2568     }
2569 
2570     @Test
2571     public void testAddRemoveEventFilter() {
2572         Transform clone = t.clone();
2573 
2574         EventHandler<TransformChangedEvent> counting =
2575                 event -> {
2576                     eventCounter++;
2577                     event.consume();
2578                 };
2579 
2580         EventHandler<TransformChangedEvent> checking =
2581                 event -> {
2582                     listenerCalled = true;
2583                 };
2584 
2585         clone.addEventFilter(TransformChangedEvent.TRANSFORM_CHANGED, counting);
2586         clone.addEventHandler(TransformChangedEvent.TRANSFORM_CHANGED, checking);
2587 
2588         eventCounter = 0;
2589         listenerCalled = false;
2590         if (TransformHelper.modify(clone, 42)) {
2591             if (t == rotateZeroAxis || t == noRotate) {
2592                 // needs two changes to be further usable
2593                 eventCounter--;
2594             }
2595             assertEquals(1, eventCounter);
2596             assertFalse(listenerCalled); // consumed by filter
2597 
2598             listenerCalled = false;
2599             TransformHelper.modify(clone, 42);
2600             assertEquals(1, eventCounter);
2601             assertFalse(listenerCalled);
2602 
2603             clone.removeEventFilter(TransformChangedEvent.TRANSFORM_CHANGED, counting);
2604 
2605             TransformHelper.modify(clone, 43);
2606             assertEquals(1, eventCounter);
2607             assertTrue(listenerCalled);
2608         } else {
2609             assertEquals(0, eventCounter);
2610         }
2611     }
2612 }