ianmackenzie / elm-geometry-prerelease / QuadraticSpline3d

A QuadraticSpline3d is a quadratic Bézier curve in 3D defined by a start point, control point and end point. This module contains functionality for


type alias QuadraticSpline3d =
Geometry.Types.QuadraticSpline3d

Constructors

with : { startPoint : Point3d, controlPoint : Point3d, endPoint : Point3d } -> QuadraticSpline3d

Construct a spline from its start point, control point and end point:

exampleSpline =
    QuadraticSpline3d.with
        { startPoint =
            Point3d.fromCoordinates ( 1, 1, 1 )
        , controlPoint =
            Point3d.fromCoordinates ( 3, 2, 1 )
        , endPoint =
            Point3d.fromCoordinates ( 3, 3, 3 )
        }

on : SketchPlane3d -> QuadraticSpline2d -> QuadraticSpline3d

Construct a 3D spline lying on a sketch plane by providing a 2D spline specified in XY coordinates within the sketch plane.

QuadraticSpline3d.on SketchPlane3d.xz <|
    QuadraticSpline2d.with
        { startPoint =
            Point2d.fromCoordinates ( 1, 1 )
        , controlPoint =
            Point2d.fromCoordinates ( 3, 4 )
        , endPoint =
            Point2d.fromCoordinates ( 5, 1 )
        }
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 1, 0, 1 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 3, 0, 4 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 5, 0, 1 )
-->     }

Properties

startPoint : QuadraticSpline3d -> Point3d

Get the start point of a spline.

QuadraticSpline3d.startPoint exampleSpline
--> Point3d.fromCoordinates ( 1, 1, 1 )

endPoint : QuadraticSpline3d -> Point3d

Get the end point of a spline. This is equal to the spline's last control point.

QuadraticSpline3d.endPoint exampleSpline
--> Point3d.fromCoordinates ( 3, 3, 3 )

controlPoint : QuadraticSpline3d -> Point3d

Get the control point of a spline.

QuadraticSpline3d.controlPoint exampleSpline
--> Point3d.fromCoordinates ( 3, 2, 1 )

startDerivative : QuadraticSpline3d -> Vector3d

Get the start derivative of a spline. This is equal to twice the vector from the spline's first control point to its second.

QuadraticSpline3d.startDerivative exampleSpline
--> Vector3d.fromComponents ( 4, 2, 0 )

endDerivative : QuadraticSpline3d -> Vector3d

Get the end derivative of a spline. This is equal to twice the vector from the spline's second control point to its third.

QuadraticSpline3d.endDerivative exampleSpline
--> Vector3d.fromComponents ( 0, 2, 4 )

boundingBox : QuadraticSpline3d -> BoundingBox3d

Compute a bounding box for a given spline. It is not guaranteed that the result will be the smallest possible bounding box, since for efficiency the bounding box is computed from the spline's control points (which cover a larger volume than the spline itself).

QuadraticSpline3d.boundingBox exampleSpline
--> BoundingBox3d.fromExtrema
-->     { minX = 1
-->     , maxX = 3
-->     , minY = 1
-->     , maxY = 3
-->     , minZ = 1
-->     , maxZ = 3
-->     }

Evaluation

pointOn : QuadraticSpline3d -> Curve.ParameterValue.ParameterValue -> Point3d

Get the point along a spline at a given parameter value:

QuadraticSpline3d.pointOn exampleSpline 0
--> Point3d.fromCoordinates ( 1, 1, 1 )

QuadraticSpline3d.pointOn exampleSpline 0.5
--> Point3d.fromCoordinates ( 2.5, 2, 1.5 )

QuadraticSpline3d.pointOn exampleSpline 1
--> Point3d.fromCoordinates ( 3, 3, 3 )

pointsAt : List Curve.ParameterValue.ParameterValue -> QuadraticSpline3d -> List Point3d

Get points along a spline at a given set of parameter values:

exampleSpline
    |> QuadraticSpline3d.pointsAt
        (ParameterValue.steps 2)
--> [ Point3d.fromCoordinates ( 1, 1, 1 )
--> , Point3d.fromCoordinates ( 2.5, 2, 1.5 )
--> , Point3d.fromCoordinates ( 3, 3, 3 )
--> ]


type Nondegenerate

If a curve has zero length (consists of just a single point), then we say that it is 'degenerate'. Some operations such as computing tangent directions are not defined on degenerate curves.

