Parallelogram


public abstract class Parallelogram

Known direct subclasses
ImmutableParallelogram

Immutable parallelogram (i.e. a quadrilateral with parallel sides), defined by its center, width, height, rotationDegrees, and skew.

MutableParallelogram

Mutable parallelogram (i.e. a quadrilateral with parallel sides), defined by its center, width, height, rotation, and skew.


This class represents a parallelogram defined by its center, width, height, rotationDegrees, and skew.

The shape of the parallelogram with width w, height h, and 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 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 MutableParallelogram or ImmutableParallelogram to create Parallelogram instances.

A Parallelogram may have a positive or negative height. One of the two horizontal edges before rotation is vertically displaced by height from the other. The sign of the height corresponds to the sign of the angle between the two semi-axes.

A 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 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 Parallelogram may also be degenerate; that is, its width or height, or both, may be zero. Degenerate Parallelograms may still have a non-zero rotation and/or skew. A Parallelogram that has both width and height of zero is effectively a point, and so rotation and skew do not affect the values of the axes or corners. A Parallelogram that has height of zero is effectively a horizontal line, and so is unaffected by skew.

A few geometric objects can be represented as special cases of a Parallelogram. A rectangle is a Parallelogram with skew of zero. (It can be rotated with respect to the axes, and hence might have a non-zero rotation.) A Box, an axis-aligned rectangle, is a Parallelogram with both rotation and skew of zero.

Summary

Public methods

final @NonNull ImmutableBox

Returns the minimum bounding box containing the Parallelogram.

final @NonNull MutableBox

Returns the minimum bounding box containing the Parallelogram.

final @NonNull List<@NonNull ImmutableVec>

Returns a list containing the 4 corners of the Parallelogram.

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 Parallelogram.

final @NonNull List<@NonNull ImmutableVec>

Returns the semi axes of this Parallelogram.

final void

Fills the MutableVecs with the semi axes of this Parallelogram.

final float

Returns the signed area of the Parallelogram.

final boolean

Returns whether the given point is contained within the Box.

abstract @NonNull Vec
abstract float

The height of the Parallelogram.

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

The rotation of the Parallelogram in degrees from its original axis-aligned orientation in the direction from the positive x-axis towards the positive y-axis.

abstract float

The horizontal displacement between the two horizontal edges of the Parallelogram pre-rotation, as a multiple of the height.

abstract @FloatRange(from = 0.0) float

The width of the Parallelogram.

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

Compares this Parallelogram with other, and returns true if both center points are considered almost equal with the given tolerance, and the difference between width and other.width is less than tolerance, and likewise for height, rotation, and skew.

Public methods

computeBoundingBox

Added in 1.0.0-alpha07
public final @NonNull ImmutableBox computeBoundingBox()

Returns the minimum bounding box containing the Parallelogram.

Performance-sensitive code should use the computeBoundingBox overload that takes a pre-allocated MutableBox, so that instance can be reused across multiple calls.

computeBoundingBox

Added in 1.0.0-alpha07
public final @NonNull MutableBox computeBoundingBox(@NonNull MutableBox outBox)

Returns the minimum bounding box containing the Parallelogram.

computeCorners

Added in 1.0.0-alpha07
public final @NonNull List<@NonNull ImmutableVeccomputeCorners()

Returns a list containing the 4 corners of the 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 = center, and u and v are the semiAxes.

Performance-sensitive code should use the computeCorners overload that takes pre-allocated MutableVecs, so that instances can be reused across multiple calls.

computeCorners

Added in 1.0.0-alpha07
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 Parallelogram.

For explanation of order, please see computeCorners above.

computeSemiAxes

Added in 1.0.0-alpha07
public final @NonNull List<@NonNull ImmutableVeccomputeSemiAxes()

Returns the semi axes of this Parallelogram. These are equal to:

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

respectively, where w = width, h = height, θ = rotation, and s = 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 computeSemiAxes overload that takes a pre-allocated MutableVecs, so that instances can be reused across multiple calls.

computeSemiAxes

Added in 1.0.0-alpha07
public final void computeSemiAxes(@NonNull MutableVec outAxis1, @NonNull MutableVec outAxis2)

Fills the MutableVecs with the semi axes of this Parallelogram. For definition please see computeSemiAxes above.

computeSignedArea

Added in 1.0.0-alpha07
public final float computeSignedArea()

Returns the signed area of the 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-alpha07
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-alpha07
public abstract @NonNull Vec getCenter()

getHeight

Added in 1.0.0-alpha07
public abstract float getHeight()

The height of the 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-alpha07
public abstract @FloatRange(from = 0.0, to = 360.0, toInclusive = false) @AngleDegreesFloat float getRotationDegrees()

The rotation of the 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-alpha07
public abstract float getSkew()

The horizontal displacement between the two horizontal edges of the Parallelogram pre-rotation, as a multiple of the height. Equivalently, this is the cotangent of the absolute angle between the semi-axes. A 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-alpha07
public abstract @FloatRange(from = 0.0) float getWidth()

The width of the Parallelogram. A 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 rotationDegrees and normalizing that to the range [0, 360).

isAlmostEqual

Added in 1.0.0-alpha07
public final boolean isAlmostEqual(
    @NonNull Parallelogram other,
    @FloatRange(from = 0.0) float tolerance
)

Compares this Parallelogram with other, and returns true if both center points are considered almost equal with the given tolerance, and the difference between width and other.width is less than tolerance, and likewise for height, rotation, and skew.