elm-geometry icon indicating copy to clipboard operation
elm-geometry copied to clipboard

Add function to find Direction3d perpendicular to two other Direction3ds

Open MartinSStewart opened this issue 4 years ago • 8 comments

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.

MartinSStewart avatar Jan 16 '20 13:01 MartinSStewart

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:

  • Return Nothing:
    • Makes sense if thought of as a cross product
    • Safest since it forces the user to explicitly handle that case
  • Return an arbitrary perpendicular direction (fall back to calling perpendicularTo on one of the directions):
    • Allows the function to return a Direction3d instead of a Maybe Direction3d
    • Consistent with perpendicularTo
    • Reasonably defensible because the result will in fact be a direction perpendicular to both inputs

Thoughts?

ianmackenzie avatar Jan 16 '20 14:01 ianmackenzie

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.

ianmackenzie avatar Jan 16 '20 14:01 ianmackenzie

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

MartinSStewart avatar Jan 16 '20 14:01 MartinSStewart

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 avatar Jan 16 '20 15:01 ianmackenzie

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

ianmackenzie avatar Jan 16 '20 15:01 ianmackenzie

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)

MartinSStewart avatar Jan 16 '20 15:01 MartinSStewart

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 avatar Jan 16 '20 15:01 ianmackenzie

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.

ianmackenzie avatar Jan 16 '20 16:01 ianmackenzie