ianmackenzie/elm-geometry/3.1.0

NOTE: the latest version is 4.0.0

Direction2d

A Direction2d represents a direction like 'up' or 'north' or 'forwards'. They are represented using X and Y components, and can be converted to vectors if necessary, but should be thought of as conceptually different. Directions have several uses, such as:

  • Constructing a vector from a length and direction
  • Determining the component of a vector in a particular direction (for example, finding the component of velocity in the up direction to get vertical speed)
  • Determining the (signed) angle between two directions
  • Defining the orientation of an axis or reference frame
type alias Direction2d coordinates =
Direction2d coordinates

Constants

x : Direction2d coordinates

Synonym for Direction2d.positiveX.

y : Direction2d coordinates

Synonym for Direction2d.positiveY.

positiveX : Direction2d coordinates

The positive X direction.

negativeX : Direction2d coordinates

The negative X direction.

positiveY : Direction2d coordinates

The positive Y direction.

negativeY : Direction2d coordinates

The negative Y direction.

Literals

degrees : Float -> Direction2d coordinates

Construct a direction from a number of degrees, given counterclockwise from the positive X axis:

Direction2d.degrees 0
--> Direction2d.positiveX


Direction2d.degrees 90
--> Direction2d.positiveY

This is a convenient shorthand for using Direction2d.fromAngle and Angle.degrees if you want to construct a direction at a fixed angle in degrees.

radians : Float -> Direction2d coordinates

Construct a direction from a number of radians, given counterclockwise from the positive X axis:

Direction2d.radians pi
--> Direction2d.negativeX


Direction2d.radians (-pi / 2)
--> Direction2d.negativeY

Constructors

Point2d units coordinates
-> Point2d units coordinates
-> Maybe (Direction2d coordinates)

Attempt to construct the direction from the first given point to the second. If the two points are coincident, returns Nothing.

point =
    Point2d.meters 1 1


Direction2d.from Point2d.origin point
--> Just (Direction2d.degrees 45)


Direction2d.from point Point2d.origin
--> Just (Direction2d.degrees -135)


Direction2d.from point point
--> Nothing
perpendicularTo : Direction2d coordinates -> Direction2d coordinates

Construct a direction perpendicular to the given direction, by rotating the given direction 90 degrees counterclockwise. Synonym for rotateCounterclockwise.

Direction2d.perpendicularTo Direction2d.x
--> Direction2d.y


Direction2d.perpendicularTo Direction2d.y
--> Direction2d.negativeX
Vector2d units coordinates
-> Vector2d units coordinates
-> Maybe ( Direction2d coordinates, Direction2d coordinates )

Attempt to form a pair of perpendicular directions from the two given vectors by performing Gram-Schmidt normalization:

  • The first returned direction will be equal to the direction of the first given vector
  • The second returned direction will be as close as possible to the second given vector while being perpendicular to the first returned direction

If either of the given vectors are zero, or if the two vectors are parallel, returns Nothing.

Direction2d.orthonormalize
    (Vector2d.meters 3 3)
    (Vector2d.meters 0 -2)
--> Just
-->     ( Direction2d.degrees 45
-->     , Direction2d.degrees -45
-->     )


Direction2d.orthonormalize
    (Vector2d.meters 3 3)
    (Vector2d.meters -2 -2)
--> Nothing
Direction2d coordinates
-> Direction2d coordinates
-> Maybe ( Direction2d coordinates, Direction2d coordinates )

Attempt to form a pair of perpendicular directions from the two given directions;

Direction2d.orthogonalize xDirection yDirection

is equivalent to

Direction2d.orthonormalize
    (Direction2d.toVector xDirection)
    (Direction2d.toVector yDirection)

Conversions

fromAngle : Angle -> Direction2d coordinates

Construct a direction from an Angle given counterclockwise from the positive X direction.

Direction2d.fromAngle (Angle.degrees 90)
--> Direction2d.y
toAngle : Direction2d coordinates -> Angle

Convert a direction to a polar angle (the counterclockwise angle from the positive X direction). The result will be in the range -180 to 180 degrees.

Direction2d.toAngle Direction2d.negativeY
--> Angle.degrees -90
toVector : Direction2d coordinates -> Vector2d Unitless coordinates

Convert a direction to a unitless vector of length 1.

Direction2d.toVector Direction2d.x
--> Vector2d.unitless 1 0

Properties

xComponent : Direction2d coordinates -> Float

Get the X component of a direction.

Direction2d.xComponent Direction2d.x
--> 1


Direction2d.xComponent Direction2d.y
--> 0
yComponent : Direction2d coordinates -> Float

Get the Y component of a direction.

Direction2d.yComponent Direction2d.x
--> 0


Direction2d.yComponent Direction2d.y
--> 1
componentIn : Direction2d coordinates -> Direction2d coordinates -> Float

Find the component of one direction in another direction. This is equal to the cosine of the angle between the directions, or equivalently the dot product of the two directions converted to unit vectors.