A Nondegenerate value represents a spline that is definitely not degenerate. It is used as input to functions such as QuadraticSpline3d.tangentDirection and can be constructed using QuadraticSpline3d.nondegenerate.

nondegenerate : QuadraticSpline3d -> Result Point3d Nondegenerate

Attempt to construct a nondegenerate spline from a general QuadraticSpline3d. If the spline is in fact degenerate (consists of a single point), returns an Err with that point.

QuadraticSpline3d.nondegenerate exampleSpline
--> Ok nondegenerateExampleSpline

fromNondegenerate : Nondegenerate -> QuadraticSpline3d

Convert a nondegenerate spline back to a general QuadraticSpline3d.

QuadraticSpline3d.fromNondegenerate
    nondegenerateExampleSpline
--> exampleSpline

tangentDirection : Nondegenerate -> Curve.ParameterValue.ParameterValue -> Direction3d

Get the tangent direction to a nondegenerate spline at a given parameter value:

QuadraticSpline3d.tangentDirection
    nondegenerateExampleSpline
    ParameterValue.zero
--> Direction3d.fromAzimuthAndElevation
-->     (degrees 26.57)
-->     (degrees 0)

QuadraticSpline3d.tangentDirection
    nondegenerateExampleSpline
    ParameterValue.half
--> Direction3d.fromAzimuthAndElevation
-->     (degrees 45)
-->     (degrees 35.26)

QuadraticSpline3d.tangentDirection
    nondegenerateExampleSpline
    ParameterValue.one
--> Direction3d.fromAzimuthAndElevation
-->     (degrees 90)
-->     (degrees 63.43)

tangentDirectionsAt : List Curve.ParameterValue.ParameterValue -> Nondegenerate -> List Direction3d

Get tangent directions to a nondegenerate spline at a given set of parameter values:

nondegenerateExampleSpline
    |> QuadraticSpline3d.tangentDirectionsAt
        (ParameterValue.steps 2)
--> [ Direction3d.fromAzimuthAndElevation
-->     (degrees 26.57)
-->     (degrees 0)
--> , Direction3d.fromAzimuthAndElevation
-->     (degrees 45)
-->     (degrees 35.26)
--> , Direction3d.fromAzimuthAndElevation
-->     (degrees 90)
-->     (degrees 63.43)
--> ]

sample : Nondegenerate -> Curve.ParameterValue.ParameterValue -> ( Point3d, Direction3d )

Get both the point and tangent direction of a nondegenerate spline at a given parameter value:

QuadraticSpline3d.sample nondegenerateExampleSpline
    ParameterValue.half
--> ( Point3d.fromCoordinates ( 2.5, 2, 1.5 )
--> , Direction3d.fromAzimuthAndElevation
-->     (degrees 45)
-->     (degrees 35.26)
--> )

samplesAt : List Curve.ParameterValue.ParameterValue -> Nondegenerate -> List ( Point3d, Direction3d )

Get points and tangent directions of a nondegenerate spline at a given set of parameter values:

nondegenerateExampleSpline
    |> QuadraticSpline3d.samplesAt
        (ParameterValue.steps 2)
--> [ ( Point3d.fromCoordinates ( 1, 1, 1 )
-->   , Direction3d.fromAzimuthAndElevation
-->         (degrees 26.57)
-->         (degrees 0)
-->   )
--> , ( Point3d.fromCoordinates ( 2.5, 2, 1.5 )
-->   , Direction3d.fromAzimuthAndElevation
-->         (degrees 45)
-->         (degrees 35.26)
-->   )
--> , ( Point3d.fromCoordinates ( 3, 3, 3 )
-->   , Direction3d.fromAzimuthAndElevation
-->         (degrees 90)
-->         (degrees 63.43)
-->   )
--> ]

Transformations

reverse : QuadraticSpline3d -> QuadraticSpline3d

Reverse a spline so that the start point becomes the end point, and vice versa.

QuadraticSpline3d.reverse exampleSpline
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 3, 3, 3 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 3, 2, 1 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 1, 1, 1 )
-->     }

scaleAbout : Point3d -> Basics.Float -> QuadraticSpline3d -> QuadraticSpline3d

Scale a spline about the given center point by the given scale.

exampleSpline
    |> QuadraticSpline3d.scaleAbout Point3d.origin 2
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 2, 2, 2 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 6, 4, 2 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 6, 6, 6 )
-->     }

rotateAround : Axis3d -> Basics.Float -> QuadraticSpline3d -> QuadraticSpline3d

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

