A Vector3d
represents a quantity such as a displacement or velocity in 3D,
and is defined by its X, Y and Z 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 Point3d
and Direction3d
than Vector3d
, and much code can avoid working directly with
Vector3d
values at all!
Geometry.Types.Vector3d
zero : Vector3d
The zero vector.
Vector3d.zero
--> Vector3d.fromComponents ( 0, 0, 0 )
fromComponents : ( Basics.Float, Basics.Float, Basics.Float ) -> Vector3d
Construct a vector from its X, Y and Z components.
vector =
Vector3d.fromComponents ( 2, 1, 3 )
from : Geometry.Types.Point3d -> Geometry.Types.Point3d -> Vector3d
Construct a vector from the first given point to the second.
startPoint =
Point3d.fromCoordinates ( 1, 1, 1 )
endPoint =
Point3d.fromCoordinates ( 4, 5, 6 )
Vector3d.from startPoint endPoint
--> Vector3d.fromComponents ( 3, 4, 5 )
withLength : Basics.Float -> Geometry.Types.Direction3d -> Vector3d
Construct a vector with the given length in the given direction.
Vector3d.withLength 5 Direction3d.y
--> Vector3d.fromComponents ( 0, 5, 0 )
on : Geometry.Types.SketchPlane3d -> Vector2d -> Vector3d
Construct a 3D vector lying on a sketch plane by providing a 2D vector specified in XY coordinates within the sketch plane.
vector2d =
Vector2d.fromComponents ( 2, 3 )
Vector3d.on SketchPlane3d.xy vector2d
--> Vector3d.fromComponents ( 2, 3, 0 )
Vector3d.on SketchPlane3d.yz vector2d
--> Vector3d.fromComponents ( 0, 2, 3 )
Vector3d.on SketchPlane3d.zx vector2d
--> Vector3d.fromComponents ( 3, 0, 2 )
A slightly more complex example:
tiltedSketchPlane =
SketchPlane3d.xy
|> SketchPlane3d.rotateAround Axis3d.x
(degrees 45)
Vector3d.on tiltedSketchPlane <|
Vector2d.fromComponents ( 1, 1 )
--> Vector3d.fromComponents ( 1, 0.7071, 0.7071 )
perpendicularTo : Vector3d -> Vector3d
Construct an arbitrary vector perpendicular to the given vector. The exact length and direction of the resulting vector are not specified, but it is guaranteed to be perpendicular to the given vector and non-zero (unless the given vector is itself zero).
Vector3d.perpendicularTo
(Vector3d.fromComponents ( 3, 0, 0 ))
--> Vector3d.fromComponents ( 0, 0, -3 )
Vector3d.perpendicularTo
(Vector3d.fromComponents ( 1, 2, 3 ))
--> Vector3d.fromComponents ( 0, -3, 2 )
Vector3d.perpendicularTo Vector3d.zero
--> Vector3d.zero
interpolateFrom : Vector3d -> Vector3d -> Basics.Float -> Vector3d
Construct a vector by interpolating from the first given vector to the second, based on a parameter that ranges from zero to one.
startVector =
Vector3d.fromComponents ( 1, 2, 4 )
endVector =
Vector3d.fromComponents ( 1, 3, 8 )
Vector3d.interpolateFrom startVector endVector 0.25
--> Vector3d.fromComponents ( 1, 2.25, 5 )
Partial application may be useful:
interpolatedVector : Float -> Vector3d
interpolatedVector =
Vector3d.interpolateFrom startVector endVector
List.map interpolatedVector [ 0, 0.5, 1 ]
--> [ Vector3d.fromComponents ( 1, 2, 4 )
--> , Vector3d.fromComponents ( 1, 2, 6 )
--> , Vector3d.fromComponents ( 1, 2, 8 )
--> ]
You can pass values less than zero or greater than one to extrapolate:
interpolatedVector -0.5
--> Vector3d.fromComponents ( 1, 2, 2 )
interpolatedVector 1.25
--> Vector3d.fromComponents ( 1, 2, 9 )
components : Vector3d -> ( Basics.Float, Basics.Float, Basics.Float )
Extract the components of a vector.
Vector3d.fromComponents ( 2, 3, 4 )
|> Vector3d.components
--> ( 2, 3, 4 )
This combined with Elm's built-in tuple destructuring provides a convenient way to extract the X, Y and Z components of a vector in one line of code:
( x, y, z ) =
Vector3d.components vector
xComponent : Vector3d -> Basics.Float
Get the X component of a vector.
Vector3d.fromComponents ( 1, 2, 3 )
|> Vector3d.xComponent
--> 1
yComponent : Vector3d -> Basics.Float
Get the Y component of a vector.
Vector3d.fromComponents ( 1, 2, 3 )
|> Vector3d.yComponent
--> 2
zComponent : Vector3d -> Basics.Float
Get the Z component of a vector.
Vector3d.fromComponents ( 1, 2, 3 )
|> Vector3d.zComponent
--> 3
length : Vector3d -> Basics.Float
Get the length (magnitude) of a vector.
Vector3d.length (Vector3d.fromComponents ( 2, 1, 2 ))
--> 3
squaredLength : Vector3d -> Basics.Float
Get the squared length of a vector. squaredLength
is slightly faster than
length
, so for example
Vector3d.squaredLength vector > tolerance * tolerance
is equivalent to but slightly more efficient than
Vector3d.length vector > tolerance
since the latter requires a square root under the hood. In many cases, however,
the speed difference will be negligible and using length
is much more
readable!
direction : Vector3d -> Maybe Geometry.Types.Direction3d
Attempt to find the direction of a vector. In the case of a zero vector,
returns Nothing
.
Vector3d.fromComponents ( 3, 0, 3 )
|> Vector3d.direction
--> Just
--> (Direction3d.fromAzimuthAndElevation
--> (degrees 0)
--> (degrees 45)
--> )
Vector3d.direction Vector3d.zero
--> Nothing
lengthAndDirection : Vector3d -> Maybe ( Basics.Float, Geometry.Types.Direction3d )
Attempt to find the length and direction of a vector. In the case of a zero
vector, returns Nothing
.
vector =
Vector3d.fromComponents ( 3, 0, 3 )
Vector3d.lengthAndDirection vector
--> Just
--> ( 4.2426
--> , Direction3d.fromAzimuthAndElevation
--> (degrees 0)
--> (degrees 45)
--> )
Vector3d.lengthAndDirection Vector3d.zero
--> Nothing
equalWithin : Basics.Float -> Vector3d -> Vector3d -> 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 =
Vector3d.fromComponents ( 2, 1, 3 )
secondVector =
Vector3d.fromComponents ( 2.0002, 0.9999, 3.0001 )
Vector3d.equalWithin 1e-3 firstVector secondVector
--> True
Vector3d.equalWithin 1e-6 firstVector secondVector
--> False
componentIn : Geometry.Types.Direction3d -> Vector3d -> Basics.Float
Find the component of a vector in an arbitrary direction, for example
verticalSpeed =
Vector3d.componentIn upDirection velocity
This is more general and flexible than using xComponent
, yComponent
or
zComponent
, all of which can be expressed in terms of componentIn
; for
example,
Vector3d.zComponent vector
is equivalent to
Vector3d.componentIn Direction3d.z vector
sum : Vector3d -> Vector3d -> Vector3d
Find the sum of two vectors.
firstVector =
Vector3d.fromComponents ( 1, 2, 3 )
secondVector =
Vector3d.fromComponents ( 4, 5, 6 )
Vector3d.sum firstVector secondVector
--> Vector3d.fromComponents ( 5, 7, 9 )
difference : Vector3d -> Vector3d -> Vector3d
Find the difference between two vectors (the first vector minus the second).
firstVector =
Vector3d.fromComponents ( 5, 6, 7 )
secondVector =
Vector3d.fromComponents ( 1, 1, 1 )
Vector3d.difference firstVector secondVector
--> Vector3d.fromComponents ( 4, 5, 6 )
dotProduct : Vector3d -> Vector3d -> Basics.Float
Find the dot product of two vectors.
firstVector =
Vector3d.fromComponents ( 1, 0, 2 )
secondVector =
Vector3d.fromComponents ( 3, 4, 5 )
Vector3d.dotProduct firstVector secondVector
--> 13
crossProduct : Vector3d -> Vector3d -> Vector3d
Find the cross product of two vectors.
firstVector =
Vector3d.fromComponents ( 2, 0, 0 )
secondVector =
Vector3d.fromComponents ( 0, 3, 0 )
Vector3d.crossProduct firstVector secondVector
--> Vector3d.fromComponents ( 0, 0, 6 )
Note that for all transformations, only the orientation of the given axis or plane is relevant, since vectors are position-independent. Think of transforming a vector as placing its tail on the relevant axis or plane and then transforming its tip.
reverse : Vector3d -> Vector3d
Reverse the direction of a vector, negating its components.
Vector3d.reverse (Vector3d.fromComponents ( 1, -3, 2 ))
--> Vector3d.fromComponents ( -1, 3, -2 )
normalize : Vector3d -> Vector3d
Normalize a vector to have a length of one. Zero vectors are left as-is.
vector =
Vector3d.fromComponents ( 3, 0, 4 )
Vector3d.normalize vector
--> Vector3d.fromComponents ( 0.6, 0, 0.8 )
Vector3d.normalize Vector3d.zero
--> Vector3d.zero
Warning: Vector3d.direction
is safer since it forces you to explicitly
consider the case where the given vector is zero. Vector3d.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
Vector3d.direction vector
|> Maybe.map Direction3d.toVector
|> Maybe.withDefault Vector3d.zero
(which is functionally equivalent to Vector3d.normalize vector
) is too high.
scaleBy : Basics.Float -> Vector3d -> Vector3d
Scale the length of a vector by a given scale.
Vector3d.fromComponents ( 1, 2, 3 )
|> Vector3d.scaleBy 3
--> Vector3d.fromComponents ( 3, 6, 9 )
rotateAround : Geometry.Types.Axis3d -> Basics.Float -> Vector3d -> Vector3d
Rotate a vector around a given axis by a given angle (in radians).
vector =
Vector3d.fromComponents ( 2, 0, 1 )
Vector3d.rotateAround Axis3d.x (degrees 90) vector
--> Vector3d.fromComponents ( 2, -1, 0 )
Vector3d.rotateAround Axis3d.z (degrees 45) vector
--> Vector3d.fromComponents ( 1.4142, 1.4142, 1 )
mirrorAcross : Geometry.Types.Plane3d -> Vector3d -> Vector3d
Mirror a vector across a plane.
vector =
Vector3d.fromComponents ( 1, 2, 3 )
Vector3d.mirrorAcross Plane3d.xy vector
--> Vector3d.fromComponents ( 1, 2, -3 )
Vector3d.mirrorAcross Plane3d.yz vector
--> Vector3d.fromComponents ( -1, 2, 3 )
projectionIn : Geometry.Types.Direction3d -> Vector3d -> Vector3d
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 =
Vector3d.fromComponents ( 1, 2, 3 )
Vector3d.projectionIn Direction3d.x vector
--> Vector3d.fromComponents ( 1, 0, 0 )
Vector3d.projectionIn Direction3d.z vector
--> Vector3d.fromComponents ( 0, 0, 3 )
projectOnto : Geometry.Types.Plane3d -> Vector3d -> Vector3d
Project a vector orthographically onto a plane. Conceptually, this means splitting the original vector into a portion parallel to the plane (perpendicular to the plane's normal direction) and a portion perpendicular to it (parallel to its normal direction), then returning the parallel (in-plane) portion.
vector =
Vector3d.fromComponents ( 2, 1, 3 )
Vector3d.projectOnto Plane3d.xy vector
--> Vector3d.fromComponents ( 2, 1, 0 )
Vector3d.projectOnto Plane3d.xz vector
--> Vector3d.fromComponents ( 2, 0, 3 )
Like other transformations, coordinate transformations of vectors depend only on the orientations of the relevant frames/sketch planes, not their positions.
For the examples, assume the following definition of a local coordinate frame, one that is rotated 30 degrees counterclockwise around the Z axis from the global XYZ frame:
rotatedFrame =
Frame3d.rotateAround Axis3d.z (degrees 30) Frame3d.xyz
relativeTo : Geometry.Types.Frame3d -> Vector3d -> Vector3d
Take a vector defined in global coordinates, and return it expressed in local coordinates relative to a given reference frame.
vector =
Vector3d.fromComponents ( 2, 0, 3 )
Vector3d.relativeTo rotatedFrame vector
--> Vector3d.fromComponents ( 1.732, -1, 3 )
placeIn : Geometry.Types.Frame3d -> Vector3d -> Vector3d
Take a vector defined in local coordinates relative to a given reference frame, and return that vector expressed in global coordinates.
vector =
Vector3d.fromComponents ( 2, 0, 3 )
Vector3d.placeIn rotatedFrame vector
--> Vector3d.fromComponents ( 1.732, 1, 3 )
projectInto : Geometry.Types.SketchPlane3d -> Vector3d -> Vector2d
Project a vector into a given sketch plane. Conceptually, this finds the orthographic projection of the vector onto the plane and then expresses the projected vector in 2D sketch coordinates.
vector =
Vector3d.fromComponents ( 2, 1, 3 )
Vector3d.projectInto SketchPlane3d.xy vector
--> Vector2d.fromComponents ( 2, 1 )
Vector3d.projectInto SketchPlane3d.yz vector
--> Vector2d.fromComponents ( 1, 3 )
Vector3d.projectInto SketchPlane3d.zx vector
--> Vector2d.fromComponents ( 3, 2 )