You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ma...@apache.org on 2021/04/09 19:41:30 UTC

[commons-geometry] branch master updated: GEOMETRY-117: implementing AffineTransformMatrix2D shear methods

This is an automated email from the ASF dual-hosted git repository.

mattjuntunen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-geometry.git


The following commit(s) were added to refs/heads/master by this push:
     new e50641a  GEOMETRY-117: implementing AffineTransformMatrix2D shear methods
e50641a is described below

commit e50641a482161c79c0605828d5d19361bf66451d
Author: Matt Juntunen <ma...@apache.org>
AuthorDate: Thu Apr 8 23:28:10 2021 -0400

    GEOMETRY-117: implementing AffineTransformMatrix2D shear methods
---
 .../euclidean/twod/AffineTransformMatrix2D.java    |  31 +++++
 .../twod/AffineTransformMatrix2DTest.java          | 127 +++++++++++++++++++++
 2 files changed, 158 insertions(+)

diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
index 0b7f658..3ae67d4 100644
--- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
+++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2D.java
@@ -301,6 +301,17 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
         return rotate(center, rotation.getAngle());
     }
 
+    /** Apply a shear to the current instance, returning the result as a new transform.
+     * @param shx multiplier by which coordinates are shifted along the positive x-axis as a factor of their
+     *      y coordinate; a value of 0 indicates no shift along the x-axis
+     * @param shy multiplier by which coordinates are shifted along the positive y-axis as a factor of their
+     *      x coordinate; a value of 0 indicates no shift along the y-axis
+     * @return a new transform containing the result of applying a shear to the current instance
+     */
+    public AffineTransformMatrix2D shear(final double shx, final double shy) {
+        return multiply(createShear(shx, shy), this);
+    }
+
     /** Get a new transform created by multiplying this instance by the argument.
      * This is equivalent to the expression {@code A * M} where {@code A} is the
      * current transform matrix and {@code M} is the given transform matrix. In
@@ -617,6 +628,26 @@ public final class AffineTransformMatrix2D extends AbstractAffineTransformMatrix
         return createRotation(center, rotation.getAngle());
     }
 
+    /** Create a transform representing a shear operation. The returned instance contains the
+     * matrix values
+     * <pre>
+     *      [ 1,    shx,  0 ]
+     *      [ shy,  1,    0 ]
+     *      [ 0,    0,    0 ]
+     * </pre>
+     * @param shx multiplier by which coordinates are shifted along the positive x-axis as a factor of their
+     *      y coordinate; a value of 0 indicates no shift along the x-axis
+     * @param shy multiplier by which coordinates are shifted along the positive y-axis as a factor of their
+     *      x coordinate; a value of 0 indicates no shift along the y-axis
+     * @return a new transform representing the shear operation
+     */
+    public static AffineTransformMatrix2D createShear(final double shx, final double shy) {
+        return new AffineTransformMatrix2D(
+                    1, shx, 0,
+                    shy, 1, 0
+                );
+    }
+
     /** Multiply two transform matrices together.
      * @param a first transform
      * @param b second transform
diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java
index 1a14d3d..c713364 100644
--- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java
+++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/twod/AffineTransformMatrix2DTest.java
@@ -426,6 +426,57 @@ public class AffineTransformMatrix2DTest {
     }
 
     @Test
+    public void testCreateShear() {
+        // act
+        final AffineTransformMatrix2D transform = AffineTransformMatrix2D.createShear(2, 3);
+
+        // assert
+        final double[] expected = {
+            1, 2, 0,
+            3, 1, 0
+        };
+        Assertions.assertArrayEquals(expected, transform.toArray(), 0.0);
+    }
+
+    @Test
+    public void testShear() {
+        // arrange
+        final AffineTransformMatrix2D a = AffineTransformMatrix2D.of(
+                1, 2, 3,
+                4, 5, 6
+            );
+
+        // act
+        final AffineTransformMatrix2D result = a.shear(-2, 3);
+
+        // assert
+        final double[] expected = {
+            -7, -8, -9,
+            7, 11, 15
+        };
+        Assertions.assertArrayEquals(expected, result.toArray(), EPS);
+    }
+
+    @Test
+    public void testShear_noShear() {
+        // arrange
+        final AffineTransformMatrix2D a = AffineTransformMatrix2D.of(
+                1, 2, 3,
+                4, 5, 6
+            );
+
+        // act
+        final AffineTransformMatrix2D result = a.shear(0, 0);
+
+        // assert
+        final double[] expected = {
+            1, 2, 3,
+            4, 5, 6
+        };
+        Assertions.assertArrayEquals(expected, result.toArray(), EPS);
+    }
+
+    @Test
     public void testApply_identity() {
         // arrange
         final AffineTransformMatrix2D transform = AffineTransformMatrix2D.identity();
@@ -527,6 +578,82 @@ public class AffineTransformMatrix2DTest {
     }
 
     @Test
+    public void testApply_shearAlongX() {
+        // arrange
+        final double shearFactor = -2;
+        final AffineTransformMatrix2D transform = AffineTransformMatrix2D.identity()
+                .shear(shearFactor, 0);
+
+        // act/assert
+        runWithCoordinates((x, y) -> {
+            final Vector2D vec = Vector2D.of(x, y);
+
+            final Vector2D expectedVec = Vector2D.of(x + (shearFactor * y), y);
+
+            EuclideanTestUtils.assertCoordinatesEqual(expectedVec, transform.apply(vec), EPS);
+        });
+    }
+
+    @Test
+    public void testApply_shearAlongY() {
+        // arrange
+        final double shearFactor = 2;
+        final AffineTransformMatrix2D transform = AffineTransformMatrix2D.identity()
+                .shear(0, shearFactor);
+
+        // act/assert
+        runWithCoordinates((x, y) -> {
+            final Vector2D vec = Vector2D.of(x, y);
+
+            final Vector2D expectedVec = Vector2D.of(x, y + (shearFactor * x));
+
+            EuclideanTestUtils.assertCoordinatesEqual(expectedVec, transform.apply(vec), EPS);
+        });
+    }
+
+    @Test
+    public void testApply_shearAlongXAndY() {
+        // arrange
+        final double shearX = 2;
+        final double shearY = -3;
+        final AffineTransformMatrix2D transform = AffineTransformMatrix2D.identity()
+                .shear(shearX, shearY);
+
+        // act/assert
+        runWithCoordinates((x, y) -> {
+            final Vector2D vec = Vector2D.of(x, y);
+
+            final Vector2D expectedVec = Vector2D.of(x + (shearX * y), y + (shearY * x));
+
+            EuclideanTestUtils.assertCoordinatesEqual(expectedVec, transform.apply(vec), EPS);
+        });
+    }
+
+    @Test
+    public void testApply_translateShear() {
+        // arrange
+        final Vector2D translation = Vector2D.of(7, 8);
+        final double shearX = -4;
+        final double shearY = 5;
+        final AffineTransformMatrix2D transform = AffineTransformMatrix2D.identity()
+                .translate(translation)
+                .shear(shearX, shearY);
+
+        // act/assert
+        runWithCoordinates((x, y) -> {
+            final Vector2D vec = Vector2D.of(x, y);
+
+            final double tx = x + translation.getX();
+            final double ty = y + translation.getY();
+
+            final Vector2D expectedVec = Vector2D.of(tx + (shearX * ty), ty + (shearY * tx));
+
+            EuclideanTestUtils.assertCoordinatesEqual(expectedVec, transform.apply(vec), EPS);
+        });
+    }
+
+
+    @Test
     public void testApply_translateScaleRotate() {
         // arrange
         final Vector2D translation = Vector2D.of(-2.0, -3.0);