ianmackenzie / elm-geometry

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

Add function to find Direction3d perpendicular to two other Direction3ds #125

Open MartinSStewart opened 4 years ago

MartinSStewart commented 4 years ago

I wasn't able to find a function with the following signature Direction3d c -> Direction3d c -> Maybe (Direction3d c) that finds a direction that's perpendicular to two other directions (aka the axis of rotation of those two directions).

This could be implemented as:

Vector3d.cross (Direction3d.toVector dir0) (Direction3d.toVector dir1) |> Vector3d.direction

This function is pretty simple but I think it's worth including because anyone who forgot what cross products do, will have trouble figuring out how to implement this (me included until @w0rm reminded me). Unfortunately, I'm not sure what's a good name for this function.

ianmackenzie commented 4 years ago

The simplest name and signature would probably be

Direction3d.cross : 
    Direction3d coordinates
    -> Direction3d coordinates
    -> Maybe (Direction3d coordinates)

but that doesn't help if you don't remember what cross products do! One option would be to call it perpendicularToBoth or perpendicularTo2 since it can be thought of as an extension of the existing perpendicularTo, but then it seems a little ambiguous what should happen if the two given directions are parallel:

Thoughts?

ianmackenzie commented 4 years ago

Side note: Vector3d.cross is designed to be used in pipeline form, so you would write

(Direction3d.toVector dir0) |> Vector3d.cross (Direction3d.toVector dir1)

instead of

Vector3d.cross (Direction3d.toVector dir0) (Direction3d.toVector dir1)

to get a right-handed cross product dir0 x dir1.

MartinSStewart commented 4 years ago

I think either perpendicularToBoth or perpendicularTo2 are good names though I'm not sure which I prefer. When trying to find this function, I looked for functions containing perpendicular or ortho so if it was named perpendicularToBoth or perpendicularTo2 then I would have found it.

I think it's best for it to return Nothing. For perpendicularTo it will consistently return an arbitrary perpendicular direction so it isn't a surprise. With this function it will only happen in an edge case so I think it's best that we force the user to handle that edge case by returning a Maybe.

Also thanks for the note about Vector3d.cross. I hadn't even thought about the handedness of the cross product (in my use case it doesn't matter at least).

Edit: I'm having second thoughts about my preference to return Maybe, Reasonably defensible because the result will in fact be a direction perpendicular to both inputs is a pretty good argument for falling back on perpendicularTo

ianmackenzie commented 4 years ago

Maybe it makes sense to have both the pure mathematical version and the convenient version:

Direction3d.cross :
    Direction3d coordinates
    -> Direction3d coordinates
    -> Maybe (Direction3d coordinates)

Direction3d.perpendicularToBoth :
    Direction3d coordinates
    -> Direction3d coordinates
    -> Direction3d coordinates
ianmackenzie commented 4 years ago

The one other thing to think about is whether it also makes sense to have a version for vectors, e.g.

Direction3d.perpendicularToTwoVectors :
    Vector3d coordinates
    -> Vector3d coordinates
    -> Direction3d coordinates
MartinSStewart commented 4 years ago

I think it’s best to just have the Direction3d.perpendicularToTwo for now. I’ve only had need for this once. While it is nice to have, I think having 3 versions of it might be too much (also I’ve changed my mind and think it should return Direction3d rather than Maybe)

ianmackenzie commented 4 years ago

Yeah, I'm not sure I'd add a vector version right away, but it would be nice to have a function name that could be naturally extended to a vector version in the future. For example Direction3d.perpendicularToBothVectors and Direction3d.perpendicularTo2Vectors both seem a bit weird to me; Direction3d.perpendicularToTwoVectors seems better but then Direction3d.perpendicularToTwo seems weird.

ianmackenzie commented 4 years ago

Actually yeah, maybe it's not worth worrying about a vector version - there's always Vector3d.cross, and (if I implement #126) Direction3d.orthonormalize2. I think I'm leaning towards Direction3d.perpendicularTo2 to emphasize that it's a pretty direct variant of Direction3d.perpendicularTo, but I might mull it over for a while.