opensolid/geometry/1.1.0

NOTE: this package is not compatible with Elm 0.19.1

OpenSolid.Vector3d

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

  • Adding or subtracting vectors
  • Finding the lengths of vectors
  • Rotating vectors
  • Converting vectors between different coordinate systems

Note that unlike in many other geometry packages where vectors are used as a general-purpose data type, OpenSolid 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!

The simplest way to create a Vector3d is by passing a tuple of X, Y and Z components to the Vector3d constructor, for example

vector =
    Vector3d ( 2, 1, 3 )

Predefined vectors

zero : Vector3d

The zero vector.

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

Although there are no predefined constants for Vector3d ( 1, 0, 0 ), Vector3d ( 0, 1, 0 ) and Vector3d ( 0, 0, 1 ), in most cases you will actually want their Direction3d versions Direction3d.x, Direction3d.y and Direction3d.z.

Constructors

perpendicularTo : Vector3d -> Vector3d

Construct an arbitrary vector perpendicular to the given vector. The exact magnitude 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 ( 3, 0, 0 ))
--> Vector3d ( 0, 0, -3 )


Vector3d.perpendicularTo (Vector3d ( 1, 2, 3 ))
--> Vector3d ( 0, -3, 2 )


Vector3d.perpendicularTo Vector3d.zero
--> Vector3d.zero

Components

components : Vector3d -> ( Float, Float, Float )

Extract the components of a vector.

Vector3d.components (Vector2d ( 2, 3, 4 ))
--> ( 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 -> Float

Get the X component of a vector.

Vector3d.xComponent (Vector3d ( 1, 2, 3 ))
--> 1
yComponent : Vector3d -> Float

Get the Y component of a vector.

Vector3d.yComponent (Vector3d ( 1, 2, 3 ))
--> 2
zComponent : Vector3d -> Float

Get the Z component of a vector.

Vector3d.zComponent (Vector3d ( 1, 2, 3 ))
--> 3
componentIn : Direction3d -> Vector3d -> 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

Comparison

equalWithin : Float -> Vector3d -> Vector3d -> 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 ( 2, 1, 3 )


secondVector =
    Vector3d ( 2.0002, 0.9999, 3.0001 )


Vector3d.equalWithin 1e-3 firstVector secondVector
--> True


Vector3d.equalWithin 1e-6 firstVector secondVector
--> False

Length and direction

length : Vector3d -> Float

Get the length (magnitude) of a vector.

Vector3d.length (Vector3d ( 2, 1, 2 ))
--> 3
squaredLength : Vector3d -> 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 Direction3d

Attempt to find the direction of a vector. In the case of a zero vector, return Nothing.

Vector3d.direction (Vector3d ( 3, 0, 4 ))
--> Just (Direction3d ( 0.6, 0, 0.8 ))


Vector3d.direction (Vector3d ( 0, 0, 0 ))
--> Nothing
lengthAndDirection : Vector3d -> Maybe ( Float, Direction3d )

Attempt to find the length and direction of a vector. In the case of a zero vector, returns Nothing.

vector =
    Vector3d ( 3, 0, 4 )


Vector3d.lengthAndDirection vector
--> Just ( 5, Direction3d ( 0.6, 0, 0.8 ) )


Vector3d.lengthAndDirection Vector3d.zero
--> Nothing

Arithmetic

sum : Vector3d -> Vector3d -> Vector3d

Find the sum of two vectors.

firstVector =
    Vector3d ( 1, 2, 3 )


secondVector =
    Vector3d ( 4, 5, 6 )


Vector3d.sum firstVector secondVector
--> Vector3d ( 5, 7, 9 )
difference : Vector3d -> Vector3d -> Vector3d

Find the difference between two vectors (the first vector minus the second).

firstVector =
    Vector3d ( 5, 6, 7 )


secondVector =
    Vector3d ( 1, 1, 1 )


Vector3d.difference firstVector secondVector
--> Vector3d ( 4, 5, 6 )
dotProduct : Vector3d -> Vector3d -> Float

Find the dot product of two vectors.

firstVector =
    Vector3d ( 1, 0, 2 )


secondVector =
    Vector3d ( 3, 4, 5 )


Vector3d.dotProduct firstVector secondVector
--> 13
crossProduct : Vector3d -> Vector3d -> Vector3d

Find the cross product of two vectors.

firstVector =
    Vector3d ( 2, 0, 0 )


secondVector =
    Vector3d ( 0, 3, 0 )


Vector3d.crossProduct firstVector secondVector
--> Vector3d ( 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.

flip : Vector3d -> Vector3d

Reverse the direction of a vector, negating its components.

Vector3d.flip (Vector3d ( 1, -3, 2 ))
--> Vector3d ( -1, 3, -2 )
scaleBy : Float -> Vector3d -> Vector3d

Scale the length of a vector by a given scale.

Vector3d.scaleBy 3 (Vector3d ( 1, 2, 3 ))
--> Vector3d ( 3, 6, 9 )
rotateAround : Axis3d -> Float -> Vector3d -> Vector3d

Rotate a vector around a given axis by a given angle (in radians).

vector =
    Vector3d ( 2, 0, 1 )


Vector3d.rotateAround Axis3d.x (degrees 90) vector
--> Vector3d ( 2, -1, 0 )


Vector3d.rotateAround Axis3d.z (degrees 45) vector
--> Vector3d ( 1.4142, 1.4142, 1 )
mirrorAcross : Plane3d -> Vector3d -> Vector3d

Mirror a vector across a plane.

vector =
    Vector3d ( 1, 2, 3 )


Vector3d.mirrorAcross Plane3d.xy vector
--> Vector3d ( 1, 2, -3 )


Vector3d.mirrorAcross Plane3d.yz vector
--> Vector3d ( -1, 2, 3 )
projectionIn : 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 ( 1, 2, 3 )


Vector3d.projectionIn Direction3d.x vector
--> Vector3d ( 1, 0, 0 )


Vector3d.projectionIn Direction3d.z vector
--> Vector3d ( 0, 0, 3 )
projectOnto : Plane3d -> Vector3d -> Vector3d

Project a vector 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 ( 2, 1, 3 )


Vector3d.projectOnto Plane3d.xy vector
--> Vector3d ( 2, 1, 0 )


Vector3d.projectOnto Plane3d.xz vector
--> Vector3d ( 2, 0, 3 )

Coordinate frames

Functions for transforming vectors between local and global coordinates in different coordinate frames. Like other transformations, coordinate transformations of vectors depend only on the orientations of the relevant frames, 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 : 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 ( 2, 0, 3 )


Vector3d.relativeTo rotatedFrame vector
--> Vector3d ( 1.732, -1, 3 )
placeIn : 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 ( 2, 0, 3 )


Vector3d.placeIn rotatedFrame vector
--> Vector3d ( 1.732, 1, 3 )

Sketch planes

Functions for converting vectors between global 3D coordinates and 2D coordinates within a particular sketch plane.

projectInto : SketchPlane3d -> Vector3d -> Vector2d

Project a vector into a given sketch plane. Conceptually, this projects the vector onto the plane and then expresses the projected vector in 2D sketch coordinates.

vector =
    Vector3d ( 2, 1, 3 )


Vector3d.projectInto SketchPlane3d.xy vector
--> Vector2d ( 2, 1 )


Vector3d.projectInto SketchPlane3d.yz vector
--> Vector2d ( 1, 3 )


Vector3d.projectInto SketchPlane3d.zx vector
--> Vector2d ( 3, 2 )