A Vector2d
represents a quantity such as a displacement or velocity in 2D,
and is defined by its X and Y components. This module contains a variety of
vector-related functionality, such as
Note that unlike in many other geometry packages where vectors are used as a
general-purpose data type, elm-geometry
has separate data types for vectors,
directions and points. In most code it is actually more common to use Point2d
and Direction2d
than Vector2d
, and much code can avoid working directly with
Vector2d
values at all!
Geometry.Types.Vector2d units coordinates
zero : Vector2d units coordinates
The vector with components (0,0).
unitless : Basics.Float -> Basics.Float -> Vector2d Quantity.Unitless coordinates
Construct a unitless Vector2d
value from its X and Y components. See also
fromUnitless
.
meters : Basics.Float -> Basics.Float -> Vector2d Length.Meters coordinates
pixels : Basics.Float -> Basics.Float -> Vector2d Pixels coordinates
millimeters : Basics.Float -> Basics.Float -> Vector2d Length.Meters coordinates
centimeters : Basics.Float -> Basics.Float -> Vector2d Length.Meters coordinates
inches : Basics.Float -> Basics.Float -> Vector2d Length.Meters coordinates
xy : Quantity Basics.Float units -> Quantity Basics.Float units -> Vector2d units coordinates
Construct a vector from its X and Y components.
vector =
Vector2d.xy (Length.meters 2) (Length.meters 3)
xyIn : Geometry.Types.Frame2d frameUnits globalCoordinates { defines : localCoordinates } -> Quantity Basics.Float units -> Quantity Basics.Float units -> Vector2d units globalCoordinates
Construct a vector given its local components within a particular frame:
rotatedFrame =
Frame2d.atOrigin
|> Frame2d.rotateBy (Angle.degrees 45)
Vector2d.xyIn rotatedFrame
(Length.meters 2)
(Length.meters 0)
--> Vector2d.xy
--> (Length.meters 1.4142)
--> (Length.meters 1.4142)
rTheta : Quantity Basics.Float units -> Angle -> Vector2d units coordinates
Construct a vector from a length and angle. The angle is measured counterclockwise from the positive X direction.
Vector2d.rTheta (Length.meters 2) (Angle.degrees 135)
-->Vector2d.meters -1.4142 1.4142
rThetaIn : Geometry.Types.Frame2d frameUnits globalCoordinates { defines : localCoordinates } -> Quantity Basics.Float units -> Angle -> Vector2d units globalCoordinates
Construct a vector given its local polar components within a particular frame:
rotatedFrame =
Frame2d.atOrigin
|> Frame2d.rotateBy (Angle.degrees 45)
Vector2d.rThetaIn rotatedFrame
(Length.meters 1)
(Angle.degrees 0)
--> Vector2d.meters 0.7071 0.7071
from : Geometry.Types.Point2d units coordinates -> Geometry.Types.Point2d units coordinates -> Vector2d units coordinates
Construct a vector from the first given point to the second.
startPoint =
Point2d.meters 1 1
endPoint =
Point2d.meters 4 5
Vector2d.from startPoint endPoint
--> Vector2d.meters 3 4
withLength : Quantity Basics.Float units -> Geometry.Types.Direction2d coordinates -> Vector2d units coordinates
Construct a vector with the given length in the given direction.
Vector2d.withLength (Length.meters 5) Direction2d.y
--> Vector2d.meters 0 5
perpendicularTo : Vector2d units coordinates -> Vector2d units coordinates
Construct a vector perpendicular to the given vector, by rotating the given
vector 90 degrees counterclockwise. The constructed vector will have the same
length as the given vector. Alias for Vector2d.rotateCounterclockwise
.
Vector2d.perpendicularTo (Vector2d.meters 1 0)
--> Vector2d.meters 0 1
Vector2d.perpendicularTo (Vector2d.meters 0 2)
--> Vector2d.meters -2 0
Vector2d.perpendicularTo (Vector2d.meters 3 1)
--> Vector2d.meters -1 3
Vector2d.perpendicularTo Vector2d.zero
--> Vector2d.zero
interpolateFrom : Vector2d units coordinates -> Vector2d units coordinates -> Basics.Float -> Vector2d units coordinates
Construct a vector by interpolating from the first given vector to the second, based on a parameter that ranges from zero to one.
startVector =
Vector2d.zero
endVector =
Vector2d.meters 8 12
Vector2d.interpolateFrom startVector endVector 0.25
--> Vector2d.meters 2 3
Partial application may be useful:
interpolatedVector : Float -> Vector2d
interpolatedVector =
Vector2d.interpolateFrom startVector endVector
List.map interpolatedVector [ 0, 0.5, 1 ]
--> [ Vector2d.meters 0 0
--> , Vector2d.meters 4 6
--> , Vector2d.meters 8 12
--> ]
You can pass values less than zero or greater than one to extrapolate:
interpolatedVector -0.5
--> Vector2d.meters -4 -6
interpolatedVector 1.25
--> Vector2d.meters 10 15
These functions are useful for interoperability with other Elm code that uses
plain Float
tuples or records to represent vectors.
fromTuple : (Basics.Float -> Quantity Basics.Float units) -> ( Basics.Float, Basics.Float ) -> Vector2d units coordinates
Construct a Vector2d
from a tuple of Float
values, by specifying what units those values are
in.
Vector2d.fromTuple Length.meters ( 2, 3 )
--> Vector2d.meters 2 3
toTuple : (Quantity Basics.Float units -> Basics.Float) -> Vector2d units coordinates -> ( Basics.Float, Basics.Float )
Convert a Vector2d
to a tuple of Float
values, by specifying what units you want the result
to be in.
vector =
Vector2d.feet 2 3
Vector2d.toTuple Length.inInches vector
--> ( 24, 36 )
fromRecord : (Basics.Float -> Quantity Basics.Float units) -> { x : Basics.Float, y : Basics.Float } -> Vector2d units coordinates
Construct a Vector2d
from a record with Float
fields, by specifying what units those fields
are in.
Vector2d.fromRecord Length.inches { x = 24, y = 36 }
--> Vector2d.feet 2 3
toRecord : (Quantity Basics.Float units -> Basics.Float) -> Vector2d units coordinates -> { x : Basics.Float, y : Basics.Float }
Convert a Vector2d
to a record with Float
fields, by specifying what units you want the
result to be in.
vector =
Vector2d.meters 2 3
Vector2d.toRecord Length.inCentimeters vector
--> { x = 200, y = 300 }
These functions allow zero-overhead conversion of vectors to and from records
with x
and y
Float
fields, useful for efficient interop with other code
that represents vectors as plain records.
fromMeters : { x : Basics.Float, y : Basics.Float } -> Vector2d Length.Meters coordinates
toMeters : Vector2d Length.Meters coordinates -> { x : Basics.Float, y : Basics.Float }
fromPixels : { x : Basics.Float, y : Basics.Float } -> Vector2d Pixels coordinates
toPixels : Vector2d Pixels coordinates -> { x : Basics.Float, y : Basics.Float }
fromUnitless : { x : Basics.Float, y : Basics.Float } -> Vector2d Quantity.Unitless coordinates
toUnitless : Vector2d Quantity.Unitless coordinates -> { x : Basics.Float, y : Basics.Float }
per : Quantity Basics.Float independentUnits -> Vector2d dependentUnits coordinates -> Vector2d (Quantity.Rate dependentUnits independentUnits) coordinates
Construct a vector representing a rate of change such as a speed:
displacement =
Vector2d.meters 6 8
velocity =
displacement |> Vector2d.per (Duration.seconds 2)
-- Get the magnitude of the velocity (the speed)
Vector2d.length velocity
--> Speed.metersPerSecond 5
for : Quantity Basics.Float independentUnits -> Vector2d (Quantity.Rate dependentUnits independentUnits) coordinates -> Vector2d dependentUnits coordinates
Multiply a rate of change vector by an independent quantity to get a total vector. For example, multiply a velocity by a duration to get a total displacement:
velocity =
Vector2d.xy
(Pixels.pixelsPerSecond 200)
(Pixels.pixelsPerSecond 50)
velocity |> Vector2d.for (Duration.seconds 0.1)
--> Vector2d.pixels 20 5
components : Vector2d units coordinates -> ( Quantity Basics.Float units, Quantity Basics.Float units )
Get the X and Y components of a vector as a tuple.
Vector2d.components (Vector2d.meters 2 3)
--> ( Length.meters 2, Length.meters 3 )
xComponent : Vector2d units coordinates -> Quantity Basics.Float units
Get the X component of a vector.
Vector2d.xComponent (Vector2d.meters 2 3)
--> Length.meters 2
yComponent : Vector2d units coordinates -> Quantity Basics.Float units
Get the Y component of a vector.
Vector2d.yComponent (Vector2d.meters 2 3)
--> Length.meters 3
componentIn : Geometry.Types.Direction2d coordinates -> Vector2d units coordinates -> Quantity Basics.Float units
Find the component of a vector in an arbitrary direction, for example
forwardSpeed =
Vector2d.componentIn forwardDirection velocity
This is more general and flexible than using xComponent
or yComponent
, both
of which can be expressed in terms of componentIn
; for example,
Vector2d.xComponent vector
is equivalent to
Vector2d.componentIn Direction2d.x vector
length : Vector2d units coordinates -> Quantity Basics.Float units
Get the length (magnitude) of a vector.
Vector2d.length (Vector2d.meters 3 4)
--> Length.meters 5
direction : Vector2d units coordinates -> Maybe (Geometry.Types.Direction2d coordinates)
Attempt to find the direction of a vector. In the case of a zero vector,
return Nothing
.
Vector2d.direction (Vector2d.meters 3 3)
--> Just (Direction2d.degrees 45)
Vector2d.direction Vector2d.zero
--> Nothing
equalWithin : Quantity Basics.Float units -> Vector2d units coordinates -> Vector2d units coordinates -> Basics.Bool
Compare two vectors within a tolerance. Returns true if the difference between the two given vectors has magnitude less than the given tolerance.
firstVector =
Vector2d.meters 1 2
secondVector =
Vector2d.meters 0.9999 2.0002
Vector2d.equalWithin (Length.millimeters 1)
firstVector
secondVector
--> True
Vector2d.equalWithin (Length.microns 1)
firstVector
secondVector
--> False
lexicographicComparison : Vector2d units coordinates -> Vector2d units coordinates -> Basics.Order
Compare two Vector2d
values lexicographically: first by X component, then
by Y. Can be used to provide a sort order for Vector2d
values.
multiplyBy : Basics.Float -> Vector2d units coordinates -> Vector2d units coordinates
Alias for scaleBy
since a Vector2d
can be kind of thought of
as either a 'mathematical' or 'geometric' object.
divideBy : Basics.Float -> Vector2d units coordinates -> Vector2d units coordinates
Divide a vector by the given value.
plus : Vector2d units coordinates -> Vector2d units coordinates -> Vector2d units coordinates
Find the sum of two vectors.
firstVector =
Vector2d.meters 1 2
secondVector =
Vector2d.meters 3 4
firstVector |> Vector2d.plus secondVector
--> Vector2d.meters 4 6
minus : Vector2d units coordinates -> Vector2d units coordinates -> Vector2d units coordinates
Find the difference between two vectors (the second vector minus the first).
firstVector =
Vector2d.meters 5 6
secondVector =
Vector2d.meters 1 3
firstVector |> Vector2d.minus secondVector
--> Vector2d.meters 4 3
Note the argument order: v1 - v2
would be written as
v1 |> Vector2d.minus v2
which is the same as
Vector2d.minus v2 v1
but the opposite of
Vector2d.minus v1 v2
dot : Vector2d units2 coordinates -> Vector2d units1 coordinates -> Quantity Basics.Float (Quantity.Product units1 units2)
Find the dot product of two vectors.
firstVector =
Vector2d.meters 1 2
secondVector =
Vector2d.meters 3 4
firstVector |> Vector2d.dot secondVector
--> Area.squareMeters 11
cross : Vector2d units2 coordinates -> Vector2d units1 coordinates -> Quantity Basics.Float (Quantity.Product units1 units2)
Find the scalar 'cross product' of two vectors in 2D. This is useful in many of the same ways as the 3D cross product:
Note the argument order: v1 x v2
would be written as
v1 |> Vector2d.cross v2
which is the same as
Vector2d.cross v2 v1
but the opposite of
Vector2d.cross v1 v2
Note that the cross product of two vectors with length units will be a vector with area units!
sum : List (Vector2d units coordinates) -> Vector2d units coordinates
Find the sum of a list of vectors.
twice : Vector2d units coordinates -> Vector2d units coordinates
Shorthand for Vector2d.scaleBy 2
.
half : Vector2d units coordinates -> Vector2d units coordinates
Shorthand for Vector2d.scaleBy 0.5
.
product : Quantity Basics.Float scalarUnits -> Vector2d vectorUnits coordinates -> Vector2d (Quantity.Product scalarUnits vectorUnits) coordinates
Multiply a scalar and a vector, resulting in a vector with units Product
scalarUnits vectorUnits
:
forceVector =
Vector2d.product mass accelerationVector
If you just want to scale a vector by a certain amount, you can use
scaleBy
instead.
times : Quantity Basics.Float scalarUnits -> Vector2d vectorUnits coordinates -> Vector2d (Quantity.Product vectorUnits scalarUnits) coordinates
Multiply a vector by a scalar quantity, resulting in a vector with units
Product vectorUnits scalarUnits
. (To the compiler Product a b
and Product b
a
are different unit types, so sometimes you will have to swap from product
to times
or vice versa to make the types work out.)
timesUnitless : Quantity Basics.Float Quantity.Unitless -> Vector2d units coordinates -> Vector2d units coordinates
Multiply a vector by a unitless quantity, leaving the units unchanged.
over : Quantity Basics.Float units1 -> Vector2d (Quantity.Product units1 units2) coordinates -> Vector2d units2 coordinates
Divide a vector with units Product units1 units2
by a scalar with units
units1
, resulting in a vector with units units2
.
accelerationVector =
forceVector |> Vector2d.over mass
over_ : Quantity Basics.Float units2 -> Vector2d (Quantity.Product units1 units2) coordinates -> Vector2d units1 coordinates
Divide a vector with units Product units1 units2
by a scalar with units
units2
, resulting in a vector with units units1
. Provided for consistency
with elm-units
but shouldn't be needed in most cases.
overUnitless : Quantity Basics.Float Quantity.Unitless -> Vector2d units coordinates -> Vector2d units coordinates
Divide a vector by a unitless quantity, leaving the units unchanged.
Note that for mirrorAcross
and projectOnto
, only the direction of the axis
affects the result, since vectors are position-independent. Think of
mirroring/projecting a vector across/onto an axis as moving the vector so its
tail is on the axis, then mirroring/projecting its tip across/onto the axis.
reverse : Vector2d units coordinates -> Vector2d units coordinates
Reverse the direction of a vector, negating its components.
Vector2d.reverse (Vector2d.meters -1 2)
--> Vector2d.meters 1 -2
(This could have been called negate
, but reverse
is more consistent with
the naming used in other modules.)
normalize : Vector2d units coordinates -> Vector2d Quantity.Unitless coordinates
Normalize a vector to have a length of one. Zero vectors are left as-is.
vector =
Vector2d.meters 3 4
Vector2d.normalize vector
--> Vector2d.meters 0.6 0.8
Vector2d.normalize Vector2d.zero
--> Vector2d.zero
Warning: Vector2d.direction
is safer since it forces you to explicitly
consider the case where the given vector is zero. Vector2d.normalize
is
primarily useful for cases like generating WebGL meshes, where defaulting to a
zero vector for degenerate cases is acceptable, and the overhead of something
like
Vector2d.direction vector
|> Maybe.map Direction2d.toVector
|> Maybe.withDefault Vector2d.zero
(which is functionally equivalent to Vector2d.normalize vector
) is too high.
scaleBy : Basics.Float -> Vector2d units coordinates -> Vector2d units coordinates
Scale the length of a vector by a given scale.
Vector2d.scaleBy 3 (Vector2d.meters 1 2)
--> Vector2d.meters 3 6
(This could have been called multiply
or times
, but scaleBy
was chosen as
a more geometrically meaningful name and to be consistent with the scaleAbout
name used in other modules.)
scaleTo : Quantity Basics.Float units2 -> Vector2d units1 coordinates -> Vector2d units2 coordinates
Scale a vector to a given length.
Vector2d.scaleTo (Length.meters 25) (Vector2d.meters 3 4)
--> Vector2d.meters 15 20
Scaling a zero vector will always result in a zero vector.
rotateBy : Angle -> Vector2d units coordinates -> Vector2d units coordinates
Rotate a vector counterclockwise by a given angle.
Vector2d.meters 1 1
|> Vector2d.rotateBy (Angle.degrees 45)
--> Vector2d.meters 0 1.4142
Vector2d.meters 1 0
|> Vector2d.rotateBy (Angle.radians pi)
--> Vector2d.meters -1 0
rotateClockwise : Vector2d units coordinates -> Vector2d units coordinates
Rotate the given vector 90 degrees clockwise;
Vector2d.rotateClockwise vector
is equivalent to
Vector2d.rotateBy (Angle.degrees -90) vector
but is more efficient.
rotateCounterclockwise : Vector2d units coordinates -> Vector2d units coordinates
Rotate the given vector 90 degrees counterclockwise;
Vector2d.rotateCounterclockwise vector
is equivalent to
Vector2d.rotateBy (Angle.degrees 90) vector
but is more efficient.
mirrorAcross : Geometry.Types.Axis2d axisUnits coordinates -> Vector2d units coordinates -> Vector2d units coordinates
Mirror a vector across a given axis.
vector =
Vector2d.meters 2 3
Vector2d.mirrorAcross Axis2d.y vector
--> Vector2d.meters -2 3
The position of the axis doesn't matter, only its orientation:
horizontalAxis =
Axis2d.withDirection Direction2d.x
(Point2d.meters 100 200)
Vector2d.mirrorAcross horizontalAxis vector
--> Vector2d.meters 2 -3
projectionIn : Geometry.Types.Direction2d coordinates -> Vector2d units coordinates -> Vector2d units coordinates
Find the projection of a vector in a particular direction. Conceptually, this means splitting the original vector into a portion parallel to the given direction and a portion perpendicular to it, then returning the parallel portion.
vector =
Vector2d.meters 2 3
Vector2d.projectionIn Direction2d.x vector
--> Vector2d.meters 2 0
Vector2d.projectionIn Direction2d.y vector
--> Vector2d.meters 0 3
projectOnto : Geometry.Types.Axis2d axisUnits coordinates -> Vector2d units coordinates -> Vector2d units coordinates
Project a vector onto an axis.
Vector2d.projectOnto Axis2d.y (Vector2d.meters 3 4)
--> Vector2d.meters 0 4
Vector2d.projectOnto Axis2d.x (Vector2d.meters -1 2)
--> Vector2d.meters -1 0
This is equivalent to finding the projection in the axis' direction.
at : Quantity Basics.Float (Quantity.Rate destinationUnits sourceUnits) -> Vector2d sourceUnits coordinates -> Vector2d destinationUnits coordinates
Convert a vector from one units type to another, by providing a conversion factor given as a rate of change of destination units with respect to source units.
worldVector =
Vector2d.meters 2 3
resolution : Quantity Float (Rate Pixels Meters)
resolution =
Pixels.pixels 100 |> Quantity.per (Length.meters 1)
worldVector |> Vector2d.at resolution
--> Vector2d.pixels 200 300
at_ : Quantity Basics.Float (Quantity.Rate sourceUnits destinationUnits) -> Vector2d sourceUnits coordinates -> Vector2d destinationUnits coordinates
Convert a vector from one units type to another, by providing an 'inverse' conversion factor given as a rate of change of source units with respect to destination units.
screenVector =
Vector2d.pixels 200 300
resolution : Quantity Float (Rate Pixels Meters)
resolution =
Pixels.pixels 50 |> Quantity.per (Length.meters 1)
screenVector |> Vector2d.at_ resolution
--> Vector2d.meters 4 6
Like other transformations, coordinate conversions of vectors depend only on the orientations of the relevant frames, not the positions of their origin points.
For the examples, assume the following frame has been defined:
rotatedFrame =
Frame2d.atOrigin
|> Frame2d.rotateBy (Angle.degrees 30)
relativeTo : Geometry.Types.Frame2d frameUnits globalCoordinates { defines : localCoordinates } -> Vector2d units globalCoordinates -> Vector2d units localCoordinates
Take a vector defined in global coordinates, and return it expressed in local coordinates relative to a given reference frame.
Vector2d.meters 2 0
|> Vector2d.relativeTo rotatedFrame
--> Vector2d.meters 1.732 -1
placeIn : Geometry.Types.Frame2d frameUnits globalCoordinates { defines : localCoordinates } -> Vector2d units localCoordinates -> Vector2d units globalCoordinates
Take a vector defined in local coordinates relative to a given reference frame, and return that vector expressed in global coordinates.
Vector2d.meters 2 0
|> Vector2d.placeIn rotatedFrame
--> Vector2d.meters 1.732 1
These constructors let you conveniently create vectors with physics-related units such as speed, acceleration and force. For example, a speed of 5 feet per second in the positive Y direction could be written as
Vector2d.feetPerSecond 0 5
and a force of 10 newtons in the negative X direction could be written as
Vector2d.newtons -10 0
metersPerSecond : Basics.Float -> Basics.Float -> Vector2d Speed.MetersPerSecond coordinates
feetPerSecond : Basics.Float -> Basics.Float -> Vector2d Speed.MetersPerSecond coordinates
kilometersPerHour : Basics.Float -> Basics.Float -> Vector2d Speed.MetersPerSecond coordinates
milesPerHour : Basics.Float -> Basics.Float -> Vector2d Speed.MetersPerSecond coordinates
metersPerSecondSquared : Basics.Float -> Basics.Float -> Vector2d Acceleration.MetersPerSecondSquared coordinates
feetPerSecondSquared : Basics.Float -> Basics.Float -> Vector2d Acceleration.MetersPerSecondSquared coordinates
gees : Basics.Float -> Basics.Float -> Vector2d Acceleration.MetersPerSecondSquared coordinates
newtons : Basics.Float -> Basics.Float -> Vector2d Force.Newtons coordinates
kilonewtons : Basics.Float -> Basics.Float -> Vector2d Force.Newtons coordinates
meganewtons : Basics.Float -> Basics.Float -> Vector2d Force.Newtons coordinates
pounds : Basics.Float -> Basics.Float -> Vector2d Force.Newtons coordinates
kips : Basics.Float -> Basics.Float -> Vector2d Force.Newtons coordinates
These functions are unsafe because they require you to track units manually. In general you should prefer other functions instead, but these functions may be useful when writing generic/library code.
unsafe : { x : Basics.Float, y : Basics.Float } -> Vector2d units coordinates
Construct a vector from its raw X and Y components as Float
values. The
values must be in whatever units the resulting point is considered to use
(usually meters or pixels). You should generally use something safer such as
meters
, fromPixels
, xy
,
fromRecord
etc.
unwrap : Vector2d units coordinates -> { x : Basics.Float, y : Basics.Float }
Extract a vector's raw X and Y components as Float
values. These values
will be in whatever units the vector has (usually meters or pixels). You should
generally use something safer such as toMeters
,
toRecord
, xComponent
etc.