patternMinor
Ray→plane and ray→quad intersection
Viewed 0 times
rayplaneintersectionandquad
Problem
This checks the intersection between a
Please, analyze if:
-
(Most importantly) I'm using instances correctly (I'm suspect something is wrong with the amount of instances on the types).
-
My design of types is correct and linguistic.
-
My code is comprehensible.
-
If I did something stupid in general.
Ray and a Plane and between a Ray and a Quad (in 3D):import Linear
data Ray a = Ray {rayPos :: V3 a, rayDir :: V3 a}
data Plane a = Plane {planePos :: V3 a, planeNorm :: V3 a}
type Quad a = V4 (V3 a)
hitPlane :: (Num a, Fractional a) => Ray a -> Plane a -> V3 a
hitPlane (Ray rPos rDir) (Plane pPos pNorm) = rPos + dot (pPos - rPos) pNorm / dot rDir pNorm *^ rDir
hitQuad :: (Ord a, Epsilon a, Num a, Floating a) => Ray a -> Quad a -> Maybe (V3 a)
hitQuad ray (quad@(V4 a b c d)) = if hitInsideQuad then Just hitPoint else Nothing
where hitInsideQuad = insideQuad hitPoint quad
planeNormal = cross (b - a) (d - a)
hitPoint = hitPlane ray (Plane a planeNormal)
insideQuad :: (Num a, Ord a) => V3 a -> Quad a -> Bool
insideQuad pos (V4 a b c d) = all inside borders where
borders = [(a,b),(b,c),(c,d),(d,a)]
inside (a,b) = dot (b - a) (pos - a) > 0Please, analyze if:
-
(Most importantly) I'm using instances correctly (I'm suspect something is wrong with the amount of instances on the types).
-
My design of types is correct and linguistic.
-
My code is comprehensible.
-
If I did something stupid in general.
Solution
I'll preface this by saying that I'm not a Haskell programmer, so take my comments advisedly.
-
I would appreciate a short comment specifying the behaviour of each type and function. For example:
This allows a reader to quickly understand the purpose of a function without having to read the code to find out. Also it provides a specification that can be checked against the implementation.
-
In geometry the term ray usually refers to the half-line with a starting point and direction. So a ray does not necessarily hit a plane, and the type of
If you intend your
-
I don't understand all the details of the class constraints.
-
-
Some of the helper functions could be usefully made into top-level functions. For example, the implementation of
-
I would appreciate a short comment specifying the behaviour of each type and function. For example:
-- The point of intersection between a ray and a plane.
hitPlane :: (Fractional a) => Ray a -> Plane a -> V3 aThis allows a reader to quickly understand the purpose of a function without having to read the code to find out. Also it provides a specification that can be checked against the implementation.
-
In geometry the term ray usually refers to the half-line with a starting point and direction. So a ray does not necessarily hit a plane, and the type of
hitPlane ought to be:hitPlane :: (RealFrac a) => Ray a -> Plane a -> Maybe (V3 a)If you intend your
Ray type to be a full line, then it ought to be called Line instead, to avoid confusion. But even a full line might not have a point of intersection with a plane, because it might be parallel to the plane. In this case there will be a division by zero error: it would be better to avoid this and return Nothing.-
I don't understand all the details of the class constraints.
hitPlane requires both Num a and Fractional a but if I understand the standard Haskell type documentation, the latter implies the former, so the Num a is redundant. Similarly for hitQuad, where Num a is redundant given that you have Floating a.-
hitQuad requires Epsilon a and Floating a, but I don't see how either of these classes is necessary. I would have expected just Ord a, Fractional a, and this combination is the same as RealFrac a.-
Some of the helper functions could be usefully made into top-level functions. For example, the implementation of
hitQuad finds the plane containing a triangle of points. But this operation is generally useful:-- The plane containing three points, with a normal chosen so that
-- the points are clockwise when looking in the normal direction.
planeContaining :: (Num a) => (V3 a, V3 a, V3 a) -> Plane a
planeContaining (a, b, c) = Plane a (cross (b - a) (c - a))Code Snippets
-- The point of intersection between a ray and a plane.
hitPlane :: (Fractional a) => Ray a -> Plane a -> V3 ahitPlane :: (RealFrac a) => Ray a -> Plane a -> Maybe (V3 a)-- The plane containing three points, with a normal chosen so that
-- the points are clockwise when looking in the normal direction.
planeContaining :: (Num a) => (V3 a, V3 a, V3 a) -> Plane a
planeContaining (a, b, c) = Plane a (cross (b - a) (c - a))Context
StackExchange Code Review Q#77336, answer score: 3
Revisions (0)
No revisions yet.