ianmackenzie / elm-geometry

2D/3D geometry package for Elm
Mozilla Public License 2.0
183 stars 26 forks source link

Add Point3d.nearestPointOnLine and Point3d.nearestPointOnTriangle #114

Open MartinSStewart opened 4 years ago

MartinSStewart commented 4 years ago

I've implemented Point3d.nearestPointOnLine and Point3d.nearestPointOnTriangle and would like to add them to elm-geometry. Code for them can be found here and tests can be found here.

Note that the tests sometimes fail when a fuzzer manages to get nearestPointOnTriangle to return the wrong result due to numerical instability. I'm not sure yet if this is a problem in practice or if it only happens with very unusual triangles (i.e, two vertices are 0.0001 meters apart and the third vertex is 100000 meters away).

In response to this comment on Slack

(although I wonder about maybe having them LineSegment3d/Triangle3d modules instead)

I chose to place these functions in Point3d because I could come up with more intuitive names then. Additionally, to me it feels like Point3d is the "subject" of these functions and it feels more natural then that the functions are in the Point3d module.

MartinSStewart commented 4 years ago

I've now also added Point2d.insideTriangle. The code for it is here and tests are here.

ianmackenzie commented 4 years ago

Just looking through the code now - a few questions/comments:

In general I try to avoid too many circular dependencies where lower-level concepts like points are aware of higher-level concepts like triangles; I think currently there are a bunch of unavoidable cyclic dependencies between what I think of as the true 'primitives' (points, vectors, directions, axes, planes, frames, sketch planes, bounding boxes) but then there's a pretty clear separation between those and higher-level actual 'geometry' types (line segments, triangles, arcs, splines etc.).

MartinSStewart commented 4 years ago

What do you think nearestPointOnTriangle should return for a point that is inside the triangle?

It currently returns the point itself if it's inside the triangle (or rather, the point projected onto the triangle).

My inclination for names would be Triangle3d.pointClosestTo and LineSegment3d.pointClosestTo

Those are good names too. I don't think it's a good idea to differentiate with Triangle3d.pointOnEdgeClosestTo and Triangle3d.interiorPointClosestTo though. To me it seems to imply that interiorPointClosestTo won't return an edge point even though numerical imprecision means we can't really have a good distinction between the two. Also I've personally never had a need for Triangle3d.pointOnEdgeClosestTo. If someone does need it, it would be easy to implement by getting all the edges of the triangle and using LineSegment3d.pointClosestTo.

Point2d.insideTriangle already exists as Triangle2d.contains

Oops. I never even thought to look for "contains" though it seems obvious in hindsight. I suppose you can swap out implementations if you'd like, or copy over the tests I wrote to make extra certain the function does what it's supposed to.

In general I try to avoid too many circular dependencies where lower-level concepts like points are aware of higher-level concepts like triangles

That's fair and with that in mind, LineSegment3d.pointClosestTo and Triangle3d.pointClosestTo seem definately like the names to go with.