implicit (empty) → 0.0.0
raw patch · 13 files changed
+1821/−0 lines, 13 filesdep +basedep +containersdep +hashmapsetup-changed
Dependencies added: base, containers, hashmap, parallel, parsec
Files
- Graphics/Implicit.hs +39/−0
- Graphics/Implicit/Definitions.hs +30/−0
- Graphics/Implicit/Export.hs +178/−0
- Graphics/Implicit/ExtOpenScad.hs +193/−0
- Graphics/Implicit/MathUtil.hs +61/−0
- Graphics/Implicit/Operations.hs +130/−0
- Graphics/Implicit/Primitives.hs +102/−0
- Graphics/Implicit/SaneOperators.hs +160/−0
- Graphics/Implicit/Tracing.hs +137/−0
- Graphics/Implicit/Tracing/GetTriangles.hs +416/−0
- LICENSE +339/−0
- Setup.hs +2/−0
- implicit.cabal +34/−0
+ Graphics/Implicit.hs view
@@ -0,0 +1,39 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++{- The sole purpose of this file it to pass on the + functionality we want to be accessible to the end user. -}++module Graphics.Implicit(+ -- Operations+ translate, + scale,+ complement,+ union, intersect, difference,+ unionR, intersectR, differenceR,+ shell,+ slice,+ bubble,+ extrude,+ extrudeR,+ extrudeOnEdgeOf,+ -- Primitives+ sphere,+ cube,+ circle,+ cylinder,+ square,+ regularPolygon,+ zsurface,+ polygon,+ --ellipse,+ -- Export+ writeSVG,+ writeSTL+) where++import Graphics.Implicit.Definitions+import Graphics.Implicit.Primitives+import Graphics.Implicit.Operations+import Graphics.Implicit.Export+
+ Graphics/Implicit/Definitions.hs view
@@ -0,0 +1,30 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++module Graphics.Implicit.Definitions where++-- Let's make things a bit nicer. +-- Following math notation ℝ, ℝ², ℝ³...+type ℝ = Float+type ℝ2 = (ℝ,ℝ)+type ℝ3 = (ℝ,ℝ,ℝ)++type ℕ = Int++-- | A chain of line segments, as in SVG+-- eg. [(0,0), (0.5,1), (1,0)] ---> /\+type Polyline = [ℝ2]++-- $ In Implicit CAD, we consider objects as functions+-- of `outwardness'. The boundary is 0, negative is the+-- interior and positive the exterior. The magnitude is+-- how far out or in.++-- | A 2D object+type Obj2 = (ℝ2 -> ℝ)++-- | A 3D object+type Obj3 = (ℝ3 -> ℝ)+++
+ Graphics/Implicit/Export.hs view
@@ -0,0 +1,178 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++module Graphics.Implicit.Export where++import Graphics.Implicit.Definitions+import Graphics.Implicit.Tracing+import System.IO+++renderRaw :: ℝ3 -> ℝ3 -> ℝ -> String -> Obj3 -> IO()+renderRaw (x1, y1, z1) (x2, y2, z2) res name obj = + -- A hacky way to encode to chars, but it will do+ let convert n = if n > 1 then 'a' else if n > 0.5 then 'b' else if n > 0.1 then 'c' else if n == 0 then 'd' else if n > -0.5 then 'e' else 'd' in+ do+ putStrLn $ show $ length $ [ obj (x,y,z) | x <- [x1, x1+res.. x2], y <- [y1, y1+res.. y2], z <- [z1, z1+res.. z2] ]+ out <- openFile name WriteMode+ mapM_ ( (hPutChar out) . convert) $ + [ obj (x,y,z) | x <- [x1, x1+res.. x2], y <- [y1, y1+res.. y2], z <- [z1, z1+res.. z2] ]+ hClose out++renderRaw2D :: ℝ2 -> ℝ2 -> ℝ -> String -> Obj2 -> IO()+renderRaw2D (x1, y1) (x2, y2) res name obj = + -- A hacky way to encode to chars, but it will do+ let convert n = if n > 1 then 'a' else if n > 0.5 then 'b' else if n > 0.1 then 'c' else if n == 0 then 'd' else if n > -0.5 then 'e' else 'd' in+ do+ putStrLn $ show $ length $ [x1, x1+res.. x2]+ putStrLn $ show $ length $ [ obj (x,y) | x <- [x1, x1+res.. x2], y <- [y1, y1+res.. y2] ]+ out <- openFile name WriteMode+ mapM_ (mapM_ ( (hPutChar out) . convert)) $ + [[ obj (x,y) | x <- [x1, x1+res.. x2] ] | y <- [y1, y1+res.. y2] ]+ hClose out++-- | Write an SVG of a 2D object+writeSVG :: + ℝ2 -- ^ lower corner of bounding box+ -> ℝ2 -- ^ upper corner of bounding box+ -> ℝ -- ^ resolution of rendering+ -> String -- ^ Filename to write SVG to+ -> Obj2 -- ^ 2D object to render as SVG+ -> IO () -- ^ Resulting IO action that will write SVG++writeSVG (x1,y1) (x2,y2) d name obj = + let + -- Note that 0,0 is the upper right hand corner and that positive is down+ grid = [(obj (x,-y), obj (x+d,-y), obj (x+d,-(y+d)), obj (x,-(y+d)), obj (x+d/2,-(y+d/2)) , (x-x1,y-y1), d ) | x <- [x1, x1+d.. x2], y <- [y1, y1 +d.. y2] ]+ multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLines $ concat $ map getLineSeg grid+ svglines = concat $ map (\line -> + " <polyline points=\"" + ++ concat (map (\(x,y) -> " " ++ show x ++ "," ++ show y) line)+ ++ "\" style=\"stroke:rgb(0,0,255);stroke-width:1;fill:none;\"/> \n" ) + multilines + text = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"> \n" + ++ svglines + ++ "</svg> "+ in do + writeFile name text++-- | Write an SVG of a 2D object (uses parallel algorithms)+writeSVG2 :: + ℝ2 -- ^ lower corner of bounding box+ -> ℝ2 -- ^ upper corner of bounding box+ -> ℝ -- ^ resolution of rendering+ -> String -- ^ Filename to write SVG to+ -> Obj2 -- ^ 2D object to render as SVG+ -> IO () -- ^ Resulting IO action that will write SVG++writeSVG2 (x1,y1) (x2,y2) d name obj = + let + grid = [[getLineSeg (obj (x,-y), obj (x+d,-y), obj (x+d,-(y+d)), obj (x,-(y+d)), obj (x+d/2,-(y+d/2)) , (x-x1,y-y1), d ) | x <- [x1, x1+d.. x2]] | y <- [y1, y1 +d.. y2] ]+ multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLinesP grid+ svglines = concat $ map (\line -> + " <polyline points=\"" + ++ concat (map (\(x,y) -> " " ++ show x ++ "," ++ show y) line)+ ++ "\" style=\"stroke:rgb(0,0,255);stroke-width:1;fill:none;\"/> \n" ) + multilines + text = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"> \n" + ++ svglines + ++ "</svg> "+ in do + writeFile name text++++writeGCode :: + ℝ2 -- ^ lower corner of bounding box+ -> ℝ2 -- ^ upper corner of bounding box+ -> ℝ -- ^ resolution of rendering+ -> FilePath -- ^ Filename to write gcode to+ -> Obj2 -- ^ 2D object to make gcode for+ -> IO () -- ^ Resulting IO action that will write gcode++writeGCode (x1,y1) (x2,y2) d name obj = + let + multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLines $ concat $ map getLineSeg [(obj (x,y), obj (x+d,y), obj (x+d,y+d), obj (x,y+d), obj (x+d/2,y+d/2) , (x,y), d ) | x <- [x1, x1+d.. x2], y <- [y1, y1 +d.. y2] ]+ gcodeHeader = "(generated by ImplicitCAD)\nM3\nG21 (units=mm)\nG00 Z5.0 (tool is off)\n\n"+ gcodeFooter = "\n%\n"+ gcodeXY :: ℝ2 -> [Char]+ gcodeXY (x,y) = "X"++ show x ++" Y"++ show y + interpretPolyline (start:next:others) = + "G00 "++ gcodeXY start ++ "\n"+ ++ "G01 Z-1.0 F100.0\n"+ ++ "G01 " ++ gcodeXY next ++ " Z-1.0 F400.0\n"+ ++ concat (map (\p -> "G01 " ++ (gcodeXY p) ++ " Z-1.0\n") others)+ ++ "G00 Z5.0\n\n"+ text = gcodeHeader+ ++ (concat $ map interpretPolyline multilines)+ ++ gcodeFooter+ in do + writeFile name text++writeGCodeHacklabLaser :: + ℝ2 -- ^ lower corner of bounding box+ -> ℝ2 -- ^ upper corner of bounding box+ -> ℝ -- ^ resolution of rendering+ -> FilePath -- ^ Filename to write gcode to+ -> Obj2 -- ^ 2D object to make gcode for+ -> IO () -- ^ Resulting IO action that will write gcode++writeGCodeHacklabLaser (x1,y1) (x2,y2) d name obj = + let + multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLines $ concat $ map getLineSeg [(obj (x,y), obj (x+d,y), obj (x+d,y+d), obj (x,y+d), obj (x+d/2,y+d/2) , (x,y), d ) | x <- [x1, x1+d.. x2], y <- [y1, y1 +d.. y2] ]+ gcodeHeader = + "(generated by ImplicitCAD, based of hacklab wiki example)\n"+ ++"M63 P0 (laser off)\n"+ ++"G0 Z0.002 (laser off)\n"+ ++"G21 (units=mm)\n"+ ++"F400 (set feedrate)\n"+ ++"M3 S1 (enable laser)\n"+ ++"\n"+ gcodeFooter = + "M5 (disable laser)\n"+ ++"G00 X0.0 Y0.0 (move to 0)\n"+ ++"M2 (end)"+ gcodeXY :: ℝ2 -> [Char]+ gcodeXY (x,y) = "X"++ show x ++" Y"++ show y + interpretPolyline (start:others) = + "G00 "++ gcodeXY start ++ "\n"+ ++ "M62 P0 (laser on)\n"+ ++ concat (map (\p -> "G01 " ++ (gcodeXY p) ++ "\n") others)+ ++ "M63 P0 (laser off)\n\n"+ text = gcodeHeader+ ++ (concat $ map interpretPolyline multilines)+ ++ gcodeFooter+ in do + writeFile name text+++writeSTL :: + ℝ3 -- ^ Lower corner of (3D) bounding box+ -> ℝ3 -- ^ Upper corner of bounding box+ -> ℝ -- ^ resolution of rendering+ -> FilePath -- ^ Name of file to write STL to+ -> Obj3 -- ^ 3D object to make STL for+ -> IO() -- ^ Resulting IO action that will write STL+writeSTL (x1,y1,z1) (x2,y2,z2) d name obj =+ let+ grid3d = [((obj(x,y,z), obj(x+d,y,z), obj(x,y+d,z), obj(x+d,y+d,z), obj(x,y,z+d), obj(x+d,y,z+d), obj(x,y+d,z+d), obj(x+d,y+d,z+d)), (x,y,z), d )| x <- [x1, x1+d.. x2], y <- [y1, y1 +d.. y2], z <- [z1, z1+d.. z2] ]+ triangles = concat $ map getTriangles grid3d+ stlHeader = "solid ImplictCADExport\n"+ stlFooter = "endsolid ImplictCADExport\n"+ vertex :: ℝ3 -> String+ vertex (x,y,z) = "vertex " ++ show x ++ " " ++ show y ++ " " ++ show z+ stlTriangle :: (ℝ3, ℝ3, ℝ3) -> String+ stlTriangle (a,b,c) =+ "facet normal 0 0 0\n"+ ++ "outer loop\n"+ ++ vertex a ++ "\n"+ ++ vertex b ++ "\n"+ ++ vertex c ++ "\n"+ ++ "endloop\n"+ ++ "endfacet\n"+ text = stlHeader+ ++ (concat $ map stlTriangle triangles)+ ++ stlFooter+ in do + writeFile name text+
+ Graphics/Implicit/ExtOpenScad.hs view
@@ -0,0 +1,193 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++-- We'd like to parse openscad code, with some improvements, for backwards compatability.++module Graphics.Implicit.ExtOpenScad where++import Prelude hiding (lookup)+import Graphics.Implicit.Definitions+import Data.Map hiding (map)+import Text.ParserCombinators.Parsec +import Text.ParserCombinators.Parsec.Expr+import Control.Monad (liftM)++type VariableLookup = Map String OpenscadObj++data OpenscadObj = OUndefined + | OBool Bool + | ONum ℝ+ | OList [OpenscadObj]+ | OString String+ | OFunc ( OpenscadObj -> OpenscadObj ) ++instance Show OpenscadObj where+ show OUndefined = "Undefined"+ show (OBool b) = show b+ show (ONum n) = show n+ show (OList l) = show l+ show (OString s) = show s+ show (OFunc f) = "<function>"++numericOFunc f = OFunc $ \oObj -> case oObj of+ ONum n -> ONum $ f n+ _ -> OUndefined++data Computation = + ControlStructure ( VariableLookup -> [Computation] -> ([Obj2], [Obj3], VariableLookup) ) [Computation]+ | Assignment (VariableLookup -> VariableLookup)+ | Object2 (VariableLookup -> Obj2)+ | Object3 (VariableLookup -> Obj3)+ | Include String++variableSymb = many1 (noneOf " ,|[]{}()*&^%$#@!~`'\"\\/;:.,<>?") <?> "variable"++variable :: GenParser Char st (VariableLookup -> OpenscadObj)+variable = liftM (\varstr -> \varlookup -> case lookup varstr varlookup of+ Nothing -> OUndefined+ Just a -> a )+ variableSymb+ + ++literal :: GenParser Char st (VariableLookup -> OpenscadObj)+literal = + try ( (string "true" >> return (\map -> OBool True) )+ <|> (string "false" >> return (\map -> OBool False) )+ <?> "boolean" )+ <|> try ( try (do+ a <- (many1 digit);+ char '.';+ b <- (many digit);+ return ( \map -> ONum ( read (a ++ "." ++ b) :: ℝ) );+ ) <|> (do+ a <- (many1 digit);+ return ( \map -> ONum ( read a :: ℝ) );+ ) <?> "number" )+ <|> try ( ( do+ string "\"";+ strlit <- many $ noneOf "\"\n";+ string "\"";+ return $ \map -> OString $ strlit;+ ) <?> "string" )+ <?> "literal"++-- space = oneOf " \t\n"++-- We represent the priority or 'fixity' of different types of expressions+-- by the Int argument++expression :: Int -> GenParser Char st (VariableLookup -> OpenscadObj)+expression 10 = (try literal) <|> (try variable )+ <|> ((do+ string "(";+ many space;+ expr <- expression 0;+ many space;+ string ")";+ return expr;+ ) <?> "bracketed expression" )+ <|> ( ( do+ string "[";+ many space;+ exprs <- sepBy (expression 0) (many space >> char ',' >> many space);+ many space;+ string "]";+ return $ \varlookup -> OList (map ($varlookup) exprs )+ ) <?> "vector/list" )+expression 9 = ( try( do + f <- expression 10;+ string "(";+ many space;+ arg <- expression 0;+ many space;+ string ")";+ return $ \varlookup ->+ case f varlookup of+ OFunc actual_func -> actual_func (arg varlookup)+ _ -> OUndefined+ ) <?> "function appliation" )+ <|> try (expression 10)+expression n@8 = try (( do + a <- expression (n+1);+ string "^";+ b <- expression n;+ return $ \varlookup -> case (a varlookup, b varlookup) of+ (ONum na, ONum nb) -> ONum (na ** nb)+ _ -> OUndefined+ ) <?> "exponentiation")+ <|> try (expression $ n+1)+expression n@7 = try (expression $ n+1)+expression n@6 = + let + mult (ONum a) (ONum b) = ONum (a*b)+ mult (ONum a) (OList b) = OList (map (mult (ONum a)) b)+ mult (OList a) (ONum b) = OList (map (mult (ONum b)) a)+ mult _ _ = OUndefined++ div (ONum a) (ONum b) = ONum (a/b)+ div (OList a) (ONum b) = OList (map (\x -> div x (ONum b)) a)+ div _ _ = OUndefined+ in try (( do + exprs <- sepBy1 (sepBy (expression $ n+1) (char '/')) (char '*')+ return $ \varlookup -> foldl1 mult $ map ( (foldl1 div) . (map ($varlookup) ) ) exprs;+ ) <?> "multiplication/division")+ <|>try (expression $ n+1)+expression n@5 =+ let + append (OList a) (OList b) = OList $ a++b+ append (OString a) (OString b) = OString $ a++b+ append _ _ = OUndefined+ in try (( do + exprs <- sepBy1 (expression $ n+1) (string "++")+ return $ \varlookup -> foldl1 append $ map ($varlookup) exprs;+ ) <?> "append") + <|>try (expression $ n+1)++expression n@4 =+ let + add (ONum a) (ONum b) = ONum (a+b)+ add (OList a) (OList b) = OList $ zipWith add a b+ add _ _ = OUndefined++ sub (ONum a) (ONum b) = ONum (a-b)+ sub (OList a) (OList b) = OList $ zipWith sub a b+ sub _ _ = OUndefined+ in try (( do + exprs <- sepBy1 (sepBy (expression $ n+1) (char '-')) (char '+')+ return $ \varlookup -> foldl1 add $ map ( (foldl1 sub) . (map ($varlookup) ) ) exprs;+ ) <?> "addition/subtraction")+ <|>try (expression $ n+1)+expression n@3 = try (expression $ n+1)+expression n@2 = try (expression $ n+1)+expression n@1 = try (expression $ n+1)+expression n@0 = try (expression $ n+1)++++testParse str = case parse (expression 0) "" str of+ Right res -> show $ res + (fromList [("sin", numericOFunc sin)] )+ Left err -> show err+++assigmentStatement = do+ var <- variableSymb+ many space+ char '='+ many space+ val <- expression 0+ return $ Assignment (\varlookup -> insert var (val varlookup) varlookup)++{-ifStatement = do+ string "if"+ many space+ char '('+ condition <- expression 0+ char ')'+ many space+ trueCase <- computationStatement-}+ ++computationStatement = assigmentStatement+
+ Graphics/Implicit/MathUtil.hs view
@@ -0,0 +1,61 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++module Graphics.Implicit.MathUtil (rmax, rmin, rmaximum, rminimum) where++import Data.List+import Graphics.Implicit.Definitions++-- | Rounded Maximum+-- Consider max(x,y) = 0, the generated curve +-- has a square-like corner. We replace it with a +-- quarter of a circle+rmax :: + ℝ -- ^ radius+ -> ℝ -- ^ first number to round maximum+ -> ℝ -- ^ second number to round maximum+ -> ℝ -- ^ resulting number+rmax r x y = if abs (x-y) < r + then y - r*sin(pi/4-asin((x-y)/r/sqrt 2)) + r+ else max x y++-- | Rounded minimum+rmin :: + ℝ -- ^ radius+ -> ℝ -- ^ first number to round minimum+ -> ℝ -- ^ second number to round minimum+ -> ℝ -- ^ resulting number+rmin r x y = if abs (x-y) < r + then y + r*sin(pi/4+asin((x-y)/r/sqrt 2)) - r+ else min x y++-- | Like rmax, but on a list instead of two.+-- Just as maximum is.+-- The implementation is to take the maximum two+-- and rmax those.++rmaximum ::+ ℝ -- ^ radius+ -> [ℝ] -- ^ numbers to take round maximum+ -> ℝ -- ^ resulting number+rmaximum _ (a:[]) = a+rmaximum r (a:b:[]) = rmax r a b+rmaximum r l = + let+ tops = reverse $ sort l+ in+ rmax r (tops !! 0) (tops !! 1)++-- | Like rmin but on a list.+rminimum ::+ ℝ -- ^ radius+ -> [ℝ] -- ^ numbers to take round minimum+ -> ℝ -- ^ resulting number+rminimum r (a:[]) = a+rminimum r (a:b:[]) = rmin r a b+rminimum r l = + let+ tops = sort l+ in+ rmin r (tops !! 0) (tops !! 1)+
+ Graphics/Implicit/Operations.hs view
@@ -0,0 +1,130 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}++module Graphics.Implicit.Operations (+ translate, + scale,+ complement,+ union, intersect, difference,+ unionR, intersectR, differenceR,+ shell,+ slice,+ bubble,+ extrude,+ extrudeR,+ extrudeOnEdgeOf+) where++import Prelude hiding ((+),(-),(*),(/))+import Graphics.Implicit.Definitions+import Graphics.Implicit.MathUtil+import Graphics.Implicit.SaneOperators+++-- | Translate an object by a vector of appropriate dimension. +translate :: + (Additive a a a, AdditiveInvertable a)+ => a -- ^ Vector to translate by (Also: a is a vector, blah, blah)+ -> (a -> ℝ) -- ^ Object to translate+ -> (a -> ℝ) -- ^ Resulting object+translate p obj = \q -> obj (q-p)++-- | Scale an object+scale :: (Multiplicative a ℝ a) => + ℝ -- ^ Amount to scale by+ -> (a -> ℝ) -- ^ Object to scale+ -> (a -> ℝ) -- ^ Resulting scaled object+scale s obj = \p -> s * obj (p/s)++complement :: + (a -> ℝ) -- ^ Object to complement+ -> (a -> ℝ) -- ^ Result+complement obj = \p -> - obj p++shell :: + ℝ -- ^ width of shell+ -> (a -> ℝ) -- ^ object to take shell of+ -> (a -> ℝ) -- ^ resulting shell+shell w a = \p -> abs (a p) - w/(2.0::ℝ)++-- | Rounded union+unionR :: + ℝ -- ^ The radius of rounding+ -> [a -> ℝ] -- ^ objects to union+ -> (a -> ℝ) -- ^ Resulting object+unionR r objs = \p -> rminimum r $ map ($p) objs++-- | Rounded minimum+intersectR :: + ℝ -- ^ The radius of rounding+ -> [a -> ℝ] -- ^ Objects to intersect+ -> (a -> ℝ) -- ^ Resulting object+intersectR r objs = \p -> rmaximum r $ map ($p) objs++-- | Rounded difference+differenceR :: + ℝ -- ^ The radius of rounding+ -> [a -> ℝ] -- ^ Objects to difference + -> (a -> ℝ) -- ^ Resulting object+differenceR r (x:xs) = \p -> rmaximum r $ (x p) :(map (negate . ($p)) xs)+++-- | Union a list of objects+union :: + [a -> ℝ] -- ^ List of objects to union+ -> (a -> ℝ) -- ^ The object resulting from the union+union objs = \p -> minimum $ map ($p) objs++-- | Intersect a list of objects+intersect :: + [a -> ℝ] -- ^ List of objects to intersect+ -> (a -> ℝ) -- ^ The object resulting from the intersection+intersect objs = \p -> maximum $ map ($p) objs++-- | Difference a list of objects+difference :: + [a -> ℝ] -- ^ List of objects to difference+ -> (a -> ℝ) -- ^ The object resulting from the difference+difference (obj:objs) = \p -> maximum $ map ($p) $ obj:(map complement objs)++-- | Slice a 3D objects at a given z value to make a 2D object.+slice :: + ℝ -- ^ z-level to cut at+ -> Obj3 -- ^ 3D object to slice from+ -> Obj2 -- ^ Resulting 2D object+slice z obj = \(a,b) -> obj (a,b,z)++-- | Bubble out a 2D object into a 3D one.+bubble :: ℝ -> Obj2 -> Obj3+bubble s obj = + let+ spsqrt n = signum n * sqrt (abs n)+ spsq n = signum n * n ** 2+ in+ \(x,y,z) -> spsqrt ( z ** 2 + s * obj (x,y) )++-- | Extrude a 2D object. (The extrusion goes into the z-plane)+extrude :: + ℝ -- ^ Length to extrude+ -> Obj2 -- ^ 2D object to extrude+ -> Obj3 -- ^ Resulting 3D object+extrude h obj = \(x,y,z) -> max (obj (x,y)) (abs (z + h/(2.0 :: ℝ )) - h)++-- | Rounded extrude. Instead of the extrude having a flat top or bottom, it is bevelled.+extrudeR ::+ ℝ -- ^ Radius of rounding+ -> ℝ -- ^ Length to extrude+ -> Obj2 -- ^ 2D object to extrude+ -> Obj3 -- ^ Resulting 3D object+extrudeR r h obj = \(x,y,z) -> rmax r (obj (x,y)) (abs (z + h/(2.0 :: ℝ)) - h)++-- | Create a 3D object by extruding a 2D object along the edge of another 2D object.+-- For example, extruding a circle on the edge of another circle would make a torus.+extrudeOnEdgeOf :: + Obj2 -- ^ Object to extrude+ -> Obj2 -- ^ Object to extrude along the edge of+ -> Obj3 -- ^ Resulting 3D object+extrudeOnEdgeOf a b = \(x,y,z) -> a (b (x,y), z) +
+ Graphics/Implicit/Primitives.hs view
@@ -0,0 +1,102 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++module Graphics.Implicit.Primitives (+ sphere,+ cube,+ circle,+ cylinder,+ square,+ regularPolygon,+ polygon,+ zsurface--,+ --ellipse+) where++import Graphics.Implicit.Definitions+import qualified Graphics.Implicit.SaneOperators as S++sphere :: + ℝ -- ^ Radius of the sphere+ -> Obj3 -- ^ Resulting sphere+sphere r = \(x,y,z) -> sqrt (x**2 + y**2 + z**2) - r++cube :: + ℝ -- ^ Width of the cube+ -> Obj3 -- ^ Resuting cube+cube l = \(x,y,z) -> (maximum $ map abs [x,y,z]) - l/2.0++cylinder :: + ℝ -- ^ Radius of the cylinder+ -> ℝ -- ^ Height of the cylinder+ -> Obj3 -- ^ Resulting cylinder+cylinder r h = \(x,y,z) -> max (sqrt(x^2+y^2) - r) (abs(z) - h)++circle :: + ℝ -- ^ radius of the circle+ -> Obj2 -- ^ resulting circle+circle r = \(x,y) -> sqrt (x**2 + y**2) - r++torus :: + ℝ -- ^ radius of the rotated circle of a torus+ -> ℝ -- ^ radius of the circle rotationaly extruded on of a torus+ -> Obj3 -- ^ resulting torus+torus r_main r_second = \(x,y,z) -> sqrt( ( sqrt (x^2 + y^2) - r_main )^2 + z^2 ) - r_second++--ellipse :: ℝ -> ℝ -> Obj2+--ellipse a b = \(x,y) ->+-- if a > b +-- then ellipse b a (y,x)+-- else sqrt ((b/a*x)* *2 + y**2) - a++square :: + ℝ -- ^ Width of the square+ -> Obj2 -- ^ Resulting square+square l = \(x,y) -> (maximum $ map abs [x,y]) - l/2.0++polygon :: + [ℝ2] -- ^ Verticies of the polygon+ -> Obj2 -- ^ Resulting polygon+polygon points = + let+ pairs = + [ (points !! n, points !! (mod (n+1) (length points) ) ) | n <- [0 .. (length points) - 1] ]+ isIn p@(p1,p2) = + let + crossing_points = + [x1 + (x2-x1)*y2/(y2-y1) |+ ((x1,y1), (x2,y2)) <- + map (\((a1,a2),(b1,b2)) -> ((a1-p1,a2-p2), (b1-p1,b2-p2)) ) pairs,+ ( (y2 < 0) && (y1 > 0) ) || ( (y2 > 0) && (y1 < 0) ) ]+ in + if odd $ length $ filter (>0) crossing_points then -1 else 1+ dist a@(a1,a2) b@(b1,b2) p@(p1,p2) =+ let+ ab = b S.- a+ nab = (1 / S.norm ab) S.* ab+ ap = p S.- a+ d = nab S.⋅ ap+ closest + | d < 0 = a+ | d > S.norm ab = b+ | otherwise = a S.+ d S.* nab+ in+ S.norm (closest S.- p)+ dists = \ p -> map (\(a,b) -> dist a b p) pairs+ in + \ p -> isIn p * minimum (dists p)++regularPolygon :: + ℕ -- ^ number of sides+ -> ℝ -- ^ radius+ -> Obj2 -- ^ resulting regular polygon+regularPolygon sides r = let sidesr = fromIntegral sides in+ \(x,y) -> maximum [ x*cos(2*pi*m/sidesr) + y*sin(2*pi*m/sidesr) | m <- [0.. sidesr -1]] - r +++zsurface :: + (ℝ2 -> ℝ) -- ^ Description of the height of the surface+ -> Obj3 -- ^ Resulting 3D object+zsurface f = \(x,y,z) -> f (x,y) - z++
+ Graphics/Implicit/SaneOperators.hs view
@@ -0,0 +1,160 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, TypeSynonymInstances, UndecidableInstances #-}++-- We're going to be working with vectors, etc, a lot.+-- I'd rather not have to break every stupid vector into+-- its components to add them or scale them...++module Graphics.Implicit.SaneOperators where++import qualified Prelude as P+import Prelude hiding ((+),(-),(*),(/))++import Graphics.Implicit.Definitions++-- * Num is too big a class and doesn't make sense for, say, vectors.++class Additive a b c | a b -> c where+ (+) :: a -> b -> c+ infixl 6 +++class Multiplicative a b c | a b -> c where+ (*) :: a -> b -> c+ infixl 7 *++class AdditiveInvertable a where+ additiveInverse :: a -> a++class MultiplicativeInvertable a where+ multiplicativeInverse :: a -> a++class Normable a where+ norm :: a -> ℝ++class InnerProductSpace a where+ (⋅) :: a -> a -> ℝ++-- * I should be able to create instances for all Num instances,+-- but Haskell's type checker doesn't seem to play nice with them.+++{-instance Num a => Additive a a a where+ a + b = a P.+ b++instance Num a => Multiplicative a a a where+ a * b = a P.* b++instance Num a => AdditiveInvertable a where+ additiveInverse a = negate a++instance Fractional a => MultiplicativeInvertable a where+ multiplicativeInverse a = 1 P./ a-}++-- So, we do this instead. :(++instance Additive ℝ ℝ ℝ where+ a + b = a P.+ b++instance Multiplicative ℝ ℝ ℝ where+ a * b = a P.* b++instance AdditiveInvertable ℝ where+ additiveInverse a = negate a++instance MultiplicativeInvertable ℝ where+ multiplicativeInverse a = 1 P./ a++instance Additive ℕ ℕ ℕ where+ a + b = a P.+ b++instance Multiplicative ℕ ℕ ℕ where+ a * b = a P.* b++instance AdditiveInvertable ℕ where+ additiveInverse a = negate a+++instance Additive ℝ ℕ ℝ where+ a + b = a P.+ (fromIntegral b)++instance Multiplicative ℝ ℕ ℝ where+ a * b = a P.* (fromIntegral b)++instance Additive ℕ ℝ ℝ where+ a + b = (fromIntegral a) P.+ b++instance Multiplicative ℕ ℝ ℝ where+ a * b = (fromIntegral a) P.* b+++(-) :: (Additive a b c) => (AdditiveInvertable b) => a -> b -> c+x - y = x + (additiveInverse y)+infixl 6 -++(/) :: (Multiplicative a b c) => (MultiplicativeInvertable b) => a -> b -> c+x / y = x * (multiplicativeInverse y)+infixl 7 /++++instance Additive ℝ2 ℝ2 ℝ2 where+ (x1, y1) + (x2, y2) = (x1+x2, y1+y2)++instance Additive ℝ3 ℝ3 ℝ3 where+ (x1, y1, z1) + (x2, y2, z2) = (x1+x2, y1+y2, z1+z2)++{-instance (Additive a b c, Additive d e f) => Additive (a,d) (b,e) (c,f) where+ (x1, y1) + (x2, y2) = (x1+x2, y1+y2)++instance (Additive a b c, Additive d e f, Additive g h i) => Additive (a,d,g) (b,e,h) (c,f,i) where+ (x1, y1, z1) + (x2, y2, z2) = (x1+x2, y1+y2, z1+z2)-}++instance Multiplicative ℝ ℝ2 ℝ2 where+ s * (x,y) = (s*x, s*y)++instance Multiplicative ℝ ℝ3 ℝ3 where+ s * (x,y,z) = (s*x, s*y, s*z)++instance AdditiveInvertable ℝ2 where+ additiveInverse (x, y) = (additiveInverse x, additiveInverse y)++instance AdditiveInvertable ℝ3 where+ additiveInverse (x, y, z) = (additiveInverse x, additiveInverse y, additiveInverse z)++{-instance (AdditiveInvertable a, AdditiveInvertable b) => AdditiveInvertable (a,b) where+ additiveInverse (x, y) = (additiveInverse x, additiveInverse y)++instance (AdditiveInvertable a, AdditiveInvertable b, AdditiveInvertable c) => AdditiveInvertable (a,b,c) where+ additiveInverse (x, y, z) = (additiveInverse x, additiveInverse y, additiveInverse z)-}++++instance (Additive a b c) => Additive (d -> a) (d -> b) (d -> c) where+ f + g = \p -> f p + g p++instance (Multiplicative a b c) => Multiplicative (d -> a) (d -> b) (d -> c) where+ f * g = \p -> f p * g p+++instance Normable ℝ where+ norm a = abs a++instance Normable ℝ2 where+ norm (a, b) = sqrt ((a**2) + (b**2))++instance Normable ℝ3 where+ norm (a, b, c) = sqrt ((a**2) + (b**2) + (c**2))++instance InnerProductSpace ℝ where+ x ⋅ y = x*y++instance InnerProductSpace ℝ2 where+ (a1, a2) ⋅ (b1, b2) = a1*b1 + a2*b2++instance InnerProductSpace ℝ3 where+ (a1, a2, a3) ⋅ (b1, b2, b3) = a1*b1 + a2*b2+a3*b3+++
+ Graphics/Implicit/Tracing.hs view
@@ -0,0 +1,137 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++module Graphics.Implicit.Tracing (+ getTriangles,+ getLineSeg,+ orderLines,+ orderLinesDC,+ orderLinesP,+ reducePolyline,+ polylineNotNull+) where++import Graphics.Implicit.Definitions+import Graphics.Implicit.Tracing.GetTriangles (getTriangles)++import Control.Parallel (par, pseq)++getLineSeg :: (ℝ,ℝ,ℝ,ℝ,ℝ,ℝ2,ℝ) -> [Polyline]+getLineSeg (x1y1,x2y1,x2y2,x1y2,c,(x,y),s) = + let + x1 = (x, y+s*x1y1/(x1y1-x1y2))+ x2 = (x+s, y+s*x2y1/(x2y1-x2y2))+ y1 = (x+s*x1y1/(x1y1-x2y1), y )+ y2 = (x+s*x1y2/(x1y2-x2y2), y+s)+ notPointLine (p1:p2:[]) = p1 /= p2+ in filter (notPointLine) $ case (x1y2 <= 0, x2y2 <= 0,+ x1y1 <= 0, x2y1 <= 0) of+ (True, True, + True, True) -> []+ (False, False,+ False, False) -> []+ (True, True, + False, False) -> [[x1, x2]]+ (False, False,+ True, True) -> [[x1, x2]]+ (False, True, + False, True) -> [[y1, y2]]+ (True, False,+ True, False) -> [[y1, y2]]+ (True, False,+ False, False) -> [[x1, y2]]+ (False, True, + True, True) -> [[x1, y2]]+ (True, True, + False, True) -> [[x1, y1]]+ (False, False,+ True, False) -> [[x1, y1]]+ (True, True, + True, False) -> [[x2, y1]]+ (False, False,+ False, True) -> [[x2, y1]]+ (True, False,+ True, True) -> [[x2, y2]]+ (False, True, + False, False) -> [[x2, y2]]+ (True, False,+ False, True) -> if c > 0+ then [[x1, y2], [x2, y1]]+ else [[x1, y1], [x2, y2]]+ (False, True, + True, False) -> if c <= 0+ then [[x1, y2], [x2, y1]]+ else [[x1, y1], [x2, y2]]+++++orderLines :: [Polyline] -> [Polyline]+orderLines [] = []+orderLines (present:remaining) =+ let+ findNext ((p3:ps):segs) = if p3 == last present then (Just (p3:ps), segs) else+ if last ps == last present then (Just (reverse $ p3:ps), segs) else+ case findNext segs of (res1,res2) -> (res1,(p3:ps):res2)+ findNext [] = (Nothing, [])+ in+ case findNext remaining of+ (Nothing, _) -> present:(orderLines remaining)+ (Just match, others) -> orderLines $ (present ++ tail match): others++reducePolyline ((x1,y1):(x2,y2):(x3,y3):others) = + if (x1,y1) == (x2,y2) then reducePolyline ((x2,y2):(x3,y3):others) else+ if abs ( (y2-y1)/(x2-x1) - (y3-y1)/(x3-x1) ) < 0.0001 + || ( (x2-x1) == 0 && (x3-x1) == 0 && (y2-y1)*(y3-y1) > 0)+ then reducePolyline ((x1,y1):(x3,y3):others)+ else (x1,y1) : reducePolyline ((x2,y2):(x3,y3):others)+reducePolyline ((x1,y1):(x2,y2):others) = + if (x1,y1) == (x2,y2) then reducePolyline ((x2,y2):others) else (x1,y1):(x2,y2):others+reducePolyline l = l++orderLinesDC :: [[[Polyline]]] -> [Polyline]+orderLinesDC segs =+ let+ halve l = splitAt (div (length l) 2) l+ splitOrder segs = case (\(x,y) -> (halve x, halve y)) $ unzip $ map (halve) segs of+ ((a,b),(c,d)) -> orderLinesDC a ++ orderLinesDC b ++ orderLinesDC c ++ orderLinesDC d+ in+ if (length segs < 5 || length (head segs) < 5 ) then concat $ concat segs else+ case (\(x,y) -> (halve x, halve y)) $ unzip $ map (halve) segs of+ ((a,b),(c,d)) ->orderLines $ + orderLinesDC a ++ orderLinesDC b ++ orderLinesDC c ++ orderLinesDC d++orderLinesP :: [[[Polyline]]] -> [Polyline]+orderLinesP segs =+ let+ halve l = splitAt (div (length l) 2) l+ splitOrder segs = case (\(x,y) -> (halve x, halve y)) $ unzip $ map (halve) segs of+ ((a,b),(c,d)) -> orderLinesDC a ++ orderLinesDC b ++ orderLinesDC c ++ orderLinesDC d+ -- force is frome real world haskell+ force xs = go xs `pseq` ()+ where go (_:xs) = go xs+ go [] = 1+ in+ if (length segs < 5 || length (head segs) < 5 ) then concat $ concat segs else+ case (\(x,y) -> (halve x, halve y)) $ unzip $ map (halve) segs of+ ((a,b),(c,d)) -> orderLines $ + let+ a' = orderLinesP a+ b' = orderLinesP b+ c' = orderLinesP c+ d' = orderLinesP d+ in (force a' `par` force b' `par` force c' `par` force d') `pseq` + (a' ++ b' ++ c' ++ d')+++polylineNotNull (a:l) = not (null l)+polylineNotNull [] = False++++{-getMesh (a1, a2, a3) (b1, b2, b3) d obj = + if abs (obj ( (a1 + b1)/2, (a2 + b2)/2, (a3 + b3)/2 )) > 2*d + then []+ else if maximum [ abs $ b1 - a1, abs $ b2 - a2, abs $ b3 - a3 ] < d + then getTriangles-}+
+ Graphics/Implicit/Tracing/GetTriangles.hs view
@@ -0,0 +1,416 @@+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)+-- Released under the GNU GPL, see LICENSE++module Graphics.Implicit.Tracing.GetTriangles (getTriangles) where++import Graphics.Implicit.Definitions+++-- This monstrosity of a function gives triangles to divde negative interior+-- regions and positive exterior ones inside a cube, based on its vertices.++-- It is based on the linearly-interpolated marching cubes algorithm.++getTriangles :: ((ℝ,ℝ,ℝ,ℝ,ℝ,ℝ,ℝ,ℝ),ℝ3,ℝ) -> [(ℝ3,ℝ3,ℝ3)]+getTriangles ((x1y1z1,x2y1z1,x1y2z1,x2y2z1,x1y1z2,x2y1z2,x1y2z2,x2y2z2), (x,y,z), d) =+ let+ --{- Linearly interpolated+ x1y1 = (x, y, z+d*x1y1z1/(x1y1z1-x1y1z2))+ x1y2 = (x, y+d, z+d*x1y2z1/(x1y2z1-x1y2z2))+ x2y1 = (x+d, y, z+d*x2y1z1/(x2y1z1-x2y1z2))+ x2y2 = (x+d, y+d, z+d*x2y2z1/(x2y2z1-x2y2z2))++ x1z1 = (x, y+d*x1y1z1/(x1y1z1-x1y2z1), z)+ x1z2 = (x, y+d*x1y1z2/(x1y1z2-x1y2z2), z+d)+ x2z1 = (x+d, y+d*x2y1z1/(x2y1z1-x2y2z1), z)+ x2z2 = (x+d, y+d*x2y1z2/(x2y1z2-x2y2z2), z+d)++ y1z1 = (x+d*x1y1z1/(x1y1z1-x2y1z1), y, z)+ y1z2 = (x+d*x1y1z2/(x1y1z2-x2y1z2), y, z+d)+ y2z1 = (x+d*x1y2z1/(x1y2z1-x2y2z1), y+d, z)+ y2z2 = (x+d*x1y2z2/(x1y2z2-x2y2z2), y+d, z+d)+ --}+++ {- Non-linearly interpolated+ x1y1 = (x, y, z+d/2)+ x1y2 = (x, y+d, z+d/2)+ x2y1 = (x+d, y, z+d/2)+ x2y2 = (x+d, y+d, z+d/2)++ x1z1 = (x, y+d/2, z)+ x1z2 = (x, y+d/2, z+d)+ x2z1 = (x+d, y+d/2, z)+ x2z2 = (x+d, y+d/2, z+d)++ y1z1 = (x+d/2, y, z)+ y1z2 = (x+d/2, y, z+d)+ y2z1 = (x+d/2, y+d,z)+ y2z2 = (x+d/2, y+d,z+d)+ --}++ -- Convenience function+ square a b c d = [(a,b,c),(d,a,c)]+ in case + -- whether the vertices are "in" or "out" form the topological + -- basis of our triangles constructions. We must consider every + -- possible case.++ -- We arrange the vertices in a human readable way++ -- BOTTOM LAYER TOP LAYER+ (x1y2z1<=0, x2y2z1<=0, x1y2z2<=0, x2y2z2<=0,+ x1y1z1<=0, x2y1z1<=0, x1y1z2<=0, x2y1z2<=0)+ of++ -- There are 256 cases to implement.+ -- Only about half are, but they're the most common ones.+ -- In practice, this has no issues redering reasonable objects.++ -- Uniform cases = empty+ (False,False, False,False,+ False,False, False,False) -> []++ (True, True, True, True,+ True, True, True, True ) -> []++ -- 2 uniform layers++ (True, True, False,False,+ True, True, False,False) -> square x1y1 x2y1 x2y2 x1y2++ (False,False, True, True,+ False,False, True, True ) -> square x1y1 x2y1 x2y2 x1y2++ (True, True, True, True,+ False,False, False,False) -> square x1z1 x2z1 x2z2 x1z2++ (False,False, False,False,+ True, True, True, True ) -> square x1z1 x2z1 x2z2 x1z2++ (False,True, False,True,+ False,True, False,True ) -> square y1z1 y2z1 y2z2 y1z2++ (True, False, True, False,+ True, False, True, False) -> square y1z1 y2z1 y2z2 y1z2+++ -- z single column++ (True, False, True, False,+ False,False, False,False) -> square x1z1 y2z1 y2z2 x1z2++ (False,True, False,True,+ False,False, False,False) -> square x2z1 y2z1 y2z2 x2z2++ (False,False, False,False,+ True, False, True, False) -> square x1z1 y1z1 y1z2 x1z2++ (False,False, False,False,+ False,True, False,True ) -> square y1z1 x2z1 x2z2 y1z2++ (False,True, False,True, + True, True, True, True ) -> square x1z1 y2z1 y2z2 x1z2++ (True, False, True, False,+ True, True, True, True ) -> square x2z1 y2z1 y2z2 x2z2++ (True, True, True, True, + False,True, False,True ) -> square x1z1 y1z1 y1z2 x1z2++ (True, True, True, True, + True, False, True, False) -> square y1z1 x2z1 x2z2 y1z2++ -- single y column++ (True, False, False,False,+ True, False, False,False) -> square x1y1 y1z1 y2z1 x1y2++ (False,True, False,False,+ False,True, False,False) -> square x2y1 y1z1 y2z1 x2y2++ (False,False, True, False,+ False,False, True, False) -> square x1y1 y1z2 y2z2 x1y2++ (False,False, False,True, + False,False, False,True ) -> square x2y1 y1z2 y2z2 x2y2++ (False,True, True, True,+ False,True, True, True) -> square x1y1 y1z1 y2z1 x1y2++ (True, False, True, True,+ True, False, True, True) -> square x2y1 y1z1 y2z1 x2y2++ (True, True, False, True,+ True, True, False, True) -> square x1y1 y1z2 y2z2 x1y2++ (True, True, True, False, + True, True, True, False) -> square x2y1 y1z2 y2z2 x2y2++ -- since x column++ (True, True, False,False,+ False,False, False,False) -> square x1y2 x1z1 x2z1 x2y2++ (False,False, False,False,+ True, True, False,False) -> square x1y1 x1z1 x2z1 x2y1++ (False,False, True, True,+ False,False, False,False) -> square x1y2 x1z2 x2z2 x2y2++ (False,False, False,False,+ False,False, True, True ) -> square x1y1 x1z2 x2z2 x2y1++ (False,False, True, True, + True, True, True, True ) -> square x1y2 x1z1 x2z1 x2y2++ (True, True, True, True, + False,False, True, True ) -> square x1y1 x1z1 x2z1 x2y1++ (True, True, False,False,+ True, True, True, True ) -> square x1y2 x1z2 x2z2 x2y2++ (True, True, True, True, + True, True, False,False) -> square x1y1 x1z2 x2z2 x2y1++ -- lone points++ (True, False, False,False,+ False,False, False,False) -> [(x1z1, y2z1, x1y2)]++ (False,True, False,False,+ False,False, False,False) -> [(x2z1, y2z1, x2y2)]++ (False,False, False,False,+ True, False, False,False) -> [(x1z1, y1z1, x1y1)]++ (False,False, False,False,+ False,True, False,False) -> [(x2z1, y1z1, x2y1)]++ (False,False, True, False,+ False,False, False,False) -> [(x1z2, y2z2, x1y2)]++ (False,False, False,True,+ False,False, False,False) -> [(x2z2, y2z2, x2y2)]++ (False,False, False,False,+ False,False, True, False) -> [(x1z2, y1z2, x1y1)]++ (False,False, False,False,+ False,False, False,True ) -> [(x2z2, y1z2, x2y1)]++ (False,True, True, True, + True, True, True, True ) -> [(x1z1, y2z1, x1y2)]++ (True, False, True, True, + True, True, True, True ) -> [(x2z1, y2z1, x2y2)]++ (True, True, True, True, + False,True, True, True ) -> [(x1z1, y1z1, x1y1)]++ (True, True, True, True, + True, False, True, True ) -> [(x2z1, y1z1, x2y1)]++ (True, True, False,True, + True, True, True, True ) -> [(x1z2, y2z2, x1y2)]++ (True, True, True, False,+ True, True, True, True ) -> [(x2z2, y2z2, x2y2)]++ (True, True, True, True, + True, True, False,True ) -> [(x1z2, y1z2, x1y1)]++ (True, True, True, True, + True, True, True, False) -> [(x2z2, y1z2, x2y1)]++ -- z flat + 1++ (False,False, True, False,+ False,False, True, True) -> [(x1y1,x2y1,x2z2), (x1y1,x2z2,y2z2), (x1y1,y2z2,x1y2)]++ (True, True, False,True,+ True, True, False,False) -> [(x1y1,x2y1,x2z2), (x1y1,x2z2,y2z2), (x1y1,y2z2,x1y2)]++ (False,False, False,True,+ False,False, True, True) -> [(x2y1,x1y1,x1z2), (x2y1,x1z2,y2z2), (x2y1,y2z2,x2y2)]++ (True, True, True, False,+ True, True, False,False) -> [(x2y1,x1y1,x1z2), (x2y1,x1z2,y2z2), (x2y1,y2z2,x2y2)]++ (False,False, True, True,+ False,False, True, False) -> [(x1y2,x2y2,x2z2), (x1y2,x2z2,y1z2), (x1y2,y1z2,x1y1)]++ (True, True, False,False,+ True, True, False,True ) -> [(x1y2,x2y2,x2z2), (x1y2,x2z2,y1z2), (x1y2,y1z2,x1y1)]++ (False,False, True, True,+ False,False, False,True) -> [(x2y2,x1y2,x1z2), (x2y2,x1z2,y1z2), (x2y2,y1z2,x2y1)]++ (True, True, False,False,+ True, True, True, False) -> [(x2y2,x1y2,x1z2), (x2y2,x1z2,y1z2), (x2y2,y1z2,x2y1)]++++ (True, False, False,False,+ True, True, False,False) -> [(x1y1,x2y1,x2z1), (x1y1,x2z1,y2z1), (x1y1,y2z1,x1y2)]++ (False,True, True, True,+ False,False, True, True) -> [(x1y1,x2y1,x2z1), (x1y1,x2z1,y2z1), (x1y1,y2z1,x1y2)]++ (False,True, False,False,+ True, True, False,False) -> [(x2y1,x1y1,x1z1), (x2y1,x1z1,y2z1), (x2y1,y2z1,x2y2)]++ (True, False, True, True,+ False,False, True, True) -> [(x2y1,x1y1,x1z1), (x2y1,x1z1,y2z1), (x2y1,y2z1,x2y2)]++ (True, True, False,False,+ True, False, False,False) -> [(x1y2,x2y2,x2z1), (x1y2,x2z1,y1z1), (x1y2,y1z1,x1y1)]++ (False,False, True, True,+ False,True, True, True) -> [(x1y2,x2y2,x2z1), (x1y2,x2z1,y1z1), (x1y2,y1z1,x1y1)]++ (True, True, False,False,+ False,True, False,False) -> [(x2y2,x1y2,x1z1), (x2y2,x1z1,y1z1), (x2y2,y1z1,x2y1)]++ (False,False, True, True,+ True, False, True, True) -> [(x2y2,x1y2,x1z1), (x2y2,x1z1,y1z1), (x2y2,y1z1,x2y1)]++ -- y flat + 1++ (True, False, True, True,+ True, False, True, False) -> [(y2z1,x2y2,x2z2),(y2z1,x2z2,y1z1),(y1z1,x2z2,y1z2)]++ (False,True, False,False,+ False,True, False,True ) -> [(y2z1,x2y2,x2z2),(y2z1,x2z2,y1z1),(y1z1,x2z2,y1z2)]++ (True, False, True, False,+ True, False, True, True ) -> [(y1z1,x2y1,x2z2),(y1z1,x2z2,y2z1),(y2z1,x2z2,y2z2)]++ (False,True, False,True,+ False,True, False,False) -> [(y1z1,x2y1,x2z2),(y1z1,x2z2,y2z1),(y2z1,x2z2,y2z2)]++ (False,True, True, True,+ False,True, False,True ) -> [(y2z1,x1y2,x1z2),(y2z1,x1z2,y1z1),(y1z1,x1z2,y1z2)]++ (True, False, False,False,+ True, False, True, False) -> [(y2z1,x1y2,x1z2),(y2z1,x1z2,y1z1),(y1z1,x1z2,y1z2)]++ (False,True, False,True,+ False,True, True, True ) -> [(y1z1,x1y1,x1z2),(y1z1,x1z2,y2z1),(y2z1,x1z2,y2z2)]++ (True, False, True, False,+ True, False, False,False) -> [(y1z1,x1y1,x1z2),(y1z1,x1z2,y2z1),(y2z1,x1z2,y2z2)]++++ (True, True, True, False,+ True, False, True, False) -> [(y2z2,x2y2,x2z1),(y2z2,x2z1,y1z2),(y1z2,x2z1,y1z1)]++ (False,False, False,True,+ False,True, False,True ) -> [(y2z2,x2y2,x2z1),(y2z2,x2z1,y1z2),(y1z2,x2z1,y1z1)]++ (True, False, True, False,+ True, True, True, False) -> [(y1z2,x2y1,x2z1),(y1z2,x2z1,y2z2),(y2z2,x2z1,y2z1)]++ (False,True, False,True,+ False,False, False,True) -> [(y1z2,x2y1,x2z1),(y1z2,x2z1,y2z2),(y2z2,x2z1,y2z1)]++ (True, True, False,True,+ False,True, False,True) -> [(y2z2,x1y2,x1z1),(y2z2,x1z1,y1z2),(y1z2,x1z1,y1z1)]++ (False,False, True, False,+ True, False, True, False) -> [(y2z2,x1y2,x1z1),(y2z2,x1z1,y1z2),(y1z2,x1z1,y1z1)]++ (False,True, False,True,+ True, True, False,True) -> [(y1z2,x1y1,x1z1),(y1z2,x1z1,y2z2),(y2z2,x1z1,y2z1)]++ (True, False, True, False,+ False,False, True, False) -> [(y1z2,x1y1,x1z1),(y1z2,x1z1,y2z2),(y2z2,x1z1,y2z1)]++++ -- x flat +1++ (True, True, True, True,+ False,False, True, False) -> [(x1z1,x2z1,x1y1),(x1y1,x2z1,x2z2),(x1y1,x2z2,y1z2)]++ (False,False, False,False,+ True, True, False,True ) -> [(x1z1,x2z1,x1y1),(x1y1,x2z1,x2z2),(x1y1,x2z2,y1z2)]++ (False,False, True, False,+ True, True, True, True) -> [(x1z1,x2z1,x1y2),(x1y2,x2z1,x2z2),(x1y2,x2z2,y2z2)]++ (True, True, False,True,+ False,False, False,False) -> [(x1z1,x2z1,x1y2),(x1y2,x2z1,x2z2),(x1y2,x2z2,y2z2)]++ (True, True, True, True,+ False,False, False,True) -> [(x2z1,x1z1,x2y1),(x2y1,x1z1,x1z2),(x2y1,x1z2,y1z2)]++ (False,False, False,False,+ True, True, True, False) -> [(x2z1,x1z1,x2y1),(x2y1,x1z1,x1z2),(x2y1,x1z2,y1z2)]++ (False,False, False,True,+ True, True, True, True) -> [(x2z1,x1z1,x2y2),(x2y2,x1z1,x1z2),(x2y2,x1z2,y2z2)]++ (True, True, True, False,+ False,False, False,False) -> [(x2z1,x1z1,x2y2),(x2y2,x1z1,x1z2),(x2y2,x1z2,y2z2)]+++ (True, True, True, True,+ True, False, False,False) -> [(x1z2,x2z2,x1y1),(x1y1,x2z2,x2z1),(x1y1,x2z1,y1z1)]++ (False,False, False,False,+ False,True, True, True ) -> [(x1z2,x2z2,x1y1),(x1y1,x2z2,x2z1),(x1y1,x2z1,y1z1)]++ (True, False, False,False,+ True, True, True, True ) -> [(x1z2,x2z2,x1y2),(x1y2,x2z2,x2z1),(x1y2,x2z1,y2z1)]++ (False,True, True, True,+ False,False, False,False) -> [(x1z2,x2z2,x1y2),(x1y2,x2z2,x2z1),(x1y2,x2z1,y2z1)]++ (True, True, True, True,+ False,True, False,False) -> [(x2z2,x1z2,x2y1),(x2y1,x1z2,x1z1),(x2y1,x1z1,y1z1)]++ (False,False, False,False,+ True, False, True, True) -> [(x2z2,x1z2,x2y1),(x2y1,x1z2,x1z1),(x2y1,x1z1,y1z1)]++ (False,True, False,False,+ True, True, True, True) -> [(x2z2,x1z2,x2y2),(x2y2,x1z2,x1z1),(x2y2,x1z1,y2z1)]++ (True, False, True, True,+ False,False, False,False) -> [(x2z2,x1z2,x2y2),(x2y2,x1z2,x1z1),(x2y2,x1z1,y2z1)]++++ (True, True, True, False,+ True, False, False,False) -> [(x1y1,x1z2,y1z1),(y1z1,x1z2,y2z2),(y1z1,y2z2,x2z1),(x2z1,y2z2,x2y2)]++ (False,False, False,True,+ False,True, True, True ) -> [(x1y1,x1z2,y1z1),(y1z1,x1z2,y2z2),(y1z1,y2z2,x2z1),(x2z1,y2z2,x2y2)]++ (True, True, False,True,+ False,True, False,False) -> [(x2y1,x2z2,y1z1),(y1z1,x2z2,y2z2),(y1z1,y2z2,x1z1),(x1z1,y2z2,x1y2)]++ (False,False, True, False,+ True, False, True, True ) -> [(x2y1,x2z2,y1z1),(y1z1,x2z2,y2z2),(y1z1,y2z2,x1z1),(x1z1,y2z2,x1y2)]+++++ (True, False, False,False,+ True, True, True, False) -> [(x1y2,x1z2,y2z1),(y2z1,x1z2,y1z2),(y2z1,y1z2,x2z1),(x2z1,y1z2,x2y1)]++ (False,True, True, True,+ False,False, False,True ) -> [(x1y2,x1z2,y2z1),(y2z1,x1z2,y1z2),(y2z1,y1z2,x2z1),(x2z1,y1z2,x2y1)]++ (False,True, False,False,+ True, True, False,True ) -> [(x2y2,x2z2,y2z1),(y2z1,x2z2,y1z2),(y2z1,y1z2,x1z1),(x1z1,y1z2,x1y1)]++ (True, False, True, True,+ False,False, True, False) -> [(x2y2,x2z2,y2z1),(y2z1,x2z2,y1z2),(y2z1,y1z2,x1z1),(x1z1,y1z2,x1y1)]+++++ _ -> []+
+ LICENSE view
@@ -0,0 +1,339 @@+ GNU GENERAL PUBLIC LICENSE+ Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The licenses for most software are designed to take away your+freedom to share and change it. By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users. This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it. (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.) You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++ To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have. You must make sure that they, too, receive or can get the+source code. And you must show them these terms so they know their+rights.++ We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++ Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software. If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++ Finally, any free program is threatened constantly by software+patents. We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary. To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++ The precise terms and conditions for copying, distribution and+modification follow.++ GNU GENERAL PUBLIC LICENSE+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++ 0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License. The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language. (Hereinafter, translation is included without limitation in+the term "modification".) Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope. The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++ 1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++ 2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++ a) You must cause the modified files to carry prominent notices+ stating that you changed the files and the date of any change.++ b) You must cause any work that you distribute or publish, that in+ whole or in part contains or is derived from the Program or any+ part thereof, to be licensed as a whole at no charge to all third+ parties under the terms of this License.++ c) If the modified program normally reads commands interactively+ when run, you must cause it, when started running for such+ interactive use in the most ordinary way, to print or display an+ announcement including an appropriate copyright notice and a+ notice that there is no warranty (or else, saying that you provide+ a warranty) and that users may redistribute the program under+ these conditions, and telling the user how to view a copy of this+ License. (Exception: if the Program itself is interactive but+ does not normally print such an announcement, your work based on+ the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole. If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works. But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++ 3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++ a) Accompany it with the complete corresponding machine-readable+ source code, which must be distributed under the terms of Sections+ 1 and 2 above on a medium customarily used for software interchange; or,++ b) Accompany it with a written offer, valid for at least three+ years, to give any third party, for a charge no more than your+ cost of physically performing source distribution, a complete+ machine-readable copy of the corresponding source code, to be+ distributed under the terms of Sections 1 and 2 above on a medium+ customarily used for software interchange; or,++ c) Accompany it with the information you received as to the offer+ to distribute corresponding source code. (This alternative is+ allowed only for noncommercial distribution and only if you+ received the program in object code or executable form with such+ an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it. For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable. However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++ 4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License. Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++ 5. You are not required to accept this License, since you have not+signed it. However, nothing else grants you permission to modify or+distribute the Program or its derivative works. These actions are+prohibited by law if you do not accept this License. Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++ 6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions. You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++ 7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all. For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices. Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++ 8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded. In such case, this License incorporates+the limitation as if written in the body of this License.++ 9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number. If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation. If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++ 10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission. For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this. Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++ NO WARRANTY++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Programs++ If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++ To do so, attach the following notices to the program. It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++ <one line to give the program's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This program is free software; you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation; either version 2 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License along+ with this program; if not, write to the Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++ Gnomovision version 69, Copyright (C) year name of author+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License. Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary. Here is a sample; alter the names:++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program+ `Gnomovision' (which makes passes at compilers) written by James Hacker.++ <signature of Ty Coon>, 1 April 1989+ Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs. If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library. If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ implicit.cabal view
@@ -0,0 +1,34 @@+Name: implicit+Version: 0.0.0+cabal-version: >= 1.6+Synopsis: Math-inspired programmatic 2&3D CAD: CSG, bevels, and shells; gcode export..+Description: A math-inspired programmatic CAD library in haskell.+ Build objects with constructive solid geometry, bevels,+ shells and more in 2D & 3D. Then export to SVGs, STLs, + or produce gcode directly!+License: GPL+License-file: LICENSE+Author: Christopher Olah+Maintainer: Christopher Olah <chris@colah.ca>+Homepage: https://github.com/colah/ImplicitCAD+build-type: Simple+Category: Graphics++Library+ Build-Depends: base >= 3 && < 5, parsec, hashmap, parallel, containers+ Exposed-Modules: + Graphics.Implicit+ Graphics.Implicit.Definitions+ Graphics.Implicit.Export+ Graphics.Implicit.ExtOpenScad+ Graphics.Implicit.MathUtil+ Graphics.Implicit.Operations+ Graphics.Implicit.Primitives+ Graphics.Implicit.SaneOperators+ Graphics.Implicit.Tracing+ Graphics.Implicit.Tracing.GetTriangles++source-repository head+ type: git+ location: https://github.com/colah/ImplicitCAD.git+