An EllipticalArc2d
is a section of an Ellipse2d
with a start and end
point. This module includes functionality for
The startAngle
and sweptAngle
values referred to below are not actually
proper angles but instead refer to values of the ellipse parameter.
However, in simple cases you don't need to worry about the difference - if
startAngle
and sweptAngle
are both multiples of 90 degrees, then you can
treat them as actual angles and everything will behave as you expect.
Geometry.Types.EllipticalArc2d
with : { centerPoint : Point2d, xDirection : Direction2d, xRadius : Basics.Float, yRadius : Basics.Float, startAngle : Basics.Float, sweptAngle : Basics.Float } -> EllipticalArc2d
Construct an elliptical arc from its center point, X direction, X and Y radii, start angle and swept angle. If you pass a negative radius, the absolute value will be used.
For example, to construct a simple 90 degree elliptical arc, you might use
exampleArc =
EllipticalArc2d.with
{ centerPoint = Point2d.origin
, xDirection = Direction2d.x
, xRadius = 2
, yRadius = 1
, startAngle = 0
, sweptAngle = degrees 90
}
To make an inclined 180 degree elliptical arc, you might use
EllipticalArc2d.with
{ centerPoint = Point2d.origin
, xDirection = Direction2d.fromAngle (degrees 30)
, xRadius = 2
, yRadius = 1
, startAngle = degrees -90
, sweptAngle = degrees 180
}
fromEndpoints : { startPoint : Point2d, endPoint : Point2d, xRadius : Basics.Float, yRadius : Basics.Float, xDirection : Direction2d, sweptAngle : Arc.SweptAngle.SweptAngle } -> Maybe EllipticalArc2d
Attempt to construct an elliptical arc from its endpoints, X direction, and X and Y radii. For any given valid set of these inputs, there are four possible solutions, so you also need to specify which of the four solutions you want - whether the swept angle of the arc should be less than or greater than 180 degrees, and whether the swept angle should be positive (counterclockwise) or negative (clockwise).
The example below is interactive; try dragging either endpoint or the tip of the X direction (or the center point to move the whole arc), clicking on the X or Y radial lines and then scrolling to changet that radius, or clicking/tapping on the various dashed arcs to switch what kind of swept angle to use.
This function will return Nothing
if no solution can found. Typically this
means that the two endpoints are too far apart, but could also mean that one of
the specified radii was negative or zero, or the two given points were
coincident.
The behavior of this function is very close to the SVG spec,
but when 'out of range' parameters are given this function will simply return
Nothing
instead of attempting to degrade gracefully (for example, by
increasing X and Y radius slightly if the given endpoints are slightly too far
apart). Note that this means this function is dangerous to use for 180 degree
arcs, since then slight numerical roundoff can mean the difference between a
solution being found and not - for 180 degree arcs it is safer to use
EllipticalArc2d.with
instead.
startAngle : EllipticalArc2d -> Basics.Float
The start angle of an elliptical arc is the value of the ellipse parameter at the start point of the arc.
EllipticalArc2d.startAngle exampleArc
--> 0
sweptAngle : EllipticalArc2d -> Basics.Float
The swept angle of an elliptical arc is the difference between values of the ellipse parameter from the start point to the end point of the arc.
EllipticalArc2d.sweptAngle exampleArc
--> degrees 90
startPoint : EllipticalArc2d -> Point2d
Get the start point of an elliptical arc.
EllipticalArc2d.startPoint exampleArc
--> Point2d.fromCoordinates ( 2, 0 )
centerPoint : EllipticalArc2d -> Point2d
axes : EllipticalArc2d -> Frame2d
xAxis : EllipticalArc2d -> Axis2d
yAxis : EllipticalArc2d -> Axis2d
xDirection : EllipticalArc2d -> Direction2d
yDirection : EllipticalArc2d -> Direction2d
xRadius : EllipticalArc2d -> Basics.Float
yRadius : EllipticalArc2d -> Basics.Float
pointOn : EllipticalArc2d -> Curve.ParameterValue.ParameterValue -> Point2d
Get the point along an elliptical arc at a given parameter value:
EllipticalArc2d.pointOn exampleArc ParameterValue.zero
--> Point2d.fromCoordinates ( 2, 0 )
EllipticalArc2d.pointOn exampleArc ParameterValue.half
--> Point2d.fromCoordinates ( 1.4142, 0.7071 )
EllipticalArc2d.pointOn exampleArc ParameterValue.one
--> Point2d.fromCoordinates ( 0, 1 )
pointsAt : List Curve.ParameterValue.ParameterValue -> EllipticalArc2d -> List Point2d
Get points along an elliptical arc at a given set of parameter values:
exampleArc
|> EllipticalArc2d.pointsAt
(ParameterValue.steps 2)
--> [ Point2d.fromCoordinates ( 2, 0 )
--> , Point2d.fromCoordinates ( 1.4142, 0.7071 )
--> , Point2d.fromCoordinates ( 0, 1 )
--> ]
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 an arc that is definitely not degenerate. It
is used as input to functions such as EllipticalArc2d.tangentDirection
and can
be constructed using EllipticalArc2d.nondegenerate
.
nondegenerate : EllipticalArc2d -> Result Point2d Nondegenerate
Attempt to construct a nondegenerate elliptical arc from a general
EllipticalArc2d
. If the arc is in fact degenerate (consists of a single
point), returns an Err
with that point.
EllipticalArc2d.nondegenerate exampleArc
--> Ok nondegenerateExampleArc
fromNondegenerate : Nondegenerate -> EllipticalArc2d
Convert a nondegenerate elliptical arc back to a general EllipticalArc2d
.
EllipticalArc2d.fromNondegenerate
nondegenerateExampleArc
--> exampleArc
tangentDirection : Nondegenerate -> Curve.ParameterValue.ParameterValue -> Direction2d
Get the tangent direction to a nondegenerate elliptical arc at a given parameter value:
EllipticalArc2d.tangentDirection nondegenerateExampleArc
ParameterValue.zero
--> Direction2d.fromAngle (degrees 90)
EllipticalArc2d.tangentDirection nondegenerateExampleArc
ParameterValue.half
--> Direction2d.fromAngle (degrees 153.4)
EllipticalArc2d.tangentDirection nondegenerateExampleArc
ParameterValue.one
--> Direction2d.fromAngle (degrees 180)
tangentDirectionsAt : List Curve.ParameterValue.ParameterValue -> Nondegenerate -> List Direction2d
Get tangent directions to a nondegenerate elliptical arc at a given set of parameter values:
nondegenerateExampleArc
|> EllipticalArc2d.tangentDirectionsAt
(ParameterValue.steps 2)
--> [ Direction2d.fromAngle (degrees 90)
--> , Direction2d.fromAngle (degrees 153.4)
--> , Direction2d.fromAngle (degrees 180)
--> ]
sample : Nondegenerate -> Curve.ParameterValue.ParameterValue -> ( Point2d, Direction2d )
Get both the point and tangent direction of a nondegenerate elliptical arc at a given parameter value:
EllipticalArc2d.sample nondegenerateExampleArc
ParameterValue.zero
--> ( Point2d.fromCoordinates ( 2, 0 )
--> , Direction2d.fromAngle (degrees 90)
--> )
EllipticalArc2d.sample nondegenerateExampleArc
ParameterValue.half
--> ( Point2d.fromCoordinates ( 1.4142, 0.7071 )
--> , Direction2d.fromAngle (degrees 153.4)
--> )
EllipticalArc2d.sample nondegenerateExampleArc
ParameterValue.one
--> ( Point2d.fromCoordinates ( 0, 1 )
--> , Direction2d.fromAngle (degrees 180)
--> )
samplesAt : List Curve.ParameterValue.ParameterValue -> Nondegenerate -> List ( Point2d, Direction2d )
Get points and tangent directions of a nondegenerate arc at a given set of parameter values:
nondegenerateExampleArc
|> EllipticalArc2d.samplesAt
(ParameterValue.steps 2)
--> [ ( Point2d.fromCoordinates ( 2, 0 )
--> , Direction2d.fromAngle (degrees 90)
--> )
--> , ( Point2d.fromCoordinates ( 1.4142, 0.7071 )
--> , Direction2d.fromAngle (degrees 153.4)
--> )
--> , ( Point2d.fromCoordinates ( 0, 1 )
--> , Direction2d.fromAngle (degrees 180)
--> )
--> ]
reverse : EllipticalArc2d -> EllipticalArc2d
Reverse the direction of an elliptical arc, so that the start point becomes the end point and vice versa. Does not change the shape of the arc or any properties of the underlying ellipse.
EllipticalArc2d.reverse exampleArc
--> EllipticalArc2d.with
--> { centerPoint = Point2d.origin
--> , xDirection = Direction2d.x
--> , xRadius = 2
--> , yRadius = 1
--> , startAngle = degrees 90
--> , sweptAngle = degrees -90
--> }
scaleAbout : Point2d -> Basics.Float -> EllipticalArc2d -> EllipticalArc2d
Scale an elliptical arc about a given point by a given scale.
exampleArc
|> EllipticalArc2d.scaleAbout Point2d.origin 3
--> EllipticalArc2d.with
--> { centerPoint = Point2d.origin
--> , xDirection = Direction2d.x
--> , xRadius = 6
--> , yRadius = 3
--> , startAngle = 0
--> , sweptAngle = degrees 90
--> }
rotateAround : Point2d -> Basics.Float -> EllipticalArc2d -> EllipticalArc2d
Rotate an elliptical arc around a given point by a given angle (in radians).
exampleArc
|> EllipticalArc2d.rotateAround Point2d.origin
(degrees 180)
--> EllipticalArc2d.with
--> { centerPoint = Point2d.origin
--> , xDirection = Direction2d.negativeX
--> , xRadius = 2
--> , yRadius = 1
--> , startAngle = 0
--> , sweptAngle = degrees 90
--> }
translateBy : Vector2d -> EllipticalArc2d -> EllipticalArc2d
Translate an elliptical arc by a given displacement.
exampleArc
|> EllipticalArc2d.translateBy
(Vector2d.fromComponents ( 2, 3 ))
--> EllipticalArc2d.with
--> { centerPoint =
--> Point2d.fromCoordinates ( 2, 3 )
--> , xDirection = Direction2d.x
--> , xRadius = 2
--> , yRadius = 1
--> , startAngle = 0
--> , sweptAngle = degrees 90
--> }
translateIn : Direction2d -> Basics.Float -> EllipticalArc2d -> EllipticalArc2d
Translate an elliptical arc in a given direction by a given distance;
EllipticalArc2d.translateIn direction distance
is equivalent to
EllipticalArc2d.translateBy
(Vector2d.withLength distance direction)
mirrorAcross : Axis2d -> EllipticalArc2d -> EllipticalArc2d
Mirror an elliptical arc across a given axis.
mirroredArc =
exampleArc
|> EllipticalArc2d.mirrorAcross Axis2d.y
EllipticalArc2d.startPoint mirroredArc
--> Point2d.fromCoordinates ( -2, 0 )
EllipticalArc2d.endPoint mirroredArc
--> Point2d.fromCoordinates ( 0, 1 )
relativeTo : Frame2d -> EllipticalArc2d -> EllipticalArc2d
Take an elliptical arc defined in global coordinates, and return it expressed in local coordinates relative to a given reference frame.
localFrame =
Frame2d.atPoint (Point2d.fromCoordinates ( 1, 2 ))
EllipticalArc2d.relativeTo localFrame exampleArc
--> EllipticalArc2d.with
--> { centerPoint =
--> Point2d.fromCoordinates ( -1, -2 )
--> , xDirection = Direction2d.x
--> , xRadius = 2
--> , yRadius = 1
--> , startAngle = 0
--> , sweptAngle = degrees 90
--> }
placeIn : Frame2d -> EllipticalArc2d -> EllipticalArc2d
Take an elliptical arc considered to be defined in local coordinates relative to a given reference frame, and return that arc expressed in global coordinates.
localFrame =
Frame2d.atPoint (Point2d.fromCoordinates ( 1, 2 ))
EllipticalArc2d.relativeTo localFrame exampleArc
--> EllipticalArc2d.with
--> { centerPoint =
--> Point2d.fromCoordinates ( 1, 2 )
--> , xDirection = Direction2d.x
--> , xRadius = 2
--> , yRadius = 1
--> , startAngle = 0
--> , sweptAngle = degrees 90
--> }
An elliptical arc that has been parameterized by arc length.
arcLengthParameterized : { maxError : Basics.Float } -> EllipticalArc2d -> ArcLengthParameterized
Build an arc length parameterization of the given elliptical arc, with a
given accuracy. Generally speaking, all operations on the resulting
ArcLengthParameterized
value will be accurate to within the specified maximum
error.
parameterizedArc =
exampleArc
|> EllipticalArc2d.arcLengthParameterized
{ maxError = 1.0e-4 }
arcLength : ArcLengthParameterized -> Basics.Float
Find the total arc length of an elliptical arc. This will be accurate to
within the tolerance given when calling arcLengthParameterized
.
arcLength : Float
arcLength =
EllipticalArc2d.arcLength parameterizedArc
arcLength
--> 2.4221
pointAlong : ArcLengthParameterized -> Basics.Float -> Maybe Point2d
Try to get the point along an elliptical arc at a given arc length. For
example, to get the true midpoint of exampleArc
:
EllipticalArc2d.pointAlong parameterizedArc
(arcLength / 2)
--> Just (Point2d.fromCoordinates ( 1.1889, 0.8041 ))
Note that this is not the same as evaulating at a parameter value of 0.5:
EllipticalArc2d.pointOn exampleArc
ParameterValue.half
--> Point2d.fromCoordinates ( 1.4142, 0.7071 )
If the given arc length is less than zero or greater than the arc length of the
arc, returns Nothing
.
tangentDirectionAlong : ArcLengthParameterized -> Basics.Float -> Maybe Direction2d
Try to get the tangent direction along an elliptical arc at a given arc
length. To get the tangent direction at the midpoint of exampleArc
:
EllipticalArc2d.tangentDirectionAlong parameterizedArc
(arcLength / 2)
--> Just (Direction2d.fromAngle (degrees 159.7))
If the given arc length is less than zero or greater than the arc length of the
elliptical arc (or if the elliptical arc is degenerate), returns Nothing
.
sampleAlong : ArcLengthParameterized -> Basics.Float -> Maybe ( Point2d, Direction2d )
Try to get the point and tangent direction along an elliptical arc at a
given arc length. To get the point and tangent direction at the midpoint of
exampleArc
:
EllipticalArc2d.sampleAlong parameterizedArc
(arcLength / 2)
--> Just
--> ( Point2d.fromCoordinates ( 1.1889, 0.8041 )
--> , Direction2d.fromAngle (degrees 159.7)
--> )
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
.
An ArcLengthParameterized
value is a combination of an
ArcLengthParameterization
and an
underlying EllipticalArc2d
. If you need to do something fancy, you can extract
these two values separately.
arcLengthParameterization : ArcLengthParameterized -> Curve.ArcLengthParameterization.ArcLengthParameterization
fromArcLengthParameterized : ArcLengthParameterized -> EllipticalArc2d
You are unlikely to need to use these functions directly, but they are useful if you are writing low-level geometric algorithms.
firstDerivative : EllipticalArc2d -> Curve.ParameterValue.ParameterValue -> Vector2d
Get the first derivative of an elliptical arc at a given parameter value:
EllipticalArc2d.firstDerivative exampleArc
ParameterValue.zero
--> Vector2d.fromComponents ( 0, 1.5708 )
EllipticalArc2d.firstDerivative exampleArc
ParameterValue.half
--> Vector2d.fromComponents ( -2.2214, 1.1107 )
EllipticalArc2d.firstDerivative exampleArc
ParameterValue.one
--> Vector2d.fromComponents ( -3.1416, 0 )
firstDerivativesAt : List Curve.ParameterValue.ParameterValue -> EllipticalArc2d -> List Vector2d
Evaluate the first derivative of an elliptical arc at a given set of parameter values:
exampleArc
|> EllipticalArc2d.firstDerivativesAt
(ParameterValue.steps 2)
--> [ Vector2d.fromComponents ( 0, 1.5708 )
--> , Vector2d.fromComponents ( -2.2214, 1.1107 )
--> , Vector2d.fromComponents ( -3.1416, 0 )
--> ]
maxSecondDerivativeMagnitude : EllipticalArc2d -> Basics.Float
Find a conservative upper bound on the magnitude of the second derivative of an elliptical arc. This can be useful when determining error bounds for various kinds of linear approximations.
exampleArc
|> EllipticalArc2d.maxSecondDerivativeMagnitude
--> 4.935