Releases: ianmackenzie/elm-geometry
4.0.0
Despite the major version bump, this is really just a clean-up release with three main changes.
Changing 3D vector/direction rotation functions to take a Direction3d
instead of an Axis3d
Previously, Vector3d.rotateAround
and Direction3d.rotateAround
took an Axis3d
as an argument even though the origin point of the axis wasn't used, only the axis direction. This was to be consistent with all other 3D rotateAround
functions, but can be confusing and in some cases could force you to create an axis with a dummy origin point, which seems messy. These two functions now accept a Direction3d
instead, so you may need to change some code from (e.g.)
Direction3d.rotateAround someAxis someDirection
to
Direction3d.rotateAround (Axis3d.direction someAxis) someDirection
Thanks @MartinSStewart for bringing this up!
Renaming ArcLengthParameterization
to ArcLength
I originally used the longer name for this module since it's the only module in elm-geometry
that doesn't have a 2d
or 3d
suffix, and I wanted to add something to make the name less likely to conflict with modules in other packages. However, several years later the Elm package repository still doesn't have any other packages that mention arc length, so it looks like the simpler name is probably OK.
No functionality has been changed, but all the names have:
3.x | 4.0 |
---|---|
ArcLengthParameterization.ArcLengthParameterization |
ArcLength.Parameterization |
ArcLengthParameterization.build |
ArcLength.parameterization |
ArcLengthParameterization.totalArcLength |
ArcLength.total |
ArcLengthParameterization.arcLengthToParameterValue |
ArcLength.toParameterValue |
ArcLengthParameterization.parameterValueToArcLength |
ArcLength.fromParameterValue |
I personally now like using the Parameterization
type qualified; instead of
import ArcLengthParameterization exposing (ArcLengthParameterization)
import Length exposing (Meters)
type alias Model =
{ parameterization : ArcLengthParameterization Meters
, -- other stuff
}
I now tend to write
import ArcLength
import Length exposing (Meters)
type alias Model =
{ parameterization : ArcLength.Parameterization Meters
, -- other stuff
}
Relaxing vector construction/transformation type signatures
This one is subtle and shouldn't actually be a breaking change for any code, since the only change is making some type signatures more permissive (all existing code should still type-check just fine, and the behaviour is unchanged). The short version is that a few vector-related functions were requiring units types to match when they didn't actually need to, and those type signatures have now been relaxed to be more permissive (and more correct!).
For example, in elm-geometry
3.x, the Vector3d.mirrorAcross
function had the following signature:
Plane3d units coordinates -> Vector3d units coordinates -> Vector3d units coordinates
The units
type parameter here will most commonly be Meters
, meaning that:
- The plane's origin point has coordinates which are
Length
(a.k.a.Quantity Float Meters
) values; that is, the coordinates are measured in meters, centimeters, feet, inches etc. - The vector's components are also
Length
values; that is, the vector is a displacement (a vector between two points).
However, it's not actually necessary for those two units types to match! Since mirroring a vector across a plane doesn't involve the plane's origin point (just the plane's normal direction, which is unitless) it's not actually necessary that the units of the vector match the units of the plane's origin point. For example, it's totally valid (and sometimes useful) to mirror a velocity vector (with units of MetersPerSecond
) across a plane with units of Meters
. As a result, Vector3d.mirrorAcross
now has the signature
Plane3d planeUnits coordinates -> Vector3d units coordinates -> Vector3d units coordinates
That is, the plane and vector are still enforced to be defined in the same coordinate system, and the units of the mirrored vector are enforced to be the same as the original vector, but the units of the plane and vector are allowed be different.
Of course, the units don't have to be different, so any existing code that (for example) mirrors a Vector3d Meters WorldCoordinates
across a Plane3d Meters WorldCoordinates
will still compile and run exactly the same as before. The Elm compiler considers this change a breaking one, but all it actually does is allow certain kinds of code that weren't allowed previously.
It's not just transformation functions like mirrorAcross
that have been updated - several vector construction functions have had similar changes. For example, it is now possible to do things like construct a velocity vector with units of MetersPerSecond
by providing its components within a sketch plane with units of Meters
:
-- elm-geometry 3.x
Vector3d.xyOn :
SketchPlane3d units coordinates3d { defines : coordinates2d }
-> Quantity Float units
-> Quantity Float units
-> Vector3d units coordinates3d
-- elm-geometry 4.0
Vector3d.xyOn :
SketchPlane3d sketchPlaneUnits coordinates3d { defines : coordinates2d }
-> Quantity Float units
-> Quantity Float units
-> Vector3d units coordinates3d
(Note how the vector units are now allowed to be different from the sketch plane units.)
Full list of functions with updated signatures:
Vector2d
xyIn
rThetaIn
relativeTo
placeIn
projectOnto
(Note that Vector2d.mirrorAcross
was the one function that actually had the correct type signature already, so didn't need to be updated.)
Vector3d
xyzIn
on
xyOn
rThetaOn
relativeTo
placeIn
rotateAround
mirrorAcross
projectOnto
projectInto
3.11.0
This release adds Spline2d
and Spline3d
modules, which are generalizations of the existing QuadraticSpline2d
/CubicSpline2d
and QuadraticSpline3d
/CubicSpline3d
modules.
In general you should prefer to use the existing modules (they're much more efficient), but the new ones are useful if you need support for fancy higher-degree splines (quartic, quintic etc.) or if you're doing something like making a graphics editor where users can choose how many points to use to define a spline curve (two for a straight line, three for a quadratic spline, four for a cubic spline, etc.).
3.10.0
This (long-delayed!) release adds several small new functions:
Polygon2d.regular
for constructing regular polygons (triangles, squares, pentagons, hexagons etc.) (thanks @gampleman in #148)Axis2d.intersectionPoint
for finding the intersection point between two 2D axesAxis3d.intersectionWithTriangle
, andAxis3d.intersectionWithRectangle
(thanks @w0rm in #146)BoundingBox2d.interpolate
andBoundingBox3d.interpolate
for interpolating within bounding boxesLineSegment2d.axis
andLineSegment3d.axis
for getting the axis that a given line segment lies on- Several functions for multiplying and dividing
Vector2d
andVector3d
byFloat
orQuantity Float Unitless
values (functionally the same thing, but different in the eyes of the type system):multiplyBy
,divideBy
,timesUnitless
andoverUnitless
for bothVector2d
andVector3d
RationalQuadraticSpline3d.approximate
andRationalCubicSpline3d.approximate
for generating polyline approximations to rational splines in 3D (useful for 3D rendering)
Adding the rational spline approximate
functions (the last bullet point above) also required adding a bunch of lower-level functionality that is less likely to be useful outside of elm-geometry
internals:
- New
VectorBoundingBox2d
andVectorBoundingBox3d
types/modules, equivalent toBoundingBox2d
andBoundingBox3d
but for bounds on vectors instead of points - Several functions for computing derivatives and bounding boxes on derivatives of different spline types (also added to elliptical arcs, for completeness)
3.9.1
This release fixes a typo in the implementation of Vector3d.perpendicularTo
which would cause it would give an incorrect (non-perpendicular) result in some cases. Please update!
3.9.0
NURBS curves
This release extends the work on spline functionality from the last release and adds support for rational quadratic and cubic splines in the RationalQuadraticSpline2d
, RationalQuadraticSpline3d
, RationalCubicSpline2d
and RationalCubicSpline3d
modules. This means it is now possible to create quadratic or cubic NURBS curves in 2D or 3D using elm-geometry
! For example, to create a NURBS curve representing a perfect circle (consisting of four rational quadratic spline segments), you could write
splineSegments =
RationalQuadraticSpline2d.bSplineSegments
[ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4 ]
[ ( Point2d.pixels 300 0, 1 )
, ( Point2d.pixels 300 300, 1 / sqrt 2 )
, ( Point2d.pixels 0 300, 1 )
, ( Point2d.pixels -300 300, 1 / sqrt 2 )
, ( Point2d.pixels -300 0, 1 )
, ( Point2d.pixels -300 -300, 1 / sqrt 2 )
, ( Point2d.pixels 0 -300, 1 )
, ( Point2d.pixels 300 -300, 1 / sqrt 2 )
, ( Point2d.pixels 300 0, 1 )
]
See Wikipedia for some explanation, but note that:
- Only the ratios between knot values matter, so the 0..4 knot sequence here is equivalent to the 0..2π knot sequence on Wikipedia.
elm-geometry
uses a different knot convention that avoids the 'dummy' first and last knots, so note that the first and last knots are only repeated twice here instead of three times.
Ellipsoids
This release also adds an Ellipsoid3d
type and module for representing ellipsoids. Thanks to @g-belmonte for contributing this in #135! (Eventually elm-3d-scene
will get support for rendering ellipsoids.)
3.8.0
This is a small release that primarily brings some basic B-spline functionality to the QuadraticSpline2d
, QuadraticSpline3d
, CubicSpline2d
and CubicSpline3d
modules, for example:
-- Construct a B-spline and get its individual cubic spline segments
CubicSpline2d.bSplineSegments :
List Float -- knot values
-> List (Point2d units coordinates) -- control points
-> List (CubicSpline2d units coordinates) -- resulting curve segments
-- Find the knot intervals corresponding to those curve segments
CubicSpline2d.bSplineIntervals : List Float -> List (Interval Float)
In addition, Circle3d
now has a toArc
function for converting a 360 degree arc (with unspecified start/end point).
3.7.0
This release is the result of a steady accumulation of contributions over the last several months - not a very cohesive story to tell here, but lots of useful new features!
New modules
This release adds new Ellipse3d
and EllipticalArc3d
modules, which are fairly straightforward 3D versions of Ellipse2d
and EllipticalArc2d
having many of the same operations.
Random value generation
A few modules now have basic functions for generating random values in 2D and 3D. You can generate random points within bounding boxes and rectangles:
BoundingBox2d.randomPoint : BoundingBox2d units coordinates -> Generator (Point2d units coordinates)
BoundingBox3d.randomPoint : BoundingBox3d units coordinates -> Generator (Point3d units coordinates)
Rectangle2d.randomPoint : Rectangle2d units coordinates -> Generator (Point2d units coordinates)
Rectangle3d.randomPoint : Rectangle3d units coordinates -> Generator (Point3d units coordinates)
You can also generate random 2D and 3D directions:
Direction2d.random : Generator (Direction2d coordinates)
Direction3d.random : Generator (Direction3d coordinates)
Future releases will likely add more random generators such as 'point within circle' , 'point within triangle' etc.
Curve approximation
This release brings some more flexibility in how to approximate curves (arcs, splines) etc. by things like polylines. The Arc2d
, Arc3d
, QuadraticSpline2d
, QuadraticSpline3d
, CubicSpline2d
, CubicSpline3d
and EllipticalArc2d
modules now all have new approximate
, segments
and numApproximationSegments
functions, for example:
Arc2d.approximate : Quantity Float units -> Arc2d units coordinates -> Polyline2d units coordinates
Arc2d.segments : Int -> Arc2d units coordinates -> Polyline2d units coordinates
Arc2d.numApproximationSegments : Quantity Float units -> Arc2d units coordinates -> Int
- The
approximate
function replacestoPolyline
, which is now deprecated since there are now multiple ways to convert a curve to a polyline. LiketoPolyline
,approximate
takes a tolerance and returns a polyline that approximates the arc to within that tolerance. - The
segments
function is a simpler version ofapproximate
that takes as an argument the number of segments to use. - Finally,
numApproximationSegments
is a lower-level function that tells you how many segments would be needed for a polyline to approximate the given arc to within the given accuracy. You can then use this to determine how many times to call functions likepointOn
orsample
.
Polygon triangulation customization
The existing Polygon2d.triangulate
turns a Polygon2d
into a triangular mesh by adding edges between existing polygon vertices. Sometimes, however, you want some extra control over the resulting triangulation - for example, you might want to ensure that all triangles are smaller than some given size. There is now a Polygon2d.triangulateWith
function and some functions for setting up some 'rules' for the triangulation:
Polygon2d.triangulateWith :
TriangulationRule units coordinates
-> Polygon2d units coordinates
-> TriangularMesh (Point2d units coordinates)
Polygon2d.maxEdgeLength : Quantity Float units -> TriangulationRule units coordinates
Polygon2d.maxTriangleDimensions : Quantity Float units -> Quantity Float units -> TriangulationRule units coordinates
Vector scaling
Vectors now have a new scaleTo
function thanks to @g-belmonte in #137:
Vector2d.scaleTo : Quantity Float units2 -> Vector2d units1 coordinates -> Vector2d units2 coordinates
Vector3d.scaleTo : Quantity Float units2 -> Vector3d units1 coordinates -> Vector3d units2 coordinates
These functions will return a vector in the same direction as the original, but scaled to the given length (or left as zero if they are zero to begin with). Note that this is capable of changing the units of the vector if you want!
Bounding box improvements
The Arc2d
, Arc3d
, Ellipse2d
and EllipticalArc2d
modules now all have boundingBox
functions. The BoundingBox2d
and BoundingBox3d
modules themselves now also have new functionality to convert between bounding boxes and X/Y/Z intervals, for example
BoundingBox2d.xy : Interval Float units -> Interval Float units -> BoundingBox2d units coordinates
BoundingBox2d.fromIntervals : ( Interval Float units, Interval Float units ) -> BoundingBox2d units coordinates
BoundingBox2d.intervals : BoundingBox2d units coordinates -> ( Interval Float units, Interval Float units )
BoundingBox2d.xInterval : BoundingBox2d units coordinates -> Interval Float units
BoundingBox2d.yInterval : BoundingBox2d units coordinates -> Interval Float units
and similar for BoundingBox3d
.
Physics-related vector constructors
The Vector2d
and Vector3d
modules got several new functions for constructing speed, acceleration and force vectors from their X/Y/Z components. For example, the Vector2d
module now has several functions such as:
Vector2d.metersPerSecond : Float -> Float -> Vector2d MetersPerSecond coordinates
Vector2d.feetPerSecondSquared : Float -> Float -> Vector2d MetersPerSecondSquared coordinates
Vector2d.kilonewtons : Float -> Float -> Vector2d Newtons coordinates
Thanks to @g-belmonte in #139 for adding these!
Miscellaneous
Other new functions in this release:
Arc3d.projectOnto : Plane3d units coordinates -> Arc3d units coordinates -> EllipticalArc3d units coordinates
-- Reverse the orientation (axial direction) of a circle
Circle3d.flip : Circle3d units coordinates -> Circle3d units coordinates
-- Alias for Plane3d.reverseNormal, for consistency with Circle3d.flip
Plane3d.flip : Plane3d units coordinates -> Plane3d units coordinates
-- Find the minimum/maximum distances of ellipses and elliptical arcs along arbitrary axes
Ellipse2d.signedDistanceAlong : Axis2d units coordinates -> Ellipse2d units coordinates -> Interval Float units
EllipticalArc2d.signedDistanceAlong : Axis2d units coordinates -> EllipticalArc2d units coordinates -> Interval Float units
3.6.0
This release brings a few useful new functions and some performance improvements. First, there's Axis3d.intersectionWithSphere
, contributed by @SuzzzWood in #128:
Axis3d.intersectionWithSphere :
Sphere3d units coordinates
-> Axis3d units coordinates
-> Maybe ( Point3d units coordinates, Point3d units coordinates )
Second, a handful of functions for measuring intervals of distances of line segments relative to axes and planes in 2D and 3D, contributed by @w0rm in #123:
LineSegment2d.signedDistanceAlong :
Axis2d units coordinates
-> LineSegment2d units coordinates
-> Interval Float units
LineSegment2d.signedDistanceFrom :
Axis2d units coordinates
-> LineSegment2d units coordinates
-> Interval Float units
LineSegment3d.signedDistanceAlong :
Axis3d units coordinates
-> LineSegment3d units coordinates
-> Interval Float units
LineSegment3d.signedDistanceFrom :
Plane3d units coordinates
-> LineSegment3d units coordinates
-> Interval Float units
Finally, the performance of arc length parameterization has been improved (particularly for 2D/3D cubic and quadratic splines). Please open an issue or reach out to @ianmackenzie on the Elm Slack if you are encountering any other performance issues with elm-geometry
!
3.5.0
This release brings a new Cone3d
module for representing/manipulating 3D cones, contributed by @w0rm in #131. (See also Andrey's corresponding PR to add support for rendering cones in elm-3d-scene
!)
3.4.0
This is a fairly small release that brings a few new bounding box related functions, all suggested by @MartinSStewart in #129 and #130:
BoundingBox2d.withDimensions :
( Quantity Float units, Quantity Float units )
-> Point2d units coordinates
-> BoundingBox2d units coordinates
BoundingBox3d.withDimensions :
( Quantity Float units, Quantity Float units, Quantity Float units )
-> Point3d units coordinates
-> BoundingBox3d units coordinates
Rectangle2d.fromBoundingBox :
BoundingBox2d units coordinates
-> Rectangle2d units coordinates
Block3d.fromBoundingBox :
BoundingBox3d units coordinates
-> Block3d units coordinates