163 lines
4.2 KiB
Haskell
163 lines
4.2 KiB
Haskell
{-# LANGUAGE BangPatterns #-}
|
|
module Shape
|
|
( module Shape.Data
|
|
, translateSH
|
|
, emptySH
|
|
, upperPrismPoly
|
|
, upperPrismPolyHalf
|
|
, prismPoly
|
|
, polyCirc
|
|
, upperBox
|
|
, translateSHz
|
|
, translateSHf
|
|
, rotateSH
|
|
, rotateSHx
|
|
, polyCircx
|
|
, scaleSH
|
|
, colorSH
|
|
, overColSH
|
|
-- , overColSHM
|
|
, overPosSH
|
|
, upperCylinder
|
|
) where
|
|
import Geometry
|
|
import Shape.Data
|
|
import Color
|
|
|
|
singleShape :: Surface -> Shape
|
|
{-# INLINE singleShape #-}
|
|
singleShape = (:[])
|
|
|
|
shMap :: (Surface -> Surface) -> Shape -> Shape
|
|
{-# INLINE shMap #-}
|
|
shMap = map
|
|
|
|
emptySH :: Shape
|
|
{-# INLINE emptySH #-}
|
|
emptySH = mempty
|
|
|
|
-- - approximate a circle by a polygon with n*2 points of radius x
|
|
polyCirc :: Int -> Float -> [Point2]
|
|
{-# INLINE polyCirc #-}
|
|
polyCirc n x = map (\a -> rotateV a (V2 x 0)) $ take (n*2) [0,pi/fromIntegral n..]
|
|
|
|
-- - approximate a circle around the x axis by a polygon with n*2 points of radius r
|
|
polyCircx :: Int -> Float -> [Point3]
|
|
polyCircx n = map (vNormaly . addZ 0) . polyCirc n
|
|
|
|
-- very "unsafe": be careful with the inputs
|
|
-- length of polys must be the same
|
|
-- points should be correctly ordered so that
|
|
-- polys form a prism-like object with quad faces between them
|
|
prismPoly
|
|
:: [Point3]
|
|
-> [Point3]
|
|
-> Shape
|
|
{-# INLINE prismPoly #-}
|
|
prismPoly upps downps = singleShape (Surface (TopPrism n) (f upps downps) black)
|
|
where
|
|
n = length upps
|
|
f (a:as) (b:bs) = a:b:f as bs
|
|
f [] _ = []
|
|
f _ [] = []
|
|
|
|
upperPrismPoly
|
|
:: Float -- ^ height, expected to be strictly positive
|
|
-> [Point2]
|
|
-> Shape
|
|
{-# INLINE upperPrismPoly #-}
|
|
upperPrismPoly h ps = singleShape (Surface (TopPrism n) (f ps) black)
|
|
where
|
|
n = length ps
|
|
g h' (V2 x y) = V3 x y h'
|
|
f (x:xs) = g h x : g 0 x : f xs
|
|
f _ = []
|
|
|
|
upperBox
|
|
:: Float -- ^ height, expected to be strictly positive
|
|
-> [Point2]
|
|
-> Shape
|
|
{-# INLINE upperBox #-}
|
|
upperBox h ps = singleShape (Surface (FlatFaces n) (f ps) white)
|
|
where
|
|
n = length ps
|
|
g h' (V2 x y) = V3 x y h'
|
|
f (x:xs) = g h x : g 0 x : f xs
|
|
f _ = []
|
|
|
|
upperCylinder
|
|
:: Float -- ^ height, expected to be strictly positive
|
|
-> [Point2]
|
|
-> Shape
|
|
{-# INLINE upperCylinder #-}
|
|
upperCylinder h ps = singleShape (Surface (RoundedFaces n) (addZ h cc:addZ 0 cc:f ps) black)
|
|
where
|
|
cc = centroid ps
|
|
n = length ps
|
|
g h' (V2 x y) = V3 x y h'
|
|
f (x:xs) = g h x : g 0 x : f xs
|
|
f _ = []
|
|
|
|
upperPrismPolyHalf
|
|
:: Float -- ^ height, expected to be strictly positive
|
|
-> [Point2]
|
|
-> Shape
|
|
{-# INLINE upperPrismPolyHalf #-}
|
|
upperPrismPolyHalf h ps = singleShape (Surface (TopPrism n) (f upps downps) black)
|
|
where
|
|
n = length ps
|
|
upps = map f' ps
|
|
downps = map f'' ps
|
|
f (a:as) (b:bs) = a:b:f as bs
|
|
f _ _ = []
|
|
f' (V2 x y) = (V3 (0.5 * x) (0.5 * y) h)
|
|
f'' (V2 x y) = (V3 x y 0)
|
|
|
|
colorSH :: Color -> Shape -> Shape
|
|
{-# INLINE colorSH #-}
|
|
colorSH = overColSH . const
|
|
|
|
overColSH :: (Point4 -> Point4) -> Shape -> Shape
|
|
{-# INLINE overColSH #-}
|
|
overColSH = shMap . overColObj
|
|
|
|
translateSH :: Point3 -> Shape -> Shape
|
|
{-# INLINE translateSH #-}
|
|
translateSH !p = overPosSH (+.+.+ p)
|
|
|
|
translateSHf :: Float -> Float -> Shape -> Shape
|
|
{-# INLINE translateSHf #-}
|
|
translateSHf !x !y = translateSH (V3 x y 0)
|
|
|
|
translateSHz :: Float -> Shape -> Shape
|
|
{-# INLINE translateSHz #-}
|
|
translateSHz !z = translateSH (V3 0 0 z)
|
|
|
|
rotateSH :: Float -> Shape -> Shape
|
|
{-# INLINE rotateSH #-}
|
|
rotateSH = overPosSH . rotate3
|
|
|
|
overPosSH :: (Point3 -> Point3) -> Shape -> Shape
|
|
{-# INLINEABLE overPosSH #-}
|
|
overPosSH = shMap . overPosObj
|
|
|
|
rotateSHx :: Float -> Shape -> Shape
|
|
{-# INLINE rotateSHx #-}
|
|
rotateSHx a = overPosSH (rotate3x a)
|
|
|
|
scaleSH :: Point3 -> Shape -> Shape
|
|
{-# INLINE scaleSH #-}
|
|
scaleSH (V3 a b c) = overPosSH (\(V3 x y z) -> V3 (x*a) (y*b) (z*c))
|
|
|
|
overColObj :: (Point4 -> Point4) -> Surface -> Surface
|
|
{-# INLINE overColObj #-}
|
|
overColObj f (Surface st vs col) = Surface st vs (f col)
|
|
|
|
--overColObjM :: Monad m => (Point4 -> m Point4) -> ShapeObj -> m ShapeObj
|
|
--{-# INLINE overColObjM #-}
|
|
--overColObjM f (ShapeObj st vs) = ShapeObj st <$> mapM (svCol f) vs
|
|
|
|
overPosObj :: (Point3 -> Point3) -> Surface -> Surface
|
|
{-# INLINE overPosObj #-}
|
|
overPosObj f (Surface st vs col) = Surface st (map f vs) col
|