direction =
    Direction2d.degrees 60


Direction2d.componentIn Direction2d.x direction
--> 0.5


Direction2d.componentIn direction direction
--> 1


Direction2d.componentIn Direction2d.x Direction2d.y
--> 0

This is more general and flexible than using xComponent or yComponent, both of which can be expressed in terms of componentIn; for example,

Direction2d.xComponent direction

is equivalent to

Direction2d.componentIn Direction2d.x direction
angleFrom : Direction2d coordinates -> Direction2d coordinates -> Angle

Find the counterclockwise angle from the first direction to the second. The result will be in the range -180 to 180 degrees.

referenceDirection =
    Direction2d.degrees 30


Direction2d.angleFrom referenceDirection Direction2d.y
--> Angle.degrees 60


Direction2d.angleFrom referenceDirection Direction2d.x
--> Angle.degrees -30

Comparison

equalWithin : Angle -> Direction2d coordinates -> Direction2d coordinates -> Bool

Compare two directions within an angular tolerance. Returns true if the absolute value of the angle between the two given directions is less than the given tolerance.

firstDirection =
    Direction2d.degrees 45


secondDirection =
    Direction2d.degrees 47


Direction2d.equalWithin (Angle.degrees 5)
    firstDirection
    secondDirection
--> True


Direction2d.equalWithin (Angle.degrees 1)
    firstDirection
    secondDirection
--> False

Transformations

reverse : Direction2d coordinates -> Direction2d coordinates

Reverse a direction.

rotateClockwise : Direction2d coordinates -> Direction2d coordinates

Rotate a direction by 90 degrees clockwise.

Direction2d.rotateClockwise Direction2d.x
--> Direction2d.negativeY
rotateCounterclockwise : Direction2d coordinates -> Direction2d coordinates

Rotate a direction by 90 degrees counterclockwise.

Direction2d.rotateClockwise Direction2d.x
--> Direction2d.y
rotateBy : Angle -> Direction2d coordinates -> Direction2d coordinates

Rotate a direction counterclockwise by a given angle.

Direction2d.rotateBy (Angle.degrees 180) Direction2d.x
--> Direction2d.negativeX
Axis2d units coordinates
-> Direction2d coordinates
-> Direction2d coordinates

Mirror a direction across a particular axis. Note that only the direction of the axis affects the result, since directions are position-independent.

slopedAxis =
    Axis2d.through
        (Point2d.meters 100 200)
        (Direction2d.degrees 45)


Direction2d.mirrorAcross slopedAxis Direction2d.x
--> Direction2d.y


Direction2d.mirrorAcross slopedAxis Direction2d.y
--> Direction2d.x

Coordinate conversions

Like other transformations, coordinate transformations of directions depend only on the orientations of the relevant frames, not the positions of their origin points.

For the examples, assume the following frames have been defined:

upsideDownFrame =
    Frame2d.atOrigin |> Frame2d.reverseY


rotatedFrame =
    Frame2d.atOrigin |> Frame2d.rotateBy (Angle.degrees 30)
Frame2d units globalCoordinates { defines : localCoordinates }
-> Direction2d globalCoordinates
-> Direction2d localCoordinates

Take a direction defined in global coordinates, and return it expressed in local coordinates relative to a given reference frame.

Direction2d.relativeTo upsideDownFrame Direction2d.y
--> Direction2d.negativeY


Direction2d.relativeTo rotatedFrame Direction2d.x
--> Direction2d.degrees -30


Direction2d.relativeTo rotatedFrame Direction2d.y
--> Direction2d.degrees 60
Frame2d units globalCoordinates { defines : localCoordinates }
-> Direction2d localCoordinates
-> Direction2d globalCoordinates

Take a direction defined in local coordinates relative to a given reference frame, and return that direction expressed in global coordinates.

Direction2d.placeIn upsideDownFrame Direction2d.y
--> Direction2d.negativeY


Direction2d.placeIn rotatedFrame Direction2d.x
--> Direction2d.degrees 30


Direction2d.placeIn rotatedFrame Direction2d.y
--> Direction2d.degrees 120

Advanced

{ x : Float
, y : Float
}
-> Direction2d coordinates

Construct a direction directly from its X and Y components. Note that you must ensure that the sum of the squares of the given components is exactly one:

Direction2d.unsafe { x = 1, y = 0 }


Direction2d.unsafe { x = 0, y = -1 }


Direction2d.unsafe { x = 0.6, y = 0.8 }

are all valid but

Direction2d.unsafe { x = 2, y = 0 }


Direction2d.unsafe { x = 1, y = 1 }

are not. Instead of using Direction2d.unsafe, it may be easier to use constructors like degrees or fromAngle (which will always result in a valid direction) or start with existing directions and transform them as necessary.

Direction2d coordinates
-> { x : Float
, y : Float
}

Extract the X and Y components of a direction as a record.