module Language.Cube (
ToSTL(..)
, Quaternion(..)
, Cube
, Block(..)
, smap
, block
, cube
, writeFileStl
, ds
, dx
, dy
, dz
, dr
, nCube
, surface'
, surface
, house
) where
import qualified Data.Serialize as C
import Data.Monoid
import qualified Data.Set as S
import qualified Data.ByteString.Lazy as BL
import Graphics.Formats.STL
class ToSTL a where
toSTL :: a -> STL
data Quaternion a = Quaternion {
us :: a
, ux :: a
, uy :: a
, uz :: a
} deriving (Show,Eq,Ord)
type Cube = Quaternion Int
instance (Num a) => Monoid (Quaternion a) where
mappend a b = a + b
mempty = Quaternion 0 0 0 0
instance (Num a) => Num (Quaternion a) where
(+) (Quaternion ax ay az ar) (Quaternion bx by bz br) =
Quaternion (ax+bx) (ay+by) (az+bz) (ar+br)
() (Quaternion ax ay az ar) (Quaternion bx by bz br) =
Quaternion (axbx) (ayby) (azbz) (arbr)
(*) (Quaternion a1 b1 c1 d1) (Quaternion a2 b2 c2 d2) =
Quaternion
(a1*a2b1*b2c1*c2d1*d2)
(a1*b2+b1*a2+c1*d2d1*c2)
(a1*c2b1*d2+c1*a2+d1*b2)
(a1*d2+b1*c2c1*b2+d1*a2)
abs (Quaternion ax ay az ar) = Quaternion (abs ax) (abs ay) (abs az) (abs ar)
signum (Quaternion ax ay az ar) = Quaternion (signum ax) (signum ay) (signum az) (signum ar)
fromInteger a = Quaternion (fromIntegral a) 0 0 0
data Block a =
Block {
units :: S.Set a
} deriving (Show,Eq,Ord)
instance (Ord a,Eq a,Num a) => Num (Block a) where
(+) (Block a) (Block b) = Block $ a <> b
() (Block a) (Block b) = Block $ (S.\\) a b
(*) (Block a) (Block b) = Block $ S.fromList $ do
au <- S.toList a
bu <- S.toList b
return (au + bu)
abs (Block a) = Block $ S.map abs a
signum (Block a) = Block $ S.map signum a
fromInteger a = Block $ S.singleton $ fromInteger a
smap :: (Ord a,Ord b) => (a -> b) -> Block a -> Block b
smap func (Block elems) = Block $ S.map func elems
block :: (Ord a) => [a] -> Block a
block elems = Block $ S.fromList elems
cube :: Int -> Int -> Int -> Cube
cube x y z = Quaternion 0 x y z
toCube :: [Int] -> Cube
toCube [s,a,b,c] = Quaternion s a b c
toCube [a,b,c] = cube a b c
toCube _ = error "toCube"
instance ToSTL (Quaternion Int) where
toSTL v = STL "" $ flip map tri2 $ \[t0,t1,t2] ->
Triangle Nothing (
ve (t0 + v),
ve (t1 + v),
ve (t2 + v))
where
ve (Quaternion _s a b c) = (fromIntegral a,fromIntegral b,fromIntegral c)
vec [a,b,c] =
case (ba)*(ca) + a of
Quaternion _s x y z | 0 <= x && x <=1 &&0 <= y && y <=1 && 0 <= z && z <=1 -> True
| otherwise -> False
vec _ = error "vec"
tri = [map toCube [a,b,c] |
a <- [[0,0,0],[0,1,1],[1,0,1],[1,1,0]],
b <- cube0,
c <- cube0,
dist a b == 1,
dist a c == 1,
dist b c == 2,
b < c ]
tri2 = map (\l@[a,b,c] -> if vec l then [a,c,b] else [a,b,c]) tri
cube0 = do
a <- [0,1]
b <- [0,1]
c <- [0,1]
return [a,b,c]
dist a b = sum $ map abs $ map (uncurry ()) $ zip a b
instance (ToSTL a) => ToSTL (Block a) where
toSTL (Block sets) = foldr (<>) mempty $ map toSTL $ S.toList sets
instance Monoid STL where
mappend (STL an at) (STL _bn bt) = STL an (at<>bt)
mempty = STL "emptry" []
instance (Ord a, Monoid a) => Monoid (Block a) where
mappend (Block a) (Block b) = Block (a<>b)
mempty = Block $ S.singleton mempty
writeFileStl :: ToSTL a => String -> a -> IO ()
writeFileStl filename stl = BL.writeFile filename $ C.encodeLazy $ toSTL stl
dz :: Cube
dz = Quaternion 0 0 0 1
dy :: Cube
dy = Quaternion 0 0 1 0
dx :: Cube
dx = Quaternion 0 1 0 0
ds :: Cube
ds = Quaternion 1 0 0 0
dr :: Float
-> Cube
-> Cube
dr theta (Quaternion _s x y z) = Quaternion (co 1) (si x) (si y) (si z)
where
co :: Int -> Int
co v = round $ cos theta * fromIntegral v
si :: Int -> Int
si v = round $ sin theta * fromIntegral v
nCube :: Int -> Block Cube
nCube n =
let lst = [0..(n1)]
in Block $ S.fromList [Quaternion 0 a b c | a <- lst,b <- lst,c <- lst]
surface' :: Block Cube -> Block Cube
surface' model = model * cube' model
where
cube' :: Block Cube
cube' = block $ [Quaternion 0 x y z| x<-[1..1], y<-[1..1], z<-[1..1]]
surface :: Block Cube -> Block Cube
surface model = model (model (surface' model) * cube2)
where
cube2 :: Block Cube
cube2 = block $ [Quaternion 0 x y z| x<-[2..2], y<-[2..2], z<-[2..2]]
house :: Block Cube
house = let house'' = (house' + square)*line
in smap (12 * dz +) $ surface house''
where
house' :: Block Cube
house' = block $ [Quaternion 0 1 x y| x<-[10..10], y<-[10..10], y < x , y < (x)]
square :: Block Cube
square = smap ((+) (12 * dz)) $ block $ [Quaternion 0 1 x y| x<-[5..5], y<-[5..5]]
line :: Block Cube
line = block $ [Quaternion 0 x 0 0 | x<-[5..5]]