Releases: ianmackenzie/elm-geometry
3.3.0
This release of elm-geometry
adds a new Rectangle3d
module and type. That's it, that's the release =)
3.2.0
elm-geometry
3.2 is out! This release brings a handful of small but useful new features requested (and in many cases contributed) by the community:
Arc2d.midpoint
,Arc3d.midpoint
andEllipticalArc2d.midpoint
for getting midpoints of circular and elliptical arcs (see #115, thanks @w0rm!)Polygon2d.centroid
for getting the centroid (center of mass) of a polygon (see #117, thanks @w0rm!)Axis2d.throughPoints
andAxis3d.throughPoints
for constructing axes that pass through two given points (thanks @MartinSStewart for the request)- Several functions for getting point coordinates and vector/direction components as tuples, bringing back some feature parity with previous versions of
elm-geometry
(thanks @MartinSStewart for the request):Point2d.coordinates
,Point2d.coordinatesIn
Point3d.coordinates
,Point3d.coordinatesIn
Vector2d.components
,Vector3d.components
Direction2d.components
,Direction3d.components
- Several functions for doing more sophisticated and/or convenient type-safe arithmetic on vectors:
Vector2d.half
,Vector2d.twice
as convenient shortand forVector2d.scaleBy
Vector2d.sum
to get the sum of a list of vectorsVector2d.product
andVector2d.times
to multiply a vector by a scalarQuantity
(analogous toQuantity.times
)Vector2d.over
andVector2d.over_
to divide a vector by a scalarQuantity
(analogous toQuantity.over
andQuantity.over_
)- plus all the same functions for
Vector3d
3.1.0
This release adds a new Cylinder3d
type and corresponding module, for representing/manipulating/querying 3D cylinders.
3.0.0
elm-geometry
3.0 is out! This release brings some small but breaking changes from the interim 2.0 release, and should hopefully now be stable for the foreseeable future.
Block3d
elm-geometry
now has a Block3d
type which is basically a 3D version of Rectangle2d
, useful for defining rectangular blocks in 3D. Unlike a BoundingBox3d
, a Block3d
does not have to be axis-aligned - it can be arbitrarily rotated, mirrored and otherwise transformed).
Bounding box constructor changes
A few bounding box related functions have been moved around/renamed for clarity/discoverability, with the end result that they're actually a bit closer to where they used to be in elm-geometry
1.x. Specifically:
- Most of the existing bounding box
hull
functions have been renamed toaggregate
; for exampleBoundingBox2d.hull3
is nowBoundingBox2d.aggregate3
. - The existing
BoundingBox2d.hull2
andBoundingBox3d.hull2
functions have been renamed tounion
(not strictly the correct term mathematically speaking, but convenient). - Most of the existing point
hull
functions have been moved to the corresponding bounding box modules; for examplePoint3d.hull
is nowBoundingBox3d.hull
(with the same signature). - The existing
Point2d.hull2
andBoundingBox3d.hull2
have been moved/renamed toBoundingBox2d.from
andBoundingBox3d.from
(matching how things worked in 1.x).
Basically, all functions that construct bounding boxes are now in bounding box modules. In addition, hullOfN
and aggregateOfN
functions have been added that basically act as combinations of hullOf
/hullN
and aggregateOf
/aggregateN
respectively.
See #107 for relevant discussion - thanks @MartinSStewart!
Miscellaneous
- The
Arc.SweptAngle
has been renamed to simplySweptAngle
for simplicity (didn't seem like that was likely to cause too many module name conflicts). - There is now an
Axis3d.intersectionWithPlane
function to find the intersection of an axis and a plane in 3D. - The
Circle2d
andSphere3d
modules now have some convenientatPoint
andatOrigin
constructors. - The
LineSegment2d
andLineSegment3d
modules now havefromPointAndVector
constructors as suggested in #110. - The type signatures of
Frame2d.atOrigin
andFrame3d.atOrigin
have been loosened slightly to matchFrame2d.atPoint Point2d.origin
andFrame3d.atPoint Point3d.atOrigin
; this was a case where the initial design was a bit too strict about coordinate system tracking and prevented some perfectly valid code from compiling. Thanks @unsoundscapes for some useful feedback here! Rectangle2d.withAxes
has been renamed back toRectangle2d.centeredOn
; I've gone back and forth on this one but I thinkcenteredOn
is more descriptive and readable.
Full diff
I think all the changes in 3.0 have been discussed above, but I may have missed something! Here's what elm diff
reported for elm-geometry
3.0 relative to 2.0:
---- ADDED MODULES - MINOR ----
Block3d
SweptAngle
---- REMOVED MODULES - MAJOR ----
Arc.SweptAngle
---- Axis3d - MINOR ----
Added:
intersectionWithPlane :
Geometry.Types.Plane3d units coordinates
-> Axis3d.Axis3d units coordinates
-> Maybe.Maybe (Point3d.Point3d units coordinates)
---- BoundingBox2d - MAJOR ----
Added:
aggregate :
BoundingBox2d.BoundingBox2d units coordinates
-> List.List (BoundingBox2d.BoundingBox2d units coordinates)
-> BoundingBox2d.BoundingBox2d units coordinates
aggregate3 :
BoundingBox2d.BoundingBox2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
aggregateN :
List.List (BoundingBox2d.BoundingBox2d units coordinates)
-> Maybe.Maybe (BoundingBox2d.BoundingBox2d units coordinates)
aggregateOf :
(a -> BoundingBox2d.BoundingBox2d units coordinates)
-> a
-> List.List a
-> BoundingBox2d.BoundingBox2d units coordinates
aggregateOfN :
(a -> BoundingBox2d.BoundingBox2d units coordinates)
-> List.List a
-> Maybe.Maybe (BoundingBox2d.BoundingBox2d units coordinates)
from :
Point2d.Point2d units coordinates
-> Point2d.Point2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
hullOfN :
(a -> Point2d.Point2d units coordinates)
-> List.List a
-> Maybe.Maybe (BoundingBox2d.BoundingBox2d units coordinates)
union :
BoundingBox2d.BoundingBox2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
Removed:
hull2 :
BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
Changed:
- hull :
BoundingBox2d units coordinates
-> List (BoundingBox2d units coordinates)
-> BoundingBox2d units coordinates
+ hull :
Point2d.Point2d units coordinates
-> List.List (Point2d.Point2d units coordinates)
-> BoundingBox2d.BoundingBox2d units coordinates
- hull3 :
BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
+ hull3 :
Point2d.Point2d units coordinates
-> Point2d.Point2d units coordinates
-> Point2d.Point2d units coordinates
-> BoundingBox2d.BoundingBox2d units coordinates
- hullN :
List (BoundingBox2d units coordinates)
-> Maybe (BoundingBox2d units coordinates)
+ hullN :
List.List (Point2d.Point2d units coordinates)
-> Maybe.Maybe (BoundingBox2d.BoundingBox2d units coordinates)
- hullOf :
(a -> BoundingBox2d units coordinates)
-> a
-> List a
-> BoundingBox2d units coordinates
+ hullOf :
(a -> Point2d.Point2d units coordinates)
-> a
-> List.List a
-> BoundingBox2d.BoundingBox2d units coordinates
---- BoundingBox3d - MAJOR ----
Added:
aggregate :
BoundingBox3d.BoundingBox3d units coordinates
-> List.List (BoundingBox3d.BoundingBox3d units coordinates)
-> BoundingBox3d.BoundingBox3d units coordinates
aggregate3 :
BoundingBox3d.BoundingBox3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
aggregateN :
List.List (BoundingBox3d.BoundingBox3d units coordinates)
-> Maybe.Maybe (BoundingBox3d.BoundingBox3d units coordinates)
aggregateOf :
(a -> BoundingBox3d.BoundingBox3d units coordinates)
-> a
-> List.List a
-> BoundingBox3d.BoundingBox3d units coordinates
aggregateOfN :
(a -> BoundingBox3d.BoundingBox3d units coordinates)
-> List.List a
-> Maybe.Maybe (BoundingBox3d.BoundingBox3d units coordinates)
from :
Point3d.Point3d units coordinates
-> Point3d.Point3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
hullOfN :
(a -> Point3d.Point3d units coordinates)
-> List.List a
-> Maybe.Maybe (BoundingBox3d.BoundingBox3d units coordinates)
union :
BoundingBox3d.BoundingBox3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
Removed:
hull2 :
BoundingBox3d units coordinates
-> BoundingBox3d units coordinates
-> BoundingBox3d units coordinates
Changed:
- hull :
BoundingBox3d units coordinates
-> List (BoundingBox3d units coordinates)
-> BoundingBox3d units coordinates
+ hull :
Point3d.Point3d units coordinates
-> List.List (Point3d.Point3d units coordinates)
-> BoundingBox3d.BoundingBox3d units coordinates
- hull3 :
BoundingBox3d units coordinates
-> BoundingBox3d units coordinates
-> BoundingBox3d units coordinates
-> BoundingBox3d units coordinates
+ hull3 :
Point3d.Point3d units coordinates
-> Point3d.Point3d units coordinates
-> Point3d.Point3d units coordinates
-> BoundingBox3d.BoundingBox3d units coordinates
- hullN :
List (BoundingBox3d units coordinates)
-> Maybe (BoundingBox3d units coordinates)
+ hullN :
List.List (Point3d.Point3d units coordinates)
-> Maybe.Maybe (BoundingBox3d.BoundingBox3d units coordinates)
- hullOf :
(a -> BoundingBox3d units coordinates)
-> a
-> List a
-> BoundingBox3d units coordinates
+ hullOf :
(a -> Point3d.Point3d units coordinates)
-> a
-> List.List a
-> BoundingBox3d.BoundingBox3d units coordinates
---- Circle2d - MINOR ----
Added:
atOrigin :
Quantity.Quantity Basics.Float units
-> Circle2d.C...
2.0.0
elm-geometry
2.0 is out! For now this is a bit of a preview release; it's feature-complete and I'm pretty happy with the API, but the docs are not yet as complete as they should be. Feel free to try out the new version, but please let me (@ianmackenzie) know on Slack if you find any gaps or errors in the documentation.
Units and coordinate systems
The main new feature in this release (that will break all your code) is the addition of type-level tracking of the units and coordinate systems associated with different values. Most types now have two type parameters; where in elm-geometry
1.x you'd have a plain
Point3d
in elm-geometry
2.x you'll have a
Point3d units coordinates
instead. Individual coordinate/component values are now Quantity
values from elm-units
, so you might construct points using
Point2d.xy (Pixels.pixels 100) (Pixels.pixels 200)
Point3d.xyz (Length.meters 2) (Length.meters 3) (Length.meters 1)
or, to be more concise (especially when prototyping/experimenting),
Point2d.pixels 100 200
Point3d.meters 2 3 1
Unlike units, which can generally be inferred to be a concrete type from usage, the coordinates
type variable is largely "optional": you can choose to annotate particular values as being in particular coordinate systems (and then the compiler can check whether those annotations are consistent with each other), but you can also often ignore it entirely. The only time a coordinates type is actually required is if you need to add a type annotation to a top level value; and in the simple case, where everything is in one coordinate system, you can do something like
type World
= World
and then annotate points as (for example)
myPoint : Point3d Meters World
myPoint =
Point3d.meters 5 10 20
If different values have different units and coordinate systems, we of course need ways to convert between them! The Frame2d
, Frame3d
and SketchPlane3d
types now both exist in a particular coordinate system and define their own coordinate system; this means that functions like placeIn
and relativeTo
now let you convert between different coordinate systems. (They always did, really, now it's just official at the type level.) For units, there are new at
and at_
functions in each module that act just like the corresponding functions at
and at_
functions in the Quantity
module.
Streamlined primitive construction
In addition to the new units/coordinate system, point/vector/direction construction has been streamlined and made significantly more flexible. For example, here are several ways of defining the same point:
-- Most flexible, useful with Json.Decode.map3 etc.
Point3d.xyz (Length.meters 2) (Length.meters 3) (Length.meters 1)
-- Very succinct, especially handy for experimentation/REPL use
Point3d.meters 2 3 1
-- Flexible conversion from plain Elm data types
Point3d.fromRecord Length.meters { x = 2, y = 3, z = 1 }
Point3d.fromTuple Length.meters ( 2, 3, 1 )
Point3d.fromRecord Length.centimeters { x = 200, y = 300, z = 100 }
Point3d.fromTuple Length.centimeters ( 200, 300, 100 )
-- Zero-overhead construction from records that happen
-- to be in 'base' units (meters or pixels)
Point3d.fromMeters { x = 2, y = 3, z = 1 }
It's also much easier to construct directions:
Direction2d.fromAngle (Angle.degrees 30) -- like before
Direction2d.degrees 30 -- handy shorthand
Direction3d.xy (Angle.degrees 45) -- an angle on the XY plane
Direction3d.yz (Angle.degrees 60) -- an angle on the YZ plane
Direction3d.xyZ (Angle.degrees 45) -- azimuth in XY...
(Angle.degrees 30) -- ...and elevation towards +Z
Direction3d.zxY (Angle.degrees 45) -- azimuth in ZX...
(Angle.degrees 30) -- ...and elevation towards +Y
Miscellaneous additions
While I was working on units and coordinate systems in the coordinate-systems
branch, several new features were contributed by various members of the community; these have all now been merged into 2.0:
expandBy
andoffsetBy
functions forBoundingBox2d
andBoundingBox3d
to allow expanding or contracting bounding boxes. (The former only ever expands, and returns a plain bounding box; the latter also supports contraction but returns aMaybe
to handle the case where the bounding box contracts to nothing.) Thanks @MrL1605!midpoint
functions forQuadraticSpline2d
,QuadraticSpline3d
,CubicSpline2d
andCubicSpline3d
as a convenient way to find the point half way along a spline by arc length (not parameter value). Thanks @MrL1605!centroid
functions forPolyline2d
andPolyline3d
to find the center of mass of a polyline. Thanks @davcamer!Polygon2d.contains
to check whether a given point is contained within a given polygon. Thanks @gampleman!Circle2d.intersectsBoundingBox
to check whether a circle touches a bounding box. Thanks @SebastianKG!
More efficient/type-safe centroid and hull functions
I took the opportunity to fix one thing that's been bothering me a bit: functions that compute the centroid or hull (bounding box) of a list of points have to return a Maybe
so that they can return Nothing
if given an empty list. There are now a few different versions of those functions for different use cases, for example:
-- If you definitely have at least one point (no Maybe!)
Point3d.centroid :
Point3d units coordinates -- first point
-> List (Point3d units coordinates) -- rest
-> Point3d units coordinates
-- If you have exactly 3 points (efficient - no list allocation/manipulation)
Point3d.centroid3 :
Point3d units coordinates
-> Point3d units coordinates
-> Point3d units coordinates
-> Point3d units coordinates
-- If you have an unknown number of points (as before)
Point3d.centroidN :
List (Point3d units coordinates)
-> Maybe (Point3d units coordinates)
This means that if you've pattern-matched a list and already have it in head/tail form, then you don't have to deal with the (impossible) Nothing
case.
As part of this change a few hull-type functions were renamed/moved around; for example BoundingBox2d.from
is now Point2d.hull2
and BoundingBox2d.containingPoints
is now Point2d.hullN
.
Simplified bounding box overlap/separation checks
The existing BoundingBox#d.overlappingBy
and BoundingBox#d.separatedBy
functions are very flexible but difficult to describe, inefficient to implement and generally a bit confusing. They've now been simplified to what are hopefully the most common/useful cases:
BoundingBox2d.overlappingByAtLeast :
Quantity Float units
-> BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
-> Bool
BoundingBox2d.separatedByAtLeast:
Quantity Float units
-> BoundingBox2d units coordinates
-> BoundingBox2d units coordinates
-> Bool
(Plus similar for BoundingBox3d
.)
There are several more smaller changes and probably some I'm forgetting; check out the API docs and reach out if you're confused/curious about anything!
1.3.0
elm-geometry
1.3.0 is out! This is a minor release with a few nice additions, all contributed by the community:
expandBy
andoffsetBy
functions forBoundingBox2d
andBoundingBox3d
to allow expanding or contracting bounding boxes. (The former only ever expands, and returns a plain bounding box; the latter also supports contraction but returns aMaybe
to handle the case where the bounding box contracts to nothing.) Thanks @MrL1605!midpoint
functions forQuadraticSpline2d
,QuadraticSpline3d
,CubicSpline2d
andCubicSpline3d
as a convenient way to find the point half way along a spline by arc length (not parameter value). Thanks @MrL1605!centroid
functions forPolyline2d
andPolyline3d
to find the center of mass of a polyline. Thanks @davcamer!Polygon2d.contains
to check whether a given point is contained within a given polygon. Thanks @gampleman!
1.2.1
Add images to Voronoi/Delaunay docs
1.2.0
elm-geometry
1.2 is out! The major feature in this release is support for generation of Delaunay triangulations and Voronoi diagrams:
Huge thanks to @folkertdev for all his work on this in #58!
Additionally, this release adds a Rectangle2d
module for directly creating and manipulating rectangles (which, unlike the similar BoundingBox2d
, can be rotated/mirrored etc.).
Last (and least, really), a few functions have been renamed - the old names have been kept for now but will likely be removed in the next major release:
1.1 | 1.2 |
---|---|
BoundingBox2d.centroid |
BoundingBox2d.centerPoint |
BoundingBox3d.centroid |
BoundingBox3d.centerPoint |
Frame2d.xy |
Frame2d.atOrigin |
Frame3d.xyz |
Frame3d.atOrigin |
Finally, shoutout to @dmy for the excellent elm-doc-preview tool. I used it quite a bit when finishing up the documentation for this release, and it made things really pleasant. Highly recommended to other package authors to let you quickly iterate on your documentation before release!
1.1.0
First release for Elm 0.19! This is almost identical to the last published release for Elm 0.18 (1.0.2), but contains a handful of new functions:
LineSegment2d.intersectionWithAxis : Axis2d -> LineSegment2d -> Maybe Point2d
Point2d.centroid : List Point2d -> Maybe Point2d
Point3d.centroid : List Point3d -> Maybe Point3d
1.0.0
elm-geometry
1.0 is out! This is effectively version 3.0 of opensolid/geometry
, with quite a few changes since opensolid/geometry
2.1.0:
- Renamed all modules to remove
OpenSolid.
prefix - Removed JSON encoding/decoding modules and split
Interval
andScalar
modules out into their own packages - Added new
ParameterValue
andSweptAngle
modules - Refactored curve evaluation functions such as
pointOn
- Improved
Polygon2d
functionality significantly - Streamlined constructors for many geometric types
- Updated spline constructors
- Added several new useful functions
- Renamed several functions
- Removed a few deprecated functions
In general, to update code written for opensolid/geometry
to use elm-geometry
, first remove the OpenSolid.
prefix from all imports. Then, follow the compiler error messages and look within these release notes to see how individual function calls should be updated (for example, search for Vector3d.with
to see that it has been replaced by Vector3d.withLength
). That said, these release notes are not exhaustive, so if you run into anything not covered here, come ask in the #geometry channel on the Elm Slack!
Renamed modules
Modules no longer include an OpenSolid.
prefix, so imports are now more succinct:
-- opensolid/geometry
import OpenSolid.Point3d as Point3d exposing (Point3d)
-- elm-geometry
import Point3d exposing (Point3d)
The module names in elm-geometry
have been chosen to try to avoid conflicts with other published Elm packages, but if you do find a conflict, please file an issue.
Removed modules
opensolid/geometry
included built-in support for JSON encoding and decoding, but after some discussion on Discourse and Slack it was decided to remove this functionality from elm-geometry
. It may reappear later, but likely as a separate package.
A couple of modules have been moved out into their own packages:
OpenSolid.Interval
has been split out intoianmackenzie/elm-interval
OpenSolid.Scalar
has been split out intoianmackenzie/elm-float-extra
, with theInterval
-related functions moved toelm-interval
New modules
Curve.ParameterValue
Evaluating points on curves now requires you to pass a ParameterValue
instead of a plain Float
. A ParameterValue
is effectively a Float
that is guaranteed to be between 0 and 1, which adds some extra type safety to curve evaluation. The ParameterValue
module includes functions for constructing ParameterValue
s from plain Float
s, and several convenient functions for constructing ranges of evenly-spaced parameter values.
Arc.SweptAngle
The Arc.SweptAngle
module replaces the duplicate SweptAngle
types and values that existed the Arc2d
and EllipticalArc2d
modules:
-- opensolid/geometry
Arc2d.smallPositive : Arc2d.SweptAngle
EllipticalArc2d.smallPositive : EllipticalArc2d.SweptAngle
-- elm-geometry
SweptAngle.smallPositive : SweptAngle.SweptAngle
Refactored curve evaluation
A very common and important operation in elm-geometry
is evaluating positions and tangent directions at various points along a curve (such as an arc or a cubic Bezier spline). A few related changes have been made in elm-geometry
to make this more type-safe and explicit. First of all, as mentioned above, curve evaluation functions now generally take ParameterValue
arguments instead of plain Float
ones:
-- opensolid/geometry
CubicSpline3d.pointOn : CubicSpline3d -> Float -> Point3d
-- elm-geometry
CubicSpline3d.pointOn : CubicSpline3d -> ParameterValue -> Point3d
You can construct a ParameterValue
using ParameterValue.clamped
, but for the common case of evaluating many points at once there are also functions for directly generating a list of parameter values and then evaluating curves at those values. For example, to get 11 points on a cubic spline (including the start and end points), you could use
pointsOnSpline =
cubicSpline |> CubicSpline3d.pointsAt (ParameterValue.steps 10)
Note that if you take 1 step along a curve you get 2 points (start and end), if you take 2 steps along a curve you get 3 points (start, middle and end), if you take 10 steps along a curve you get 11 points, etc.
Curves now also support evaluating tangent directions and 'samples' (point/tangent direction pairs), but only if the curve is nondegenerate. If a curve is actually just a single point (e.g. a spline where all control points are equal), then the curve is said to be degenerate and the tangent direction is undefined. All curve types (Arc3d
, EllipticalArc2d
, CubicSpline3d
etc.) now have functions like
CubicSpline3d.nondegenerate : CubicSpline3d -> Result Point3d CubicSpline3d.Nondegenerate
to attempt to convert a curve to its guaranteed-nondegenerate form. If the curve is in fact degenerate (consists of a single point) then you will get an Err
with that point instead. Once you have a Nondegenerate
value, you can then use it to evaluate tangent directions and samples:
CubicSpline3d.tangentDirection : CubicSpline3d.Nondegenerate -> ParameterValue -> Direction3d
CubicSpline3d.sample : CubicSpline3d.Nondegenerate -> ParameterValue -> ( Point3d, Direction3d )
For example, if you wanted to animate along a cubic spline, you might call CubicSpline3d.nondegenerate
first to try to get a nondegenerate curve. If that succeeds, then use the resulting Nondegenerate
value to evaluate points and tangent directions along the curve. If it fails, then you should apply special-case logic - perhaps drop that curve entirely from your animation path, or display your animated object in a fixed position (using the point returned in the Err
case) with some default orientation.
Polygon2d
improvements
The Polygon2d
module has been improved significantly in this release. First of all, polygons can now have holes, which necessitated several changes:
Polygon2d.fromVertices
has been renamed toPolygon2d.singleLoop
to emphasize that it constructs a polygon without holesPolygon2d.with
has been added to construct polygons with holesPolygon2d.outerLoop
andPolygon2d.innerLoops
accessors have been addedPolygon2d.clockwiseArea
,Polygon2d.counterclockwiseArea
andPolygon2d.mapVertices
have been removed since they could not easily be made to work with the new polygon representation
Polygon2d.convexHull
has been added to compute the convex hull of a set of points (thanks @gampleman!):
Finally, polygons can now be triangulated, so you can define a polygon just by specifying its outline (and holes, if it has any)
then use Polygon2d.triangulate
to turn that polygon into a list of triangles:
This is primarily useful for WebGL rendering but has many other applications.
Streamlined constructors
There was a significant push in this release to streamline geometry construction functions. Many functions that previously took a single record argument have been reworked to take multiple arguments instead, with the following goals in mind:
- Reduce verbosity
- Support partial application/work well with
|>
,map
,map2
etc. - Try not to sacrifice too much clarity/explicitness
For example,
-- opensolid/geometry
Vector2d.with { length = 3, direction = Direction2d.x }
can now be written as
-- elm-geometry
Vector2d.withLength 3 Direction2d.x
Similarly,
-- opensolid/geometry
Axis2d.with { originPoint = point, direction = direction }
can now be written as
-- elm-geometry
Axis2d.through point direction
-- OR
Axis2d.withDirection direction point
Having both versions allow you to do different things with partial application:
-- A list of axes in different directions all passing through the same origin point
List.map (Axis2d.through point) directions
-- A list of parallel axes (all having the same direction) through different points
List.map (Axis2d.withDirection direction) points
Many other constructors have been similarly updated:
opensolid/geometry |
elm-geometry |
---|---|
Arc2d.fromEndpoints |
Arc2d.withRadius: Float -> SweptAngle -> Point2d -> Point2d -> Maybe Arc2d |
Arc2d.with |
Arc2d.sweptAround: Point2d -> Float -> Point2d -> Arc2d |
Arc3d.around |
Arc3d.sweptAround: Axis3d -> Float -> Point3d -> Arc3d |
Axis3d.with |
Axis3d.through: Point3d -> Direction3d -> Axis3d Axis3d.withDirection: Direction3d -> Point3d -> Axis3d |
Circle2d.with |
Circle2d.withRadius: Float -> Point2d -> Circle2d |
Circle3d.with |
Circle3d.withRadius: Float -> Direction3d -> Point3d -> Circle3d |
Direction3d.with |
Direction3d.fromAzimuthAndElevation: ( Float, Float ) -> Direction3d |
Frame2d.with |
Frame2d.withXDirection: Direction2d -> Point2d -> Frame2d Frame2d.withYDirection: Direction2d -> Point2d -> Frame2d |
Frame3d.with |
Frame3d.withXDirection: Direction3d -> Point3d -> Frame3d Frame3d.withYDirection: Direction3d -> Point3d -> Frame3d `Frame3... |