exampleSpline
    |> QuadraticSpline3d.rotateAround Axis3d.z
        (degrees 90)
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( -1, 1, 1 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( -2, 3, 1 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( -3, 3, 3 )
-->     }

translateBy : Vector3d -> QuadraticSpline3d -> QuadraticSpline3d

Translate a spline by a given displacement.

displacement =
    Vector3d.fromComponents ( 2, 3, 1 )

exampleSpline
    |> QuadraticSpline3d.translateBy displacement
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 3, 4, 2 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 5, 5, 2 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 5, 6, 4 )
-->     }

translateIn : Direction3d -> Basics.Float -> QuadraticSpline3d -> QuadraticSpline3d

Translate an arc in a given direction by a given distance;

QuadraticSpline3d.translateIn direction distance

is equivalent to

QuadraticSpline3d.translateBy
    (Vector3d.withLength distance direction)

mirrorAcross : Plane3d -> QuadraticSpline3d -> QuadraticSpline3d

Mirror a spline across a plane.

QuadraticSpline3d.mirrorAcross Plane3d.xy exampleSpline
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 1, 1, -1 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 3, 2, -1 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 3, 3, -3 )
-->     }

projectOnto : Plane3d -> QuadraticSpline3d -> QuadraticSpline3d

Find the orthographic projection of a spline onto a plane.

QuadraticSpline3d.projectOnto Plane3d.xy exampleSpline
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 1, 1, 0 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 3, 2, 0 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 3, 3, 0 )
-->     }

Coordinate conversions

relativeTo : Frame3d -> QuadraticSpline3d -> QuadraticSpline3d

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

localFrame =
    Frame3d.atPoint
        (Point3d.fromCoordinates ( 1, 2, 3 ))

QuadraticSpline3d.relativeTo localFrame exampleSpline
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 0, -1, -2 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 2, 0, -2 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 2, 1, 0 )
-->     }

placeIn : Frame3d -> QuadraticSpline3d -> QuadraticSpline3d

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

localFrame =
    Frame3d.atPoint
        (Point3d.fromCoordinates ( 1, 2, 3 ))

QuadraticSpline3d.placeIn localFrame exampleSpline
--> QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 2, 3, 4 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 4, 4, 4 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 4, 5, 6 )
-->     }

Sketch planes

projectInto : SketchPlane3d -> QuadraticSpline3d -> QuadraticSpline2d

Project a spline into a given sketch plane. Conceptually, finds the orthographic projection of the spline onto the plane and then expresses the projected spline in 2D sketch coordinates.

exampleSpline
    |> QuadraticSpline3d.projectInto SketchPlane3d.yz
--> QuadraticSpline2d.with
-->     { startPoint =
-->         Point2d.fromCoordinates ( 1, 1 )
-->     , controlPoint =
-->         Point2d.fromCoordinates ( 2, 1 )
-->     , endPoint =
-->         Point2d.fromCoordinates ( 3, 3 )
-->     }

Subdivision

bisect : QuadraticSpline3d -> ( QuadraticSpline3d, QuadraticSpline3d )

Split a spline into two roughly equal halves.

QuadraticSpline3d.bisect exampleSpline
--> ( QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 1, 1, 1 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 2, 2.5 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 3, 2.5 )
-->     }
--> , QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 3, 2.5 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 4, 2.5 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 3, 3, 3 )
-->     }
--> )

Equivalent to QuadraticSpline3d.splitAt ParameterValue.half.

splitAt : Curve.ParameterValue.ParameterValue -> QuadraticSpline3d -> ( QuadraticSpline3d, QuadraticSpline3d )

Split a spline at a particular parameter value, resulting in two smaller splines.

parameterValue =
    ParameterValue.clamped 0.75

QuadraticSpline3d.splitAt parameterValue exampleSpline
--> ( QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 1, 1, 1 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 2, 1.5, 1 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 2.5, 2, 1.5 )
-->     }
--> , QuadraticSpline3d.with
-->     { startPoint =
-->         Point3d.fromCoordinates ( 2.5, 2, 1.5 )
-->     , controlPoint =
-->         Point3d.fromCoordinates ( 3, 2.5, 2 )
-->     , endPoint =
-->         Point3d.fromCoordinates ( 3, 3, 3 )
-->     }
--> )

Arc length parameterization


type ArcLengthParameterized

A spline that has been parameterized by arc length.

arcLengthParameterized : { maxError : Basics.Float } -> QuadraticSpline3d -> ArcLengthParameterized

