ianmackenzie / elm-geometry-prerelease / Vector3d

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!


type alias Vector3d =
Geometry.Types.Vector3d

Predefined vectors

zero : Vector3d

The zero vector.

Vector3d.zero
--> Vector3d.fromComponents ( 0, 0, 0 )

Constructors

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

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

Comparison

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

Measurement

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

Arithmetic

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 )

Transformations

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 )

Coordinate conversions

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 )