# Parallelogram

Artifact: [androidx.ink:ink-geometry](https://developer.android.com/jetpack/androidx/releases/ink) [View Source](https://cs.android.com/search?q=file:androidx/ink/geometry/Parallelogram.kt+class:androidx.ink.geometry.Parallelogram) Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

*** ** * ** ***


```
public abstract class Parallelogram
```

<br />

Known direct subclasses [ImmutableParallelogram](https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram), [MutableParallelogram](https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram)

|---|---|
| `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram` | Immutable parallelogram (i.e. a quadrilateral with parallel sides), defined by its `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram#center()`, `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram#width()`, `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram#height()`, `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram#rotationDegrees()`, and `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram#skew()`. |
| `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram` | Mutable parallelogram (i.e. a quadrilateral with parallel sides), defined by its `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram#center()`, `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram#(androidx.ink.geometry.MutableVec,kotlin.Float,kotlin.Float,kotlin.Float,kotlin.Float)`, `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram#height()`, `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram#(androidx.ink.geometry.MutableVec,kotlin.Float,kotlin.Float,kotlin.Float,kotlin.Float)`, and `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram#skew()`. |

*** ** * ** ***

This class represents a parallelogram defined by its `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#center()`, `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()`, `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()`, `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()`, and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()`.

The shape of the parallelogram with `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()` `w`, `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()` `h`, and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()` `s` is this before rotation:

```
     s*h
   |---|__________  Displaced horizontal edge
  ⎡       /         /
  ⎢      /         /
  ⎢     /         /
h ⎢    /         /
  ⎢   /         /
  ⎢  /         /
  ⎣ /_________/  Undisplaced horizontal edge
    |---|
         w
```

The parallelogram is then translated so that its center is in the correct position and rotated by rotation `θ` (in radians in the equations below).

These parameters of a `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` are used to define a pair of vector semi-axes:

```
u = {.5 * w * cos(θ), .5 * w * sin(θ)}
v = {.5 * h * (s * cos(θ) - sin(θ)), .5 * h * (s * sin(θ) + cos(θ))}
```

From the semi-axes, we define the shape of the parallelogram as the set of all points c + 𝛼 \* u + 𝛽 \* v, where `c` is the center, and `𝛼` and `𝛽` are real numbers in the interval -1, 1.

Note: Java code should use the factory static function `from*` in `https://developer.android.com/reference/androidx/ink/geometry/MutableParallelogram` or `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram` to create `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` instances.

A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` may have a positive or negative `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()`. One of the two horizontal edges before rotation is vertically displaced by `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()` from the other. The sign of the height corresponds to the sign of the angle between the two semi-axes.

A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` may have a positive or negative skew (aka shear). The horizontal edge before rotation that is displaced vertically by height is also displaced horizontally by skew times height. The skew can be positive or negative, a positive skew corresponds to a smaller absolute angle between the two semi-axes. The skew is equal to the cotangent of the absolute angle between the two semi-axes.

A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` may *not* have a negative width. If an operation on a parallelogram or the construction of a parallelogram would result in a negative width, it is instead normalized, by negating both the width and the height, adding 180 to the angle of rotation, and normalizing rotation to the range \[0, 360).

A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` may also be degenerate; that is, its `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()` or `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()`, or both, may be zero. Degenerate `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`s may still have a non-zero `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()` and/or `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()`. A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` that has both `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()` and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()` of zero is effectively a point, and so `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()` and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()` do not affect the values of the axes or corners. A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` that has `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()` of zero is effectively a horizontal line, and so is unaffected by `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()`.

A few geometric objects can be represented as special cases of a `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. A rectangle is a `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` with `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()` of zero. (It can be rotated with respect to the axes, and hence might have a non-zero `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()`.) A `https://developer.android.com/reference/androidx/ink/geometry/Box`, an axis-aligned rectangle, is a `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` with both `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()` and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()` of zero.

## Summary

| ### Public methods |
|---|---|
| `final @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/ImmutableBox` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeBoundingBox()()` Returns the minimum bounding box containing the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableBox` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeBoundingBox(androidx.ink.geometry.MutableBox)(@https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableBox outBox)` Returns the minimum bounding box containing the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/java/util/List.html<@https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/ImmutableVec>` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeCorners()()` Returns a list containing the 4 corners of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final void` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeCorners(androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec)( @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableVec outCorner1, @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableVec outCorner2, @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableVec outCorner3, @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableVec outCorner4 )` Populates the 4 output points with the corners of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/java/util/List.html<@https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/ImmutableVec>` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeSemiAxes()()` Returns the semi axes of this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final void` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeSemiAxes(androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec)(@https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableVec outAxis1, @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/MutableVec outAxis2)` Fills the `https://developer.android.com/reference/androidx/ink/geometry/MutableVec`s with the semi axes of this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final float` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeSignedArea()()` Returns the signed area of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final boolean` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#contains(androidx.ink.geometry.ImmutableVec)(@https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/ImmutableVec point)` Returns whether the given point is contained within the Box. |
| `abstract @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/Vec` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#getCenter()()` |
| `abstract float` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#getHeight()()` The height of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `abstract @https://developer.android.com/reference/androidx/annotation/FloatRange(from = 0.0, to = 360.0, toInclusive = false) @https://developer.android.com/reference/androidx/ink/geometry/AngleDegreesFloat float` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#getRotationDegrees()()` The rotation of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` in degrees from its original axis-aligned orientation in the direction from the positive x-axis towards the positive y-axis. |
| `abstract float` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#getSkew()()` The horizontal displacement between the two horizontal edges of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` pre-rotation, as a multiple of the height. |
| `abstract @https://developer.android.com/reference/androidx/annotation/FloatRange(from = 0.0) float` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#getWidth()()` The width of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |
| `final boolean` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)( @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/Parallelogram other, @https://developer.android.com/reference/androidx/annotation/FloatRange(from = 0.0) float tolerance )` Compares this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` with `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)`, and returns true if both `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#center()` points are considered almost equal with the given `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)`, and the difference between `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()` and `other.width` is less than `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)`, and likewise for `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()`, `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()`, and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()`. |
| `abstract @https://developer.android.com/reference/androidx/annotation/NonNull https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram` | `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#toImmutable()()` Returns an `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram` that is equivalent to this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. |

## Public methods

### computeBoundingBox

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final @NonNull ImmutableBox computeBoundingBox()
```

Returns the minimum bounding box containing the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`.

Performance-sensitive code should use the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeBoundingBox()` overload that takes a pre-allocated `https://developer.android.com/reference/androidx/ink/geometry/MutableBox`, so that instance can be reused across multiple calls.

### computeBoundingBox

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final @NonNull MutableBox computeBoundingBox(@NonNull MutableBox outBox)
```

Returns the minimum bounding box containing the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`.

### computeCorners

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final @NonNull List<@NonNull ImmutableVec> computeCorners()
```

Returns a list containing the 4 corners of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`.

Corners are numbered 0, 1, 2, 3. In a Y-up coordinate system, the corners of the base rectangle are, in order: bottom-left, bottom-right, top-right, top-left. In a Y-down coordinate system, they are: top-left, top-right, bottom-right, bottom-left. The corners keep their numbering through any skew and/or rotation applied to the base rectangle. Numerically, the corners are equivalent to: `C - u - v C + u - v C + u + v C - u + v` Where `C` = `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#center()`, and `u` and `v` are the semi-axes

Performance-sensitive code should use the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeCorners()` overload that takes pre-allocated `https://developer.android.com/reference/androidx/ink/geometry/MutableVec`s, so that instances can be reused across multiple calls.

### computeCorners

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final void computeCorners(
    @NonNull MutableVec outCorner1,
    @NonNull MutableVec outCorner2,
    @NonNull MutableVec outCorner3,
    @NonNull MutableVec outCorner4
)
```

Populates the 4 output points with the corners of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`.

For explanation of order, please see `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeCorners(androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec)` above.

### computeSemiAxes

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final @NonNull List<@NonNull ImmutableVec> computeSemiAxes()
```

Returns the semi axes of this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. These are equal to:

```
- (.5 * w * cos(θ), .5 * w * sin(θ))
- (.5 * h * (s * cos(θ) - sin(θ)), .5 * h * (s * sin(θ) + cos(θ)))
```

respectively, where w = `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()`, h = `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()`, θ = `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()`, and s = `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()`

The semi-axes of a parallelogram are two vectors. Each one points from the center to the midpoint of an edge. The first semi-axis points from the center to the midpoint of the edge between corners 1 and 2, and the second semi-axis points from the center to the midpoint of the edge between corners 2 and 3. In a Y-up coordinate system, on the base rectangle, these two edges are the right and top, respectively. In a Y-down coordinate system, on the base rectangle, they are the right and bottom, respectively.

Performance-sensitive code should use the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeSemiAxes()` overload that takes a pre-allocated `https://developer.android.com/reference/androidx/ink/geometry/MutableVec`s, so that instances can be reused across multiple calls.

### computeSemiAxes

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final void computeSemiAxes(@NonNull MutableVec outAxis1, @NonNull MutableVec outAxis2)
```

Fills the `https://developer.android.com/reference/androidx/ink/geometry/MutableVec`s with the semi axes of this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. For definition please see `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#computeSemiAxes(androidx.ink.geometry.MutableVec,androidx.ink.geometry.MutableVec)` above.

### computeSignedArea

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final float computeSignedArea()
```

Returns the signed area of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. If either the width or the height is zero, this will be equal to zero; if the width is non-zero, then this will have the same sign as the height.

### contains

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final boolean contains(@NonNull ImmutableVec point)
```

Returns whether the given point is contained within the Box. Points that lie exactly on the Box's boundary are considered to be contained.

### getCenter

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public abstract @NonNull Vec getCenter()
```

### getHeight

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public abstract float getHeight()
```

The height of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. May be positive or negative, corresponding to whether the angle from the first semi-axis to the second is also positive or negative.

### getRotationDegrees

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public abstract @FloatRange(from = 0.0, to = 360.0, toInclusive = false) @AngleDegreesFloat float getRotationDegrees()
```

The rotation of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` in degrees from its original axis-aligned orientation in the direction from the positive x-axis towards the positive y-axis.

### getSkew

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public abstract float getSkew()
```

The horizontal displacement between the two horizontal edges of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` pre-rotation, as a multiple of the height. Equivalently, this is the cotangent of the absolute angle between the semi-axes. A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` may have a positive or negative skew, a greater skew indicates a smaller absolute angle between the semi-axes.

### getWidth

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public abstract @FloatRange(from = 0.0) float getWidth()
```

The width of the `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. A `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` may *not* have a negative width. If an operation on a parallelogram would result in a negative width, it is instead normalized, by negating both the width and the height, adding 180 to `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()` and normalizing that to the range \[0, 360).

### isAlmostEqual

Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/ink#1.0.0)

```
public final boolean isAlmostEqual(
    @NonNull Parallelogram other,
    @FloatRange(from = 0.0) float tolerance
)
```

Compares this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` with `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)`, and returns true if both `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#center()` points are considered almost equal with the given `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)`, and the difference between `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#width()` and `other.width` is less than `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#isAlmostEqual(androidx.ink.geometry.Parallelogram,kotlin.Float)`, and likewise for `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#height()`, `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#rotationDegrees()`, and `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram#skew()`.

### toImmutable

Added in [1.1.0-alpha11](https://developer.android.com/jetpack/androidx/releases/ink#1.1.0-alpha11)

```
public abstract @NonNull ImmutableParallelogram toImmutable()
```

Returns an `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram` that is equivalent to this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram`. If this `https://developer.android.com/reference/androidx/ink/geometry/Parallelogram` is immutable, the returned `https://developer.android.com/reference/androidx/ink/geometry/ImmutableParallelogram` will be the same instance.