Build an arc length parameterization of the given spline, with a given accuracy. Generally speaking, all operations on the resulting ArcLengthParameterized value will be accurate to within the specified maximum error.

parameterizedSpline =
    exampleSpline
        |> QuadraticSpline3d.arcLengthParameterized
            { maxError = 1.0e-4 }

arcLength : ArcLengthParameterized -> Basics.Float

Find the total arc length of a spline.

QuadraticSpline3d.arcLength parameterizedSpline
--> 3.8175

In this example, the result will be accurate to within 1.0e-4 since that was the tolerance used when constructing parameterizedSpline.

pointAlong : ArcLengthParameterized -> Basics.Float -> Maybe Point3d

Try to get the point along a spline at a given arc length. For example, to get the point a quarter of the way along exampleSpline:

QuadraticSpline3d.pointAlong parameterizedSpline
    (arcLength / 4)
--> Just <|
-->     Point3d.fromCoordinates
-->         ( 1.8227, 1.4655, 1.1083 )

Note that this is not the same as evaulating at a parameter value of 1/4:

QuadraticSpline3d.pointOn exampleSpline 0.25
--> Point3d.fromCoordinates ( 1.875, 1.5, 1.125 )

If the given arc length is less than zero or greater than the arc length of the spline, returns Nothing.

tangentDirectionAlong : ArcLengthParameterized -> Basics.Float -> Maybe Direction3d

Try to get the tangent direction along a spline at a given arc length. To get the tangent direction a quarter of the way along exampleSpline:

QuadraticSpline3d.tangentDirectionAlong
    parameterizedSpline
    (arcLength / 4)
--> Just <|
-->     Direction3d.fromAzimuthAndElevation
-->         (degrees 33.09)
-->         (degrees 14.26)

If the given arc length is less than zero or greater than the arc length of the spline (or if the spline is degenerate), returns Nothing.

sampleAlong : ArcLengthParameterized -> Basics.Float -> Maybe ( Point3d, Direction3d )

Try to get the point and tangent direction along a spline at a given arc length. To get the point and tangent direction a quarter of the way along exampleSpline:

QuadraticSpline3d.sampleAlong parameterizedSpline
    (0.25 * arcLength)
--> Just
-->     ( Point3d.fromCoordinates
-->         ( 1.8227, 1.4655, 1.1083 )
-->     , Direction3d.fromAzimuthAndElevation
-->         (degrees 33.09)
-->         (degrees 14.26)
-->     )

If the given arc length is less than zero or greater than the arc length of the spline (or if the spline is degenerate), Nothing is returned.

Low level

An ArcLengthParameterized value is a combination of an ArcLengthParameterization and an underlying QuadraticSpline3d. If you need to do something fancy, you can extract these two values separately.

arcLengthParameterization : ArcLengthParameterized -> Curve.ArcLengthParameterization.ArcLengthParameterization

fromArcLengthParameterized : ArcLengthParameterized -> QuadraticSpline3d

Get the original QuadraticSpline3d from which an ArcLengthParameterized value was constructed.

Differentiation

You are unlikely to need to use these functions directly, but they are useful if you are writing low-level geometric algorithms.

firstDerivative : QuadraticSpline3d -> Curve.ParameterValue.ParameterValue -> Vector3d

Get the first derivative of a spline at a given parameter value:

QuadraticSpline3d.derivative exampleSpline
    ParameterValue.zero
--> Vector3d.fromComponents ( 4, 2, 0 )

QuadraticSpline3d.derivative exampleSpline
    ParameterValue.half
--> Vector3d.fromComponents ( 2, 2, 2 )

QuadraticSpline3d.derivative exampleSpline
    ParameterValue.one
--> Vector3d.fromComponents ( 0, 2, 4 )

Note that the derivative interpolates linearly from end to end.

firstDerivativesAt : List Curve.ParameterValue.ParameterValue -> QuadraticSpline3d -> List Vector3d

Evaluate the first derivative of a spline at a range of parameter values:

exampleSpline
    |> QuadraticSpline3d.firstDerivativesAt
        (ParameterValue.steps 2)
--> [ Vector3d.fromComponents ( 4, 2, 0 )
--> , Vector3d.fromComponents ( 2, 2, 2 )
--> , Vector3d.fromComponents ( 0, 2, 4 )
--> ]

secondDerivative : QuadraticSpline3d -> Vector3d

Get the second derivative of a spline (for a quadratic spline, this is a constant).