diff --git a/Graphics/Implicit.hs b/Graphics/Implicit.hs
--- a/Graphics/Implicit.hs
+++ b/Graphics/Implicit.hs
@@ -22,6 +22,7 @@
 	rect3R,
 	circle,
 	cylinder,
+	cylinder2,
 	rectR,
 	--regularPolygon,
 	--zsurface,
@@ -29,116 +30,17 @@
 	-- Export
 	writeSVG,
 	writeSTL,
+	writeOBJ,
+	writeTHREEJS,
+	writeSCAD2,
+	writeSCAD3,
+	writeGCodeHacklabLaser,
 	runOpenscad
 ) where
 
 -- Let's be explicit about where things come from :)
-import Graphics.Implicit.Definitions (ℝ, ℝ2, ℝ3, SymbolicObj2, SymbolicObj3)
-import qualified Graphics.Implicit.Primitives as Prim
-import qualified Graphics.Implicit.Export as Export
+import Graphics.Implicit.Primitives
 import Graphics.Implicit.ExtOpenScad (runOpenscad)
-import Graphics.Implicit.Operations 
-	(translate, scale, complement, 
-	 union,  intersect,  difference,
-	 unionR, intersectR, differenceR,
-	 extrudeR, extrudeOnEdgeOf, shell)
-
--- The versions of objects that should be used by default.
--- Import Graphics.Implicit.Primitives to override
-
-type DObj3 = SymbolicObj3
-type DObj2 = SymbolicObj2
-
--- We're going to force some of the types to be less flexible 
--- than they are for ease of use for the end user...
-
-writeSTL ::
-	ℝ           -- ^ Resolution
-	-> FilePath -- ^ STL file to write to
-	-> DObj3    -- ^ 3D object to write
-	-> IO()     -- ^ Writing action!
-
-writeSTL = Export.writeSTL
-
-writeSVG :: 
-	ℝ           -- ^ Resolution
-	-> FilePath -- ^ SVG File to be written to
-	-> DObj2    -- ^ 2D object to write
-	-> IO()     -- ^ Writing action!
-
-writeSVG = Export.writeSVG
-
-
-sphere ::
-	ℝ           -- ^ Radius of the sphere
-	-> DObj3    -- ^ Resulting sphere
-sphere = Prim.sphere
-rect3R ::
-	ℝ           -- ^ Radius of roudning
-	-> ℝ3       -- ^ bot-left-out corner
-	-> ℝ3       -- ^ top-right-in corner
-	 -> DObj3   -- ^ Resuting 3D rect
-rect3R = Prim.rect3R
-
-cylinder2 ::
-	ℝ           -- ^ Radius of the cylinder	
-	-> ℝ        -- ^ Second radius of the cylinder
-	-> ℝ        -- ^ Height of the cylinder
-	-> DObj3    -- ^ Resulting cylinder
-cylinder2 = Prim.cylinder2
-
-circle ::
-	ℝ          -- ^ radius of the circle
-	-> DObj2   -- ^ resulting circle
-circle = Prim.circle
-
-rectR ::
-	ℝ          -- ^ Radius of rounding
-	-> ℝ2      -- ^ (x1, y1)
-	-> ℝ2      -- ^ (x2 ,y2)
-	-> DObj2   -- ^ rect between (x1,y1) and (x2,y2)
-rectR = Prim.rectR
-
-polygon ::
-	[ℝ2]      -- ^ Verticies of the polygon
-	 -> DObj2   -- ^ Resulting polygon
-polygon = Prim.polygonR 0
-
-
-
-cylinder ::
-	ℝ         -- ^ Radius of the cylinder	
-	-> ℝ      -- ^ Height of the cylinder
-	-> DObj3   -- ^ Resulting cylinder
-cylinder r h = cylinder2 r r h
-
-cylinderC :: 
-	ℝ         -- ^ Radius of the cylinder	
-	-> ℝ      -- ^ Height of the cylinder
-	-> DObj3    -- ^ Resulting cylinder
-cylinderC r h = translate (0,0,-h/2.0) $ cylinder r h
-
-
-cylinder2C :: 
-	ℝ         -- ^ Radius of the cylinder	
-	-> ℝ      -- ^ Second radius of the cylinder
-	-> ℝ      -- ^ Height of the cylinder
-	-> DObj3   -- ^ Resulting cylinder
-cylinder2C r1 r2 h = translate (0,0,-h/2.0) $ cylinder2 r1 r2 h
-
-
-
-
-
-
-
-
+import Graphics.Implicit.Export
 
--- This function is commented out because it doesn't obey the magnitude requirement.
--- Refer to blog post.
--- It needs to be fixed at some point, but the math is somewhat non-trivial.
---ellipse :: ℝ -> ℝ -> Obj2
---ellipse a b
---    | a < b = \(x,y) -> sqrt ((b/a*x)**2 + y**2) - a
---    | otherwise = \(x,y) -> sqrt (x**2 + (a/b*y)**2) - b
 
diff --git a/Graphics/Implicit/Definitions.hs b/Graphics/Implicit/Definitions.hs
--- a/Graphics/Implicit/Definitions.hs
+++ b/Graphics/Implicit/Definitions.hs
@@ -3,6 +3,11 @@
 
 module Graphics.Implicit.Definitions where
 
+-- a few imports for great evil :(
+-- we want global IO refs.
+import Data.IORef (IORef, newIORef, readIORef)
+import System.IO.Unsafe (unsafePerformIO)
+
 -- Let's make things a bit nicer. 
 -- Following math notation ℝ, ℝ², ℝ³...
 type ℝ = Float
@@ -11,6 +16,12 @@
 
 type ℕ = Int
 
+-- nxn matrices
+-- eg. M2 ℝ = M₂(ℝ)
+type M2 a = ((a,a),(a,a))
+type M3 a = ((a,a,a),(a,a,a),(a,a,a))
+
+
 -- | A chain of line segments, as in SVG
 -- eg. [(0,0), (0.5,1), (1,0)] ---> /\
 type Polyline = [ℝ2]
@@ -18,9 +29,17 @@
 -- | A triangle (a,b,c) = a trinagle with vertices a, b and c
 type Triangle = (ℝ3, ℝ3, ℝ3)
 
+-- | A triangle ((v1,n1),(v2,n2),(v3,n3)) has vertices v1, v2, v3
+--   with corresponding normals n1, n2, and n3
+type NormedTriangle = ((ℝ3, ℝ3), (ℝ3, ℝ3), (ℝ3, ℝ3))
+
+
 -- | A triangle mesh is a bunch of triangles :)
 type TriangleMesh = [Triangle]
 
+-- | A normed triangle mesh is a bunch of normed trianlges!!
+type NormedTriangleMesh = [NormedTriangle]
+
 -- $ 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
@@ -64,7 +83,7 @@
 	| IntersectR2 ℝ [SymbolicObj2]
 	-- Simple transforms
 	| Translate2 ℝ2 SymbolicObj2
-	| Scale2 ℝ SymbolicObj2
+	| Scale2 ℝ2 SymbolicObj2
 	| Rotate2 ℝ SymbolicObj2
 	-- Boundary mods
 	| Outset2 ℝ SymbolicObj2
@@ -76,19 +95,20 @@
 -- | A symbolic 3D format!
 
 data SymbolicObj3 = 
-	-- Some simple primitives
+	-- Primitives
 	  Rect3R ℝ ℝ3 ℝ3
 	| Sphere ℝ
-	-- Some (rounded) CSG
+	| Cylinder ℝ ℝ ℝ -- h r1 r2
+	-- (Rounded) CSG
 	| Complement3 SymbolicObj3
 	| UnionR3 ℝ [SymbolicObj3]
 	| IntersectR3 ℝ [SymbolicObj3]
 	| DifferenceR3 ℝ [SymbolicObj3]
-	-- Some simple transofrms
+	-- Simple transforms
 	| Translate3 ℝ3 SymbolicObj3
-	| Scale3 ℝ SymbolicObj3
+	| Scale3 ℝ3 SymbolicObj3
 	| Rotate3 (ℝ,ℝ,ℝ) SymbolicObj3
-	-- Some boundary based transforms
+	-- Boundary mods
 	| Outset3 ℝ SymbolicObj3
 	| Shell3 ℝ SymbolicObj3
 	-- Misc
@@ -96,18 +116,51 @@
 	-- 2D based
 	| ExtrudeR ℝ SymbolicObj2 ℝ
 	| ExtrudeRotateR ℝ ℝ SymbolicObj2 ℝ
-	| ExtrudeRMod ℝ (ℝ -> ℝ2 -> ℝ2) SymbolicObj2 ℝ
+	| ExtrudeRM 
+		ℝ                 -- ^ rounding radius
+		(Maybe (ℝ -> ℝ))  -- ^ twist
+		(Maybe (ℝ -> ℝ))  -- ^ scale
+		(Maybe (ℝ -> ℝ2)) -- ^ translate
+		SymbolicObj2      -- ^ object to extrude
+		(Either ℝ (ℝ2 -> ℝ)) -- ^ height to extrude to
 	| ExtrudeOnEdgeOf SymbolicObj2 SymbolicObj2
 	deriving Show
 
--- | Rectiliniar 2D set
-type Rectiliniar2 = [Box2]
+-- | Rectilinear 2D set
+type Rectilinear2 = [Box2]
 
--- | Rectiliniar 2D set
-type Rectiliniar3 = [Box3]
+-- | Rectilinear 2D set
+type Rectilinear3 = [Box3]
 
 -- | Make ALL the functions Showable!
 --   This is very handy when testing functions in interactive mode...
 instance Show (a -> b) where
 	show f = "<function>"
 
+-- | Now for something that makes me a bad person...
+--   I promise I'll use it for good, not evil!
+--   I don't want to reparse the program arguments 
+--   everytime I want to know if XML errors are needed.
+
+{-# NOINLINE xmlErrorOn #-}
+
+xmlErrorOn :: IORef Bool
+xmlErrorOn = unsafePerformIO $ newIORef False
+
+errorMessage :: Int -> String -> IO()
+errorMessage line msg = do
+		useXML <- readIORef xmlErrorOn
+		let
+			msg' = "At line <line>" ++ show line ++ "</line>:" ++ msg
+			-- dropXML inTag (x:xs)
+			dropXML inQuote False ('"':xs) = '"':dropXML (not inQuote) False  xs
+			dropXML True    _     ( x :xs) = x:dropXML True    False  xs
+			dropXML False   False ('<':xs) =   dropXML False   True  xs
+			dropXML False   True  ('>':xs) =   dropXML False   False xs
+			dropXML inQuote True  ( _ :xs) =   dropXML inQuote True  xs
+			dropXML inQuote False ( x :xs) = x:dropXML inQuote False xs
+			dropXML _       _        []    = []
+		if useXML 
+			then putStrLn $ "<error>" ++ msg' ++ "</error>"
+			else putStrLn $ dropXML False False $ msg'
+		return ()
diff --git a/Graphics/Implicit/Export.hs b/Graphics/Implicit/Export.hs
--- a/Graphics/Implicit/Export.hs
+++ b/Graphics/Implicit/Export.hs
@@ -12,14 +12,14 @@
 import Graphics.Implicit.Export.Definitions
 
 -- instances of DiscreteApproxable...
-import Graphics.Implicit.Export.BoxedObj2
-import Graphics.Implicit.Export.BoxedObj3
 import Graphics.Implicit.Export.SymbolicObj2
 import Graphics.Implicit.Export.SymbolicObj3
 
 -- File formats
 import qualified Graphics.Implicit.Export.PolylineFormats as PolylineFormats
 import qualified Graphics.Implicit.Export.TriangleMeshFormats as TriangleMeshFormats
+import qualified Graphics.Implicit.Export.NormedTriangleMeshFormats as NormedTriangleMeshFormats
+import qualified Graphics.Implicit.Export.SymbolicFormats as SymbolicFormats
 
 -- Write an object in a given formet...
 
@@ -40,9 +40,13 @@
 writeSVG res = writeObject res PolylineFormats.svg
 
 writeSTL res = writeObject res  TriangleMeshFormats.stl
+writeOBJ res = writeObject res  NormedTriangleMeshFormats.obj
+writeTHREEJS res = writeObject res  TriangleMeshFormats.jsTHREE
 
 writeGCodeHacklabLaser res = writeObject res PolylineFormats.hacklabLaserGCode
 
+writeSCAD3 res filename obj = writeFile filename (SymbolicFormats.scad3 res obj)
+writeSCAD2 res filename obj = writeFile filename (SymbolicFormats.scad2 res obj)
 
 
 {-
diff --git a/Graphics/Implicit/Export/BoxedObj2.hs b/Graphics/Implicit/Export/BoxedObj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Export/BoxedObj2.hs
+++ /dev/null
@@ -1,14 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Export.BoxedObj2 where
-
-import Graphics.Implicit.Definitions
-
-import Graphics.Implicit.Export.Definitions
-import Graphics.Implicit.Export.MarchingSquares
-
-instance DiscreteAproxable BoxedObj2 [Polyline] where
-	discreteAprox res (obj,(a,b)) = getContour a b (res,res) obj
diff --git a/Graphics/Implicit/Export/BoxedObj3.hs b/Graphics/Implicit/Export/BoxedObj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Export/BoxedObj3.hs
+++ /dev/null
@@ -1,12 +0,0 @@
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Export.BoxedObj3 where
-
-import Graphics.Implicit.Definitions
-
-import Graphics.Implicit.Export.Definitions
-import Graphics.Implicit.Export.MarchingCubes
-
-instance DiscreteAproxable BoxedObj3 TriangleMesh where
-	discreteAprox res (obj,(a,b)) = getMesh a b res obj
diff --git a/Graphics/Implicit/Export/Definitions.hs b/Graphics/Implicit/Export/Definitions.hs
--- a/Graphics/Implicit/Export/Definitions.hs
+++ b/Graphics/Implicit/Export/Definitions.hs
@@ -8,7 +8,7 @@
 -- | There is a discrete way to aproximate this object.
 --   eg. Aproximating a 3D object with a tirangle mesh
 --       would be DiscreteApproxable Obj3 TriangleMesh
-class DiscreteAproxable obj aprox | obj -> aprox where
+class DiscreteAproxable obj aprox where
 	discreteAprox :: ℝ -> obj -> aprox
 
 
diff --git a/Graphics/Implicit/Export/MarchingCubes.hs b/Graphics/Implicit/Export/MarchingCubes.hs
deleted file mode 100644
--- a/Graphics/Implicit/Export/MarchingCubes.hs
+++ /dev/null
@@ -1,510 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-module Graphics.Implicit.Export.MarchingCubes (getMesh, getMesh2) where
-
-import Graphics.Implicit.Definitions
-import Control.Parallel (par, pseq)
-
--- | getMesh gets a triangle mesh describe the boundary of your 3D
---  object. 
---  There are many getMesh functions in this file. THis one is the
---  simplest and should be least bug prone. Use it for debugging.
-getMesh :: ℝ3 -> ℝ3 -> ℝ -> Obj3 -> TriangleMesh
-getMesh (x1, y1, z1) (x2, y2, z2) res obj = 
-	let
-		-- How many steps will we take on each axis?
-		nx = fromIntegral $ ceiling $ (x2 - x1) / res
-		ny = fromIntegral $ ceiling $ (y2 - y1) / res
-		nz = fromIntegral $ ceiling $ (y2 - y1) / res
-		-- Divide it up and compute the polylines
-		triangles :: [TriangleMesh]
-		triangles = [getCubeTriangles
-		           (x1 + (x2 - x1)*mx/nx,     y1 + (y2 - y1)*my/ny,     z1 + (z2 - z1)*mz/nz)
-		           (x1 + (x2 - x1)*(mx+1)/nx, y1 + (y2 - y1)*(my+1)/ny, z1 + (z2 - z1)*(mz+1)/nz)
-		           obj
-		     | mx <- [0.. nx-1], my <- [0..ny-1], mz <- [0..nz-1] ]
-	in
-		concat $ triangles
-
-
-getMesh2 (x1,y1,z1) (x2,y2,z2) res obj = 
-	let 
-		dx = abs $ x2 - x1
-		dy = abs $ y2 - y1
-		dz = abs $ z2 - z1
-		d = maximum [dx, dy, dz]
-		ffloor = fromIntegral . floor
-		fceil = fromIntegral . ceiling
-	in
-		if (abs.obj) ( (x1 + x2)/2, (y1 + y2)/2, (z1 + z2)/2) > d*0.9 then []
-		else
-		if d <= res
-		then getCubeTriangles (x1,y1,z1) (x1+res,y1+res,z1+res) obj
-		else let
-			xs = if dx <= res then [(x1, x2)] else [(x1,xm), (xm, x2)] 
-				where xm = x1 + res * fceil ( ffloor (dx/res) / 2.0)
-			ys = if dy <= res then [(y1, y2)] else [(y1,xm), (xm, y2)] 
-				where xm = y1 + res * fceil ( ffloor (dy/res) / 2.0)
-			zs = if dz <= res then [(z1, z2)] else [(z1,xm), (xm, z2)] 
-				where xm = z1 + res * fceil ( ffloor (dz/res) / 2.0)
-			partitions = [getMesh (x1', y1', z1') (x2', y2', z2') res obj
-				|  (x1',x2') <- xs, (y1', y2') <- ys, (z1',z2') <- zs ]
-		in
-			concat partitions
-
-
-getMesh3 (x1,y1,z1) (x2,y2,z2) res obj = 
-	let 
-		dx = abs $ x2 - x1
-		dy = abs $ y2 - y1
-		dz = abs $ z2 - z1
-		d = maximum [dx, dy, dz]
-		ffloor = fromIntegral . floor
-		fceil = fromIntegral . ceiling
-	in
-		if (abs.obj) ( (x1 + x2)/2, (y1 + y2)/2, (z1 + z2)/2) > d*0.9 then []
-		else
-		if d <= res
-		then getCubeTriangles (x1,y1,z1) (x1+res,y1+res,z1+res) obj
-		else let
-			xs = if dx <= res then [(x1, x2)] else [(x1,xm), (xm, x2)] 
-				where xm = x1 + res * fceil ( ffloor (dx/res) / 2.0)
-			ys = if dy <= res then [(y1, y2)] else [(y1,xm), (xm, y2)] 
-				where xm = y1 + res * fceil ( ffloor (dy/res) / 2.0)
-			zs = if dz <= res then [(z1, z2)] else [(z1,xm), (xm, z2)] 
-				where xm = z1 + res * fceil ( ffloor (dz/res) / 2.0)
-			partitions = [getMesh (x1', y1', z1') (x2', y2', z2') res obj
-				|  (x1',x2') <- xs, (y1', y2') <- ys, (z1',z2') <- zs ]
-		in
-			foldr1 par partitions `pseq` concat partitions
-
-
-
--- | 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.
-
-getCubeTriangles :: ℝ3 -> ℝ3 -> Obj3 -> [Triangle]
-getCubeTriangles (x1, y1, z1) (x2, y2, z2) obj =
-	let
-		(x,y,z) = (x1, y1, z1)
-		
-		x1y1z1 = obj (x1, y1, z1)
-		x2y1z1 = obj (x2, y1, z1)
-		x1y2z1 = obj (x1, y2, z1)
-		x2y2z1 = obj (x2, y2, z1)
-		x1y1z2 = obj (x1, y1, z2)
-		x2y1z2 = obj (x2, y1, z2)
-		x1y2z2 = obj (x1, y2, z2)
-		x2y2z2 = obj (x2, y2, z2)
-
-		dx = x2 - x1
-		dy = y2 - y1
-		dz = z2 - z1
-		
-		--{- Linearly interpolated
-		x1y1 = (x,    y,    z+dz*x1y1z1/(x1y1z1-x1y1z2))
-		x1y2 = (x,    y+dy, z+dz*x1y2z1/(x1y2z1-x1y2z2))
-		x2y1 = (x+dx, y,    z+dz*x2y1z1/(x2y1z1-x2y1z2))
-		x2y2 = (x+dx, y+dy, z+dz*x2y2z1/(x2y2z1-x2y2z2))
-
-		x1z1 = (x,    y+dy*x1y1z1/(x1y1z1-x1y2z1), z)
-		x1z2 = (x,    y+dy*x1y1z2/(x1y1z2-x1y2z2), z+dz)
-		x2z1 = (x+dx, y+dy*x2y1z1/(x2y1z1-x2y2z1), z)
-		x2z2 = (x+dx, y+dy*x2y1z2/(x2y1z2-x2y2z2), z+dz)
-
-		y1z1 = (x+dx*x1y1z1/(x1y1z1-x2y1z1), y,    z)
-		y1z2 = (x+dx*x1y1z2/(x1y1z2-x2y1z2), y,    z+dz)
-		y2z1 = (x+dx*x1y2z1/(x1y2z1-x2y2z1), y+dy, z)
-		y2z2 = (x+dx*x1y2z2/(x1y2z2-x2y2z2), y+dy, z+dz)
-		--}
-
-
-		{- Non-linearly interpolated
-		x1y1 = (x,    y,    z+dz/2)
-		x1y2 = (x,    y+dy, z+dz/2)
-		x2y1 = (x+dx, y,    z+dz/2)
-		x2y2 = (x+dx, y+dy, z+dz/2)
-
-		x1z1 = (x,    y+dy/2, z)
-		x1z2 = (x,    y+dy/2, z+dz)
-		x2z1 = (x+dx, y+dy/2, z)
-		x2z2 = (x+dx, y+dy/2, z+dz)
-
-		y1z1 = (x+dx/2, y,   z)
-		y1z2 = (x+dx/2, y,   z+dz)
-		y2z1 = (x+dx/2, y+dy,z)
-		y2z2 = (x+dx/2, y+dy,z+dz)
-		--}
-
-		-- 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.
-
-		-- Yes, there's some symetries that could reduce the amount of code...
-		-- But I don't think they're worth exploiting...
-		-- In particular, since we're not implementing any case, 
-		-- it would make catching the ones we don't implement... problematic.
-
-		-- 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)]
-
-
-
-
-		_ -> []
-
diff --git a/Graphics/Implicit/Export/MarchingSquares.hs b/Graphics/Implicit/Export/MarchingSquares.hs
--- a/Graphics/Implicit/Export/MarchingSquares.hs
+++ b/Graphics/Implicit/Export/MarchingSquares.hs
@@ -4,7 +4,8 @@
 module Graphics.Implicit.Export.MarchingSquares (getContour) where
 
 import Graphics.Implicit.Definitions
-import Control.Parallel (par, pseq)
+import Control.Parallel.Strategies (using, parList, rdeepseq)
+import Debug.Trace
 
 -- | getContour gets a polyline describe the edge of your 2D
 --  object. It's really the only function in this file you need
@@ -25,9 +26,34 @@
 		     | mx <- [0.. nx-1] ] | my <- [0..ny-1] ]
 		-- Cleanup, cleanup, everybody cleanup!
 		-- (We connect multilines, delete redundant vertices on them, etc)
-		multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLinesP $ linesOnGrid
+		multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLinesDC $ linesOnGrid
 	in
 		multilines
+
+getContour2 :: ℝ2 -> ℝ2 -> ℝ2 -> Obj2 -> [Polyline]
+getContour2 (x1, y1) (x2, y2) (dx, dy) obj = 
+	let
+		-- How many steps will we take on each axis?
+		nx = fromIntegral $ ceiling $ (x2 - x1) / dx
+		ny = fromIntegral $ ceiling $ (y2 - y1) / dy
+		-- Grid mapping funcs
+		fromGrid (mx, my) = (x1 + (x2 - x1)*mx/nx, y1 + (y2 - y1)*my/ny)
+		toGrid (x,y) =(\a-> traceShow a a) (floor $ nx*(x-x1)/(x2-x1), floor $ ny*(y-y1)/(y2-y1) ) :: (ℕ, ℕ)
+		-- Evalueate obj on a grid, in parallel.
+		valsOnGrid :: [[ℝ]]
+		valsOnGrid = [[ obj (fromGrid (mx, my)) | mx <- [0.. nx-1] ] | my <- [0..ny-1] ]
+		              `using` parList rdeepseq
+		-- A faster version of the obj. Sort of like memoization, but done in advance, in parallel.
+		preEvaledObj p = valsOnGrid !! my !! mx where (mx,my) = toGrid p
+		-- Divide it up and compute the polylines
+		linesOnGrid :: [[[Polyline]]]
+		linesOnGrid = [[getSquareLineSegs (fromGrid (mx, my)) (fromGrid (mx+1, my+1)) preEvaledObj
+		     | mx <- [0.. nx-1] ] | my <- [0..ny-1] ]
+		-- Cleanup, cleanup, everybody cleanup!
+		-- (We connect multilines, delete redundant vertices on them, etc)
+		multilines = (filter polylineNotNull) $ (map reducePolyline) $ orderLinesDC $ linesOnGrid
+	in
+		multilines
 		
 
 -- | This function gives line segmensts to divde negative interior
@@ -139,11 +165,13 @@
 	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 :: [a] -> ([a], [a])
 		halve l = splitAt (div (length l) 2) l
-		splitOrder segs = case (\(x,y) -> (halve x, halve y)) $ unzip $ map (halve) segs of
+		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
@@ -151,6 +179,7 @@
 			((a,b),(c,d)) ->orderLines $ 
 				orderLinesDC a ++ orderLinesDC b ++ orderLinesDC c ++ orderLinesDC d
 
+{-
 orderLinesP :: [[[Polyline]]] -> [Polyline]
 orderLinesP segs =
 	let
@@ -172,6 +201,7 @@
 					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)
diff --git a/Graphics/Implicit/Export/NormedTriangleMeshFormats.hs b/Graphics/Implicit/Export/NormedTriangleMeshFormats.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/NormedTriangleMeshFormats.hs
@@ -0,0 +1,40 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.NormedTriangleMeshFormats where
+
+import Graphics.Implicit.Definitions
+
+obj normedtriangles = text
+	where
+		-- A vertex line; v (0.0, 0.0, 1.0) = "v 0.0 0.0 1.0\n"
+		v :: ℝ3 -> String
+		v (x,y,z) = "v "  ++ show x ++ " " ++ show y ++ " " ++ show z ++ "\n"
+		-- A normal line; n (0.0, 0.0, 1.0) = "vn 0.0 0.0 1.0\n"
+		n :: ℝ3 -> String
+		n (x,y,z) = "vn " ++ show x ++ " " ++ show y ++ " " ++ show z ++ "\n"
+		verts = do
+			-- extract the vertices for each triangle
+			-- recall that a normed triangle is of the form ((vert, norm), ...)
+			((a,_),(b,_),(c,_)) <- normedtriangles
+			-- The vertices from each triangle take up 3 position in the resulting list
+			[a,b,c]
+		norms = do
+			-- extract the normals for each triangle
+			((_,a),(_,b),(_,c)) <- normedtriangles
+			-- The normals from each triangle take up 3 position in the resulting list
+			[a,b,c]
+		vertcode = concat $ map v verts
+		normcode = concat $ map n norms
+		trianglecode = concat $ do
+			n <- map ((+1).(*3)) [0,1 .. length normedtriangles -1]
+			let
+				vta = show  n   -- ++ "//" ++ show  n
+				vtb = show (n+1)-- ++ "//" ++ show (n+1)
+				vtc = show (n+2)-- ++ "//" ++ show (n+2)
+			return $ "f " ++ vta ++ " " ++ vtb ++ " " ++ vtc ++ " " ++ "\n"
+		text = vertcode ++ normcode ++ trianglecode
+
+
+
+
diff --git a/Graphics/Implicit/Export/PolylineFormats.hs b/Graphics/Implicit/Export/PolylineFormats.hs
--- a/Graphics/Implicit/Export/PolylineFormats.hs
+++ b/Graphics/Implicit/Export/PolylineFormats.hs
@@ -6,6 +6,9 @@
 
 import Graphics.Implicit.Definitions
 
+import Text.Printf (printf)
+
+svg :: [Polyline] -> String
 svg polylines = text
 	where
 		-- SVG is stupidly laid out... (0,0) is the top left corner
@@ -22,6 +25,7 @@
 			++ svglines		
 			++ "</svg> "
 
+hacklabLaserGCode :: [Polyline] -> String
 hacklabLaserGCode polylines = text
 	where
 		gcodeHeader = 
@@ -36,8 +40,9 @@
 			"M5 (disable laser)\n"
 			++"G00 X0.0 Y0.0 (move to 0)\n"
 			++"M2 (end)"
+		showF n = printf "%.4f" n
 		gcodeXY :: ℝ2 -> [Char]
-		gcodeXY (x,y) = "X"++ show x ++" Y"++ show y 
+		gcodeXY (x,y) = "X"++ showF x ++" Y"++ showF y 
 		interpretPolyline (start:others) = 
 			"G00 "++ gcodeXY start ++ "\n"
 			++ "M62 P0 (laser on)\n"
diff --git a/Graphics/Implicit/Export/Render.hs b/Graphics/Implicit/Export/Render.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render.hs
@@ -0,0 +1,264 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE ParallelListComp #-}
+
+module Graphics.Implicit.Export.Render where
+
+import Debug.Trace
+
+import Graphics.Implicit.Definitions
+import Graphics.Implicit.Export.Render.Definitions
+
+-- Here's the plan for rendering a cube (the 2D case is trivial):
+
+-- (1) We calculate midpoints using interpolate.
+--     This guarentees that our mesh will line up everywhere.
+--     (Contrast with calculating them in getSegs)
+
+import Graphics.Implicit.Export.Render.Interpolate (interpolate)
+
+-- (2) We calculate the segments separating the inside and outside of our
+--     object on the sides of the cube.
+--     getSegs internally uses refine from RefineSegs to subdivide the segs
+--     to better match the boundary.
+
+import Graphics.Implicit.Export.Render.GetSegs (getSegs, getSegs')
+-- import Graphics.Implicit.Export.Render.RefineSegs (refine)
+
+-- (3) We put the segments from all sides of the cube together
+--     and extract closed loops.
+
+import Graphics.Implicit.Export.Render.GetLoops (getLoops)
+
+-- (4) We tesselate the loops, using a mixtur of triangles and squares
+
+import Graphics.Implicit.Export.Render.TesselateLoops (tesselateLoop)
+
+-- (5) We try to merge squares, then turn everything into triangles.
+
+import Graphics.Implicit.Export.Render.HandleSquares (mergedSquareTris)
+
+-- Success: This is our mesh.
+
+-- Each step is done in parallel using Control.Parallel.Strategies
+
+import Control.Parallel.Strategies (using, rdeepseq, parListChunk)
+
+-- The actual code is just a bunch of ugly argument passing.
+-- Utility functions can be found at the end.
+
+getMesh :: ℝ3 -> ℝ3 -> ℝ -> Obj3 -> TriangleMesh
+getMesh (x1, y1, z1) (x2, y2, z2) res obj = 
+	let
+		dx = x2-x1
+		dy = y2-y1
+		dz = z2-z1
+
+		-- How many steps will we take on each axis?
+		nx = ceiling $ dx / res
+		ny = ceiling $ dy / res
+		nz = ceiling $ dz / res
+
+		rx = dx/fromIntegral nx
+		ry = dy/fromIntegral ny
+		rz = dz/fromIntegral nz
+
+		l ! (a,b,c) = l !! c !! b !! a
+
+		pZs = [ z1 + rz*n | n <- [0.. fromIntegral nz] ]
+		pYs = [ y1 + ry*n | n <- [0.. fromIntegral ny] ]
+		pXs = [ x1 + rx*n | n <- [0.. fromIntegral nx] ]
+
+
+		{-# INLINE par3DList #-}
+		par3DList lenx leny lenz f = 
+			[[[f 
+				(\n -> x1 + rx*fromIntegral (mx+n)) mx 
+				(\n -> y1 + ry*fromIntegral (my+n)) my 
+				(\n -> z1 + rz*fromIntegral (mz+n)) mz
+			| mx <- [0..lenx] ] | my <- [0..leny] ] | mz <- [0..lenz] ] 
+				`using` (parListChunk (max 1 $ div lenz 32) rdeepseq)
+
+
+		-- Evaluate obj to avoid waste in mids, segs, later.
+
+		objV = par3DList (nx+2) (ny+2) (nz+2) $ \x _ y _ z _ -> obj (x 0, y 0, z 0)
+
+		-- (1) Calculate mid poinsts on X, Y, and Z axis in 3D space.
+
+		midsZ = [[[
+				 interpolate (z0, objX0Y0Z0) (z1, objX0Y0Z1) (appAB obj x0 y0) res
+				 | x0 <- pXs |                  objX0Y0Z0 <- objY0Z0 | objX0Y0Z1 <- objY0Z1
+				]| y0 <- pYs |                  objY0Z0 <- objZ0 | objY0Z1 <- objZ1
+				]| z0 <- pZs | z1 <- tail pZs | objZ0   <- objV  | objZ1   <- tail objV
+				] `using` (parListChunk (max 1 $ div nz 32) rdeepseq)
+
+		midsY = [[[
+				 interpolate (y0, objX0Y0Z0) (y1, objX0Y1Z0) (appAC obj x0 z0) res
+				 | x0 <- pXs |                  objX0Y0Z0 <- objY0Z0 | objX0Y1Z0 <- objY1Z0
+				]| y0 <- pYs | y1 <- tail pYs | objY0Z0 <- objZ0 | objY1Z0 <- tail objZ0
+				]| z0 <- pZs |                  objZ0   <- objV 
+				] `using` (parListChunk (max 1 $ div nz 32) rdeepseq)
+
+		midsX = [[[
+				 interpolate (x0, objX0Y0Z0) (x1, objX1Y0Z0) (appBC obj y0 z0) res
+				 | x0 <- pXs | x1 <- tail pXs | objX0Y0Z0 <- objY0Z0 | objX1Y0Z0 <- tail objY0Z0
+				]| y0 <- pYs |                  objY0Z0 <- objZ0 
+				]| z0 <- pZs |                  objZ0   <- objV 
+				] `using` (parListChunk (max 1 $ div nz 32) rdeepseq)
+
+		-- Calculate segments for each side
+
+		segsZ = [[[ 
+			map2  (inj3 z0) $ getSegs (x0,y0) (x1,y1) (obj **$ z0)
+			    (objX0Y0Z0, objX1Y0Z0, objX0Y1Z0, objX1Y1Z0)
+			    (midA0, midA1, midB0, midB1)
+			 |x0<-pXs|x1<-tail pXs|midB0<-mX'' |midB1<-mX'T    |midA0<-mY'' |midA1<-tail mY''
+			 |objX0Y0Z0<-objY0Z0|objX1Y0Z0<-tail objY0Z0|objX0Y1Z0<-objY1Z0|objX1Y1Z0<-tail objY1Z0
+			]|y0<-pYs|y1<-tail pYs|mX'' <-mX'  |mX'T <-tail mX'|mY'' <-mY'
+			 |objY0Z0 <- objZ0 | objY1Z0 <- tail objZ0
+			]|z0<-pZs             |mX'  <-midsX|                mY'  <-midsY
+			 |objZ0 <- objV
+			] `using` (parListChunk (max 1 $ div nz 32) rdeepseq) -- -}
+			{-let
+				iteree = zip3D3 (lag3 points) (lag3s22 midsY) (lag3s12 midsX)
+				transform (((x0,y0,z0),(x1,y1,z1)), (midA0,midA1), (midB0,midB1)) =
+					map2  (inj3 z0) $ 
+						getSegs (x0,y0) (x1,y1) (obj **$ z0) (midA0, midA1, midB0, midB1)
+				result = for3 iteree transform
+			in
+				result --`using` (parListChunk (max 1 $ div lenz 32) rdeepseq)-}
+		  {-par3DList (nx-1) (ny-1) (nz) $ \x mx y my z mz ->
+		       map2  (inj3 (z 0)) $ getSegs'
+		           (x 0, y 0)
+                   (x 1, y 1)
+                   (obj **$ z 0)
+		           (midsY ! (mx, my, mz), midsY ! (mx+1, my, mz),
+		            midsX ! (mx, my, mz), midsX ! (mx, my+1, mz)) -- -}
+		segsY = [[[ 
+			map2  (inj2 y0) $ getSegs (x0,z0) (x1,z1) (obj *$* y0) 
+			     (objX0Y0Z0,objX1Y0Z0,objX0Y0Z1,objX1Y0Z1)
+			     (midA0, midA1, midB0, midB1)
+			 |x0<-pXs|x1<-tail pXs|midB0<-mB'' |midB1<-mBT'      |midA0<-mA'' |midA1<-tail mA''
+			 |objX0Y0Z0<-objY0Z0|objX1Y0Z0<-tail objY0Z0|objX0Y0Z1<-objY0Z1|objX1Y0Z1<-tail objY0Z1
+			]|y0<-pYs|             mB'' <-mB'  |mBT' <-mBT       |mA'' <-mA'
+			 |objY0Z0 <- objZ0 | objY0Z1 <- objZ1
+			]|z0<-pZs|z1<-tail pZs|mB'  <-midsX|mBT  <-tail midsX|mA'  <-midsZ 
+			 |objZ0 <- objV | objZ1 <- tail objV
+			] `using` (parListChunk (max 1 $ div nz 32) rdeepseq) -- -}
+			{-let
+				iteree = zip3D3 (lag3 points) (lag3s22 midsZ) (lag3s02 midsX)
+				transform (((x0,y0,z0),(x1,y1,z1)), (midA0,midA1), (midB0,midB1)) =
+					map2  (inj2 y0) $ 
+						getSegs (x0,z0) (x1,z1) (obj *$* y0) (midA0, midA1, midB0, midB1)
+				result = for3 iteree transform
+			in
+				result -}
+			{-par3DList (nx-1) (ny) (nz-1) $ \x mx y my z mz ->
+		       map2  (inj2 (y 0)) $ getSegs' 
+		           (x 0, z 0)
+                   (x 1, z 1)
+                   (obj *$* y 0)
+		           (midsZ ! (mx, my, mz), midsZ ! (mx+1, my, mz),
+		            midsX ! (mx, my, mz), midsX ! (mx, my, mz+1))
+		-- -}
+
+		segsX = 
+			[[[ 
+			map2  (inj1 x0) $ getSegs (y0,z0) (y1,z1) (obj $** x0) 
+			     (objX0Y0Z0,objX0Y1Z0,objX0Y0Z1,objX0Y1Z1)
+			     (midA0, midA1, midB0, midB1)
+			 |x0<-pXs|             midB0<-mB'' |midB1<-mBT'      |midA0<-mA'' |midA1<-mA'T
+			 |objX0Y0Z0<-objY0Z0|objX0Y1Z0<-    objY1Z0|objX0Y0Z1<-objY0Z1|objX0Y1Z1<-     objY1Z1
+			]|y0<-pYs|y1<-tail pYs|mB'' <-mB'  |mBT' <-mBT       |mA'' <-mA'  |mA'T <-tail mA'
+			 |objY0Z0  <-objZ0  |objY1Z0  <-tail objZ0  |objY0Z1  <-objZ1  |objY1Z1  <-tail objZ1  
+			]|z0<-pZs|z1<-tail pZs|mB'  <-midsY|mBT  <-tail midsY|mA'  <-midsZ 
+			 |objZ0 <- objV | objZ1 <- tail objV
+			]  `using` (parListChunk (max 1 $ div nz 32) rdeepseq) -- -}
+			{-let
+				iteree = zip3D3 (lag3 points) (lag3s12 midsZ) (lag3s02 midsY)
+				transform (((x0,y0,z0),(x1,y1,z1)), (midA0,midA1), (midB0,midB1)) =
+					map2  (inj1 x0) $ 
+						getSegs (y0,z0) (y1,z1) (obj $** x0) (midA0, midA1, midB0, midB1)
+				result = for3 iteree transform
+			in
+				result -}
+
+			{-par3DList (nx) (ny-1) (nz-1) $ \x mx y my z mz ->
+		       map2  (inj1 (x 0)) $ getSegs'
+		           (y 0, z 0)
+                   (y 1, z 1)
+                   (obj $** x 0)
+		           (midsZ ! (mx, my, mz), midsZ ! (mx, my+1, mz),
+		            midsY ! (mx, my, mz), midsY ! (mx, my, mz+1) ) -- -}
+
+		-- (3) & (4) : get and tesselate loops
+ 
+		sqTris = [[[
+		    concat $ map (tesselateLoop res obj) $ getLoops $ concat [
+		                segX''',
+		           mapR segX''T,
+		           mapR segY''',
+		                segY'T',
+		                segZ''',
+		           mapR segZT''
+		        ]
+
+			 | segZ'''<- segZ''| segZT''<- segZT'
+			 | segY'''<- segY''| segY'T'<- segY'T
+			 | segX'''<- segX''| segX''T<- tail segX''
+
+			]| segZ'' <- segZ' | segZT' <- segZT
+			 | segY'' <- segY' | segY'T <- tail segY'
+			 | segX'' <- segX'
+
+			]| segZ'  <- segsZ | segZT  <- tail segsZ
+			 | segY' <- segsY
+			 | segX' <- segsX
+		       ] `using` (parListChunk (nx*ny*(max 1 $ div nz 32)) rdeepseq)
+	
+	in mergedSquareTris $ concat $ concat $ concat sqTris -- (5) merge squares, etc
+
+
+
+-- silly utility functions
+
+inj1 a (b,c) = (a,b,c)
+inj2 b (a,c) = (a,b,c)
+inj3 c (a,b) = (a,b,c)
+
+infixr 0 $**
+infixr 0 *$*
+infixr 0 **$
+f $** a = \(b,c) -> f (a,b,c)
+f *$* b = \(a,c) -> f (a,b,c)
+f **$ c = \(a,b) -> f (a,b,c)
+
+appAB f a b = \c -> f (a,b,c)
+appBC f b c = \a -> f (a,b,c)
+appAC f a c = \b -> f (a,b,c)
+
+map2 f = map (map f)
+map2R f = map (reverse . map f)
+mapR = map reverse
+
+{-
+lagzip a = zip a (tail a)
+tupzip (a,b) = zip a b
+tupzip3 (a,b,c) = zip3 a b c
+
+zipD2 a b = map tupzip $ zip a b
+zipD3 a b = map (map tupzip) . map tupzip $ zip a b
+
+zip3D3 a b c = map (map tupzip3) . map tupzip3 $ zip3 a b c
+
+lag3s02 = map (map tupzip) . map tupzip . lagzip
+lag3s12 = map (map tupzip) . map lagzip
+lag3s22 = map (map lagzip)
+
+lag3 :: [[[a]]] -> [[[(a,a)]]]
+lag3 a = zipD3 a $ map (map tail) $ map tail $ tail a
+
+for3 = flip (map . map . map)
+-}
diff --git a/Graphics/Implicit/Export/Render/Definitions.hs b/Graphics/Implicit/Export/Render/Definitions.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/Definitions.hs
@@ -0,0 +1,14 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.Definitions where
+
+import Graphics.Implicit.Definitions
+import Control.DeepSeq
+
+data TriSquare = Sq (ℝ3,ℝ3,ℝ3) ℝ ℝ2 ℝ2 | Tris [Triangle]
+
+instance NFData TriSquare where
+	rnf (Sq b z xS yS) = rnf (b,z,xS,yS)
+	rnf (Tris tris) = rnf tris
+
diff --git a/Graphics/Implicit/Export/Render/GetLoops.hs b/Graphics/Implicit/Export/Render/GetLoops.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/GetLoops.hs
@@ -0,0 +1,31 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.GetLoops (getLoops) where
+
+getLoops :: Eq a => [[a]] -> [[[a]]]
+getLoops a = getLoops' a []
+
+getLoops' :: Eq a => [[a]] -> [[a]] -> [[[a]]]
+
+getLoops' [] [] = []
+
+getLoops' (x:xs) [] = getLoops' xs [x]
+
+getLoops' segs workingLoop | head (head workingLoop) == last (last workingLoop) =
+	workingLoop : getLoops' segs []
+
+getLoops' segs workingLoop =
+	let
+		presEnd = last $ last workingLoop
+		connects (x:xs) = x == presEnd
+		possibleConts = filter connects segs
+		nonConts = filter (not . connects) segs
+		(next, unused) = if null possibleConts
+			then error "unclosed loop in paths given"
+			else (head possibleConts, tail possibleConts ++ nonConts)
+	in
+		if null next
+		then workingLoop : getLoops' segs []
+		else getLoops' unused (workingLoop ++ [next])
+
diff --git a/Graphics/Implicit/Export/Render/GetSegs.hs b/Graphics/Implicit/Export/Render/GetSegs.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/GetSegs.hs
@@ -0,0 +1,79 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.GetSegs where
+
+import Graphics.Implicit.Definitions
+import Graphics.Implicit.Export.Render.RefineSegs (refine)
+
+getSegs' (x1, y1) (x2, y2) obj (midx1V,midx2V,midy1V,midy2V) = 
+	let
+		x1y1 = obj (x1, y1)
+		x2y1 = obj (x2, y1)
+		x1y2 = obj (x1, y2)
+		x2y2 = obj (x2, y2)
+	in
+		getSegs (x1, y1) (x2, y2) obj (x1y1, x2y1, x1y2, x2y2) (midx1V,midx2V,midy1V,midy2V)
+
+getSegs :: ℝ2 -> ℝ2 -> Obj2 -> (ℝ,ℝ,ℝ,ℝ) -> (ℝ,ℝ,ℝ,ℝ) -> [Polyline]
+{-- INLINE getSegs #-}
+getSegs (x1, y1) (x2, y2) obj (x1y1, x2y1, x1y2, x2y2) (midx1V,midx2V,midy1V,midy2V) = 
+	let 
+		(x,y) = (x1, y1)
+
+		-- Let's evlauate obj at a few points...
+		c = obj ((x1+x2)/2, (y1+y2)/2)
+
+		dx = x2 - x1
+		dy = y2 - y1
+		res = sqrt (dx*dy)
+
+		midx1 = (x,      midx1V )
+		midx2 = (x + dx, midx2V )
+		midy1 = (midy1V , y )
+		midy2 = (midy2V, y + dy)
+
+		notPointLine (p1:p2:[]) = p1 /= p2
+
+	in map (refine res obj) . filter (notPointLine) $ case (x1y2 <= 0, x2y2 <= 0,
+	                                 x1y1 <= 0, x2y1 <= 0) of
+
+		-- Yes, there's some symetries that could reduce the amount of code...
+		-- But I don't think they're worth exploiting...
+		(True,  True, 
+		 True,  True)  -> []
+		(False, False,
+		 False, False) -> []
+		(True,  True, 
+		 False, False) -> [[midx1, midx2]]
+		(False, False,
+		 True,  True)  -> [[midx2, midx1]]
+		(False, True, 
+		 False, True)  -> [[midy2, midy1]]
+		(True,  False,
+		 True,  False) -> [[midy1, midy2]]
+		(True,  False,
+		 False, False) -> [[midx1, midy2]]
+		(False, True, 
+		 True,  True)  -> [[midy2, midx1]]
+		(True,  True, 
+		 False, True)  -> [[midx1, midy1]]
+		(False, False,
+		 True,  False) -> [[midy1, midx1]]
+		(True,  True, 
+		 True,  False) -> [[midy1, midx2]]
+		(False, False,
+		 False, True)  -> [[midx2, midy1]]
+		(True,  False,
+		 True,  True)  -> [[midx2, midy2]]
+		(False, True, 
+		 False, False) -> [[midy2, midx2]]
+		(True,  False,
+		 False, True)  -> if c <= 0
+			then [[midx1, midy1], [midx2, midy2]]
+			else [[midx1, midy2], [midx2, midy1]]
+		(False, True, 
+		 True,  False) -> if c <= 0
+			then [[midy2, midx1], [midy1, midx2]]
+			else [[midy1, midx1], [midy2, midx2]]
+
diff --git a/Graphics/Implicit/Export/Render/HandleSquares.hs b/Graphics/Implicit/Export/Render/HandleSquares.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/HandleSquares.hs
@@ -0,0 +1,68 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.HandleSquares (mergedSquareTris) where
+
+import Graphics.Implicit.Definitions
+import Graphics.Implicit.Export.Render.Definitions
+import qualified Graphics.Implicit.SaneOperators as S
+import GHC.Exts (groupWith)
+
+mergedSquareTris sqTris = 
+	let
+		triTriangles = concat $ map (\(Tris a) -> a) $ filter isTris sqTris	
+		squares = filter (not . isTris) sqTris
+		planeAligned = groupWith (\(Sq basis z _ _) -> (basis,z)) squares
+		joined = map 
+			( concat . (map joinYaligned) . groupWith (\(Sq _ _ _ yS) -> yS)
+			. concat . (map joinXaligned) . groupWith (\(Sq _ _ xS _) -> xS)) 
+			planeAligned
+		finishedSquares = concat joined
+	in
+		triTriangles ++ concat (map squareToTri finishedSquares)
+
+
+isTris (Tris _) = True
+isTris _ = False
+
+joinXaligned (pres@(Sq b z xS (y1,y2)):sqs) = 
+	let
+		isNext (Sq _ _ _ (a,_)) = a == y2
+		isPrev (Sq _ _ _ (_,a)) = a == y1
+	in case filter isNext sqs of
+		[Sq _ _ _ (_, y3)] -> 
+			joinXaligned ((Sq b z xS (y1,y3)):(filter (not.isNext) sqs))
+		_ -> case filter isPrev sqs of
+			[Sq _ _ _ (y0, _)] -> 
+				joinXaligned ((Sq b z xS (y0,y2)):(filter (not.isPrev) sqs))
+			_ -> pres : joinXaligned sqs
+joinXaligned [] = []
+
+
+joinYaligned (pres@(Sq b z (x1,x2) yS):sqs) = 
+	let
+		isNext (Sq _ _ (a,_) _) = a == x2
+		isPrev (Sq _ _ (_,a) _) = a == x1
+	in case filter isNext sqs of
+		[Sq _ _ (_, x3) _] -> 
+			joinYaligned ((Sq b z (x1,x3) yS):(filter (not.isNext) sqs))
+		_ -> case filter isPrev sqs of
+			[Sq _ _ (x0, _) _] -> 
+				joinYaligned ((Sq b z (x0,x2) yS):(filter (not.isPrev) sqs))
+			_ -> pres : joinYaligned sqs
+joinYaligned [] = []
+
+
+squareToTri (Sq (b1,b2,b3) z (x1,x2) (y1,y2)) =
+	let
+		zV = b3 S.* z
+		(x1V, x2V) = (x1 S.* b1, x2 S.* b1)
+		(y1V, y2V) = (y1 S.* b2, y2 S.* b2)
+		a = zV S.+ x1V S.+ y1V
+		b = zV S.+ x2V S.+ y1V
+		c = zV S.+ x1V S.+ y2V
+		d = zV S.+ x2V S.+ y2V
+	in
+		[(a,b,c),(c,b,d)]
+
+
diff --git a/Graphics/Implicit/Export/Render/Interpolate.hs b/Graphics/Implicit/Export/Render/Interpolate.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/Interpolate.hs
@@ -0,0 +1,53 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.Interpolate (interpolate) where
+
+interpolate (a,aval) (b,bval) _ _ | aval*bval > 0 = a
+interpolate (a,aval) (b,bval) f res = 
+	let
+		a' = (a*95+5*b)/100
+		b' = (b*95+5*a)/100
+		a'val = f a'
+		b'val = f b'
+		deriva = abs $ 20*(aval - a'val)
+		derivb = abs $ 20*(bval - b'val)
+	in if deriva < 0.1 || derivb < 0.1
+	then interpolate_bin 0 
+		(if aval*a'val > 0 then (a',a'val) else (a,aval))
+		(if bval*b'val > 0 then (b',b'val) else (b,bval))
+		f
+	else  interpolate_lin 0 
+		(if aval*a'val > 0 then (a',a'val) else (a,aval))
+		(if bval*b'val > 0 then (b',b'val) else (b,bval))
+		f res
+
+interpolate_lin _ (a, 0) _ _ _ = a
+interpolate_lin _ _ (b, 0) _ _ = b
+interpolate_lin n (a, aval) (b, bval) obj res | aval /= bval= 
+	let
+		mid = a + (b-a)*aval/(aval-bval)
+		midval = obj mid
+	in if abs midval < res/500 || mid > 3
+	then mid
+	else if midval * aval > 0
+	then interpolate_lin (n+1) (mid, midval) (b, bval) obj res
+	else interpolate_lin (n+1) (a,aval) (mid, midval) obj res
+interpolate_lin _ (a, _) _ _ _ = a
+
+interpolate_bin n (a,aval) (b,bval) f = if aval > bval
+	then interpolate_bin' n (a,aval) (b,bval) f
+	else interpolate_bin' n (b,bval) (a,aval) f
+
+interpolate_bin' 4 (a,aval) (b,bval) f = 
+	if abs aval < abs bval
+	then a
+	else b
+interpolate_bin' n (a,aval) (b,bval) f =
+	let
+		mid = (a+b)/2
+		midval = f mid
+	in if midval > 0
+	then interpolate_bin' (n+1) (mid,midval) (b,bval) f
+	else interpolate_bin' (n+1) (a,aval) (mid,midval) f
+
diff --git a/Graphics/Implicit/Export/Render/RefineSegs.hs b/Graphics/Implicit/Export/Render/RefineSegs.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/RefineSegs.hs
@@ -0,0 +1,75 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.RefineSegs where
+
+import Graphics.Implicit.Definitions
+import qualified Graphics.Implicit.SaneOperators as S
+import Graphics.Implicit.SaneOperators ((⋅), (⨯), norm, normalized)
+
+refine :: ℝ -> Obj2 -> [ℝ2] -> [ℝ2]
+refine res obj = simplify res . detail' res obj
+
+
+detail' res obj [p1@(x1,y1), p2@(x2,y2)] | (x2-x1)^2 + (y2-y1)^2 > res^2/200 = 
+		detail 0 res obj [p1,p2]
+detail' _ _ a = a
+
+detail :: Int -> ℝ -> (ℝ2 -> ℝ) -> [ℝ2] -> [ℝ2]
+detail n res obj [p1@(x1,y1), p2@(x2,y2)] | n < 2 =
+	let
+		mid@(midX, midY) = (p1 S.+ p2) S./ (2 :: ℝ)
+		midval = obj mid 
+	in if abs midval < res / 40
+	then [(x1,y1), (x2,y2)]
+	else let
+		normal = (\(a,b) -> (b, -a)) $ normalized (p2 S.- p1) 
+		derivN = -(obj (mid S.- (normal S.* (midval/2))) - midval) S.* (2/midval)
+	in if abs derivN > 0.5 && abs derivN < 2
+	then let
+		mid' = mid S.- (normal S.* (midval / derivN))
+	in detail (n+1) res obj [(x1,y1), mid'] 
+	   ++ tail (detail (n+1) res obj [mid', (x2,y2)] )
+	else let
+		derivX = (obj (midX + res/100, midY) - midval)*100/res
+		derivY = (obj (midX, midY + res/100) - midval)*100/res
+		derivNormSq = derivX^2+derivY^2
+	in if abs derivNormSq > 0.09 && abs derivNormSq < 4
+	then let
+		(dX, dY) = (- derivX*midval/derivNormSq, - derivY*midval/derivNormSq)
+		mid'@(midX', midY') = 
+			(midX + dX, midY + dY)
+		midval' = obj mid'
+		posRatio = midval/(midval - midval')
+		mid''@(midX'', midY'') = (midX + dX*posRatio, midY + dY*posRatio)
+	in 
+		detail (n+1) res obj [(x1,y1), mid''] ++ tail (detail (n+1) res obj [mid'', (x2,y2)] )
+	else [(x1,y1), (x2,y2)]
+
+
+detail _ _ _ x = x
+
+simplify res = {-simplify3 . simplify2 res . -} simplify1
+
+simplify1 :: [ℝ2] -> [ℝ2]
+simplify1 (a:b:c:xs) =
+	if abs ( ((b S.- a) ⋅ (c S.- a)) - norm (b S.- a) * norm (c S.- a) ) < 0.0001
+	then simplify1 (a:c:xs)
+	else a : simplify1 (b:c:xs)
+simplify1 a = a
+
+{-
+simplify2 :: ℝ -> [ℝ2] -> [ℝ2]
+simplify2 res [a,b,c,d] = 
+	if norm (b S.- c) < res/10
+	then [a, ((b S.+ c) S./ (2::ℝ)), d]
+	else [a,b,c,d]
+simplify2 _ a = a
+
+simplify3 (a:as) | length as > 5 = simplify3 $ a : half (init as) ++ [last as]
+	where
+		half (a:b:xs) = a : half xs
+		half a = a
+simplify3 a = a
+
+-}
diff --git a/Graphics/Implicit/Export/Render/TesselateLoops.hs b/Graphics/Implicit/Export/Render/TesselateLoops.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/Render/TesselateLoops.hs
@@ -0,0 +1,77 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.Render.TesselateLoops (tesselateLoop) where
+
+import Graphics.Implicit.Definitions
+import Graphics.Implicit.Export.Render.Definitions
+import qualified Graphics.Implicit.SaneOperators as S
+import Graphics.Implicit.SaneOperators ((⋅),norm,(⨯),normalized)
+import Debug.Trace
+
+tesselateLoop :: ℝ -> Obj3 -> [[ℝ3]] -> [TriSquare]
+
+tesselateLoop _ _ [] = []
+
+tesselateLoop _ _ [[a,b],[_,c],[_,_]] = return $ Tris [(a,b,c)]
+
+tesselateLoop res obj [[_,_], as@(_:_:_:_),[_,_], bs@(_:_:_:_)] | length as == length bs =
+	concat $ map (tesselateLoop res obj) $ 
+		[[[a1,b1],[b1,b2],[b2,a2],[a2,a1]] | ((a1,b1),(a2,b2)) <- zip (init pairs) (tail pairs)]
+			where pairs = zip (reverse as) bs
+
+tesselateLoop res obj [as@(_:_:_:_),[_,_], bs@(_:_:_:_), [_,_] ] | length as == length bs =
+	concat $ map (tesselateLoop res obj) $ 
+		[[[a1,b1],[b1,b2],[b2,a2],[a2,a1]] | ((a1,b1),(a2,b2)) <- zip (init pairs) (tail pairs)]
+			where pairs = zip (reverse as) bs
+
+tesselateLoop res obj [[a,_],[b,_],[c,_],[d,_]] | (a S.+ c) == (b S.+ d) =
+	let
+		b1 = normalized $ a S.- b
+		b2 = normalized $ c S.- b
+		b3 = b1 ⨯ b2
+	in [Sq (b1,b2,b3) (a ⋅ b3) (a ⋅ b1, c ⋅ b1) (a ⋅ b2, c ⋅ b2) ]
+
+tesselateLoop res obj [[a,_],[b,_],[c,_],[d,_]] | obj ((a S.+ c) S./ (2 :: ℝ)) < res/30 =
+	return $ Tris $ [(a,b,c),(a,c,d)]
+
+tesselateLoop res obj pathSides = return $ Tris $
+	let
+		path' = concat $ map init pathSides
+		(early_tris,path) = shrinkLoop 0 path' res obj
+	in if null path
+	then early_tris
+	else let
+		len = fromIntegral $ length path :: ℝ
+		mid@(midx,midy,midz) = (foldl1 (S.+) path) S./ len
+		midval = obj mid
+		preNormal = foldl1 (S.+) $
+			[ a ⨯ b | (a,b) <- zip path (tail path ++ [head path]) ]
+		preNormalNorm = norm preNormal
+		normal = preNormal S./ preNormalNorm
+		deriv = (obj (mid S.+ (normal S.* (res/100)) ) - midval)/res*100
+		mid' = mid S.- normal S.* (midval/deriv)
+	in if abs midval > res/50 && preNormalNorm > 0.5 && abs deriv > 0.5 
+		      && abs (deriv*midval) < 1.1*res && 5*abs (obj mid') < abs midval
+		then early_tris ++ [(a,b,mid') | (a,b) <- zip path (tail path ++ [head path]) ]
+		else early_tris ++ [(a,b,mid) | (a,b) <- zip path (tail path ++ [head path]) ]
+
+
+shrinkLoop :: Int -> [ℝ3] -> ℝ -> Obj3 -> ([Triangle], [ℝ3])
+
+shrinkLoop _ path@[a,b,c] res obj =
+	if   abs (obj ((a S.+ b S.+ c) S./ (3::ℝ) )) < res/50
+	then 
+		( [(a,b,c)], [])
+	else 
+		([], path)
+
+shrinkLoop n path@(a:b:c:xs) res obj | n < length path =
+	if abs (obj ((a S.+ c) S./ (2::ℝ) )) < res/50
+	then 
+		let (tris,remainder) = shrinkLoop 0 (a:c:xs) res obj
+		in ((a,b,c):tris, remainder)
+	else 
+		shrinkLoop (n+1) (b:c:xs ++ [a]) res obj
+
+shrinkLoop _ path _ _ = ([],path)
diff --git a/Graphics/Implicit/Export/Symbolic/CoerceSymbolic2.hs b/Graphics/Implicit/Export/Symbolic/CoerceSymbolic2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Export/Symbolic/CoerceSymbolic2.hs
+++ /dev/null
@@ -1,28 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Export.Symbolic.CoerceSymbolic2 (coerceSymbolic2) where
-
-import Graphics.Implicit.Definitions
-
-import Graphics.Implicit.Export.Definitions
-import Graphics.Implicit.Operations
-import Graphics.Implicit.Primitives
-
-coerceSymbolic2 :: SymbolicObj2 -> BoxedObj2
-coerceSymbolic2 (EmbedBoxedObj2 boxedObj) = boxedObj
-coerceSymbolic2 (RectR r a b) = rectR r a b
-coerceSymbolic2 (Circle r ) = circle r
-coerceSymbolic2 (PolygonR r points) = polygonR r points
-coerceSymbolic2 (UnionR2 r objs) = unionR r (map coerceSymbolic2 objs)
-coerceSymbolic2 (IntersectR2 r objs) = intersectR r (map coerceSymbolic2 objs)
-coerceSymbolic2 (DifferenceR2 r objs) = differenceR r (map coerceSymbolic2 objs)
-coerceSymbolic2 (Complement2 obj) = complement $ coerceSymbolic2 obj
-coerceSymbolic2 (Shell2 w obj) = shell w $ coerceSymbolic2 obj
-coerceSymbolic2 (Translate2 v obj) = translate v $ coerceSymbolic2 obj
-coerceSymbolic2 (Scale2 s obj) = scale s $ coerceSymbolic2 obj
-coerceSymbolic2 (Rotate2 a obj) = rotateXY a $ coerceSymbolic2 obj
-coerceSymbolic2 (Outset2 d obj) = outset 2 $ coerceSymbolic2 obj
-
diff --git a/Graphics/Implicit/Export/Symbolic/CoerceSymbolic3.hs b/Graphics/Implicit/Export/Symbolic/CoerceSymbolic3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Export/Symbolic/CoerceSymbolic3.hs
+++ /dev/null
@@ -1,33 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
--- We just want to export the instance...
-module Graphics.Implicit.Export.Symbolic.CoerceSymbolic3 (coerceSymbolic3) where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Export.Definitions
-
-import Graphics.Implicit.Operations
-import Graphics.Implicit.Primitives
-
-import Graphics.Implicit.Export.Symbolic.CoerceSymbolic2
-
-coerceSymbolic3 :: SymbolicObj3 -> BoxedObj3
-coerceSymbolic3 (EmbedBoxedObj3 boxedObj) = boxedObj
-coerceSymbolic3 (Rect3R r a b) = rect3R r a b
-coerceSymbolic3 (Sphere r ) = sphere r
-coerceSymbolic3 (UnionR3 r objs) = unionR r (map coerceSymbolic3 objs)
-coerceSymbolic3 (IntersectR3 r objs) = intersectR r (map coerceSymbolic3 objs)
-coerceSymbolic3 (DifferenceR3 r objs) = differenceR r (map coerceSymbolic3 objs)
-coerceSymbolic3 (Complement3 obj) = complement $ coerceSymbolic3 obj
-coerceSymbolic3 (Shell3 w obj) = shell w $ coerceSymbolic3 obj
-coerceSymbolic3 (Translate3 v obj) = translate v $ coerceSymbolic3 obj
-coerceSymbolic3 (Scale3 s obj) = scale s $ coerceSymbolic3 obj
-coerceSymbolic3 (Outset3 d obj) = outset d $ coerceSymbolic3 obj
-coerceSymbolic3 (Rotate3 rot obj) = rotate3 rot $ coerceSymbolic3 obj
-coerceSymbolic3 (ExtrudeR r obj h) = extrudeR r (coerceSymbolic2 obj) h
-coerceSymbolic3 (ExtrudeRMod r mod obj h) = extrudeRMod r mod (coerceSymbolic2 obj) h
-coerceSymbolic3 (ExtrudeOnEdgeOf obj1 obj2) = extrudeOnEdgeOf (coerceSymbolic2 obj1) (coerceSymbolic2 obj2)
-
diff --git a/Graphics/Implicit/Export/SymbolicFormats.hs b/Graphics/Implicit/Export/SymbolicFormats.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/Export/SymbolicFormats.hs
@@ -0,0 +1,81 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+module Graphics.Implicit.Export.SymbolicFormats where
+
+import Graphics.Implicit.Definitions
+import Data.List as List
+
+scad3 :: ℝ -> SymbolicObj3 -> String
+
+scad3 res (UnionR3 0 objs) = 
+	"union() {\n"
+	++ concat (map ((++"\n") . scad3 res) objs)
+	++ "}\n"
+scad3 res (DifferenceR3 0 objs) = 
+	"difference() {\n"
+	++ concat (map ((++"\n") . scad3 res) objs)
+	++ "}\n"
+scad3 res (IntersectR3 0 objs) = 
+	"intersection() {\n"
+	++ concat (map ((++"\n") . scad3 res) objs)
+	++ "}\n"
+scad3 res (Translate3 (x,y,z) obj) =
+	"translate ([" ++ show x ++ "," ++ show y ++ "," ++ show z ++ "]) "
+	++ scad3 res obj
+scad3 res (Scale3 (x,y,z) obj) =
+	"scale ([" ++ show x ++ "," ++ show y ++ "," ++ show z ++ "]) "
+	++ scad3 res obj
+scad3 _ (Rect3R 0 (x1,y1,z1) (x2,y2,z2)) =
+	"translate ([" ++ show x1 ++ "," ++ show y1 ++ "," ++ show z1 ++ "]) "
+	++ "cube ([" ++ show (x2-x1) ++ "," ++ show (y2-y1) ++ "," ++ show (z2-z1) ++ "]);"
+scad3 _ (Cylinder h r1 r2) =
+	"cylinder(r1 = " ++ show r1 ++ ", r2 = " ++ show r2 ++ ", " ++ show h ++ ");"
+scad3 _ (Sphere r) =
+	"sphere(r = " ++ show r ++");"
+scad3 res (ExtrudeR 0 obj h) =
+	"linear_extrude(" ++ show h ++ ")"
+	++ scad2 res obj
+scad3 res (ExtrudeRotateR 0 twist obj h) = 
+	"linear_extrude(" ++ show h ++ ", twist = " ++ show twist ++ " )"
+	++ scad2 res obj
+scad3 res (ExtrudeRM 0 (Just twist) Nothing Nothing obj (Left height)) =
+	let
+		for a b = map b a
+		a ++! b = a ++ show b
+	in (\pieces -> "union(){" ++ concat pieces ++ "}") . for (init [0, res.. height]) $ \h ->
+		"rotate ([0,0," ++! twist h ++ "]) "
+		++ "linear_extrude(" ++! res ++ ", twist = " ++! (twist (h+res) - twist h) ++ " )"
+		++ scad2 res obj
+
+scad2 res (UnionR2 0 objs) = 
+	"union() {\n"
+	++ concat (map ((++"\n") . scad2 res) objs)
+	++ "}\n"
+scad2 res (DifferenceR2 0 objs) = 
+	"difference() {\n"
+	++ concat (map ((++"\n") . scad2 res) objs)
+	++ "}\n"
+scad2 res (IntersectR2 0 objs) = 
+	"intersection() {\n"
+	++ concat (map ((++"\n") . scad2 res) objs)
+	++ "}\n"
+scad2 res (Translate2 (x,y) obj) =
+	"translate ([" ++ show x ++ "," ++ show y ++ "," ++ "]) "
+	++ scad2 res obj
+scad2 res (Scale2 (x,y) obj) =
+	"scale ([" ++ show x ++ "," ++ show y ++ "]) "
+	++ scad2 res obj
+scad2 _ (RectR 0 (x1,y1) (x2,y2)) =
+	"translate ([" ++ show x1 ++ "," ++ show y1 ++ "]) "
+	++ "cube ([" ++ show (x2-x1) ++ "," ++ show (y2-y1) ++ "]);"
+scad2 _ (Circle r) = "circle(" ++ show r ++ ");"
+scad2 _ (PolygonR 0 points) = 
+	"polygon(" 
+	++ "[" 
+	++ (concat. List.intersperse "," . map (\(a,b) -> "["++show a++","++show b++"]" ) $ points)
+	++ "]"
+	++ ");"
+
+
+
diff --git a/Graphics/Implicit/Export/SymbolicObj2.hs b/Graphics/Implicit/Export/SymbolicObj2.hs
--- a/Graphics/Implicit/Export/SymbolicObj2.hs
+++ b/Graphics/Implicit/Export/SymbolicObj2.hs
@@ -14,34 +14,45 @@
 import Graphics.Implicit.Export.Definitions
 import Graphics.Implicit.Export.MarchingSquares
 import Graphics.Implicit.Export.MarchingSquaresFill
-import Graphics.Implicit.Operations
 import Graphics.Implicit.Primitives
+import Graphics.Implicit.ObjectUtil
 
-import Graphics.Implicit.Export.Symbolic.CoerceSymbolic2
-import Graphics.Implicit.Export.Symbolic.CoerceSymbolic3
 import Graphics.Implicit.Export.Symbolic.Rebound2
 import Graphics.Implicit.Export.Symbolic.Rebound3
 
+
 import qualified Graphics.Implicit.SaneOperators as S
 
 instance DiscreteAproxable SymbolicObj2 [Polyline] where
 	discreteAprox res obj = symbolicGetContour res obj
 
+symbolicGetOrientedContour :: ℝ ->  SymbolicObj2 -> [Polyline]
+symbolicGetOrientedContour res symbObj = map orient $ symbolicGetContour res symbObj
+	where
+		obj = getImplicit2 symbObj
+		orient :: Polyline -> Polyline
+		orient points@(x:y:_) = 
+			let 
+				v = (\(a,b) -> (b, -a)) (y S.- x)
+				dv = v S./ (S.norm v / res / 0.1)
+			in if obj (x S.+ dv) - obj x > 0
+			then points
+			else reverse points
 
 symbolicGetContour :: ℝ ->  SymbolicObj2 -> [Polyline]
 symbolicGetContour _ (RectR 0 (x1,y1) (x2,y2)) = [[ (x1,y1), (x2,y1), (x2,y2), (x1,y2), (x1,y1) ]]
 symbolicGetContour res (Circle r) = [[ ( r*cos(2*pi*m/n), r*sin(2*pi*m/n) ) | m <- [0.. n] ]] where
 	n = max 5 (fromIntegral $ ceiling $ 2*pi*r/res)
 symbolicGetContour res (Translate2 v obj) = map (map (S.+ v) ) $ symbolicGetContour res obj
-symbolicGetContour res (Scale2 s obj) = map (map (S.* s)) $ symbolicGetContour res obj
-symbolicGetContour res obj = case rebound2 (coerceSymbolic2 obj) of
+symbolicGetContour res (Scale2 s obj) = map (map (S.⋯* s)) $ symbolicGetContour res obj
+symbolicGetContour res obj = case rebound2 (getImplicit2 obj, getBox2 obj) of
 	(obj, (a,b)) -> getContour a b (res,res) obj
 
 
 symbolicGetContourMesh :: ℝ ->  SymbolicObj2 -> [(ℝ2,ℝ2,ℝ2)]
 symbolicGetContourMesh res (Translate2 v obj) = map (\(a,b,c) -> (a S.+ v, b S.+ v, c S.+ v) )  $
 	symbolicGetContourMesh res obj
-symbolicGetContourMesh res (Scale2 s obj) = map (\(a,b,c) -> (a S.* s, b S.* s, c S.* s) )  $
+symbolicGetContourMesh res (Scale2 s obj) = map (\(a,b,c) -> (a S.⋯* s, b S.⋯* s, c S.⋯* s) )  $
 	symbolicGetContourMesh res obj
 symbolicGetContourMesh _ (RectR 0 (x1,y1) (x2,y2)) = [((x1,y1), (x2,y1), (x2,y2)), ((x2,y2), (x1,y2), (x1,y1)) ]
 symbolicGetContourMesh res (Circle r) = 
@@ -51,7 +62,7 @@
 	  )| m <- [0.. n-1] ] 
 	where
 		n = max 5 (fromIntegral $ ceiling $ 2*pi*r/res)
-symbolicGetContourMesh res obj = case rebound2 (coerceSymbolic2 obj) of
+symbolicGetContourMesh res obj = case rebound2 (getImplicit2 obj, getBox2 obj) of
 	(obj, (a,b)) -> getContourMesh a b (res,res) obj
 
 
diff --git a/Graphics/Implicit/Export/SymbolicObj3.hs b/Graphics/Implicit/Export/SymbolicObj3.hs
--- a/Graphics/Implicit/Export/SymbolicObj3.hs
+++ b/Graphics/Implicit/Export/SymbolicObj3.hs
@@ -12,27 +12,33 @@
 import Graphics.Implicit.Definitions
 
 import Graphics.Implicit.Export.Definitions
-import Graphics.Implicit.Export.MarchingCubes
+import Graphics.Implicit.Export.Render (getMesh)
 
-import Graphics.Implicit.Operations
 import Graphics.Implicit.Primitives
+import Graphics.Implicit.ObjectUtil
+import Graphics.Implicit.MathUtil
 
 import Graphics.Implicit.Export.SymbolicObj2
 
 import qualified Graphics.Implicit.SaneOperators as S
 
-import Graphics.Implicit.Export.Symbolic.CoerceSymbolic2
-import Graphics.Implicit.Export.Symbolic.CoerceSymbolic3
+import qualified Data.Maybe as Maybe
+
 import Graphics.Implicit.Export.Symbolic.Rebound2
 import Graphics.Implicit.Export.Symbolic.Rebound3
-import Graphics.Implicit.Export.Util (divideMeshTo, dividePolylineTo)
+--import Graphics.Implicit.Export.Util (divideMeshTo, dividePolylineTo)
+import Graphics.Implicit.Export.Util (normTriangle)
 
 
 instance DiscreteAproxable SymbolicObj3 TriangleMesh where
 	discreteAprox res obj = symbolicGetMesh res obj
 
+instance DiscreteAproxable SymbolicObj3 NormedTriangleMesh where
+	discreteAprox res obj = map (normTriangle res (getImplicit3 obj)) $ symbolicGetMesh res obj
+
 symbolicGetMesh :: ℝ -> SymbolicObj3 -> [(ℝ3, ℝ3, ℝ3)]
 
+{--
 -- A translated objects mesh is its mesh translated.
 symbolicGetMesh res (Translate3 v obj) = 
 	map (\(a,b,c) -> (a S.+ v, b S.+ v, c S.+ v) ) (symbolicGetMesh res obj)
@@ -43,34 +49,48 @@
 		mesh :: [(ℝ3, ℝ3, ℝ3)]
 		mesh = symbolicGetMesh res obj
 		scaleTriangle :: (ℝ3, ℝ3, ℝ3) -> (ℝ3, ℝ3, ℝ3)
-		scaleTriangle (a,b,c) = (s S.* a, s S.* b, s S.* c)
+		scaleTriangle (a,b,c) = (s S.⋯* a, s S.⋯* b, s S.⋯* c)
 	in map scaleTriangle  mesh
 
 -- A couple triangles make a cube...
 symbolicGetMesh _ (Rect3R 0 (x1,y1,z1) (x2,y2,z2)) = 
 	let
 		square a b c d = [(a,b,c),(d,a,c)]
+		rsquare a b c d = [(c,b,a),(c,a,d)]
 	in
-		   square (x1,y1,z1) (x2,y1,z1) (x2,y2,z1) (x1,y2,z1)
+		   rsquare (x1,y1,z1) (x2,y1,z1) (x2,y2,z1) (x1,y2,z1)
 		++ square (x1,y1,z2) (x2,y1,z2) (x2,y2,z2) (x1,y2,z2)
 		++ square (x1,y1,z1) (x2,y1,z1) (x2,y1,z2) (x1,y1,z2)
-		++ square (x1,y2,z1) (x2,y2,z1) (x2,y2,z2) (x1,y2,z2)
+		++ rsquare (x1,y2,z1) (x2,y2,z1) (x2,y2,z2) (x1,y2,z2)
 		++ square (x1,y1,z1) (x1,y1,z2) (x1,y2,z2) (x1,y2,z1)
-		++ square (x2,y1,z1) (x2,y1,z2) (x2,y2,z2) (x2,y2,z1)
+		++ rsquare (x2,y1,z1) (x2,y1,z2) (x2,y2,z2) (x2,y2,z1)
 
--- Use spherical coordiantes to create an easy tesselation of a sphere
-symbolicGetMesh res (Sphere r) = 
-	let
+-- Use spherical coordinates to create an easy tesselation of a sphere
+symbolicGetMesh res (Sphere r) = half1 ++ half2
+	where
+		-- Convenience functions for mesh generation
 		square a b c d = [(a,b,c),(d,a,c)]
-		n = max 5 (fromIntegral $ ceiling $ 3*r/res)
-	in
-		concat [ square
-		 (r*cos(2*pi*m1/n),     r*sin(2*pi*m1/n)*cos(pi*m2/n),     r*sin(2*pi*m1/n)*sin(pi*m2/n) ) 
-		 (r*cos(2*pi*(m1+1)/n), r*sin(2*pi*(m1+1)/n)*cos(pi*m2/n), r*sin(2*pi*(m1+1)/n)*sin(pi*m2/n) ) 
-		 (r*cos(2*pi*(m1+1)/n), r*sin(2*pi*(m1+1)/n)*cos(pi*(m2+1)/n), r*sin(2*pi*(m1+1)/n)*sin(pi*(m2+1)/n) ) 
-		 (r*cos(2*pi*m1/n),     r*sin(2*pi*m1/n)*cos(pi*(m2+1)/n), r*sin(2*pi*m1/n)*sin(pi*(m2+1)/n)) 
-		  | m1 <- [0.. n-1], m2 <- [0.. n-1] ]
+		rsquare a b c d = [(c,b,a),(c,a,d)]
+		-- Number of steps of φ and θ respectivly
+		m = max 3 (fromIntegral $ ceiling $ 1.5*r/res)
+		n = 2*m
+		-- Spherical coordinates
+		spherical θ φ = (r*cos(θ), r*sin(θ)*cos(φ), r*sin(θ)*sin(φ))
+		-- Function placing steps on sphere
+		f n' m' = spherical (2*pi*n'/n) (pi*m'/m)
+		-- Mesh in two pieces..
+		half1 = concat [ square (f m1 m2) (f (m1+1) m2) (f (m1+1) (m2+1)) (f m1 (m2+1)) 
+		                | m1 <- [0.. m-1], m2 <- [0.. m-1] ]
+		half2 = concat [ rsquare (f m1 m2) (f (m1+1) m2) (f (m1+1) (m2+1)) (f m1 (m2+1)) 
+		                | m1 <- [m.. n-1], m2 <- [0.. m-1] ]
 
+{-symbolicGetMesh res (UnionR3 r [ExtrudeR ra obja ha, ExtrudeR rb objb hb]) 
+	| ha == hb && ra == rb = symbolicGetMesh res $ ExtrudeR ra (UnionR2 r [obja, objb]) ha
+
+symbolicGetMesh res (UnionR3 r [ExtrudeR ra obja ha, ExtrudeR rb objb hb, ExtrudeR rc objc hc]) 
+	| ha == hb && ha == hc && ra == rb && ra == rc = 
+		symbolicGetMesh res $ ExtrudeR ra (UnionR2 r [obja, objb, objc]) ha-}
+
 -- We can compute a mesh of a rounded, extruded object from it contour, 
 -- contour filling trinagles, and magic.
 -- General approach:
@@ -81,7 +101,7 @@
 	let
 		-- Get a Obj2 (magnitude descriptor object)
 		obj2mag :: ℝ2 -> ℝ -- Obj2
-		obj2mag = fst $ coerceSymbolic2 obj2
+		obj2mag = getImplicit2 obj2
 		-- The amount that a point (x,y) on the top should be lifted
 		-- from h-r. Because of rounding, the edges should be h-r,
 		-- but it should increase inwards.
@@ -89,6 +109,8 @@
 		-- Turn a polyline into a list of its segments
 		segify (a:b:xs) = (a,b):(segify $ b:xs)
 		segify _ = []
+		-- Flip a triangle. It's the same triangle with opposite handedness.
+		flipTri (a,b,c) = (a,c,b)
 		-- Turn a segment a--b into a list of triangles forming (a--b)×(r,h-r)
 		-- The dh stuff is to compensate for rounding errors, etc, and ensure that
 		-- the sides meet the top and bottom
@@ -96,14 +118,14 @@
 			[((x1,y1,r-dh x1 y1), (x2,y2,r-dh x2 y2), (x2,y2,h-r+dh x2 y2)), 
 			 ((x1,y1,r-dh x1 y1), (x2,y2,h-r+dh x2 y2), (x1,y1,h-r+dh x1 y1)) ]
 		-- Get a contour polyline for obj2, turn it into a list of segments
-		segs = concat $ map segify $ symbolicGetContour res obj2
+		segs = concat $ map segify $ symbolicGetOrientedContour res obj2
 		-- Create sides for the main body of our object = segs × (r,h-r)
 		side_tris = concat $ map (\(a,b) -> segToSide a b) segs
 		-- Triangles that fill the contour. Make sure the mesh is at least (res/5) fine.
 		-- --res/5 because xyres won't always match up with normal res and we need to compensate.
 		fill_tris = {-divideMeshTo (res/5) $-} symbolicGetContourMesh res obj2
 		-- The bottom. Use dh to determine the z coordinates
-		bottom_tris = [((a1,a2,r-dh a1 a2), (b1,b2,r - dh b1 b2), (c1,c2,r - dh c1 c2)) 
+		bottom_tris = map flipTri $ [((a1,a2,r-dh a1 a2), (b1,b2,r - dh b1 b2), (c1,c2,r - dh c1 c2)) 
 				| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
 		-- Same idea at the top.
 		top_tris = [((a1,a2,h-r+dh a1 a2), (b1,b2,h-r+dh b1 b2), (c1,c2,h-r+dh c1 c2)) 
@@ -113,14 +135,18 @@
 		side_tris ++ bottom_tris ++ top_tris 
 
 
--- This is quite similar to the one above
--- Key differences are the seperation of the middle part into many layers,
--- and the final transform.
-symbolicGetMesh res  (ExtrudeRMod r mod obj2 h) = 
+symbolicGetMesh res  (ExtrudeRM r twist scale translate obj2 h) = 
 	let
 		-- Get a Obj2 (magnitude descriptor object)
 		obj2mag :: Obj2 -- = ℝ2 -> ℝ
-		obj2mag = fst $ coerceSymbolic2 obj2
+		obj2mag = getImplicit2 obj2
+		-- cleanup twist, scale, etc
+		twist' = Maybe.fromMaybe (const 0) twist
+		scale' = Maybe.fromMaybe (const 1) scale
+		translate' = Maybe.fromMaybe (const (0,0)) translate
+		h' = case h of
+			Left n -> const n
+			Right f -> f
 		-- The amount that a point (x,y) on the top should be lifted
 		-- from h-r. Because of rounding, the edges should be h-r,
 		-- but it should increase inwards.
@@ -128,8 +154,10 @@
 		-- Turn a polyline into a list of its segments
 		segify (a:b:xs) = (a,b):(segify $ b:xs)
 		segify _ = []
+		-- Flip a triangle. It's the same triangle with opposite handedness.
+		flipTri (a,b,c) = (a,c,b)
 		-- The number of steps we're going to do the sides in:
-		n = fromIntegral $ ceiling $ h/res
+		n = max 4 $ fromIntegral $ ceiling $ h' (0,0)/res
 		-- Turn a segment a--b into a list of triangles forming 
 		--    (a--b)×(r+(h-2r)*m/n,r+(h-2r)*(m+1)/n)
 		-- The dh stuff is to compensate for rounding errors, etc, and ensure that
@@ -139,22 +167,22 @@
 			let
 				-- Change across the main body of the object,
 				-- at (x1,y1) and (x2,y2) respectivly
-				mainH1 = h - 2*r + 2*dh x1 y1
-				mainH2 = h - 2*r + 2*dh x2 y2
+				mainH1 = h' (x1, y1) - 2*r + 2*dh x1 y1
+				mainH2 = h' (x2, y2) - 2*r + 2*dh x2 y2
 				-- level a (lower) and level b (upper)
 				la1 = r-dh x1 y1  +  mainH1*m/n
 				lb1 = r-dh x1 y1  +  mainH1*(m+1)/n
-				la2 = r-dh x2 y2  +  mainH1*m/n
-				lb2 = r-dh x2 y2  +  mainH1*(m+1)/n
+				la2 = r-dh x2 y2  +  mainH2*m/n
+				lb2 = r-dh x2 y2  +  mainH2*(m+1)/n
 			in
 				-- Resulting triangles: 
 				[((x1,y1,la1), (x2,y2,la2), (x2,y2,lb2)), 
 				 ((x1,y1,la1), (x2,y2,lb2), (x1,y1,lb1)) ]
 		-- Get a contour polyline for obj2, turn it into a list of segments
-		segs = concat $ map segify $ symbolicGetContour res obj2
+		segs = concat $ map segify $ symbolicGetOrientedContour res obj2
 		-- Create sides for the main body of our object = segs × (r,h-r)
 		-- Many layers...
-		side_tris = concat $
+		side_tris = map flipTri $ concat $
 			[concat $ map (\(a,b) -> segToSide m a b) segs | m <- [0.. n-1] ]
 		-- Triangles that fill the contour. Make sure the mesh is at least (res/5) fine.
 		-- --res/5 because xyres won't always match up with normal res and we need to compensate.
@@ -163,13 +191,16 @@
 		bottom_tris = [((a1,a2,r-dh a1 a2), (b1,b2,r - dh b1 b2), (c1,c2,r - dh c1 c2)) 
 				| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
 		-- Same idea at the top.
-		top_tris = [((a1,a2,h-r+dh a1 a2), (b1,b2,h-r+dh b1 b2), (c1,c2,h-r+dh c1 c2)) 
+		top_tris = map flipTri $ [((a1,a2,h' (a1,a2) -r+dh a1 a2), (b1,b2,h' (b1,b2) -r+dh b1 b2), (c1,c2,h' (c1,c2)-r+dh c1 c2)) 
 				| ((a1,a2),(b1,b2),(c1,c2)) <- fill_tris]
 		-- Mesh modifiers in individual components
+		k = 2*pi/360
 		fx :: ℝ3 -> ℝ
-		fx (x,y,z) = fst $ mod z (x,y)
+		fx (x,y,z) = let (tx,ty) = translate' z in
+			scale' z *((x+tx)*cos(k*twist' z) + (y+ty)*sin(k*twist' z))
 		fy :: ℝ3 -> ℝ
-		fy (x,y,z) = snd $ mod z (x,y)
+		fy (x,y,z) =let (tx,ty) = translate' z in
+			scale' z *((x+tx)*sin(k*twist' z) - (y+ty)*cos(k*twist' z))
 		-- function to transform a triangle
 		transformTriangle :: (ℝ3,ℝ3,ℝ3) -> (ℝ3,ℝ3,ℝ3)
 		transformTriangle (a@(_,_,z1), b@(_,_,z2), c@(_,_,z3)) = 
@@ -177,12 +208,34 @@
 
 	in
 		map transformTriangle (side_tris ++ bottom_tris ++ top_tris)
+-}
 
+symbolicGetMesh res inputObj@(UnionR3 r objs) = 
+	let
+		boxes = map getBox3 objs
+		boxedObjs = zip boxes objs
+		
+		sepFree ((box,obj):others) = 
+			if length (filter (box3sWithin r box) boxes) > 1
+			then (\(a,b) -> (obj:a,b)) $ sepFree others
+			else (\(a,b) -> (a,obj:b)) $ sepFree others
+		sepFree [] = ([],[])
+
+		(dependants, independents) = sepFree boxedObjs
+	in if null independents
+	then case rebound3 (getImplicit3 inputObj, getBox3 inputObj) of
+		(obj, (a,b)) -> getMesh a b res obj 
+	else if null dependants
+	then concat $ map (symbolicGetMesh res) independents
+	else concat $ 
+		map (symbolicGetMesh res) independents 
+		++ [symbolicGetMesh res (UnionR3 r dependants)]
+
 -- If all that fails, coerce and apply marching cubes :(
 -- (rebound is for being safe about the bounding box --
 --  it slightly streches it to make sure nothing will 
 --  have problems because it is right at the edge )
 symbolicGetMesh res  obj = 
-	case rebound3 (coerceSymbolic3 obj) of
+	case rebound3 (getImplicit3 obj, getBox3 obj) of
 		(obj, (a,b)) -> getMesh a b res obj 
 
diff --git a/Graphics/Implicit/Export/TriangleMeshFormats.hs b/Graphics/Implicit/Export/TriangleMeshFormats.hs
--- a/Graphics/Implicit/Export/TriangleMeshFormats.hs
+++ b/Graphics/Implicit/Export/TriangleMeshFormats.hs
@@ -24,3 +24,42 @@
 			++ (concat $ map stlTriangle triangles)
 			++ stlFooter
 
+
+jsTHREE :: TriangleMesh -> String
+jsTHREE triangles = text
+	where
+		-- some dense JS. Let's make helper functions so that we don't repeat code each line
+		header = 
+			"var Shape = function(){\n"
+			++  "var s = this;\n"
+			++  "THREE.Geometry.call(this);\n"
+			++  "function vec(x,y,z){return new THREE.Vector3(x,y,z);}\n"
+			++  "function v(x,y,z){s.vertices.push(vec(x,y,z));}\n"
+			++  "function f(a,b,c){"
+			++    "s.faces.push(new THREE.Face3(a,b,c));"
+			++  "}\n"
+		footer =
+			"}\n"
+			++ "Shape.prototype = new THREE.Geometry();\n"
+			++ "Shape.prototype.constructor = Shape;\n"
+		-- A vertex line; v (0.0, 0.0, 1.0) = "v(0.0,0.0,1.0);\n"
+		v :: ℝ3 -> String
+		v (x,y,z) = "v("  ++ show x ++ "," ++ show y ++ "," ++ show z ++ ");\n"
+		-- A face line
+		f :: Int -> Int -> Int -> String
+		f posa posb posc = 
+			"f(" ++ show posa ++ "," ++ show posb ++ "," ++ show posc ++ ");"
+		verts = do
+			-- extract the vertices for each triangle
+			-- recall that a normed triangle is of the form ((vert, norm), ...)
+			(a,b,c) <- triangles
+			-- The vertices from each triangle take up 3 position in the resulting list
+			[a,b,c]
+		vertcode = concat $ map v verts
+		facecode = concat $ do
+			(n,_) <- zip [0, 3 ..] triangles
+			let
+				(posa, posb, posc) = (n, n+1, n+2)
+			return $ f posa posb posc
+		text = header ++ vertcode ++ facecode ++ footer
+
diff --git a/Graphics/Implicit/Export/Util.hs b/Graphics/Implicit/Export/Util.hs
--- a/Graphics/Implicit/Export/Util.hs
+++ b/Graphics/Implicit/Export/Util.hs
@@ -5,13 +5,40 @@
 
 -- Functions to make meshes/polylines finer.
 
-module Graphics.Implicit.Export.Util (divideMesh2To, divideMeshTo, dividePolylineTo) where
+module Graphics.Implicit.Export.Util {-(divideMesh2To, divideMeshTo, dividePolylineTo)-} where
 
--- import Prelude hiding ((+),(-),(*),(/))
+import Prelude hiding ((+),(-),(*),(/))
 import Graphics.Implicit.Definitions
-import qualified Graphics.Implicit.SaneOperators as S
+import Graphics.Implicit.SaneOperators
 
--- If we need to make a 2D mesh finer...
+normTriangle :: ℝ -> Obj3 -> Triangle -> NormedTriangle
+normTriangle res obj tri@(a,b,c) = 
+	(normify a', normify b', normify c') 
+		where 
+			normify = normVertex res obj
+			a' = (a + r*b + r*c)/(1.02 :: ℝ)
+			b' = (b + r*a + r*c)/(1.02 :: ℝ)
+			c' = (c + r*b + r*a)/(1.02 :: ℝ)
+			r = 0.01 :: ℝ
+
+normVertex :: ℝ -> Obj3 -> ℝ3 -> (ℝ3, ℝ3)
+normVertex res obj p@(x,y,z) = 
+	let
+		-- D_vf(p) = ( f(p) - f(p+v) ) /|v|
+		-- but we'll actually scale v by res, so then |v| = res
+		-- and that f is obj
+		-- and is fixed at p
+		-- so actually: d v = ...
+		d :: ℝ3 -> ℝ
+		d v = ( obj (p + (res/(100::ℝ))*v) - obj (p - (res/(100::ℝ))*v) ) /(res/(50::ℝ))
+		dx = d (1, 0, 0)
+		dy = d (0, 1, 0)
+		dz = d (0, 0, 1)
+		nonUnitNormal = (dx,dy,dz)
+		normal = nonUnitNormal / norm nonUnitNormal
+	in ((x,y,z), normal)
+
+{--- If we need to make a 2D mesh finer...
 divideMesh2To :: ℝ -> [(ℝ2, ℝ2, ℝ2)] -> [(ℝ2, ℝ2, ℝ2)]
 divideMesh2To res mesh =
 	let 
@@ -73,4 +100,4 @@
 			else [polyline !! n]
 
 
-
+-}
diff --git a/Graphics/Implicit/ExtOpenScad.hs b/Graphics/Implicit/ExtOpenScad.hs
--- a/Graphics/Implicit/ExtOpenScad.hs
+++ b/Graphics/Implicit/ExtOpenScad.hs
@@ -3,16 +3,18 @@
 
 -- We'd like to parse openscad code, with some improvements, for backwards compatability.
 
-module Graphics.Implicit.ExtOpenScad (runOpenscad) where
+module Graphics.Implicit.ExtOpenScad (runOpenscad, OpenscadObj (..) ) where
 
+import Graphics.Implicit.ExtOpenScad.Definitions (OpenscadObj (..) )
 import Graphics.Implicit.ExtOpenScad.Default (defaultObjects)
-import Graphics.Implicit.ExtOpenScad.Statements (computationStatement, runComputations)
+import Graphics.Implicit.ExtOpenScad.Statements (computationStatement)
+import Graphics.Implicit.ExtOpenScad.Util.Computation (runComputations)
 
-import Text.ParserCombinators.Parsec (parse, many1)
+import Text.ParserCombinators.Parsec (parse, many1, many, space, eof)
 import Control.Monad (liftM)
 
 -- Small wrapper to handle parse errors, etc
-runOpenscad str = case parse (many1 computationStatement) ""  str of
+runOpenscad str = case parse (do {s <- many1 computationStatement; many space; eof; return s}) ""  str of
 	Right res -> Right $ runComputationsDefault res
 	Left  err ->  Left err
 
diff --git a/Graphics/Implicit/ExtOpenScad/Default.hs b/Graphics/Implicit/ExtOpenScad/Default.hs
--- a/Graphics/Implicit/ExtOpenScad/Default.hs
+++ b/Graphics/Implicit/ExtOpenScad/Default.hs
@@ -7,6 +7,7 @@
 
 import Graphics.Implicit.Definitions
 import Graphics.Implicit.ExtOpenScad.Definitions
+import Graphics.Implicit.ExtOpenScad.Primitives
 import Data.Map (Map, fromList)
 
 defaultObjects :: VariableLookup -- = Map String OpenscadObj
@@ -15,47 +16,52 @@
 	++ defaultFunctions
 	++ defaultFunctions2
 	++ defaultFunctionsSpecial
+	++ defaultModules
 
-defaultConstants = map (\(a,b) -> (a, ONum b))
+-- Missing standard ones:
+-- rand, lookup, 
+
+defaultConstants = map (\(a,b) -> (a, toOObj (b::ℝ) ))
 	[("pi", pi)]
 
-defaultFunctions = map (\(a,b) -> (a, numericOFunc b))
+defaultFunctions = map (\(a,b) -> (a, toOObj ( b :: ℝ -> ℝ)))
 	[
 		("sin",   sin),
 		("cos",   cos),
 		("tan",   tan),
+		("asin",  asin),
+		("acos",  acos),
+		("atan",  atan),
 		("abs",   abs),
 		("sign",  signum),
 		("floor", fromIntegral . floor ),
 		("ceil",  fromIntegral . ceiling ),
-		("exp",   exp)
+		("round", fromIntegral . round ),
+		("exp",   exp),
+		("ln",    log),
+		("log",   log),
+		("sign",  signum),
+		("sqrt",  sqrt)
 	]
 
-defaultFunctions2 = map (\(a,b) -> (a, numericOFunc2 b))
+defaultFunctions2 = map (\(a,b) -> (a, toOObj (b :: ℝ -> ℝ -> ℝ) ))
 	[
 		("max", max),
-		("min", min)
+		("min", min),
+		("atan2", atan2),
+		("pow", (**))
 	]
 
-defaultFunctionsSpecial = [("map", mapfunc)]
-
--- Stupid functions for convering to openscad objects follow:
-
-mapfunc = OFunc $ \oObj -> case oObj of
-	OFunc f -> OFunc $ \oObj2 -> case oObj2 of
-		OList l -> OList $ map f l
-		_ -> OUndefined
-	_ -> OUndefined
-
-numericOFunc f = OFunc $ \oObj -> case oObj of
-	ONum n -> ONum $ f n
-	_ -> OUndefined
+defaultFunctionsSpecial = 
+	[
+		("map", toOObj $ flip $ 
+			(map :: (OpenscadObj -> OpenscadObj) -> [OpenscadObj] -> [OpenscadObj] ) 
+		)
+		
+	]
 
 
-numericOFunc2 f = OFunc $ \oObj -> case oObj of
-	ONum n -> OFunc $ \oObj2 -> case oObj2 of
-		ONum n2 -> ONum $ f n n2
-		_ -> OUndefined
-	_ -> OUndefined
+defaultModules =
+	map (\(a,b) -> (a, OModule b)) primitives
 
 
diff --git a/Graphics/Implicit/ExtOpenScad/Definitions.hs b/Graphics/Implicit/ExtOpenScad/Definitions.hs
--- a/Graphics/Implicit/ExtOpenScad/Definitions.hs
+++ b/Graphics/Implicit/ExtOpenScad/Definitions.hs
@@ -3,10 +3,15 @@
 
 -- We'd like to parse openscad code, with some improvements, for backwards compatability.
 
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ScopedTypeVariables, IncoherentInstances, ViewPatterns  #-}
+
 module Graphics.Implicit.ExtOpenScad.Definitions where
 
 import Graphics.Implicit.Definitions
+import Data.Typeable (TypeRep)
 import Data.Map (Map)
+import Data.Maybe (isJust)
+import Control.Monad as Monad
 
 -- Lets make it easy to change the object types we're using :)
 
@@ -15,16 +20,111 @@
 -- | The 3D object type to be used in ExtOpenScad
 type Obj3Type = SymbolicObj3
 
+-- | To look up OpenscadObj variables with a string name
 type VariableLookup = Map String OpenscadObj
 
+-- | Objects for our OpenSCAD-like language
 data OpenscadObj = OUndefined 
 		 | OBool Bool 
 		 | ONum ℝ
 		 | OList [OpenscadObj]
 		 | OString String
 		 | OFunc ( OpenscadObj -> OpenscadObj ) 
-		 | OModule (ArgParser ComputationStateModifier)
+		 | OModule ([ComputationStateModifier]  -> ArgParser ComputationStateModifier)
+		 | OError [String]
 
+instance Eq OpenscadObj where
+	(ONum a) == (ONum b) = a == b
+	(OBool a) == (OBool b) = a == b
+	(OList a) == (OList b) = a == b
+	(OString a) == (OString b) = a == b
+	_ == _ = False
+
+-- | We'd like to be able to turn OpenscadObjs into a given Haskell type
+class OTypeMirror a where
+	fromOObj :: OpenscadObj -> Maybe a
+	toOObj :: a -> OpenscadObj
+
+instance OTypeMirror OpenscadObj where
+	fromOObj a = Just a
+	toOObj a = a
+
+instance OTypeMirror ℝ where
+	fromOObj (ONum n) = Just n
+	fromOObj _ = Nothing
+	toOObj n = ONum n
+
+instance OTypeMirror ℕ where
+	fromOObj (ONum n) = if n == fromIntegral (floor n) then Just (floor n) else Nothing
+	fromOObj _ = Nothing
+	toOObj n = ONum $ fromIntegral n
+
+instance OTypeMirror Bool where
+	fromOObj (OBool b) = Just b
+	fromOObj _ = Nothing
+	toOObj b = OBool b
+
+instance OTypeMirror String where
+	fromOObj (OString str) = Just str
+	fromOObj _ = Nothing
+	toOObj str = OString str
+
+instance forall a. (OTypeMirror a) => OTypeMirror (Maybe a) where
+	fromOObj a = Just $ fromOObj a
+	toOObj (Just a) = toOObj a
+	toOObj Nothing  = OUndefined
+
+instance forall a. (OTypeMirror a) => OTypeMirror [a] where
+	fromOObj (OList list) = Monad.sequence . map fromOObj $ list
+	fromOObj _ = Nothing
+	toOObj list = OList $ map toOObj list
+
+instance forall a b. (OTypeMirror a, OTypeMirror b) => OTypeMirror (a,b) where
+	fromOObj (OList ((fromOObj -> Just a):(fromOObj -> Just b):[])) = Just (a,b)
+	fromOObj _ = Nothing
+	toOObj (a,b) = OList [toOObj a, toOObj b]
+
+
+instance forall a b c. (OTypeMirror a, OTypeMirror b, OTypeMirror c) => OTypeMirror (a,b,c) where
+	fromOObj (OList ((fromOObj -> Just a):(fromOObj -> Just b):(fromOObj -> Just c):[])) = 
+		Just (a,b,c)
+	fromOObj _ = Nothing
+	toOObj (a,b,c) = OList [toOObj a, toOObj b, toOObj c]
+
+instance forall a b. (OTypeMirror a, OTypeMirror b) => OTypeMirror (a -> b) where
+	fromOObj (OFunc f) =  Just $ \input ->
+		let
+			oInput = toOObj input
+			oOutput = f oInput
+			output = fromOObj oOutput :: Maybe b
+		in case output of
+			Just out -> out
+			Nothing -> error $ "coercing OpenscadObj to a -> b isn't always safe; use a -> Maybe b"
+			              ++ " (trace: " ++ show oInput ++ " -> " ++ show oOutput ++ " )"
+	fromOObj _ = Nothing
+	toOObj f = OFunc $ \oObj -> 
+		case fromOObj oObj :: Maybe a of
+			Nothing  -> OError ["bad input type"]
+			Just obj -> toOObj $ f obj
+
+
+instance forall a b. (OTypeMirror a, OTypeMirror b) => OTypeMirror (Either a b) where
+	fromOObj (fromOObj -> Just (x :: a)) = Just $ Left  x
+	fromOObj (fromOObj -> Just (x :: b)) = Just $ Right x
+	fromOObj _ = Nothing
+
+	toOObj (Right x) = toOObj x
+	toOObj (Left  x) = toOObj x
+
+objTypeStr (OUndefined) = "Undefined"
+objTypeStr (OBool   _ ) = "Bool"
+objTypeStr (ONum    _ ) = "Number"
+objTypeStr (OList   _ ) = "List"
+objTypeStr (OString _ ) = "String"
+objTypeStr (OFunc   _ ) = "Function"
+objTypeStr (OModule _ ) = "Module"
+objTypeStr (OError  _ ) = "Error"
+
 instance Show OpenscadObj where
 	show OUndefined = "Undefined"
 	show (OBool b) = show b
@@ -32,10 +132,28 @@
 	show (OList l) = show l
 	show (OString s) = show s
 	show (OFunc f) = "<function>"
+	show (OModule _) = "module"
+	show (OError msgs) = "Execution Error:\n" ++ foldl1 (\a b -> a ++ "\n" ++ b) msgs
 
-data ArgParser a = ArgParser String (Maybe OpenscadObj) (OpenscadObj -> ArgParser a) 
+-- | Handles parsing arguments to modules
+data ArgParser a 
+                 -- | For actual argument entries:
+                 --   ArgParser (argument name) (default) (doc) (next Argparser...)
+                 = ArgParser String (Maybe OpenscadObj) String (OpenscadObj -> ArgParser a) 
+                 -- | For returns:
+                 --   ArgParserTerminator (return value)
                  | ArgParserTerminator a 
-                 | ArgParserFail
+                 -- | For failure:
+                 --   ArgParserFailIf (test) (error message) (child for if true)
+                 | ArgParserFailIf Bool String (ArgParser a)
+                 --  An example, then next
+                 | ArgParserExample String (ArgParser a)
+                 --  A string to run as a test, then invariants for the results, then next
+                 | ArgParserTest String [TestInvariant] (ArgParser a)
+	deriving (Show)
+
+data TestInvariant = EulerCharacteristic Int 
+	deriving (Show)
 
 type ComputationState = IO (VariableLookup, [Obj2Type], [Obj3Type])
 
diff --git a/Graphics/Implicit/ExtOpenScad/Expressions.hs b/Graphics/Implicit/ExtOpenScad/Expressions.hs
--- a/Graphics/Implicit/ExtOpenScad/Expressions.hs
+++ b/Graphics/Implicit/ExtOpenScad/Expressions.hs
@@ -13,6 +13,17 @@
 import Text.ParserCombinators.Parsec 
 import Text.ParserCombinators.Parsec.Expr
 
+errorAsAppropriate _   err@(OError _)   _ = err
+errorAsAppropriate _   _   err@(OError _) = err
+errorAsAppropriate name a b = OError 
+	["Can't " ++ name ++ " objects of types " ++ objTypeStr a ++ " and " ++ objTypeStr b ++ "."]
+
+pad parser = do
+	many space
+	a <- parser
+	many space
+	return a
+
 variableSymb = many1 (noneOf " ,|[]{}()+-*&^%#@!~`'\"\\/;:.,<>?=") <?> "variable"
 
 variable :: GenParser Char st (VariableLookup -> OpenscadObj)
@@ -48,18 +59,18 @@
 
 expression :: Int -> GenParser Char st (VariableLookup -> OpenscadObj)
 expression 10 = (try literal) <|> (try variable )
-	<|> ((do
+	<|> ((do -- ( 1 + 5 )
 		string "(";
 		expr <- expression 0;
 		string ")";
 		return expr;
 	) <?> "bracketed expression" )
-	<|> ( try ( do
+	<|> ( try ( do -- [ 3, a, a+1, b, a*b ]
 		string "[";
 		exprs <- sepBy (expression 0) (char ',' );
 		string "]";
 		return $ \varlookup -> OList (map ($varlookup) exprs )
-	) <|> ( do
+	) <|> ( do -- eg.  [ a : 1 : a + 10 ]
 		string "[";
 		exprs <- sepBy (expression 0) (char ':' );
 		string "]";
@@ -76,88 +87,135 @@
 		applyArgs :: OpenscadObj -> [OpenscadObj] -> OpenscadObj
 		applyArgs obj []  = obj
 		applyArgs (OFunc f) (arg:others) = applyArgs (f arg) others 
-		applyArgs _ _ = OUndefined
+		applyArgs a b = errorAsAppropriate "apply" a (OList b)
 		-- List splicing, like in Python. 'Cause list splicing is
 		-- awesome!
+		-- eg. a = [0:10]; a[2:4] = [2,3,4]
 		splice :: [a] -> ℝ -> ℝ -> [a]
 		splice [] _ _     = []
 		splice (x:xs) a b 
-			| floor a < 0 =      splice xs (fromIntegral $ length xs + floor a) (fromIntegral $ floor b)
-			| floor b < 0 =      splice xs (fromIntegral $ floor a) ( fromIntegral $ length xs + floor b)
-			| floor a > 0 =      splice xs (fromIntegral $ floor a - 1) (fromIntegral $ floor b)
-			| floor b > 0 = x : (splice xs (fromIntegral $ floor a) (fromIntegral $ floor b - 1 ) )
+			| floor a < 0 =   splice xs 
+				(fromIntegral $ length xs + floor a) (fromIntegral $ floor b)
+			| floor b < 0 =   splice xs 
+				(fromIntegral $ floor a) ( fromIntegral $ length xs + floor b)
+			| floor a > 0 =   splice xs 
+				(fromIntegral $ floor a - 1) (fromIntegral $ floor b)
+			| floor b > 0 =
+				x : (splice xs (fromIntegral $ floor a) (fromIntegral $ floor b - 1 ) )
 			| otherwise = []
+		modifier = 
+			(try $ (do
+				many space
+				string "("
+				args <- sepBy 
+					(expression 0) 
+					(many space >> char ',' >> many space)
+				string ")"
+				many space
+				return $ \f varlookup -> applyArgs (f varlookup) (map ($varlookup) args) 
+			<?> "function application"
+			)) <|> (try $ (do
+				many space
+				string "[";
+				i <- pad $ expression 0;
+				string "]";
+				many space
+				return $ \l varlookup ->
+					case (l varlookup, i varlookup) of
+						(OList actual_list, ONum ind) -> actual_list !! (floor ind)
+						(OString str, ONum ind) -> OString $ [str !! (floor ind)]
+						_ -> OUndefined
+			<?> "list indexing"
+			)) <|> (try $ ( do
+				string "[";
+				many space
+				start <- (try $ expression 0) <|> (many space >> return (\_ -> OUndefined));
+				many space
+				char ':';
+				many space
+				end   <- (try $ expression 0) <|> (many space >> return (\_ -> OUndefined));
+				many space
+				string "]";
+				return $ \l varlookup ->
+					case (l varlookup, start varlookup, end varlookup) of
+						(OList  list, ONum a,     ONum b    ) -> 
+									OList   $ splice list a b
+						(OString str, ONum a,     ONum b    ) -> 
+									OString $ splice str  a b
+						(OList  list, OUndefined, ONum b    ) -> 
+									OList   $ splice list 0 b
+						(OString str, OUndefined, ONum b    ) -> 
+									OString $ splice str  0 b
+						(OList  list, ONum a,     OUndefined) -> 
+									OList   $ splice list a (1.0/0.0)
+						(OString str, ONum a,     OUndefined) -> 
+									OString $ splice str  a (1.0/0.0)
+						(OList  list, OUndefined, OUndefined) -> 
+									OList   $ splice list 0 (1.0/0.0)
+						(OString str, OUndefined, OUndefined) -> 
+									OString $ splice str  0 (1.0/0.0)
+						_ -> OUndefined
+			<?> "list splicing"))
+		
 	in ( try( do 
-		f <- expression 10;
+		obj <- expression 10;
 		many space
-		string "(";
-		args <- sepBy (expression 0) (many space >> char ',' >> many space);
-		string ")";
-		return $ \varlookup -> applyArgs (f varlookup) (map ($varlookup) args) 
-	) <?> "function appliation" )
-	<|> ( try( do 
-		l <- expression 10;
-		string "[";
-		i <- expression 0;
-		string "]";
-		return $ \varlookup ->
-			case (l varlookup, i varlookup) of
-				(OList actual_list, ONum ind) -> actual_list !! (floor ind)
-				(OString str, ONum ind) -> OString $ [str !! (floor ind)]
-				_ -> OUndefined
-	) <?> "list indexing" )
-	<|> ( try( do 
-		l <- expression 10;
-		string "[";
-		start <- (try $ expression 0) <|> (many space >> return (\_ -> OUndefined));
-		char ':';
-		end   <- (try $ expression 0) <|> (many space >> return (\_ -> OUndefined));
-		string "]";
-		return $ \varlookup ->
-			case (l varlookup, start varlookup, end varlookup) of
-				(OList  list, ONum a,     ONum b    ) -> OList   $ splice list a b
-				(OString str, ONum a,     ONum b    ) -> OString $ splice str  a b
-				(OList  list, OUndefined, ONum b    ) -> OList   $ splice list 0 b
-				(OString str, OUndefined, ONum b    ) -> OString $ splice str  0 b
-				(OList  list, ONum a,     OUndefined) -> OList   $ splice list a (1.0/0.0)
-				(OString str, ONum a,     OUndefined) -> OString $ splice str  a (1.0/0.0)
-				(OList  list, OUndefined, OUndefined) -> OList   $ splice list 0 (1.0/0.0)
-				(OString str, OUndefined, OUndefined) -> OString $ splice str  0 (1.0/0.0)
-				_ -> OUndefined
-	) <?> "list splicing" )
+		mods <- modifier `sepBy` (many space)
+		many space
+		return $ \varlookup -> foldl (\a b -> b a) obj mods $ varlookup
+		) <?> "list splicing" )
 	<|> try (expression 10)
 expression n@8 = try (( do 
 		a <- expression (n+1);
+		many space
 		string "^";
+		many space
 		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 = 
+expression n@7 = 
 	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
+		mult a         b         = errorAsAppropriate "multiply" a b
 
 		div (ONum a)  (ONum b) = ONum  (a/b)
 		div (OList a) (ONum b) = OList (map (\x -> div x (ONum b)) a)
-		div _         _        = OUndefined
+		div a         b        = errorAsAppropriate "divide" a b
 	in try (( do 
-		exprs <- sepBy1 (sepBy1 (expression $ n+1) (char '/')) (char '*')
+		-- outer list is multiplication, inner division. objects are 
+		-- expressions and take a varlookup to evaluate.
+		-- eg. "1*2*3/4/5*6*7/8"
+		--     [[vl→1],[vl→2],[vl→3,vl→4,vl→5],[vl→6],[vl→7,vl→8]]
+		exprs <- sepBy1 (sepBy1 (pad $ expression $ n+1) 
+			(many space >> char '/' >> many space )) 
+			(many space >> char '*' >> many space)
+		--     [[1],[2],[3,4,5],[6],[7,8]]
+		--     [ 1,  2,  3/4/5,  6,  7/8 ]
+		--       1 * 2 * 3/4/5 * 6 * 7/8 
 		return $ \varlookup -> foldl1 mult $ map ( (foldl1 div) . (map ($varlookup) ) ) exprs;
 	) <?> "multiplication/division")
 	<|>try (expression $ n+1)
+expression n@6 =
+	let 
+		omod (ONum a) (ONum b) = ONum $ fromIntegral $ mod (floor a) (floor b)
+		omod a        b        = errorAsAppropriate "modulo" a b
+	in try (( do 
+		exprs <- sepBy1 (expression $ n+1) (many space >> string "%" >> many space)
+		return $ \varlookup -> foldl1 omod $ map ($varlookup) exprs;
+	) <?> "modulo") 
+	<|>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
+		append a           b           = errorAsAppropriate "append" a b
 	in try (( do 
-		exprs <- sepBy1 (expression $ n+1) (string "++")
+		exprs <- sepBy1 (expression $ n+1) (many space >> string "++" >> many space)
 		return $ \varlookup -> foldl1 append $ map ($varlookup) exprs;
 	) <?> "append") 
 	<|>try (expression $ n+1)
@@ -166,13 +224,18 @@
 	let 
 		add (ONum a) (ONum b) = ONum (a+b)
 		add (OList a) (OList b) = OList $ zipWith add a b
-		add _ _ = OUndefined
+		add a b = errorAsAppropriate "add" a b
 
 		sub (ONum a) (ONum b) = ONum (a-b)
 		sub (OList a) (OList b) = OList $ zipWith sub a b
-		sub _ _ = OUndefined
+		sub a b = errorAsAppropriate "subtract" a b
 	in try (( do 
-		exprs <- sepBy1 (sepBy1 (expression $ n+1) ( char '-')) (char '+')
+		-- Similar to multiply & divide
+		-- eg. "1+2+3-4-5+6-7" 
+		--     [[1],[2],[3,4,5],[6,7]]
+		exprs <- sepBy1 (sepBy1 (pad $ expression $ n+1) 
+			(many space >> char '-' >> many space )) 
+			(many space >> char '+' >> many space)
 		return $ \varlookup -> foldl1 add $ map ( (foldl1 sub) . (map ($varlookup) ) ) exprs;
 	) <?> "addition/subtraction")
 	<|>try (expression $ n+1)
@@ -180,14 +243,43 @@
 	let
 		negate (ONum n) = ONum (-n)
 		negate (OList l) = OList $ map negate l
-		negate _ = OUndefined
+		negate a = OError ["Can't negate " ++ objTypeStr a ++ "(" ++ show a ++ ")"]
 	in try (do
 		char '-'
 		many space
 		expr <- expression $ n+1
-		return $ \varlookup -> negate $ expr varlookup
+		return $ negate . expr
+	) <|> try (do
+		char '+'
+		many space
+		expr <- expression $ n+1
+		return $ expr
 	) <|> try (expression $ n+1)
 expression n@2 = try (expression $ n+1)
-expression n@1 = try (expression $ n+1)
+expression n@1 = 
+	try ( do
+		let 
+			numCompareToExprCompare f a b varlookup =
+				case (fromOObj (a varlookup) :: Maybe ℝ, fromOObj (b varlookup) :: Maybe ℝ) of
+					(Just a, Just b) -> f a b
+					_ -> False
+			numericComparisons = fmap numCompareToExprCompare $
+				    (try $ string "==" >> return (==) )
+				<|> (try $ string "!=" >> return (/=) )
+				<|> (try $ string ">=" >> return (>=) )
+				<|> (try $ string "<=" >> return (<=) )
+				<|> (try $ string ">"  >> return (>)  )
+				<|> (try $ string "<"  >> return (<)  )
+		firstExpr <- expression $ n+1
+		otherExpr <- many $ do
+			comparison <- numericComparisons
+			expr <- expression $ n+1
+			return (comparison, expr)
+		return $ if null otherExpr then firstExpr else fmap toOObj $ fst $ foldl 
+			(\(bstart, prevExpr) (comp, nextExpr) -> 
+				(\vlookup -> bstart vlookup && comp prevExpr nextExpr vlookup, nextExpr) )
+			(\vlookup -> True, firstExpr)
+			otherExpr
+	)<|> try (expression $ n+1)
 expression n@0 = try (do { many space; expr <- expression $ n+1; many space; return expr}) <|> try (expression $ n+1)
 
diff --git a/Graphics/Implicit/ExtOpenScad/Primitives.hs b/Graphics/Implicit/ExtOpenScad/Primitives.hs
--- a/Graphics/Implicit/ExtOpenScad/Primitives.hs
+++ b/Graphics/Implicit/ExtOpenScad/Primitives.hs
@@ -7,123 +7,368 @@
 -- The code is fairly straightforward; an explanation of how 
 -- the first one works is provided.
 
--- Note: Primitives must be added to the computationStatement parser in
--- Graphics.Implicit.ExtOpenScad.Statements to have any effect!!!
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ScopedTypeVariables  #-}
 
-module Graphics.Implicit.ExtOpenScad.Primitives where
+module Graphics.Implicit.ExtOpenScad.Primitives (primitives) where
 
-import Prelude hiding (lookup)
 import Graphics.Implicit.Definitions
-import qualified Graphics.Implicit.Primitives as Prim
 import Graphics.Implicit.ExtOpenScad.Definitions
-import Graphics.Implicit.ExtOpenScad.Expressions
 import Graphics.Implicit.ExtOpenScad.Util
-import Data.Map (Map, lookup)
-import Text.ParserCombinators.Parsec 
-import Text.ParserCombinators.Parsec.Expr
-import Control.Monad (liftM)
+import Graphics.Implicit.ExtOpenScad.Util.ArgParser
+import Graphics.Implicit.ExtOpenScad.Util.Computation
 
+import qualified Graphics.Implicit.Primitives as Prim
+import Data.Maybe (fromMaybe, isNothing)
+import qualified Graphics.Implicit.SaneOperators as S
+
+primitives :: [(String, [ComputationStateModifier] ->  ArgParser ComputationStateModifier)]
+primitives = [ sphere, cube, square, cylinder, circle, polygon, union, difference, intersect, translate, scale, rotate, extrude, pack, shell ]
+
+moduleWithSuite name modArgMapper = (name, modArgMapper)
+moduleWithoutSuite name modArgMapper = (name, \suite -> modArgMapper)
+
+
 -- **Exmaple of implementing a module**
 -- sphere is a module without a suite named sphere,
 -- this means that the parser will look for this like
 --       sphere(args...);
 sphere = moduleWithoutSuite "sphere" $ do
+	example "sphere(3);"
+	example "sphere(r=5);"
 	-- What are the arguments?
 	-- The radius, r, which is a (real) number.
-	-- If we didn't specify real, we'd get an openscadObj
-	-- but we use the real convenience function.
 	-- Because we don't provide a default, this ends right
 	-- here if it doesn't get a suitable argument!
-	r <- realArgument "r";
+	r :: ℝ <- argument "r" 
+	            `doc` "radius of the sphere"
 	-- So what does this module do?
 	-- It adds a 3D object, a sphere of radius r,
 	-- using the sphere implementation in Prim
 	-- (Graphics.Implicit.Primitives)
-	addObj3 $ Prim.sphere r;
+	addObj3 $ Prim.sphere r
 
 cube = moduleWithoutSuite "cube" $ do
-	size <- argument "size";
-	center <- boolArgumentWithDefault "center" False;
-	r  <- realArgumentWithDefault "r" 0;
+
+	-- examples
+	example "cube(size = [2,3,4], center = true, r = 0.5);"
+	example "cube(4);"
+
+	-- arguments
+	size   :: Either ℝ ℝ3  <- argument "size"
+	                    `doc` "cube size"
+	center :: Bool <- argument "center" 
+	                    `doc` "should center?"  
+	                    `defaultTo` False
+	r      :: ℝ    <- argument "r"
+	                    `doc` "radius of rounding" 
+	                    `defaultTo` 0
+
+	-- Tests
+	test "cube(4);"
+		`eulerCharacteristic` 2
+	test "cube(size=[2,3,4]);"
+		`eulerCharacteristic` 2
+
+	-- A helper function for making rect3's accounting for centerdness
+	let rect3 x y z = 
+		if center  
+		then Prim.rect3R r (-x/2, -y/2, -z/2) (x/2, y/2, z/2)
+		else Prim.rect3R r (0, 0, 0)  (x, y, z)
+
 	case size of
-		OList ((ONum x):(ONum y):(ONum z):[]) -> 
-			if center  
-			then addObj3 $ Prim.rect3R r (-x/2, -y/2, -z/2) (x/2, y/2, z/2)
-			else addObj3 $ Prim.rect3R r (0,0,0) (x,y,z)
-		ONum w -> 
-			if center
-			then addObj3 $ Prim.rect3R r (-w/2,-w/2,-w/2) (w/2,w/2,w/2)
-			else addObj3 $ Prim.rect3R r (0,0,0) (w,w,w)
-		_ -> noChange;
+		Right (x,y,z) -> addObj3 $ rect3 x y z
+		Left   w      -> addObj3 $ rect3 w w w
 
--- What about $fn for regular n-gon prisms? This will break models..
+
+
+square = moduleWithoutSuite "square" $ do
+
+	-- examples 
+	example "square(size = [3,4], center = true, r = 0.5);"
+	example "square(4);"
+
+	-- arguments
+	size   :: Either ℝ ℝ2  <- argument "size"
+	                    `doc`  "square size"
+	center :: Bool <- argument "center" 
+	                    `doc` "should center?"  
+	                    `defaultTo` False
+	r      :: ℝ    <- argument "r"
+	                    `doc` "radius of rounding" 
+	                    `defaultTo` 0
+
+	-- Tests
+	test "square(2);"
+		`eulerCharacteristic` 0
+	test "square(size=[2,3]);"
+		`eulerCharacteristic` 0
+
+	-- A helper function for making rect2's accounting for centerdness
+	let rect x y = 
+		if center  
+		then Prim.rectR r (-x/2, -y/2) (x/2, y/2)
+		else Prim.rectR r (  0,    0 ) ( x,   y )
+
+	-- caseOType matches depending on whether size can be coerced into
+	-- the right object. See Graphics.Implicit.ExtOpenScad.Util
+	case size of
+		Left   w    -> addObj2 $ rect w w
+		Right (x,y) -> addObj2 $ rect x y
+
+
+
 cylinder = moduleWithoutSuite "cylinder" $ do
-	h  <- realArgumentWithDefault "h"  1;
-	r  <- realArgumentWithDefault "r"  1;
-	r1 <- realArgumentWithDefault "r1" 1;
-	r2 <- realArgumentWithDefault "r2" 1;
-	center <- boolArgumentWithDefault "center" False;
-	if r1 == 1 && r2 == 1
-		then if center
-			then addObj3 $ Prim.cylinderC r h
-			else addObj3 $ Prim.cylinder  r h
-		else if center
-			then addObj3 $ Prim.cylinder2C r1 r2 h
-			else addObj3 $ Prim.cylinder2  r1 r2 h
 
+	example "cylinder(r=10, h=30, center=true);"
+	example "cylinder(r1=4, r2=6, h=10);"
+	example	"cylinder(r=5, h=10, $fn = 6);"
 
+	-- arguments
+	r      :: ℝ    <- argument "r"
+				`defaultTo` 1
+				`doc` "radius of cylinder"
+	h      :: ℝ    <- argument "h"
+				`defaultTo` 1
+				`doc` "height of cylinder"
+	r1     :: ℝ    <- argument "r1"
+				`defaultTo` 1
+				`doc` "bottom radius; overrides r"
+	r2     :: ℝ    <- argument "r2"
+				`defaultTo` 1
+				`doc` "top radius; overrides r"
+	fn     :: ℕ    <- argument "$fn"
+				`defaultTo` (-1)
+				`doc` "number of sides, for making prisms"
+	center :: Bool <- argument "center"
+				`defaultTo` False
+				`doc` "center cylinder with respect to z?"
+
+	-- Tests
+	test "cylinder(r=10, h=30, center=true);"
+		`eulerCharacteristic` 0
+	test "cylinder(r=5, h=10, $fn = 6);"
+		`eulerCharacteristic` 0
+
+	-- The result is a computation state modifier that adds a 3D object, 
+	-- based on the args.
+	addObj3 $ if r1 == 1 && r2 == 1
+		then let
+			obj2 = if fn  < 0 then Prim.circle r else Prim.polygonR 0 $
+				let sides = fromIntegral fn 
+				in [(r*cos θ, r*sin θ )| θ <- [2*pi*n/sides | n <- [0.0 .. sides - 1.0]]]
+			obj3 = Prim.extrudeR 0 obj2 h
+		in if center
+			then Prim.translate (0,0,-h/2) obj3
+			else obj3
+		else if center
+			then  Prim.translate (0,0,-h/2) $ Prim.cylinder2 r1 r2 h
+			else Prim.cylinder2  r1 r2 h
+
 circle = moduleWithoutSuite "circle" $ do
-	r  <- realArgument "r";
-	fn <- intArgumentWithDefault "$fn" (-1);
+	
+	example "circle(r=10); // circle"
+	example "circle(r=5, $fn=6); //hexagon"
+
+	-- Arguments
+	r  :: ℝ <- argument "r"
+		`doc` "radius of the circle"
+	fn :: ℕ <- argument "$fn" 
+		`doc` "if defined, makes a regular polygon with n sides instead of a circle"
+		`defaultTo` (-1)
+
+	test "circle(r=10);"
+		`eulerCharacteristic` 0
+
 	if fn < 3
 		then addObj2 $ Prim.circle r
-		else addObj2 $ Prim.polygonR 0 [(r*cos θ, r*sin θ )| θ <- [2*pi*n/fromIntegral fn | n <- [0.0 .. fromIntegral fn - 1.0]]]
-		--else addObj2 $ Prim.regularPolygon fn r
+		else addObj2 $ Prim.polygonR 0 $
+			let sides = fromIntegral fn 
+			in [(r*cos θ, r*sin θ )| θ <- [2*pi*n/sides | n <- [0.0 .. sides - 1.0]]]
 
-square = moduleWithoutSuite "square" $ do
-	size <- argument "size";
-	center <- boolArgumentWithDefault "center" False;
-	r  <- realArgumentWithDefault "r" 0;
-	case size of
-		OList ((ONum x):(ONum y):[]) -> 
-			if center  
-			then addObj2 $ Prim.rectR r (-x/2, -y/2) (x/2, y/2)
-			else addObj2 $ Prim.rectR r (0,0) (x, y)
-		ONum w -> 
-			if center
-			then addObj2 $ Prim.rectR r (-w/2, -w/2) (w/2, w/2)
-			else addObj2 $ Prim.rectR r (0,0) (w,w)
+polygon = moduleWithoutSuite "polygon" $ do
+	
+	example "polygon ([(0,0), (0,10), (10,0)]);"
+	
+	points :: [ℝ2] <-  argument "points" 
+	                    `doc` "vertices of the polygon"
+	paths :: [ℕ ]  <- argument "paths" 
+	                    `doc` "order to go through vertices; ignored for now"
+	                    `defaultTo` []
+	r      :: ℝ     <- argument "r"
+	                    `doc` "rounding of the polygon corners; ignored for now"
+	                    `defaultTo` 0
+	case paths of
+		[] -> addObj2 $ Prim.polygonR 0 points
 		_ -> noChange;
 
 
-polygon = moduleWithoutSuite "polygon" $ do
-	points <- argument "points";
-	pathes <- argumentWithDefault "pathes" (OUndefined);
+
+
+union = moduleWithSuite "union" $ \suite -> do
+	r :: ℝ <- argument "r"
+		`defaultTo` 0.0
+		`doc` "Radius of rounding for the union interface"
+	if r > 0
+		then getAndCompressSuiteObjs suite (Prim.unionR r) (Prim.unionR r)
+		else getAndCompressSuiteObjs suite Prim.union Prim.union
+
+intersect = moduleWithSuite "intersection" $ \suite -> do
+	r :: ℝ <- argument "r"
+		`defaultTo` 0.0
+		`doc` "Radius of rounding for the intersection interface"
+	if r > 0
+		then getAndCompressSuiteObjs suite (Prim.intersectR r) (Prim.intersectR r)
+		else getAndCompressSuiteObjs suite Prim.intersect Prim.intersect
+
+difference = moduleWithSuite "difference" $ \suite -> do
+	r :: ℝ <- argument "r"
+		`defaultTo` 0.0
+		`doc` "Radius of rounding for the difference interface"
+	if r > 0
+		then getAndCompressSuiteObjs suite (Prim.differenceR r) (Prim.differenceR r)
+		else getAndCompressSuiteObjs suite Prim.difference Prim.difference
+
+translate = moduleWithSuite "translate" $ \suite -> do
+
+	example "translate ([2,3]) circle (4);"
+	example "translate ([5,6,7]) sphere(5);"
+
+	v :: Either ℝ (Either ℝ2 ℝ3) <- argument "v"
+		`doc` "vector to translate by"
+	
+	let 
+		translateObjs shift2 shift3 = 
+			getAndTransformSuiteObjs suite (Prim.translate shift2) (Prim.translate shift3)
+	
+	case v of
+		Left   x              -> translateObjs (x,0) (x,0,0)
+		Right (Left (x,y))    -> translateObjs (x,y) (x,y,0.0)
+		Right (Right (x,y,z)) -> translateObjs (x,y) (x,y,z)
+
+deg2rad x = x / 180.0 * pi
+
+-- This is mostly insane
+rotate = moduleWithSuite "rotate" $ \suite -> do
+	a <- argument "a"
+		`doc` "value to rotate by; angle or list of angles"
+
+	-- caseOType matches depending on whether size can be coerced into
+	-- the right object. See Graphics.Implicit.ExtOpenScad.Util
+	-- Entries must be joined with the operator <||>
+	-- Final entry must be fall through.
+	caseOType a $
+		       ( \xy  ->
+			getAndTransformSuiteObjs suite (Prim.rotate $ deg2rad xy ) (Prim.rotate3 (deg2rad xy, 0, 0) )
+		) <||> ( \(yz,xy,xz) ->
+			getAndTransformSuiteObjs suite (Prim.rotate $ deg2rad xy ) (Prim.rotate3 (deg2rad yz, deg2rad xz, deg2rad xy) )
+		) <||> ( \(yz,xz) ->
+			getAndTransformSuiteObjs suite (id ) (Prim.rotate3 (deg2rad yz, deg2rad xz, 0))
+		) <||> ( \_  -> noChange )
+
+
+scale = moduleWithSuite "scale" $ \suite -> do
+
+	example "scale(2) square(5);"
+	example "scale([2,3]) square(5);"
+	example "scale([2,3,4]) cube(5);"
+
+	v :: Either ℝ (Either ℝ2 ℝ3) <- argument "v"
+		`doc` "vector or scalar to scale by"
+	
 	let
-		extractTupleList :: [OpenscadObj] -> Maybe [ℝ2]
-		extractTupleList []  = Just []
-		extractTupleList (OList ((ONum x):(ONum y):[]):others) = 
-			case extractTupleList others of
-				Just l -> Just $ (x,y):l
-				Nothing -> Nothing
-		extractTupleList _ = Nothing
+		scaleObjs strech2 strech3 = 
+			getAndTransformSuiteObjs suite (Prim.scale strech2) (Prim.scale strech3)
+	
+	case v of
+		Left   x              -> scaleObjs (x,0) (x,0,0)
+		Right (Left (x,y))    -> scaleObjs (x,y) (x,y,0.0)
+		Right (Right (x,y,z)) -> scaleObjs (x,y) (x,y,z)
 
-		extractNumList :: [OpenscadObj] -> Maybe [ℝ]
-		extractNumList [] = Just []
-		extractNumList ((ONum n):others) = 
-			case extractNumList others of
-				Just l -> Just $ n:l
-				Nothing -> Nothing
-		extractNumList _ = Nothing
+extrude = moduleWithSuite "linear_extrude" $ \suite -> do
+	example "extrude(10) square(5);"
 
-		in case (points, pathes) of
-			(OList pointList, OUndefined) -> case extractTupleList pointList of
-				Just tupleList -> addObj2 $ Prim.polygonR 0 tupleList
-				Nothing -> noChange
-			{-(OList pointList, OList pathList) -> 
-				case (extractTupleList pointList, extractNumList pathList) of
-					(Just l1, Just l2) -> -}
-			_ -> noChange;
+	height :: Either ℝ (ℝ -> ℝ -> ℝ) <- argument "height" `defaultTo` (Left 1)
+		`doc` "height to extrude to..."
+	center :: Bool <- argument "center" `defaultTo` False
+		`doc` "center? (the z component)"
+	twist  :: Maybe (Either ℝ (ℝ  -> ℝ)) <- argument "twist"  `defaultTo` Nothing
+		`doc` "twist as we extrude, either a total amount to twist or a function..."
+	scale  :: Maybe (Either ℝ (ℝ  -> ℝ)) <- argument "scale"  `defaultTo` Nothing
+		`doc` "scale according to this funciton as we extrud..."
+	translate :: Maybe (Either ℝ2 (ℝ -> ℝ2)) <- argument "translate"  `defaultTo` Nothing
+		`doc` "translate according to this funciton as we extrude..."
+	r      :: ℝ   <- argument "r"      `defaultTo` 0
+		`doc` "round the top?"
+	
+	let
+		degRotate = (\θ (x,y) -> (x*cos(θ)+y*sin(θ), y*cos(θ)-x*sin(θ))) . (*(2*pi/360))
 
+		heightn = case height of
+				Left  h -> h
+				Right f -> f 0 0
 
+		height' = case height of
+			Right f -> Right $ uncurry f
+			Left a -> Left a
+
+		shiftAsNeeded =
+			if center
+			then Prim.translate (0,0,-heightn/2.0)
+			else id
+		
+		funcify :: S.Multiplicative ℝ a a => Either a (ℝ -> a) -> ℝ -> a
+		funcify (Left val) h = (h/heightn) S.* val
+		funcify (Right f ) h = f h
+		
+		twist' = fmap funcify twist
+		scale' = fmap funcify scale
+		translate' = fmap funcify translate
 	
+	getAndModUpObj2s suite $ \obj -> case height of
+		Left constHeight | isNothing twist && isNothing scale && isNothing translate ->
+			shiftAsNeeded $ Prim.extrudeR r obj constHeight
+		_ -> 
+			shiftAsNeeded $ Prim.extrudeRM r twist' scale' translate' obj height'
+
+
+{-rotateExtrudeStatement = moduleWithSuite "rotate_extrude" $ \suite -> do
+	h <- realArgument "h"
+	center <- boolArgumentWithDefault "center" False
+	twist <- realArgumentWithDefault 0.0
+	r <- realArgumentWithDefault "r" 0.0
+	getAndModUpObj2s suite (\obj -> Prim.extrudeRMod r (\θ (x,y) -> (x*cos(θ)+y*sin(θ), y*cos(θ)-x*sin(θ)) )  obj h) 
+-}
+
+shell = moduleWithSuite "shell" $ \suite -> do
+	w :: ℝ <- argument "w"
+			`doc` "width of the shell..."
+	
+	getAndTransformSuiteObjs suite (Prim.shell w) (Prim.shell w)
+
+-- Not a perenant solution! Breaks if can't pack.
+pack = moduleWithSuite "pack" $ \suite -> do
+
+	example "pack ([45,45], sep=2) { circle(10); circle(10); circle(10); circle(10); }"
+
+	-- arguments
+	size :: ℝ2 <- argument "size"
+		`doc` "size of 2D box to pack objects within"
+	sep  :: ℝ  <- argument "sep"
+		`doc` "mandetory space between objects"
+
+	-- The actual work...
+	return $  \ ioWrappedState -> do
+		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
+		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
+		if not $ null obj3s2
+			then case Prim.pack3 size sep obj3s2 of
+				Just solution -> return (varlookup2, obj2s, obj3s ++ [solution] )
+				Nothing       -> do 
+					putStrLn "Can't pack given objects in given box with present algorithm"
+					return (varlookup2, obj2s, obj3s)
+			else case Prim.pack2 size sep obj2s2 of
+				Just solution -> return (varlookup2, obj2s ++ [solution], obj3s)
+				Nothing       -> do 
+					putStrLn "Can't pack given objects in given box with present algorithm"
+					return (varlookup2, obj2s, obj3s)
+
diff --git a/Graphics/Implicit/ExtOpenScad/Statements.hs b/Graphics/Implicit/ExtOpenScad/Statements.hs
--- a/Graphics/Implicit/ExtOpenScad/Statements.hs
+++ b/Graphics/Implicit/ExtOpenScad/Statements.hs
@@ -1,5 +1,3 @@
-
-
 -- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
 -- Released under the GNU GPL, see LICENSE
 
@@ -7,19 +5,26 @@
 
 -- Implement statements for things other than primitive objects!
 
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ScopedTypeVariables, NoMonomorphismRestriction  #-}
+
 module Graphics.Implicit.ExtOpenScad.Statements where
 
 import Prelude hiding (lookup)
 import Graphics.Implicit.Definitions
+import Graphics.Implicit.ObjectUtil (getBox2, getBox3)
 import Graphics.Implicit.ExtOpenScad.Definitions
 import Graphics.Implicit.ExtOpenScad.Expressions
 import Graphics.Implicit.ExtOpenScad.Util
 import Graphics.Implicit.ExtOpenScad.Primitives
-import qualified Graphics.Implicit.Operations as Op
-import Data.Map (Map, lookup, insert)
+import qualified Graphics.Implicit.Primitives as Prim
+import Data.Map (Map, lookup, insert, union)
 import Text.ParserCombinators.Parsec 
 import Text.ParserCombinators.Parsec.Expr
 import Control.Monad (liftM)
+import System.Plugins.Load (load_, LoadStatus(..))
+import Control.Monad (forM_)
+import Graphics.Implicit.ExtOpenScad.Util.ArgParser
+import Graphics.Implicit.ExtOpenScad.Util.Computation
 
 tryMany = (foldl1 (<|>)) . (map try)
 
@@ -30,15 +35,17 @@
 		many space
 		s <- tryMany [
 			ifStatement,
-			forStatement, 
-			unionStatement,
-			intersectStatement,
-			differenceStatement,
-			translateStatement,
-			rotateStatement,
-			scaleStatement,
-			extrudeStatement,
-			shellStatement
+			forStatement,
+			throwAway,
+			userModuleDeclaration,
+			unimplemented "mirror",
+			unimplemented "multmatrix",
+			unimplemented "color",
+			unimplemented "render",
+			unimplemented "surface",
+			unimplemented "projection",
+			unimplemented "rotate_extrude",
+			unimplemented "import_stl"
 			-- rotateExtrudeStatement
 			]
 		many space
@@ -49,19 +56,19 @@
 			echoStatement,
 			assigmentStatement,
 			includeStatement,
-			useStatement,
-			sphere,
-			cube,
-			square,
-			cylinder,
-			circle,
-			polygon
+			useStatement
 			]
 		many space
 		char ';'
 		many space
 		return s
-	)<|> (many space >> comment)
+	)<|> (try $ many space >> comment)
+	<|> (try $ do
+		many space
+		s <- userModule
+		many space
+		return s
+	)
 
 
 
@@ -91,10 +98,6 @@
 	return stmts
 	) <?> "statement suite"
 
--- | Run a list of computations!
---   We start with a state and run it through a bunch of ComputationStateModifier s.
-runComputations :: ComputationState -> [ComputationStateModifier]  -> ComputationState
-runComputations = foldl (\a b -> b $ a)
 
 -- | We think of comments as statements that do nothing. It's just convenient.
 comment = 
@@ -107,9 +110,18 @@
 		manyTill anyChar (try $ string "*/")
 	)) >> return id) <?> "comment"
 
+throwAway :: GenParser Char st ComputationStateModifier
+throwAway = do
+	many space
+	oneOf "%*"
+	many space
+	computationStatement
+	return id
+
 -- An included statement! Basically, inject another openscad file here...
 includeStatement :: GenParser Char st ComputationStateModifier
 includeStatement = (do
+	line <- fmap sourceLine getPosition
 	string "include"
 	many space
 	string "<"
@@ -117,19 +129,33 @@
 	string ">"
 	return $ \ ioWrappedState -> do
 		state@(varlookup,obj2s,obj3s) <- ioWrappedState;
-		content <- readFile filename
-		case parse (many1 computationStatement) ""  content of
-			Left  err ->  do
-				putStrLn $ "Error parsing included file " ++ filename
-				putStrLn $ show err
-				putStrLn $ "Ignoring included file " ++ filename ++ "..."
-				return state
-			Right result -> runComputations (return state) result
+		case reverse filename of
+			'o':'.':_ -> do
+				loaded :: LoadStatus VariableLookup
+					<- load_ filename ["."] "openscadAPI"
+				case loaded of
+					LoadFailure errs -> do
+						putStrLn $ show errs
+						return state
+					LoadSuccess _ newapi -> do
+						putStrLn "Loaded Haskell Module..."
+						return (union varlookup newapi, obj2s, obj3s)
+			_ -> do
+				content <- readFile filename
+				case parse (many1 computationStatement) ""  content of
+					Left  err ->  do
+						errorMessage line $ 
+							"Error parsing included file <file>" ++ filename ++ "</file>\n"
+							++ show err
+							++ "Ignoring included file <file>" ++ filename ++ "</file>..."
+						return state
+					Right result -> runComputations (return state) result
 	) <?> "include statement"
 
 -- In a use statement, variables are imported but we drop any existing 2D/3D objects.
 useStatement :: GenParser Char st ComputationStateModifier
 useStatement = (do
+	line <- fmap sourceLine getPosition
 	string "use"
 	many space
 	string "<"
@@ -140,9 +166,10 @@
 		content <- readFile filename
 		case parse (many1 computationStatement) ""  content of
 			Left  err ->  do
-				putStrLn $ "Error parsing used file " ++ filename
-				putStrLn $ show err
-				putStrLn $ "Ignoring used file " ++ filename ++ "..."
+				errorMessage line $ 
+					"Error parsing included file <file>" ++ filename ++ "</file>\n"
+					++ show err
+					++ "Ignoring included file <file>" ++ filename ++ "</file>..."
 				return state
 			Right result -> runComputations (return (varlookup,[],[])) result
 	) <?> "use statement"
@@ -152,18 +179,32 @@
 assigmentStatement :: GenParser Char st ComputationStateModifier
 assigmentStatement = 
 	(try $ do
-		varSymb <- variableSymb
+		line <- fmap sourceLine getPosition
+		pattern <- patternMatcher
 		many space
 		char '='
 		many space
 		valExpr <- expression 0
 		return $ \ ioWrappedState -> do
-			(varlookup, obj2s, obj3s) <- ioWrappedState
+			state@(varlookup, obj2s, obj3s) <- ioWrappedState
 			let
 				val = valExpr varlookup
-			return (insert varSymb val varlookup, obj2s, obj3s) 
+				match = pattern val
+			case match of
+				Just dictWithNew -> case val of
+					OError e -> do
+						errorMessage line $ 
+							"error in evaluating assignment statement assigned value:"
+							++ concat (map ("\n   "++) e)
+						return (union dictWithNew varlookup, obj2s, obj3s) 
+					_ -> return (union dictWithNew varlookup, obj2s, obj3s) 
+				Nothing -> do
+					errorMessage line $ "pattern match fail in assignment statement"
+					return state
 	) <|> (try $ do 
-		varSymb <- variableSymb
+		line <- fmap sourceLine getPosition
+		varSymb <- (try $ string "function" >> many1 space >> variableSymb) 
+		            <|> variableSymb
 		many space
 		char '('
 		many space
@@ -181,25 +222,49 @@
 					\argObj -> makeFunc baseExpr xs (insert argVar argObj varlookup')
 				makeFunc baseExpr [] varlookup' = baseExpr varlookup'
 				val = makeFunc valExpr argVars varlookup
-			return (insert varSymb val varlookup, obj2s, obj3s)
+			case val of
+				OError e -> do
+					errorMessage line $ "error in evaluating assignment statement assigned value:"
+						++ concat (map ("\n   "++) e)
+					return (insert varSymb val varlookup, obj2s, obj3s)
+				_ -> return (insert varSymb val varlookup, obj2s, obj3s)
 	)<?> "assignment statement"
 
 -- | An echo statement (parser)
 echoStatement :: GenParser Char st ComputationStateModifier
 echoStatement = do
+	line <- fmap sourceLine getPosition
 	string "echo"
 	many space
 	char '('
 	many space
-	val <- expression 0
+	exprs <- expression 0 `sepBy` (many space >> char ',' >> many space)
 	many space
 	char ')'
 	return $  \ ioWrappedState -> do
 		state@(varlookup, _, _) <- ioWrappedState
-		putStrLn $ show $ val varlookup
+		let 
+			vals = map ($varlookup) exprs
+			isError (OError _) = True
+			isError _ = False
+			show2 (OString str) = str
+			show2 a = show a
+		errorMessage line $ 
+			if any isError vals 
+			then 
+				"in module <module>echo</module>:"
+				++ ( concat $ concat $ 
+					map (map ("\n   "++)) $ 
+						map (\(OError errs) -> errs) $ filter isError vals
+				   )
+			else
+				unwords $ map show2 vals
+
 		return state
 
+ifStatement :: GenParser Char st ComputationStateModifier
 ifStatement = (do
+	line <- fmap sourceLine getPosition
 	string "if"
 	many space
 	char '('
@@ -211,22 +276,33 @@
 	statementsFalseCase <- try (string "else" >> many space >> suite ) <|> (return [])
 	return $  \ ioWrappedState -> do
 		state@(varlookup, _, _) <- ioWrappedState
-		if case bexpr varlookup of  
-				OBool b -> b
-				_ -> False
-			then runComputations (return state) statementsTrueCase
-			else runComputations (return state) statementsFalseCase
+		case bexpr varlookup of
+			OBool bval -> 
+				if bval
+				then runComputations (return state) statementsTrueCase
+				else runComputations (return state) statementsFalseCase
+			OError errs -> do
+				errorMessage line $ " error while evaluating if statement conditional:" 
+				         ++ concat (map ("\n    " ++) errs)
+				return state
+			obj -> do
+				errorMessage line $ "inappropriate type for if statement conditional:\n"
+				        ++ "   value " ++ show obj ++ " is not a boolean."
+				return state
 	) <?> "if statement"
 
+forStatement :: GenParser Char st ComputationStateModifier
 forStatement = (do
+	line <- fmap sourceLine getPosition
 	-- a for loop is of the form:
 	--      for ( vsymb = vexpr   ) loopStatements
-	-- eg.  for ( a     = [1,2,3] ) {echo(a); echo "lol";}
+	-- eg.  for ( a     = [1,2,3] ) {echo(a);   echo "lol";}
+	-- eg.  for ( [a,b] = [[1,2]] ) {echo(a+b); echo "lol";}
 	string "for"
 	many space
 	char '('
 	many space
-	vsymb <- variableSymb
+	pattern <- patternMatcher
 	many space
 	char '='
 	vexpr <- expression 0
@@ -243,20 +319,34 @@
 				-> OpenscadObj      -- ^ The value of vsymb for this iteration
 				-> ComputationState -- ^ The resulting state
 			loopOnce ioWrappedState val =  do
-				(varlookup, a, b) <- ioWrappedState;
+				state@(varlookup, a, b) <- ioWrappedState;
 				let
-					vsymbSetState = return (insert vsymb val varlookup, a, b)
+					match = pattern val
+					vsymbSetState = case match of
+						Just dictWithNew -> return (union dictWithNew varlookup, a, b) 
+						Nothing -> do
+							errorMessage line $ "Pattern match fail in for loop step"
+							return state
 				runComputations vsymbSetState loopStatements
 		-- Then loops once for every entry in vexpr
-		foldl (loopOnce) (return state) $ case vexpr varlookup of 
-			OList l -> l;
-			_       -> [];
+		case vexpr varlookup of 
+			OList l -> foldl (loopOnce) (return state) l
+			OError errs -> do
+				errorMessage line $ "Error while evaluating for loop array:" 
+				         ++ concat (map ("\n    " ++) errs)
+				return state
+			obj     -> do
+				errorMessage line $ "Error in for loop iteration array:\n"
+				        ++ "   Inappropriate type for loop iterated array:\n"
+				        ++ "       value " ++ show obj ++ " is not a list."
+				return state
 	) <?> "for statement"
 
 moduleWithSuite ::
 	String -> ([ComputationStateModifier] -> ArgParser ComputationStateModifier)
 	-> GenParser Char st ComputationStateModifier
 moduleWithSuite name argHandeler = (do
+	line <- fmap sourceLine getPosition
 	string name;
 	many space;
 	(unnamed, named) <- moduleArgsUnit
@@ -268,144 +358,125 @@
 			(map ($varlookup) unnamed) 
 			(map (\(a,b) -> (a, b varlookup)) named) (argHandeler statements)
 			of
-				Just computationModifier ->  computationModifier (return state)
-				Nothing -> (return state);
+				(Just computationModifier, []) ->  computationModifier (return state)
+				(Nothing, []) -> do
+					errorMessage line $ "Module <module>" ++ name 
+						++ "</module> failed without a message"
+					return state
+				(Nothing, errs) -> do
+					errorMessage line $  "Module <module>" ++ name 
+						++ "</module> failed with the following messages:"
+						++ concat (map ("  "++) errs)
+					return state
+				(Just computationModifier, errs) -> do
+					errorMessage line $ "Module <module>" ++ name 
+						++ "</module> gave the following warnings:"
+						++ concat (map ("  "++) errs)
+					computationModifier (return state)
 	) <?> (name ++ " statement")
 
+unimplemented :: String -> GenParser Char st ComputationStateModifier
+unimplemented name = do
+	line <- fmap sourceLine getPosition
+	string name
+	many space;
+	moduleArgsUnit
+	many space;
+	(try suite <|> (many space >> char ';' >> return []))
+	return $ \ ioWrappedState -> do
+		state <- ioWrappedState
+		errorMessage line $ "OpenSCAD command " ++ name ++ " not yet implemented"
+		return state
 
-getAndModUpObj2s :: (Monad m) => [ComputationStateModifier] 
-	-> (Obj2Type -> Obj3Type)
-	-> m ComputationStateModifier
-getAndModUpObj2s suite obj2mod = 
-	return $  \ ioWrappedState -> do
-		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
-		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
-		return 
-			(varlookup2,
-			 obj2s, 
-			 obj3s ++ (case obj2s2 of [] -> []; x:xs -> [obj2mod x])  )
 
-getAndCompressSuiteObjs :: (Monad m) => [ComputationStateModifier] 
-	-> ([Obj2Type] -> Obj2Type)
-	-> ([Obj3Type] -> Obj3Type)
-	-> m ComputationStateModifier
-getAndCompressSuiteObjs suite obj2modifier obj3modifier = 
-	return $  \ ioWrappedState -> do
-		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
-		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
-		return 
-			(varlookup2,
-			 obj2s ++ (case obj2s2 of [] -> []; _ -> [obj2modifier obj2s2]), 
-			 obj3s ++ (case obj3s2 of [] -> []; _ -> [obj3modifier obj3s2])  )
-
-getAndTransformSuiteObjs :: (Monad m) => [ComputationStateModifier] 
-	-> (Obj2Type -> Obj2Type)
-	-> (Obj3Type -> Obj3Type)
-	-> m ComputationStateModifier
-getAndTransformSuiteObjs suite obj2modifier obj3modifier = 
-	return $  \ ioWrappedState -> do
-		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
-		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
-		return 
-			(varlookup2,
-			 obj2s ++ (map obj2modifier obj2s2),
-			 obj3s ++ (map obj3modifier obj3s2)   )
+userModule :: GenParser Char st ComputationStateModifier
+userModule = do
+	line <- fmap sourceLine getPosition
+	name <- variableSymb;
+	many space;
+	(unnamed, named) <- moduleArgsUnit
+	many space;
+	statements <- ( try suite <|> (many space >> char ';' >> return []))
+	return $ \ ioWrappedState -> do
+		state@(varlookup, obj2s, obj3s) <- ioWrappedState
+		case lookup name varlookup of
+			Just (OModule m) -> 
+				case argMap 
+					(map ($varlookup) unnamed) 
+					(map (\(a,b) -> (a, b varlookup)) named) 
+					(m statements)
+				of
+				(Just computationModifier, []) ->  
+					computationModifier (return state)
+				(Nothing, []) -> do
+					errorMessage line $ "Module <module>" ++ name 
+						++ "</module> failed without a message"
+					return state
+				(Nothing, errs) -> do
+					errorMessage line $  "Module <module>" ++ name 
+						++ "</module> failed with the following messages:"
+						++ concat (map ("  "++) errs)
+					return state
+				(Just computationModifier, errs) -> do
+					errorMessage line $ "Module <module>" ++ name 
+						++ "</module> gave the following warnings:"
+						++ concat (map ("  "++) errs)
+					computationModifier (return state)
+			_ -> do
+				errorMessage line $  "module <module>" ++ name ++ "</module> is not in scope"
+				return state
 
 
-unionStatement = moduleWithSuite "union" $ \suite -> do
-	r <- realArgumentWithDefault "r" 0.0
-	if r > 0
-		then getAndCompressSuiteObjs suite (Op.unionR r) (Op.unionR r)
-		else getAndCompressSuiteObjs suite Op.union Op.union
-
-intersectStatement = moduleWithSuite "intersection" $ \suite -> do
-	r <- realArgumentWithDefault "r" 0.0
-	if r > 0
-		then getAndCompressSuiteObjs suite (Op.intersectR r) (Op.intersectR r)
-		else getAndCompressSuiteObjs suite Op.intersect Op.intersect
-
-differenceStatement = moduleWithSuite "difference" $ \suite -> do
-	r <- realArgumentWithDefault "r" 0.0
-	if r > 0
-		then getAndCompressSuiteObjs suite (Op.differenceR r) (Op.differenceR r)
-		else getAndCompressSuiteObjs suite Op.difference Op.difference
-
-translateStatement = moduleWithSuite "translate" $ \suite -> do
-	v <- argument "v"
-	case v of
-		OList ((ONum x):(ONum y):(ONum z):[]) -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,y) ) (Op.translate (x,y,z))
-		OList ((ONum x):(ONum y):[]) -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,y) ) (Op.translate (x,y,0.0))
-		OList ((ONum x):[]) -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,0.0) ) (Op.translate (x,0.0,0.0))
-		ONum x -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,0.0) ) (Op.translate (x,0.0,0.0))
-		_ -> noChange
-
--- This is mostly insane
-rotateStatement = moduleWithSuite "rotate" $ \suite -> do
-	a <- argument "a"
-	case a of
-		ONum xy -> getAndTransformSuiteObjs suite (Op.rotateXY xy ) (Op.rotate3 (xy, 0, 0) )
-		OList ((ONum yz):(ONum xz):(ONum xy):[]) -> 
-			getAndTransformSuiteObjs suite (Op.rotateXY xy ) (Op.rotate3 (yz, xz, xy) )
-		OList ((ONum yz):(ONum xz):[]) -> 
-			getAndTransformSuiteObjs suite (id ) (Op.rotate3 (yz, xz, 0))
-		OList ((ONum yz):[]) -> 
-			getAndTransformSuiteObjs suite (id) (Op.rotate3 (yz, 0, 0))
-		_ -> noChange
+userModuleDeclaration :: GenParser Char st ComputationStateModifier
+userModuleDeclaration = do
+	string "module"
+	many space;
+	newModuleName <- variableSymb;
+	many space;
+	args <- moduleArgsUnitDecl
+	many space;
+	codeStatements <- suite
+	return $ \ envIOWrappedState -> do
+		(envVarlookup, envObj2s, envObj3s) <- envIOWrappedState
+		let 
+			newModule = OModule $ \childrenStatements -> do 
+				argVarlookupModifier <- args envVarlookup
+				return $ \contextIOWrappedState -> do
+					contextState@(contextVarLookup, contextObj2s, contextObj3s)
+						<- contextIOWrappedState
+					(_, childObj2s, childObj3s) <- runComputations 
+						(return contextState)
+						childrenStatements;
+					let
+						children = ONum $ fromIntegral  
+							(length childObj2s + length childObj3s)
+						child = OModule $ \suite -> do
+							n :: ℕ <- argument "n";
+							if n <= length childObj3s 
+							         then addObj3 (childObj3s !! n)
+							         else addObj2 (childObj2s !! (n+1-length childObj3s))
+						childBox = OFunc $ \n -> case fromOObj n :: Maybe ℕ of
+							Just n  | n < length childObj3s + length childObj2s ->  
+								if n <= length childObj3s 
+							         then toOObj $ getBox3 (childObj3s !! n)
+							         else toOObj $ getBox2 (childObj2s !! (n+1-length childObj3s))
+							Nothing -> OUndefined
+						varlookupForCode = 
+							(insert "child" child) $ 
+							(insert "children" children) $
+							(insert "childBox" childBox) $
+							(insert newModuleName newModule) $
+							envVarlookup
+					(_, resultObj2s, resultObj3s) 
+						<- runComputations 
+							(return (argVarlookupModifier varlookupForCode,[],[]))
+							codeStatements
+					return (
+						contextVarLookup, 
+						contextObj2s ++ resultObj2s, 
+						contextObj3s ++ resultObj3s
+						)
+		return (insert newModuleName (newModule) envVarlookup, envObj2s, envObj3s)
 
 
-scaleStatement = moduleWithSuite "scale" $ \suite -> do
-	v <- argument "v"
-	case v of
-		{-OList ((ONum x):(ONum y):(ONum z):[]) -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,y) ) (Op.translate (x,y,z))
-		OList ((ONum x):(ONum y):[]) -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,y) ) (Op.translate (x,y,0.0))
-		OList ((ONum x):[]) -> 
-			getAndTransformSuiteObjs suite (Op.translate (x,0.0) ) (Op.translate (x,0.0,0.0)-}
-		ONum s ->
-			getAndTransformSuiteObjs suite (Op.scale s) (Op.scale s)
-
-extrudeStatement = moduleWithSuite "linear_extrude" $ \suite -> do
-	height <- realArgument "height"
-	center <- boolArgumentWithDefault "center" False
-	twist  <- argumentWithDefault "twist" (ONum 0)
-	r <- realArgumentWithDefault "r" 0
-	let
-		degRotate = (\θ (x,y) -> (x*cos(θ)+y*sin(θ), y*cos(θ)-x*sin(θ))) . (*(2*pi/360))
-		shiftAsNeeded =
-			if center
-			then Op.translate (0,0,-height/2.0)
-			else id
-	case twist of
-		ONum 0 -> getAndModUpObj2s suite (\obj -> shiftAsNeeded $ Op.extrudeR r obj height) 
-		ONum rot ->
-			getAndModUpObj2s suite (\obj -> 
-				shiftAsNeeded $ Op.extrudeRMod r 
-					(degRotate . (*(rot/height)))  
-					obj height
-				)
-		OFunc rotf ->
-			getAndModUpObj2s suite (\obj -> 
-				shiftAsNeeded $ Op.extrudeRMod r 
-					(\h -> degRotate $ case rotf (ONum h) of
-							ONum n -> n
-							_ -> 0
-					) obj height
-				)
-
-{-rotateExtrudeStatement = moduleWithSuite "rotate_extrude" $ \suite -> do
-	h <- realArgument "h"
-	center <- boolArgumentWithDefault "center" False
-	twist <- realArgumentWithDefault 0.0
-	r <- realArgumentWithDefault "r" 0.0
-	getAndModUpObj2s suite (\obj -> Op.extrudeRMod r (\θ (x,y) -> (x*cos(θ)+y*sin(θ), y*cos(θ)-x*sin(θ)) )  obj h) 
--}
-
-shellStatement = moduleWithSuite "shell" $ \suite -> do
-	w <- realArgumentWithDefault "w" 0.0
-	getAndTransformSuiteObjs suite (Op.shell w) (Op.shell w)
 
diff --git a/Graphics/Implicit/ExtOpenScad/Util.hs b/Graphics/Implicit/ExtOpenScad/Util.hs
--- a/Graphics/Implicit/ExtOpenScad/Util.hs
+++ b/Graphics/Implicit/ExtOpenScad/Util.hs
@@ -1,82 +1,46 @@
+-- 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.
+
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ScopedTypeVariables  #-}
+
 module Graphics.Implicit.ExtOpenScad.Util where
 
 import Prelude hiding (lookup)
 import Graphics.Implicit.Definitions
 import Graphics.Implicit.ExtOpenScad.Definitions
 import Graphics.Implicit.ExtOpenScad.Expressions
+import Graphics.Implicit.ExtOpenScad.Util.ArgParser
 import Data.Map (Map, lookup, insert)
+import qualified Data.Map as Map
+import qualified Data.Maybe as Maybe
 import qualified Data.List
 import Text.ParserCombinators.Parsec 
 import Text.ParserCombinators.Parsec.Expr
-import Control.Monad (liftM)
+import Data.Maybe (isJust,isNothing)
+import Control.Monad (forM_)
 
-instance Monad ArgParser where
-	(ArgParser str fallback f) >>= g = ArgParser str fallback (\a -> (f a) >>= g)
-	(ArgParserTerminator a) >>= g = g a
-	(ArgParserFail) >>= g = ArgParserFail
-	return a = ArgParserTerminator a
 
-argMap :: [OpenscadObj] -> [(String, OpenscadObj)] -> ArgParser a -> Maybe a
-argMap _ _ (ArgParserTerminator a) = Just a
-argMap _ _ ArgParserFail = Nothing
-argMap (x:unnamedArgs) namedArgs (ArgParser _ _ f) = 
-	argMap unnamedArgs namedArgs (f x)
-argMap [] namedArgs (ArgParser str fallback f) = case Data.List.lookup str namedArgs of
-	Just a -> argMap [] namedArgs (f a)
-	Nothing -> case fallback of
-		Just b -> argMap [] namedArgs (f b)
-		Nothing -> Nothing
-
-argument :: String -> ArgParser OpenscadObj
-argument str = ArgParser str Nothing (\a -> return a)
-
-realArgument :: String -> ArgParser ℝ
-realArgument str = ArgParser str Nothing (\a -> case a of {(ONum a) -> return a; _ -> ArgParserFail;})
-
-intArgument :: String -> ArgParser Int
-intArgument str = ArgParser str Nothing (\a -> case a of {(ONum a) -> return (floor a); _ -> ArgParserFail;})
-
-boolArgument :: String -> ArgParser Bool
-boolArgument str = ArgParser str Nothing (\a -> case a of {(OBool a) -> return a; _ -> ArgParserFail;})
-
-argumentWithDefault :: String -> OpenscadObj -> ArgParser OpenscadObj
-argumentWithDefault str fallback = ArgParser str (Just fallback) (\a -> return a)
-
-realArgumentWithDefault :: String -> ℝ -> ArgParser ℝ
-realArgumentWithDefault str fallback = ArgParser str (Just (ONum fallback)) 
-	(\a -> case a of {(ONum a) -> return a; _ -> ArgParserFail;})
-
-intArgumentWithDefault :: String -> Int -> ArgParser Int
-intArgumentWithDefault str fallback = ArgParser str (Just (ONum (fromIntegral fallback))) 
-	(\a -> case a of {(ONum a) -> return (floor a); _ -> ArgParserFail;})
-
-boolArgumentWithDefault :: String -> Bool -> ArgParser Bool
-boolArgumentWithDefault str fallback = ArgParser str (Just (OBool fallback)) 
-	(\a -> case a of {(OBool a) -> return a; _ -> ArgParserFail;})
-
-addObj2 :: (Monad m) => Obj2Type -> m ComputationStateModifier
-addObj2 obj = return $  \ ioWrappedState -> do
-		(varlookup, obj2s, obj3s) <- ioWrappedState
-		return (varlookup, obj2s ++ [obj], obj3s)
+type Any = OpenscadObj
 
-addObj3 :: (Monad m) => Obj3Type -> m ComputationStateModifier
-addObj3 obj = return $  \ ioWrappedState -> do
-		(varlookup, obj2s, obj3s) <- ioWrappedState
-		return (varlookup, obj2s, obj3s ++ [obj])
+caseOType = flip ($)
 
-changeObjs :: (Monad m) => ([Obj2Type] -> [Obj2Type]) -> ([Obj3Type] -> [Obj3Type]) -> m ComputationStateModifier
-changeObjs mod2s mod3s = return $  \ ioWrappedState -> do
-		(varlookup, obj2s, obj3s) <- ioWrappedState
-		return (varlookup, mod2s obj2s, mod3s obj3s)
+infixr 2 <||>
 
-runIO ::  (Monad m) => IO() -> m ComputationStateModifier
-runIO newio = return $  \ ioWrappedState -> do
-		state <- ioWrappedState
-		newio
-		return state
+(<||>) :: forall desiredType out. (OTypeMirror desiredType)
+	=> (desiredType -> out) 
+	-> (OpenscadObj -> out)
+	-> (OpenscadObj -> out)
 
-noChange :: (Monad m) => m ComputationStateModifier
-noChange = return id
+(<||>) f g = \input ->
+	let
+		coerceAttempt = fromOObj input :: Maybe desiredType
+	in 
+		if isJust coerceAttempt -- ≅ (/= Nothing) but no Eq req
+		then f $ (\(Just a) -> a) coerceAttempt
+		else g input
 
 moduleArgsUnit ::  
 	GenParser Char st ([VariableLookup -> OpenscadObj], [(String, VariableLookup -> OpenscadObj)])
@@ -84,14 +48,14 @@
 	char '(';
 	many space;
 	args <- sepBy ( 
-		(try $ do
+		(try $ do -- eg. a = 12
 			symb <- variableSymb;
 			many space;
 			char '=';
 			many space;
 			expr <- expression 0;
 			return $ Right (symb, expr);
-		) <|> (try $ do
+		) <|> (try $ do -- eg. a(x,y) = 12
 			symb <- variableSymb;
 			many space;
 			char '('
@@ -108,7 +72,7 @@
 				makeFunc baseExpr [] varlookup' = baseExpr varlookup'
 				funcExpr = makeFunc expr argVars
 			return $ Right (symb, funcExpr);
-		) <|> (do {
+		) <|> (do { -- eg. 12
 			expr <- expression 0;
 			return $ Left expr;
 		})
@@ -122,23 +86,56 @@
 		unnamed = map (\(Left a) -> a) $ filter (not . isRight) $ args
 		in return (unnamed, named)
 
-
-moduleWithoutSuite :: 
-	String -> ArgParser ComputationStateModifier -> GenParser Char st ComputationStateModifier
-
-moduleWithoutSuite name argHandeler = (do
-	string name;
+moduleArgsUnitDecl ::  
+	GenParser Char st (VariableLookup -> ArgParser (VariableLookup -> VariableLookup))
+moduleArgsUnitDecl = do
+	char '(';
 	many space;
-	(unnamed, named) <- moduleArgsUnit
-	return $ \ ioWrappedState -> do
-		state@(varlookup, obj2s, obj3s) <- ioWrappedState
-		case argMap 
-			(map ($varlookup) unnamed) 
-			(map (\(a,b) -> (a, b varlookup)) named) argHandeler 
-			of
-				Just computationModifier ->  computationModifier (return state)
-				Nothing -> (return state);
-	) <?> name
+	args <- sepBy ( 
+		(try $ do
+			symb <- variableSymb;
+			many space;
+			char '=';
+			many space;
+			expr <- expression 0;
+			return $ \varlookup -> 
+				ArgParser symb (Just$ expr varlookup) "" (\val -> return $ insert symb val);
+		) <|> (try $ do
+			symb <- variableSymb;
+			many space;
+			char '('
+			many space
+			argVars <- sepBy variableSymb (many space >> char ',' >> many space)
+			char ')'
+			many space
+			char '=';
+			many space;
+			expr <- expression 0;
+			let
+				makeFunc baseExpr (argVar:xs) varlookup' = OFunc $ 
+					\argObj -> makeFunc baseExpr xs (insert argVar argObj varlookup')
+				makeFunc baseExpr [] varlookup' = baseExpr varlookup'
+				funcExpr = makeFunc expr argVars
+			return $ \varlookup ->
+ 				ArgParser symb (Just$ funcExpr varlookup) "" (\val -> return $ insert symb val);
+		) <|> (do {
+			vsymb <- variableSymb;
+			return $ \varlookup ->
+ 				ArgParser vsymb Nothing "" (\val -> return $ insert vsymb val);
+		})
+		) (many space >> char ',' >> many space);
+	many space;	
+	char ')';
+	let
+		merge :: 
+			(ArgParser (VariableLookup -> VariableLookup))
+			->  (ArgParser (VariableLookup -> VariableLookup))
+			->  (ArgParser (VariableLookup -> VariableLookup))
+		merge a b = do
+			a' <- a
+			b' <- b
+			return (b'.a')
+	return $ \varlookup -> foldl merge (return id) $ map ($varlookup) $ args
 
 
 pad parser = do
@@ -147,4 +144,33 @@
 	many space
 	return a
 
+
+
+patternMatcher :: GenParser Char st (OpenscadObj -> Maybe VariableLookup)
+patternMatcher =
+	(do 
+		char '_'
+		return (\obj -> Just Map.empty)
+	) <|> ( do
+		a <- literal
+		return $ \obj ->
+			if obj == (a undefined)
+			then Just (Map.empty)
+			else Nothing
+	) <|> ( do
+		symb <- variableSymb
+		return $ \obj -> Just $ Map.singleton symb obj
+	) <|> ( do
+		char '['
+		many space
+		components <- patternMatcher `sepBy` (many space >> char ',' >> many space)
+		many space
+		char ']'
+		return $ \obj -> case obj of
+			OList l -> 
+				if length l == length components
+				then fmap Map.unions $ sequence $ zipWith ($) components l
+				else Nothing
+			_ -> Nothing
+	)
 
diff --git a/Graphics/Implicit/ExtOpenScad/Util/ArgParser.hs b/Graphics/Implicit/ExtOpenScad/Util/ArgParser.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ExtOpenScad/Util/ArgParser.hs
@@ -0,0 +1,186 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ScopedTypeVariables  #-}
+
+-- | We're going to give ourselves all sorts of goodies to parse OpenSCAD style module arguments here!!!
+--   To see the awesomeness of this applied, look at Primitives
+--   
+--   Our tool of choice is ArgParser. 
+--   It handles argument input, but also examples and unit tests for modules
+
+module Graphics.Implicit.ExtOpenScad.Util.ArgParser (
+
+	-- $ Note: The actual definition of ArgParser is in Defintions, 
+	--   to avoid the pain of circular dependencies.
+
+	-- * ArgParser building functions
+	-- ** argument & combinators
+	argument,
+	doc,
+	defaultTo,
+	-- ** example
+	example,
+	-- ** test & combinators
+	test,
+	eulerCharacteristic,
+
+	-- * Tools for handeling ArgParsers	
+	argMap,
+	getArgParserDocs,
+	Doc (..), DocPart (..)
+
+	)where
+
+import Graphics.Implicit.ExtOpenScad.Definitions
+
+import qualified Data.Map as Map
+import qualified Data.Maybe as Maybe
+import qualified Control.Exception as Ex
+
+--  * Instance Declarations
+
+-- | ArgParser is a monad.
+--   In some ways, an applicative functor would be nicer -- extracting docs 
+--   would be less crazy --,  but we want do notation for prettiness.
+
+instance Monad ArgParser where
+
+	-- return is easy: if we want an ArgParser that just gives us a, that is 
+	-- ArgParserTerminator a
+	return a = ArgParserTerminator a
+
+	-- Now things get more interesting. We need to describe how (>>=) works.
+	-- Let's get the hard ones out of the way first.
+	-- ArgParser actually 
+	(ArgParser str fallback doc f) >>= g = ArgParser str fallback doc (\a -> (f a) >>= g)
+	(ArgParserFailIf b errmsg child) >>= g = ArgParserFailIf b errmsg (child >>= g)
+	-- These next to is easy, they just pass the work along to their child
+	(ArgParserExample str child) >>= g = ArgParserExample str (child >>= g)
+	(ArgParserTest str tests child) >>= g = ArgParserTest str tests (child >>= g)
+	-- And an ArgParserTerminator happily gives away the value it contains
+	(ArgParserTerminator a) >>= g = g a
+
+-- * ArgParser building functions
+
+-- ** argument and combinators
+
+argument :: forall desiredType. (OTypeMirror desiredType) => String -> ArgParser desiredType
+argument name = 
+	ArgParser name Nothing "" $ \oObjVal -> do
+		let
+			val = fromOObj oObjVal :: Maybe desiredType
+			errmsg = case oObjVal of
+				OError errs -> "error in computing value for arugment " ++ name
+				             ++ ": " ++ concat errs
+				_   ->  "arg " ++ show oObjVal ++ " not compatible with " ++ name
+		-- Using /= Nothing would require Eq desiredType
+		ArgParserFailIf (Maybe.isNothing val) errmsg $ ArgParserTerminator $ (\(Just a) -> a) val
+
+doc (ArgParser name defMaybeVal oldDoc next) doc =
+	ArgParser name defMaybeVal doc next
+
+defaultTo :: forall a. (OTypeMirror a) => ArgParser a -> a -> ArgParser a
+defaultTo (ArgParser name oldDefMaybeVal doc next) newDefVal = 
+	ArgParser name (Just $ toOObj newDefVal) doc next
+
+-- ** example
+
+example :: String -> ArgParser ()
+example str = ArgParserExample str (return ())
+
+-- * test and combinators
+
+test :: String -> ArgParser ()
+test str = ArgParserTest str [] (return ())
+
+eulerCharacteristic :: ArgParser a -> Int -> ArgParser a
+eulerCharacteristic (ArgParserTest str tests child) χ =
+	ArgParserTest str ((EulerCharacteristic χ) : tests) child
+
+-- * Tools for handeling ArgParsers
+
+-- | Apply arguments to an ArgParser
+
+argMap :: 
+	   [OpenscadObj]            -- ^ Unnamed Arguments
+	-> [(String, OpenscadObj)]  -- ^ Named Arguments
+	-> ArgParser a              -- ^ ArgParser to apply them to
+	-> (Maybe a, [String])      -- ^ (result, error messages)
+
+argMap a b = argMap2 a (Map.fromList b)
+
+
+
+argMap2 :: [OpenscadObj] -> Map.Map String OpenscadObj -> ArgParser a -> (Maybe a, [String])
+
+argMap2 unnamedArgs namedArgs (ArgParser name fallback _ f) = 
+	case Map.lookup name namedArgs of
+		Just a -> argMap2 
+			unnamedArgs 
+			(Map.delete name namedArgs) 
+			(f a)
+		Nothing -> case unnamedArgs of
+			x:xs -> argMap2 xs namedArgs (f x)
+			[]   -> case fallback of
+				Just b  -> argMap2 [] namedArgs (f b)
+				Nothing -> (Nothing, ["No value and no default for argument " ++ name])
+
+argMap2 a b (ArgParserTerminator val) = 
+	(Just val,
+		if length a + Map.size b > 0
+		then ["unused arguments"]
+		else []
+	)
+
+argMap2 a b (ArgParserFailIf test err child) = 
+	if test 
+	then (Nothing, [err])
+	else argMap2 a b child
+
+argMap2 a b (ArgParserExample str child) = argMap2 a b child
+
+argMap2 a b (ArgParserTest str tests child) = argMap2 a b child
+
+
+-- | We need a format to extract documentation into
+data Doc = Doc String [DocPart]
+             deriving (Show)
+
+data DocPart = ExampleDoc String
+             | ArgumentDoc String (Maybe String) String
+             deriving (Show)
+
+
+--   Here there be dragons!
+--   Because we made this a Monad instead of applicative functor, there's now sane way to do this.
+--   We give undefined (= an error) and let laziness prevent if from ever being touched.
+--   We're using IO so that we can catch an error if this backfires.
+--   If so, we *back off*.
+
+-- | Extract Documentation from an ArgParser
+
+getArgParserDocs :: 
+	(ArgParser a)    -- ^ ArgParser
+	-> IO [DocPart]  -- ^ Docs (sadly IO wrapped)
+
+getArgParserDocs (ArgParser name fallback doc fnext) = 
+	do
+		otherDocs <- Ex.catch (getArgParserDocs $ fnext undefined) (\(e :: Ex.SomeException) -> return [])
+		return $ (ArgumentDoc name (fmap show fallback) doc):otherDocs
+
+getArgParserDocs (ArgParserExample str child) =
+	do
+		childResults <- getArgParserDocs child
+		return $ (ExampleDoc str) : childResults
+
+-- We try to look at as little as possible, to avoid the risk of triggering an error.
+-- Yay laziness!
+
+getArgParserDocs (ArgParserTest   _ _ child ) = getArgParserDocs child
+getArgParserDocs (ArgParserFailIf _ _ child ) = getArgParserDocs child
+
+-- To look at this one would almost certainly be death (exception)
+getArgParserDocs (ArgParserTerminator _ ) = return []
+
+
diff --git a/Graphics/Implicit/ExtOpenScad/Util/Computation.hs b/Graphics/Implicit/ExtOpenScad/Util/Computation.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ExtOpenScad/Util/Computation.hs
@@ -0,0 +1,79 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ScopedTypeVariables  #-}
+
+-- | Utilities for dealing with computations, in particular ComputationStateModifier
+
+module Graphics.Implicit.ExtOpenScad.Util.Computation where
+
+import Graphics.Implicit.Definitions
+import Graphics.Implicit.ExtOpenScad.Definitions
+
+-- | Run a list of computations!
+--   We start with a state and run it through a bunch of ComputationStateModifier s.
+runComputations :: ComputationState -> [ComputationStateModifier]  -> ComputationState
+runComputations = foldl (\a b -> b $ a)
+
+addObj2 :: (Monad m) => Obj2Type -> m ComputationStateModifier
+addObj2 obj = return $  \ ioWrappedState -> do
+		(varlookup, obj2s, obj3s) <- ioWrappedState
+		return (varlookup, obj2s ++ [obj], obj3s)
+
+addObj3 :: (Monad m) => Obj3Type -> m ComputationStateModifier
+addObj3 obj = return $  \ ioWrappedState -> do
+		(varlookup, obj2s, obj3s) <- ioWrappedState
+		return (varlookup, obj2s, obj3s ++ [obj])
+
+changeObjs :: (Monad m) => ([Obj2Type] -> [Obj2Type]) -> ([Obj3Type] -> [Obj3Type]) -> m ComputationStateModifier
+changeObjs mod2s mod3s = return $  \ ioWrappedState -> do
+		(varlookup, obj2s, obj3s) <- ioWrappedState
+		return (varlookup, mod2s obj2s, mod3s obj3s)
+
+runIO ::  (Monad m) => IO() -> m ComputationStateModifier
+runIO newio = return $  \ ioWrappedState -> do
+		state <- ioWrappedState
+		newio
+		return state
+
+noChange :: (Monad m) => m ComputationStateModifier
+noChange = return id
+
+getAndModUpObj2s :: (Monad m) => [ComputationStateModifier] 
+	-> (Obj2Type -> Obj3Type)
+	-> m ComputationStateModifier
+getAndModUpObj2s suite obj2mod = 
+	return $  \ ioWrappedState -> do
+		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
+		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
+		return 
+			(varlookup2,
+			 obj2s, 
+			 obj3s ++ (case obj2s2 of [] -> []; x:xs -> [obj2mod x])  )
+
+getAndCompressSuiteObjs :: (Monad m) => [ComputationStateModifier] 
+	-> ([Obj2Type] -> Obj2Type)
+	-> ([Obj3Type] -> Obj3Type)
+	-> m ComputationStateModifier
+getAndCompressSuiteObjs suite obj2modifier obj3modifier = 
+	return $  \ ioWrappedState -> do
+		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
+		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
+		return 
+			(varlookup2,
+			 obj2s ++ (case obj2s2 of [] -> []; _ -> [obj2modifier obj2s2]), 
+			 obj3s ++ (case obj3s2 of [] -> []; _ -> [obj3modifier obj3s2])  )
+
+getAndTransformSuiteObjs :: (Monad m) => [ComputationStateModifier] 
+	-> (Obj2Type -> Obj2Type)
+	-> (Obj3Type -> Obj3Type)
+	-> m ComputationStateModifier
+getAndTransformSuiteObjs suite obj2modifier obj3modifier = 
+	return $  \ ioWrappedState -> do
+		(varlookup,  obj2s,  obj3s)  <- ioWrappedState
+		(varlookup2, obj2s2, obj3s2) <- runComputations (return (varlookup, [], [])) suite
+		return 
+			(varlookup2,
+			 obj2s ++ (map obj2modifier obj2s2),
+			 obj3s ++ (map obj3modifier obj3s2)   )
+
diff --git a/Graphics/Implicit/MathUtil.hs b/Graphics/Implicit/MathUtil.hs
--- a/Graphics/Implicit/MathUtil.hs
+++ b/Graphics/Implicit/MathUtil.hs
@@ -1,11 +1,37 @@
 -- 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
+module Graphics.Implicit.MathUtil (rmax, rmin, rmaximum, rminimum, distFromLineSeg, pack, box3sWithin) where
 
 import Data.List
 import Graphics.Implicit.Definitions
+import qualified Graphics.Implicit.SaneOperators as S
 
+-- | The distance a point p is from a line segment (a,b)
+distFromLineSeg :: ℝ2 -> (ℝ2, ℝ2) -> ℝ
+distFromLineSeg p@(p1,p2) (a@(a1,a2), b@(b1,b2)) = S.norm (closest S.- p)
+	where
+		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
+
+		
+
+box3sWithin :: ℝ -> (ℝ3, ℝ3) -> (ℝ3,ℝ3) -> Bool
+box3sWithin r ((ax1, ay1, az1),(ax2, ay2, az2)) ((bx1, by1, bz1),(bx2, by2, bz2)) =
+	let
+		near (a1, a2) (b1, b2) = not $ (a2 + r < b1) || (b2 + r < a1)
+	in
+		   (ax1,ax2) `near` (bx1, bx2)
+		&& (ay1,ay2) `near` (by1, by2)
+		&& (az1,az2) `near` (bz1, bz2)
+
+
 -- | Rounded Maximum
 -- Consider  max(x,y) = 0, the generated curve 
 -- has a square-like corner. We replace it with a 
@@ -58,4 +84,43 @@
 		tops = sort l
 	in
 		rmin r (tops !! 0) (tops !! 1)
+
+
+pack :: 
+	Box2           -- ^ The box to pack within
+	-> ℝ           -- ^ The space seperation between items
+	-> [(Box2, a)] -- ^ Objects with their boxes
+	-> ([(ℝ2, a)], [(Box2, a)] ) -- ^ Packed objects with their positions, objects that could be packed
+
+pack (dx, dy) sep objs = packSome sortedObjs (dx, dy)
+	where
+		compareBoxesByY  ((_, ay1), (_, ay2))  ((_, by1), (_, by2)) = 
+				compare (abs $ by2-by1) (abs $ ay2 - ay1)
+
+		sortedObjs = sortBy 
+			(\(boxa, _) (boxb, _) -> compareBoxesByY boxa boxb ) 
+			objs
+
+		tmap1 f (a,b) = (f a, b)
+		tmap2 f (a,b) = (a, f b)
+
+		--packSome :: [(Box2,a)] -> Box2 -> ([(ℝ2,a)], [(Box2,a)])
+		packSome (presObj@(((x1,y1),(x2,y2)),obj):otherBoxedObjs) box@((bx1, by1), (bx2, by2)) = 
+			if abs (x2 - x1) <= abs (bx2-bx1) && abs (y2 - y1) <= abs (by2-by1)
+			then 
+				let
+					row = tmap1 (((bx1-x1,by1-y1), obj):) $
+						packSome otherBoxedObjs ((bx1+x2-x1+sep, by1), (bx2, by1 + y2-y1))
+					rowAndUp = 
+						if abs (by2-by1) - abs (y2-y1) > sep
+						then tmap1 ((fst row) ++ ) $
+							packSome (snd row) ((bx1, by1 + y2-y1+sep), (bx2, by2))
+						else row
+				in
+					rowAndUp
+			else
+				tmap2 (presObj:) $ packSome otherBoxedObjs box
+		packSome [] _ = ([], [])
+
+
 
diff --git a/Graphics/Implicit/ObjectUtil.hs b/Graphics/Implicit/ObjectUtil.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ObjectUtil.hs
@@ -0,0 +1,12 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
+
+module Graphics.Implicit.ObjectUtil(getImplicit3, getImplicit2, getBox3, getBox2) where
+
+import Graphics.Implicit.ObjectUtil.GetImplicit3
+import Graphics.Implicit.ObjectUtil.GetImplicit2
+import Graphics.Implicit.ObjectUtil.GetBox3
+import Graphics.Implicit.ObjectUtil.GetBox2
+
diff --git a/Graphics/Implicit/ObjectUtil/GetBox2.hs b/Graphics/Implicit/ObjectUtil/GetBox2.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ObjectUtil/GetBox2.hs
@@ -0,0 +1,107 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
+
+module Graphics.Implicit.ObjectUtil.GetBox2 (getBox2) where
+
+import Prelude hiding ((+),(-),(*),(/))
+import qualified Prelude as P
+import Graphics.Implicit.SaneOperators
+import Graphics.Implicit.Definitions
+import qualified Graphics.Implicit.MathUtil as MathUtil
+import Data.List (nub)
+
+getBox2 :: SymbolicObj2 -> Box2
+
+-- Primitives
+getBox2 (RectR r a b) = (a,b)
+
+getBox2 (Circle r ) =  ((-r, -r), (r,r))
+
+getBox2 (PolygonR r points) = ((minimum xs, minimum ys), (maximum xs, maximum ys)) 
+	 where (xs, ys) = unzip points
+
+-- (Rounded) CSG
+getBox2 (Complement2 symbObj) = 
+	((-infty, -infty), (infty, infty)) where infty = (1::ℝ)/(0 ::ℝ)
+
+getBox2 (UnionR2 r symbObjs) =
+	let 
+		boxes = map getBox2 symbObjs
+		isEmpty = ( == ((0,0),(0,0)) )
+		(leftbot, topright) = unzip $ filter (not.isEmpty) boxes
+		(lefts, bots) = unzip leftbot
+		(rights, tops) = unzip topright
+		left = minimum lefts
+		bot = minimum bots
+		right = maximum rights
+		top = maximum tops
+	in
+		((left-r,bot-r),(right+r,top+r))
+
+getBox2 (DifferenceR2 r symbObjs) =
+	let 
+		firstBox:_ = map getBox2 symbObjs
+	in
+		firstBox
+
+getBox2 (IntersectR2 r symbObjs) = 
+	let 
+		boxes = map getBox2 symbObjs
+		(leftbot, topright) = unzip boxes
+		(lefts, bots) = unzip leftbot
+		(rights, tops) = unzip topright
+		left = maximum lefts
+		bot = maximum bots
+		right = minimum rights
+		top = minimum tops
+	in
+		((left-r,bot-r),(right+r,top+r))
+
+-- Simple transforms
+getBox2 (Translate2 v symbObj) =
+	let
+		(a,b) = getBox2 symbObj
+	in
+		if (a,b) == ((0,0),(0,0))
+		then ((0,0),(0,0))
+		else (a+v, b+v)
+
+getBox2 (Scale2 s symbObj) =
+	let
+		(a,b) = getBox2 symbObj
+	in
+		(s ⋯* a, s ⋯* b)
+
+getBox2 (Rotate2 θ symbObj) = 
+	let
+		((x1,y1),(x2,y2)) = getBox2 symbObj
+		rotate (x,y) = ( cos(θ)*x - sin(θ)*y, sin(θ)*x + cos(θ)*y)
+		(xa, ya) = rotate (x1, y1)
+		(xb, yb) = rotate (x1, y2)
+		(xc, yc) = rotate (x2, y1)
+		(xd, yd) = rotate (x2, y2)
+		minx = minimum [xa, xb, xc, xd]
+		miny = minimum [ya, yb, yc, yd]
+		maxx = maximum [xa, xb, xc, xd]
+		maxy = maximum [ya, yb, yc, yd]
+	in
+		((minx, miny), (maxx, maxy))
+
+-- Boundary mods
+getBox2 (Shell2 w symbObj) = 
+	let
+		(a,b) = getBox2 symbObj
+		d = w/(2.0::ℝ)
+	in
+		(a - (d,d), b + (d,d))
+
+getBox2 (Outset2 d symbObj) =
+	let
+		(a,b) = getBox2 symbObj
+	in
+		(a - (d,d), b + (d,d))
+
+-- Misc
+getBox2 (EmbedBoxedObj2 (obj,box)) = box
diff --git a/Graphics/Implicit/ObjectUtil/GetBox3.hs b/Graphics/Implicit/ObjectUtil/GetBox3.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ObjectUtil/GetBox3.hs
@@ -0,0 +1,144 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
+
+module Graphics.Implicit.ObjectUtil.GetBox3 (getBox3) where
+
+import Prelude hiding ((+),(-),(*),(/))
+import Graphics.Implicit.SaneOperators
+import Graphics.Implicit.Definitions
+import qualified Graphics.Implicit.MathUtil as MathUtil
+import Data.Maybe (fromMaybe)
+
+import  Graphics.Implicit.ObjectUtil.GetBox2 (getBox2)
+
+getBox3 :: SymbolicObj3 -> Box3
+
+-- Primitives
+getBox3 (Rect3R r a b) = (a,b)
+
+getBox3 (Sphere r ) = ((-r, -r, -r), (r,r,r))
+
+getBox3 (Cylinder h r1 r2) = ( (-r,-r,0), (r,r,h) ) where r = max r1 r2
+
+-- (Rounded) CSG
+getBox3 (Complement3 symbObj) = 
+	((-infty, -infty, -infty), (infty, infty, infty)) where infty = (1::ℝ)/(0 ::ℝ)
+
+getBox3 (UnionR3 r symbObjs) = ((left-r,bot-r,inward-r), (right+r,top+r,out+r))
+	where 
+		boxes = map getBox3 symbObjs
+		isEmpty = ( == ((0,0,0),(0,0,0)) )
+		(leftbot, topright) = unzip $ filter (not.isEmpty) boxes
+		(lefts, bots, ins) = unzip3 leftbot
+		(rights, tops, outs) = unzip3 topright
+		left = minimum lefts
+		bot = minimum bots
+		inward = minimum ins
+		right = maximum rights
+		top = maximum tops
+		out = maximum outs
+
+getBox3 (IntersectR3 r symbObjs) = 
+	let 
+		boxes = map getBox3 symbObjs
+		(leftbot, topright) = unzip boxes
+		(lefts, bots, ins) = unzip3 leftbot
+		(rights, tops, outs) = unzip3 topright
+		left = maximum lefts
+		bot = maximum bots
+		inward = maximum ins
+		right = minimum rights
+		top = minimum tops
+		out = minimum outs
+	in
+		if   top   > bot 
+		  && right > left 
+		  && out   > inward
+		then ((left,bot,inward),(right,top,out))
+		else ((0,0,0),(0,0,0))
+
+getBox3 (DifferenceR3 r symbObjs) = firstBox
+	where
+		firstBox:_ = map getBox3 symbObjs
+
+-- Simple transforms
+getBox3 (Translate3 v symbObj) =
+	let
+		(a,b) = getBox3 symbObj
+	in
+		(a+v, b+v)
+
+getBox3 (Scale3 s symbObj) =
+	let
+		(a,b) = getBox3 symbObj
+	in
+		(s ⋯* a, s ⋯* b)
+
+getBox3 (Rotate3 _ symbObj) = ( (-d, -d, -d), (d, d, d) )
+	where
+		((x1,y1, z1), (x2,y2, z2)) = getBox3 symbObj
+		d = (sqrt (2::ℝ) *) $ maximum $ map abs [x1, x2, y1, y2, z1, z2]
+
+-- Boundary mods
+getBox3 (Shell3 w symbObj) = 
+	let
+		(a,b) = getBox3 symbObj
+		d = w/(2.0::ℝ)
+	in
+		(a - (d,d,d), b + (d,d,d))
+
+getBox3 (Outset3 d symbObj) =
+	let
+		(a,b) = getBox3 symbObj
+	in
+		(a - (d,d,d), b + (d,d,d))
+
+-- Misc
+getBox3 (EmbedBoxedObj3 (obj,box)) = box
+
+-- 2D Based
+getBox3 (ExtrudeR r symbObj h) = ((x1,y1,0),(x2,y2,h))
+	where
+		((x1,y1),(x2,y2)) = getBox2 symbObj
+
+getBox3 (ExtrudeOnEdgeOf symbObj1 symbObj2) =
+	let
+		((ax1,ay1),(ax2,ay2)) = getBox2 symbObj1
+		((bx1,by1),(bx2,by2)) = getBox2 symbObj2
+	in
+		((bx1+ax1, by1+ax1, ay2), (bx2+ax2, by2+ax2, ay2))
+
+
+getBox3 (ExtrudeRM r twist scale translate symbObj (Left h)) = 
+	let
+		((x1,y1),(x2,y2)) = getBox2 symbObj
+		dx = x2 - x1
+		dy = y2 - y1
+		svals =  map (fromMaybe (const 1) scale) $ [0,h/(2::ℝ),h]
+		sval = maximum $ map abs $ svals
+		d = sval * sqrt (dx^2 + dy^2)
+		(tvalsx, tvalsy) = unzip $ map (fromMaybe (const (0,0)) translate) $ [0,h/(2::ℝ),h]
+		(tminx, tminy) = (minimum tvalsx, minimum tvalsy)
+		(tmaxx, tmaxy) = (maximum tvalsx, maximum tvalsy)
+	in
+		((-d+tminx, -d+tminy, 0),(d+tmaxx, d+tmaxy, h)) 
+
+getBox3 (ExtrudeRM r twist scale translate symbObj (Right hf)) = 
+	let
+		((x1,y1),(x2,y2)) = getBox2 symbObj
+		dx = x2 - x1
+		dy = y2 - y1
+		h = maximum [hf (x1,y1), hf (x2,y1), hf (x2,y2), hf (x1,y2), hf ((x1+x2)/(2::ℝ), (y1+y2)/(2::ℝ))]
+		svals =  map (fromMaybe (const 1) scale) $ [0,h/(2::ℝ),h]
+		sval = maximum $ map abs $ svals
+		d = sval * sqrt (dx^2 + dy^2)
+		(tvalsx, tvalsy) = unzip $ map (fromMaybe (const (0,0)) translate) $ [0,h/(2::ℝ),h]
+		(tminx, tminy) = (minimum tvalsx, minimum tvalsy)
+		(tmaxx, tmaxy) = (maximum tvalsx, maximum tvalsy)
+	in
+		((-d+tminx, -d+tminy, 0),(d+tmaxx, d+tmaxy, h))
+
+
+
diff --git a/Graphics/Implicit/ObjectUtil/GetImplicit2.hs b/Graphics/Implicit/ObjectUtil/GetImplicit2.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ObjectUtil/GetImplicit2.hs
@@ -0,0 +1,107 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
+
+module Graphics.Implicit.ObjectUtil.GetImplicit2 (getImplicit2) where
+
+import Prelude hiding ((+),(-),(*),(/))
+import qualified Prelude as P
+import Graphics.Implicit.SaneOperators
+import Graphics.Implicit.Definitions
+import qualified Graphics.Implicit.MathUtil as MathUtil
+import Data.List (nub)
+
+getImplicit2 :: SymbolicObj2 -> Obj2
+
+-- Primitives
+getImplicit2 (RectR r (x1,y1) (x2,y2)) = \(x,y) -> MathUtil.rmaximum r
+	[abs (x-dx/(2::ℝ)-x1) - dx/(2::ℝ), abs (y-dy/(2::ℝ)-y1) - dy/(2::ℝ)]
+		where (dx, dy) = (x2-x1, y2-y1)
+
+getImplicit2 (Circle r ) = 
+	\(x,y) -> sqrt (x**2 + y**2) - r
+
+getImplicit2 (PolygonR r points) = 
+	\p -> let
+		pair :: Int -> (ℝ2,ℝ2)
+		pair n = (points !! n, points !! (mod (n + (1::Int) ) (length points) ) )
+		pairs =  [ pair n | n <- [0 .. (length points) - (1 :: Int)] ]
+		relativePairs =  map (\(a,b) -> (a - p, b - p) ) pairs
+		crossing_points =
+			[x2 - y2*(x2-x1)/(y2-y1) | ((x1,y1), (x2,y2)) <-relativePairs,
+			   ( (y2 <= 0) && (y1 >= 0) ) || ( (y2 >= 0) && (y1 <= 0) ) ]
+		seemsInRight = odd $ length $ filter (>0) $ nub crossing_points
+		seemsInLeft = odd $ length $ filter (<0) $ nub crossing_points
+		isIn = seemsInRight && seemsInLeft
+		dists = map (MathUtil.distFromLineSeg p) pairs :: [ℝ]
+	in
+		minimum dists * if isIn then - (1 :: ℝ) else (1 :: ℝ)
+
+-- (Rounded) CSG
+getImplicit2 (Complement2 symbObj) = 
+	let
+		obj = getImplicit2 symbObj
+	in
+		\p -> - obj p
+
+getImplicit2 (UnionR2 r symbObjs) =
+	let 
+		objs = map getImplicit2 symbObjs
+	in
+		if r == 0
+		then \p -> minimum $ map ($p) objs 
+		else \p -> MathUtil.rminimum r $ map ($p) objs
+
+getImplicit2 (DifferenceR2 r symbObjs) =
+	let 
+		obj:objs = map getImplicit2 symbObjs
+		complement obj = \p -> - obj p
+	in
+		if r == 0
+		then \p -> maximum $ map ($p) $ obj:(map complement objs) 
+		else \p -> MathUtil.rmaximum r $ map ($p) $ obj:(map complement objs) 
+
+getImplicit2 (IntersectR2 r symbObjs) = 
+	let 
+		objs = map getImplicit2 symbObjs
+	in
+		if r == 0
+		then \p -> maximum $ map ($p) objs 
+		else \p -> MathUtil.rmaximum r $ map ($p) objs
+
+-- Simple transforms
+getImplicit2 (Translate2 v symbObj) =
+	let
+		obj = getImplicit2 symbObj
+	in
+		\p -> obj (p-v)
+
+getImplicit2 (Scale2 s@(sx,sy) symbObj) =
+	let
+		obj = getImplicit2 symbObj
+	in
+		\p -> (max sx sy) * obj (p ⋯/ s)
+
+getImplicit2 (Rotate2 θ symbObj) = 
+	let
+		obj = getImplicit2 symbObj
+	in
+		\(x,y) -> obj ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x)
+
+-- Boundary mods
+getImplicit2 (Shell2 w symbObj) = 
+	let
+		obj = getImplicit2 symbObj
+	in
+		\p -> abs (obj p) - w/(2.0::ℝ)
+
+getImplicit2 (Outset2 d symbObj) =
+	let
+		obj = getImplicit2 symbObj
+	in
+		\p -> obj p - d
+
+-- Misc
+getImplicit2 (EmbedBoxedObj2 (obj,box)) = obj
+
diff --git a/Graphics/Implicit/ObjectUtil/GetImplicit3.hs b/Graphics/Implicit/ObjectUtil/GetImplicit3.hs
new file mode 100644
--- /dev/null
+++ b/Graphics/Implicit/ObjectUtil/GetImplicit3.hs
@@ -0,0 +1,139 @@
+-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
+-- Released under the GNU GPL, see LICENSE
+
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, ViewPatterns #-}
+
+module Graphics.Implicit.ObjectUtil.GetImplicit3 (getImplicit3) where
+
+import Prelude hiding ((+),(-),(*),(/))
+import Graphics.Implicit.SaneOperators
+import Graphics.Implicit.Definitions
+import qualified Graphics.Implicit.MathUtil as MathUtil
+import qualified Data.Maybe as Maybe
+
+import  Graphics.Implicit.ObjectUtil.GetImplicit2 (getImplicit2)
+
+getImplicit3 :: SymbolicObj3 -> Obj3
+
+-- Primitives
+getImplicit3 (Rect3R r (x1,y1,z1) (x2,y2,z2)) = \(x,y,z) -> MathUtil.rmaximum r
+	[abs (x-dx/(2::ℝ)-x1) - dx/(2::ℝ), abs (y-dy/(2::ℝ)-y1) - dy/(2::ℝ), abs (z-dz/(2::ℝ)-z1) - dz/(2::ℝ)]
+		where (dx, dy, dz) = (x2-x1, y2-y1, z2-z1)
+
+getImplicit3 (Sphere r ) = 
+	\(x,y,z) -> sqrt (x**2 + y**2 + z**2) - r
+
+getImplicit3 (Cylinder h r1 r2) = \(x,y,z) ->
+	let
+		d = sqrt(x^2+y^2) - ((r2-r1)/h*z+r1)
+		θ = atan2 (r2-r1) h
+	in
+		max (d * cos θ) (abs(z-h/(2::ℝ)) - h/(2::ℝ))
+
+-- (Rounded) CSG
+getImplicit3 (Complement3 symbObj) = 
+	let
+		obj = getImplicit3 symbObj
+	in
+		\p -> - obj p
+
+getImplicit3 (UnionR3 r symbObjs) =
+	let 
+		objs = map getImplicit3 symbObjs
+	in
+		if r == 0
+		then \p -> minimum $ map ($p) objs 
+		else \p -> MathUtil.rminimum r $ map ($p) objs
+
+getImplicit3 (IntersectR3 r symbObjs) = 
+	let 
+		objs = map getImplicit3 symbObjs
+	in
+		if r == 0
+		then \p -> maximum $ map ($p) objs 
+		else \p -> MathUtil.rmaximum r $ map ($p) objs
+
+getImplicit3 (DifferenceR3 r symbObjs) =
+	let 
+		obj:objs = map getImplicit3 symbObjs
+		complement obj = \p -> - obj p
+	in
+		if r == 0
+		then \p -> maximum $ map ($p) $ obj:(map complement objs) 
+		else \p -> MathUtil.rmaximum r $ map ($p) $ obj:(map complement objs) 
+
+-- Simple transforms
+getImplicit3 (Translate3 v symbObj) =
+	let
+		obj = getImplicit3 symbObj
+	in
+		\p -> obj (p-v)
+
+getImplicit3 (Scale3 s@(sx,sy,sz) symbObj) =
+	let
+		obj = getImplicit3 symbObj
+	in
+		\p -> (maximum [sx, sy, sz]) * obj (p ⋯/ s)
+
+getImplicit3 (Rotate3 (yz, xz, xy) symbObj) = 
+	let
+		obj = getImplicit3 symbObj
+		rotateYZ :: ℝ -> (ℝ3 -> ℝ) -> (ℝ3 -> ℝ)
+		rotateYZ θ obj = \(x,y,z) -> obj ( x, cos(θ)*z - sin(θ)*y, cos(θ)*y + sin(θ)*z)
+		rotateXZ :: ℝ -> (ℝ3 -> ℝ) -> (ℝ3 -> ℝ)
+		rotateXZ θ obj = \(x,y,z) -> obj ( cos(θ)*x + sin(θ)*z, y, cos(θ)*z - sin(θ)*x)
+		rotateXY :: ℝ -> (ℝ3 -> ℝ) -> (ℝ3 -> ℝ)
+		rotateXY θ obj = \(x,y,z) -> obj ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x, z)
+	in
+		rotateYZ yz $ rotateXZ xz $ rotateXY xy $ obj
+
+-- Boundary mods
+getImplicit3 (Shell3 w symbObj) = 
+	let
+		obj = getImplicit3 symbObj
+	in
+		\p -> abs (obj p) - w/(2::ℝ)
+
+getImplicit3 (Outset3 d symbObj) =
+	let
+		obj = getImplicit3 symbObj
+	in
+		\p -> obj p - d
+
+-- Misc
+getImplicit3 (EmbedBoxedObj3 (obj,box)) = obj
+
+-- 2D Based
+getImplicit3 (ExtrudeR r symbObj h) = 
+	let
+		obj = getImplicit2 symbObj
+	in
+		\(x,y,z) -> MathUtil.rmax r (obj (x,y)) (abs (z - h/(2::ℝ)) - h/(2::ℝ))
+
+getImplicit3 (ExtrudeRM r twist scale translate symbObj height) = 
+	let
+		obj = getImplicit2 symbObj
+		twist' = Maybe.fromMaybe (const 0) twist
+		scale' = Maybe.fromMaybe (const 1) scale
+		translate' = Maybe.fromMaybe (const (0,0)) translate
+		height' (x,y) = case height of
+			Left n -> n
+			Right f -> f (x,y)
+		scaleVec :: ℝ -> ℝ2 -> ℝ2
+		scaleVec  s = \(x,y) -> (x/s, y/s)
+		rotateVec :: ℝ -> ℝ2 -> ℝ2
+		rotateVec θ (x,y) = (x*cos(θ)+y*sin(θ), y*cos(θ)-x*sin(θ)) 
+		k = (pi :: ℝ)/(180:: ℝ)
+	in
+		\(x,y,z) -> let h = height' (x,y) in
+			MathUtil.rmax r 
+				(obj . rotateVec (-k*twist' z) . scaleVec (scale' z) . (\a -> a- translate' z) $ (x,y))
+				(abs (z - h/(2::ℝ)) - h/(2::ℝ))
+
+
+getImplicit3 (ExtrudeOnEdgeOf symbObj1 symbObj2) =
+	let
+		obj1 = getImplicit2 symbObj1
+		obj2 = getImplicit2 symbObj2
+	in
+		\(x,y,z) -> obj1 (obj2 (x,y), z)
diff --git a/Graphics/Implicit/Operations.hs b/Graphics/Implicit/Operations.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations.hs
+++ /dev/null
@@ -1,71 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations (
-	BasicObj, MagnitudeObj,
-	translate, 
-	scale,
-	rotateXY,
-	complement,
-	union,  intersect,  difference, 
-	unionR,  intersectR,  differenceR, 
-	outset,
-	shell,
-	extrudeR, extrudeRMod,
-	extrudeOnEdgeOf,
-	rotate3
-) where
-
--- classes in here provide basicaly everything we're exporting...
-import Graphics.Implicit.Operations.Definitions
-
--- Then we have a bunch of isntances, corresponding to each file name.
-import Graphics.Implicit.Operations.Obj2
-import Graphics.Implicit.Operations.Obj3
-import Graphics.Implicit.Operations.ObjPair
-import Graphics.Implicit.Operations.BoxedObj2
-import Graphics.Implicit.Operations.BoxedObj3
-import Graphics.Implicit.Operations.BoxedObjPair
-import Graphics.Implicit.Operations.SymbolicObj2
-import Graphics.Implicit.Operations.SymbolicObj3
-import Graphics.Implicit.Operations.SymbolicObjPair
-
-
-
-{- Old stuff that may need to be incorporated into the larger structure later
-
--- | 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)
-
-
--- | 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) 
-
-
--}
diff --git a/Graphics/Implicit/Operations/Box2.hs b/Graphics/Implicit/Operations/Box2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/Box2.hs
+++ /dev/null
@@ -1,68 +0,0 @@
-
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.Box2 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-
--- CSG on 2D boxes
--- Not precise, since not all CSG of such is a 2D box, 
--- but result will be a super set. We will use this for bounding boxes.
--- Empty boxes will always be ((0,0),(0,0)) for convenience :)
-instance BasicObj Box2 ℝ2 where
-	translate _ ((0,0),(0,0)) = ((0,0),(0,0))
-	translate p (a,b) = (a+p, b+p)
-	scale s (a,b) = (s*a, s*b)
-	rotateXY θ ((x1,y1),(x2,y2)) = 
-		let
-			rotate (x,y) = ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x)
-			(xa, ya) = rotate (x1, y1)
-			(xb, yb) = rotate (x1, y2)
-			(xc, yc) = rotate (x2, y1)
-			(xd, yd) = rotate (x2, y2)
-			minx = minimum [xa, xb, xc, xd]
-			miny = minimum [ya, yb, yc, yd]
-			maxx = maximum [xa, xb, xc, xd]
-			maxy = maximum [ya, yb, yc, yd]
-		in
-			((minx, miny), (maxx, maxy))
-	complement _ = ((-infty, -infty), (infty, infty))
-	union boxes = ((left,bot),(right,top)) where
-			isEmpty = ( == ((0,0),(0,0)) )
-			(leftbot, topright) = unzip $ filter (not.isEmpty) boxes
-			(lefts, bots) = unzip leftbot
-			(rights, tops) = unzip topright
-			left = minimum lefts
-			bot = minimum bots
-			right = maximum rights
-			top = maximum tops
-	intersect boxes = 
-		let
-			(leftbot, topright) = unzip boxes
-			(lefts, bots) = unzip leftbot
-			(rights, tops) = unzip topright
-			left = maximum lefts
-			bot = maximum bots
-			right = minimum rights
-			top = minimum tops
-		in
-			if top > bot && right > left 
-			then ((left,bot),(right,top))
-			else ((0,0),(0,0))
-	difference (firstBox : otherBoxes) = firstBox
-
-
-instance MagnitudeObj Box2 where
-	outset d (a,b) = (a - (d,d), b + (d,d))
-	shell w (a,b) = (a - (w/(2.0::ℝ),w/(2.0::ℝ)), b + (w/(2.0::ℝ),w/(2.0::ℝ)))
-	unionR r boxes = outset r $ union boxes
-	intersectR r boxes = outset r $ intersect boxes
-	differenceR r boxes = outset r $ difference boxes
diff --git a/Graphics/Implicit/Operations/Box3.hs b/Graphics/Implicit/Operations/Box3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/Box3.hs
+++ /dev/null
@@ -1,65 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.Box3 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-instance BasicObj Box3 ℝ3 where
-	translate _ ((0,0,0),(0,0,0)) = ((0,0,0),(0,0,0))
-	translate p (a,b) = (a+p, b+p)
-	scale s (a,b) = (s*a, s*b)
-	rotateXY θ ((x1,y1,z1),(x2,y2,z2)) = 
-		let
-			rotate (x,y) = ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x)
-			(xa, ya) = rotate (x1, y1)
-			(xb, yb) = rotate (x1, y2)
-			(xc, yc) = rotate (x2, y1)
-			(xd, yd) = rotate (x2, y2)
-			minx = minimum [xa, xb, xc, xd]
-			miny = minimum [ya, yb, yc, yd]
-			maxx = maximum [xa, xb, xc, xd]
-			maxy = maximum [ya, yb, yc, yd]
-		in
-			((minx, miny,z1), (maxx, maxy,z2))
-	complement _ = ((-infty, -infty,-infty), (infty, infty, infty))
-	union boxes = ((left,bot,inward),(right,top,out)) where
-			isEmpty = ( == ((0,0,0),(0,0,0)) )
-			(leftbot, topright) = unzip $ filter (not.isEmpty) boxes
-			(lefts, bots, ins) = unzip3 leftbot
-			(rights, tops, outs) = unzip3 topright
-			left = minimum lefts
-			bot = minimum bots
-			inward = minimum ins
-			right = maximum rights
-			top = maximum tops
-			out = maximum outs
-	intersect boxes = 
-		let
-			(leftbot, topright) = unzip boxes
-			(lefts, bots, ins) = unzip3 leftbot
-			(rights, tops, outs) = unzip3 topright
-			left = maximum lefts
-			bot = maximum bots
-			inward = maximum ins
-			right = minimum rights
-			top = minimum tops
-			out = minimum outs
-		in
-			if top > bot && right > left && out > inward
-			then ((left,bot,inward),(right,top,out))
-			else ((0,0,0),(0,0,0))
-	difference (firstBox : otherBoxes) = firstBox
-
-instance MagnitudeObj Box3 where
-	outset d (a,b) = (a - (d,d,d), b + (d,d,d))
-	shell w (a,b) = (a - (w/(2.0::ℝ),w/(2.0::ℝ),w/(2.0::ℝ)), b + (w/(2.0::ℝ),w/(2.0::ℝ),w/(2.0::ℝ)))
-	unionR r boxes = outset r $ union boxes
-	intersectR r boxes = outset r $ intersect boxes
-	differenceR r boxes = outset r $ difference boxes
diff --git a/Graphics/Implicit/Operations/BoxPair.hs b/Graphics/Implicit/Operations/BoxPair.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/BoxPair.hs
+++ /dev/null
@@ -1,30 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Operations.BoxPair where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Operations.Definitions
-
-
--- | Operations that are specific to some part of a
---   2D-3D dimensional object pair.
-instance PairObj Box2 ℝ2 Box3 ℝ3 where
-
-	extrudeR _ ((x1,y1),(x2,y2)) h = ((x1,y1,0),(x2,y2,h))
-	-- This is kind of tricky, because we have no idea what kind of crazy function will come up with...
-	-- So we're going to give them 3x play space. We'll mention people should mostly shrink objs...
-	-- I fully intend to do crazy symbolic stuff almost everywhere, so I'm not too worried about speed.
-	extrudeRMod _ _ ((x1,y1),(x2,y2)) h = ((x1 - dx, y1 - dy, 0),(x2 + dx, y2+ dy, h)) 
-		where
-			dx = x2 - x1
-			dy = y2 - y1
-	extrudeOnEdgeOf ((ax1,ay1),(ax2,ay2)) ((bx1,by1),(bx2,by2)) = 
-		((bx1+ax1, by1+ax1, ay2), (bx2+ax2, by2+ax2, ay2))
-	rotate3 _ ((x1,y1, z1),(x2,y2, z2)) = ( (-d, -d, -d), (d, d, d) )
-		where
-			d = (sqrt 2 *) $ maximum $ map abs [x1, x2, y1, y2, z1, z2]
-
diff --git a/Graphics/Implicit/Operations/BoxedObj2.hs b/Graphics/Implicit/Operations/BoxedObj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/BoxedObj2.hs
+++ /dev/null
@@ -1,38 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.BoxedObj2 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Operations.Box2
-import Graphics.Implicit.Operations.Obj2
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-
-instance BasicObj (Boxed2 Obj2) ℝ2 where
-	translate p (obj, box) = (translate p obj, translate p box)
-	scale s (obj, box) = (scale s obj, scale s box)
-	rotateXY θ (obj, box) = (rotateXY θ obj, rotateXY θ box)
-	complement (obj, box) = (complement obj, complement box )
-	union bobjs = (union objs, union boxes) where
-		(objs, boxes) = unzip bobjs
-	intersect bobjs = (intersect objs, intersect boxes) where
-		(objs, boxes) = unzip bobjs
-	difference bobjs = (difference objs, difference boxes) where
-		(objs, boxes) = unzip bobjs
-
-
-instance MagnitudeObj (Boxed2 Obj2) where
-	outset  d     (obj, box) = (outset d obj, outset d box)
-	shell   w     (obj, box) = (shell  w obj, shell  w box)
-	unionR      r bobjs      = (unionR      r objs, unionR      r boxes) where
-		(objs, boxes) = unzip bobjs
-	intersectR  r bobjs      = (intersectR  r objs, intersectR  r boxes) where
-		(objs, boxes) = unzip bobjs
-	differenceR r bobjs      = (differenceR r objs, differenceR r boxes) where
-		(objs, boxes) = unzip bobjs
diff --git a/Graphics/Implicit/Operations/BoxedObj3.hs b/Graphics/Implicit/Operations/BoxedObj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/BoxedObj3.hs
+++ /dev/null
@@ -1,36 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.BoxedObj3 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Operations.Box3
-import Graphics.Implicit.Operations.Obj3
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-instance BasicObj (Boxed3 Obj3) ℝ3 where
-	translate p (obj, box) = (translate p obj, translate p box)
-	scale s (obj, box) = (scale s obj, scale s box)
-	rotateXY θ (obj, box) = (rotateXY θ obj, rotateXY θ box)
-	complement (obj, box) = (complement obj, complement box )
-	union bobjs = (union objs, union boxes) where
-		(objs, boxes) = unzip bobjs
-	intersect bobjs = (intersect objs, intersect boxes) where
-		(objs, boxes) = unzip bobjs
-	difference bobjs = (difference objs, difference boxes) where
-		(objs, boxes) = unzip bobjs
-
-instance MagnitudeObj (Boxed3 Obj3) where
-	outset  d     (obj, box) = (outset d obj, outset d box)
-	shell   w     (obj, box) = (shell  w obj, shell  w box)
-	unionR      r bobjs      = (unionR      r objs, unionR      r boxes) where
-		(objs, boxes) = unzip bobjs
-	intersectR  r bobjs      = (intersectR  r objs, intersectR  r boxes) where
-		(objs, boxes) = unzip bobjs
-	differenceR r bobjs      = (differenceR r objs, differenceR r boxes) where
-		(objs, boxes) = unzip bobjs
diff --git a/Graphics/Implicit/Operations/BoxedObjPair.hs b/Graphics/Implicit/Operations/BoxedObjPair.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/BoxedObjPair.hs
+++ /dev/null
@@ -1,22 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Operations.BoxedObjPair where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Operations.ObjPair
-import Graphics.Implicit.Operations.BoxPair
-
-
--- | Operations that are specific to some part of a
---   2D-3D dimensional object pair.
-instance PairObj BoxedObj2 ℝ2 BoxedObj3 ℝ3 where
-
-	extrudeR r (obj, box) h = (extrudeR r obj h, extrudeR r box h)
-	extrudeRMod r mod (obj, box) h = (extrudeRMod r mod obj h, extrudeRMod r mod box h)
-	extrudeOnEdgeOf (obj1, box1) (obj2, box2) = (extrudeOnEdgeOf obj1 obj2, extrudeOnEdgeOf box1 box2)
-	rotate3 rot (obj, box) =  (rotate3 rot obj, rotate3 rot box)
diff --git a/Graphics/Implicit/Operations/Definitions.hs b/Graphics/Implicit/Operations/Definitions.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/Definitions.hs
+++ /dev/null
@@ -1,141 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Operations.Definitions where
-
-import Graphics.Implicit.Definitions
-
-
-infty = (1 :: ℝ) / (0 :: ℝ)
-
--- | Very basic operations objects
-class BasicObj obj vec | obj -> vec where
-	
-	-- | Translate an object by a vector of appropriate dimension. 
-	translate :: 
-		vec      -- ^ Vector to translate by (Also: a is a vector, blah, blah)
-		-> obj   -- ^ Object to translate
-		-> obj   -- ^ Resulting object
-
-	-- | Scale an object
-	scale :: 
-		ℝ       -- ^ Amount to scale by
-		-> obj  -- ^ Object to scale
-		-> obj  -- ^ Resulting scaled object
-
-	rotateXY ::
-		ℝ       -- ^ Amount to rotate by
-		-> obj  -- ^ Object to rotate
-		-> obj  -- ^ Resulting rotated object		
-	
-	-- | Complement an Object
-	complement :: 
-		obj     -- ^ Object to complement
-		-> obj  -- ^ Result
-	
-	-- | Union a list of objects
-	union :: 
-		[obj]  -- ^ List of objects to union
-		-> obj -- ^ The object resulting from the union
-
-	-- | Difference a list of objects
-	difference :: 
-		[obj]  -- ^ List of objects to difference
-		-> obj -- ^ The object resulting from the difference
-	
-	-- | Intersect a list of objects
-	intersect :: 
-		[obj]  -- ^ List of objects to intersect
-		-> obj -- ^ The object resulting from the intersection
-
-
-
-
-
--- | Operations that involve an idea of how far you are outwards
-class MagnitudeObj obj where
-
-	-- | Outset an object.
-	outset :: 
-		ℝ        -- ^ distance to outset
-		-> obj   -- ^ object to outset
-		-> obj   -- ^ resulting object
-
-	-- | Make a shell of an object.
-	shell :: 
-		ℝ        -- ^ width of shell
-		-> obj   -- ^ object to take shell of
-		-> obj   -- ^ resulting shell
-	
-	-- | Rounded union
-	unionR :: 
-		ℝ        -- ^ The radius of rounding
-		-> [obj] -- ^ objects to union
-		-> obj   -- ^ Resulting object
-	
-	-- | Rounded minimum
-	intersectR :: 
-		ℝ        -- ^ The radius of rounding
-		-> [obj] -- ^ Objects to intersect
-		-> obj   -- ^ Resulting object
-	
-	-- | Rounded difference
-	differenceR :: 
-		ℝ        -- ^ The radius of rounding
-		-> [obj] -- ^ Objects to difference 
-		-> obj   -- ^ Resulting object
-
-
--- | Inset an object.
-inset :: MagnitudeObj obj =>
-	ℝ        -- ^ distance to inset
-	-> obj   -- ^ object to inset
-	-> obj   -- ^ resulting object
-inset d obj = outset (-d) obj
-
-
--- | Operations that are specific to some part of a
---   2D-3D dimensional object pair.
-class PairObj obj2 vec2 obj3 vec3 
-              | obj2 -> vec2, obj3 -> vec3, obj2 -> obj3, obj3 -> obj2 
-      where
-
-	-- | Extrude a rounded object
-	extrudeR :: 
-		ℝ       -- ^ Radius of rounding
-		-> obj2 -- ^ 2D Object to extrude
-		-> ℝ    -- ^ length to extrude it
-		-> obj3 -- ^ Resulting 3D object
-
-	-- | Extrude a rounded 2D object, modifying it over height
-	--   Comment: Technically, extrudeR = extrudeRMod id, but then we 
-	--    couldn't be clever with symbolics :) 
-	extrudeRMod :: 
-		ℝ       -- ^ Radius of rounding
-		-> (ℝ -> ℝ2 -> ℝ2) -- ^ Function to modify each layer:
-		                   -- Height transforming at,
-		                   -- Input 2D transform,
-		                   -- New point!
-		-> obj2      -- ^ 2D Object to extrude
-		-> ℝ         -- ^ length to extrude it
-		-> obj3      -- ^ Resulting 3D object
-
-	-- | Extrude one 2D object about the edge of another.
-	--   Example: 2 circles produce a torus
-	--   Comment: extrudeOnEdgeOf a b can be thought of as a 
-	--   projection of a×b.
-	extrudeOnEdgeOf ::
-		obj2     -- ^ Object to extrude
-		-> obj2  -- ^ Object to extrude along the edge of
-		-> obj3  -- ^ Resulting 3D object
-
-	-- | Like openscad rotate...
-	--   Comment: Rotations are not abelian -- watch out!
-	rotate3 ::
-		(ℝ, ℝ, ℝ)   -- ^ Rotater (YZ, XZ, XY)
-		-> obj3     -- ^ Object to rotate
-		-> obj3     -- ^ Resulting object
-
diff --git a/Graphics/Implicit/Operations/Obj2.hs b/Graphics/Implicit/Operations/Obj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/Obj2.hs
+++ /dev/null
@@ -1,29 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.Obj2 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-
-instance BasicObj Obj2 ℝ2 where
-	translate p obj = \q -> obj (q-p)
-	scale s obj = \p -> s * obj (p/s)
-	rotateXY θ obj = \(x,y) -> obj ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x)
-	complement obj = \p -> - obj p
-	union objs = \p -> minimum $ map ($p) objs
-	intersect objs = \p -> maximum $ map ($p) objs
-	difference (obj:objs) = \p -> maximum $ map ($p) $ obj:(map complement objs)
-
-instance MagnitudeObj Obj2 where
-	outset d obj = \p -> obj p - d
-	shell w a = \p -> abs (a p) - w/(2.0::ℝ)
-	unionR r objs = \p -> rminimum r $ map ($p) objs
-	intersectR r objs = \p -> rmaximum r $ map ($p) objs
-	differenceR r (x:xs) = \p -> rmaximum r $ (x p) :(map (negate . ($p)) xs)
diff --git a/Graphics/Implicit/Operations/Obj3.hs b/Graphics/Implicit/Operations/Obj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/Obj3.hs
+++ /dev/null
@@ -1,29 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.Obj3 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-
-instance BasicObj Obj3 ℝ3 where
-	translate p obj = \q -> obj (q-p)
-	scale s obj = \p -> s * obj (p/s)
-	rotateXY θ obj = \(x,y,z) -> obj ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x, z)
-	complement obj = \p -> - obj p
-	union objs = \p -> minimum $ map ($p) objs
-	intersect objs = \p -> maximum $ map ($p) objs
-	difference (obj:objs) = \p -> maximum $ map ($p) $ obj:(map complement objs)
-
-instance MagnitudeObj Obj3 where
-	outset d obj = \p -> obj p - d
-	shell w a = \p -> abs (a p) - w/(2.0::ℝ)
-	unionR r objs = \p -> rminimum r $ map ($p) objs
-	intersectR r objs = \p -> rmaximum r $ map ($p) objs
-	differenceR r (x:xs) = \p -> rmaximum r $ (x p) :(map (negate . ($p)) xs)
diff --git a/Graphics/Implicit/Operations/ObjPair.hs b/Graphics/Implicit/Operations/ObjPair.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/ObjPair.hs
+++ /dev/null
@@ -1,34 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Operations.ObjPair where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.Operations.Definitions
-
-
-
-instance PairObj Obj2 ℝ2 Obj3 ℝ3 where
-
-	-- Notice that \(x,y,z) = obj2 (x,y) infinitly extrudes a obj2 in both directions.
-	-- We essentially do that but rounded intersect it to get the desired height.
-	extrudeR r obj h = \(x,y,z) -> rmax r (obj (x,y)) (abs (z - h/2.0) - h/2.0)
-
-	-- As above, but (obj $ mod z (x,y)) to modify to the object over ehight :)
-	extrudeRMod r mod obj h = \(x,y,z) -> rmax r (obj $ mod z (x,y)) (abs (z - h/2.0) - h/2.0)
-
-	-- We feed the output of one object as an input to another.
-	extrudeOnEdgeOf a b = \(x,y,z) -> a (b (x,y), z)
-
-	rotate3 (yz, xz, xy) obj = 
-		let
-			rotateYZ θ obj = \(x,y,z) -> obj ( x, cos(θ)*z - sin(θ)*y, cos(θ)*y + sin(θ)*z)
-			rotateXZ θ obj = \(x,y,z) -> obj ( cos(θ)*x + sin(θ)*z, y, cos(θ)*z - sin(θ)*x)
-			rotateXY θ obj = \(x,y,z) -> obj ( cos(θ)*x + sin(θ)*y, cos(θ)*y - sin(θ)*x, z)
-		in
-			rotateYZ yz $ rotateXZ xz $ rotateXY xy $ obj
-
diff --git a/Graphics/Implicit/Operations/SymbolicObj2.hs b/Graphics/Implicit/Operations/SymbolicObj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/SymbolicObj2.hs
+++ /dev/null
@@ -1,29 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.SymbolicObj2 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-
-instance BasicObj SymbolicObj2 ℝ2 where
-	translate = Translate2
-	scale     = Scale2
-	rotateXY  = Rotate2
-	complement= Complement2
-	union     = UnionR2 0
-	intersect = IntersectR2 0
-	difference= DifferenceR2 0
-
-instance MagnitudeObj SymbolicObj2 where
-	outset      = Outset2
-	shell       = Shell2 
-	unionR      = UnionR2 
-	intersectR  = UnionR2 
-	differenceR = DifferenceR2
diff --git a/Graphics/Implicit/Operations/SymbolicObj3.hs b/Graphics/Implicit/Operations/SymbolicObj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/SymbolicObj3.hs
+++ /dev/null
@@ -1,29 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Operations.SymbolicObj3 where
-
-import Prelude hiding ((+),(-),(*),(/))
-import Graphics.Implicit.Operations.Definitions
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.SaneOperators
-
-
-instance BasicObj SymbolicObj3 ℝ3 where
-	translate = Translate3
-	scale     = Scale3
-	rotateXY θ= Rotate3 (0,0, θ)
-	complement= Complement3
-	union     = UnionR3 0
-	intersect = IntersectR3 0
-	difference= DifferenceR3 0
-
-instance MagnitudeObj SymbolicObj3 where
-	outset      = Outset3
-	shell       = Shell3
-	unionR      = UnionR3 
-	intersectR  = UnionR3 
-	differenceR = DifferenceR3
diff --git a/Graphics/Implicit/Operations/SymbolicObjPair.hs b/Graphics/Implicit/Operations/SymbolicObjPair.hs
deleted file mode 100644
--- a/Graphics/Implicit/Operations/SymbolicObjPair.hs
+++ /dev/null
@@ -1,21 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Operations.SymbolicObjPair where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Operations.Definitions
-
-
--- | Operations that are specific to some part of a
---   2D-3D dimensional object pair.
-instance PairObj SymbolicObj2 ℝ2 SymbolicObj3 ℝ3 where
-
-	extrudeR = ExtrudeR 
-	extrudeRMod = ExtrudeRMod
-	extrudeOnEdgeOf = ExtrudeOnEdgeOf
-	rotate3 = Rotate3
-
diff --git a/Graphics/Implicit/Primitives.hs b/Graphics/Implicit/Primitives.hs
--- a/Graphics/Implicit/Primitives.hs
+++ b/Graphics/Implicit/Primitives.hs
@@ -1,81 +1,196 @@
 -- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
 -- Released under the GNU GPL, see LICENSE
 
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances, NoMonomorphismRestriction #-}
 
-module Graphics.Implicit.Primitives (
-	sphere,
-	circle,
-	cylinder, cylinderC, cylinder2, cylinder2C,
-	rect3R, rectR,
-	regularPolygon,
-	polygonR,
-	zsurface
-) where
+module Graphics.Implicit.Primitives where
 
--- Some type definitions :)
 import Graphics.Implicit.Definitions
+import Data.List (sortBy)
+import Graphics.Implicit.MathUtil   (pack)
+import Graphics.Implicit.ObjectUtil (getBox2, getBox3, getImplicit2, getImplicit3)
 
--- Most of the functions we're exporting come from here
--- They are methods of classes.
-import Graphics.Implicit.Primitives.Definitions
+-- $ 3D Primitives
 
--- These files implement the classes for types
--- corresponding to the name of the file.
-import Graphics.Implicit.Primitives.Obj2
-import Graphics.Implicit.Primitives.Obj3
-import Graphics.Implicit.Primitives.BoxedObj2
-import Graphics.Implicit.Primitives.BoxedObj3
-import Graphics.Implicit.Primitives.SymbolicObj2
-import Graphics.Implicit.Primitives.SymbolicObj3
+sphere ::
+	ℝ                  -- ^ Radius of the sphere
+	-> SymbolicObj3    -- ^ Resulting sphere
 
--- We export a few functions modified by operations
--- for users conveniences...
-import Graphics.Implicit.Operations
+sphere r = Sphere r
 
--- If you are confused as to how these functions work, please refer to
--- http://christopherolah.wordpress.com/2011/11/06/manipulation-of-implicit-functions-with-an-eye-on-cad/
+rect3R ::
+	ℝ                 -- ^ Rounding of corners
+	-> ℝ3             -- ^ Bottom.. corner
+	-> ℝ3             -- ^ Top right... corner
+	-> SymbolicObj3   -- ^ Resuting cube - (0,0,0) is bottom left...
 
-cylinder :: (PrimitiveSupporter3 obj, BasicObj obj ℝ3) =>
-	ℝ         -- ^ Radius of the cylinder	
-	-> ℝ      -- ^ Height of the cylinder
-	-> obj    -- ^ Resulting cylinder
-cylinder r h = cylinder2 r r h
+rect3R = Rect3R
 
-cylinderC :: (PrimitiveSupporter3 obj, BasicObj obj ℝ3) =>
-	ℝ         -- ^ Radius of the cylinder	
-	-> ℝ      -- ^ Height of the cylinder
-	-> obj    -- ^ Resulting cylinder
-cylinderC r h = translate (0,0,-h/2.0) $ cylinder r h
+cylinder2 ::
+	ℝ                   -- ^ Radius of the cylinder	
+	-> ℝ                -- ^ Second radius of the cylinder
+	-> ℝ                -- ^ Height of the cylinder
+	-> SymbolicObj3     -- ^ Resulting cylinder
 
+cylinder2 r1 r2 h = Cylinder h r1 r2
 
-cylinder2C :: (PrimitiveSupporter3 obj, BasicObj obj ℝ3) =>
-	ℝ         -- ^ Radius of the cylinder	
-	-> ℝ      -- ^ Second radius of the cylinder
-	-> ℝ      -- ^ Height of the cylinder
-	-> obj    -- ^ Resulting cylinder
-cylinder2C r1 r2 h = translate (0,0,-h/2.0) $ cylinder2 r1 r2 h
+cylinder r = cylinder2 r r
 
+-- $ 2D Primitives
 
+circle ::
+	ℝ               -- ^ radius of the circle
+	-> SymbolicObj2 -- ^ resulting circle
 
-regularPolygon ::
-	ℕ       -- ^ number of sides
-	-> ℝ    -- ^ radius
-	-> Obj2 -- ^ resulting regular polygon
-regularPolygon sides r = polygonR 0 [ (r*cos(2*pi*m/sidesr), r*sin(2*pi*m/sidesr)) | m <- [0.. sidesr -1]]
-	where sidesr = fromIntegral sides
+circle   = Circle
 
+rectR ::
+	ℝ
+	-> ℝ2           -- ^ Bottom left corner
+	-> ℝ2           -- ^ Top right corner
+	-> SymbolicObj2 -- ^ Resulting square (bottom right = (0,0) )
 
-zsurface ::
-	(ℝ2 -> ℝ) -- ^ Description of the height of the surface
-	-> Obj3   -- ^ Resulting 3D object
-zsurface f = \(x,y,z) -> f (x,y) - z
+rectR = RectR
 
+polygonR ::
+	ℝ                -- ^ Rouding of the polygon
+	-> [ℝ2]          -- ^ Verticies of the polygon
+	-> SymbolicObj2  -- ^ Resulting polygon
 
--- This function is commented out because it doesn't obey the magnitude requirement.
--- Refer to blog post.
--- It needs to be fixed at some point, but the math is somewhat non-trivial.
---ellipse :: ℝ -> ℝ -> Obj2
---ellipse a b
---    | a < b = \(x,y) -> sqrt ((b/a*x)**2 + y**2) - a
---    | otherwise = \(x,y) -> sqrt (x**2 + (a/b*y)**2) - b
+polygonR = PolygonR
+
+polygon = polygonR 0
+
+-- $ Shared Operations
+
+class Object obj vec | obj -> vec where
+	
+	-- | Translate an object by a vector of appropriate dimension. 
+	translate :: 
+		vec      -- ^ Vector to translate by (Also: a is a vector, blah, blah)
+		-> obj   -- ^ Object to translate
+		-> obj   -- ^ Resulting object
+
+	-- | Scale an object
+	scale :: 
+		vec     -- ^ Amount to scale by
+		-> obj  -- ^ Object to scale
+		-> obj  -- ^ Resulting scaled object	
+	
+	-- | Complement an Object
+	complement :: 
+		obj     -- ^ Object to complement
+		-> obj  -- ^ Result
+	
+	-- | Rounded union
+	unionR :: 
+		ℝ        -- ^ The radius of rounding
+		-> [obj] -- ^ objects to union
+		-> obj   -- ^ Resulting object
+	
+	-- | Rounded minimum
+	intersectR :: 
+		ℝ        -- ^ The radius of rounding
+		-> [obj] -- ^ Objects to intersect
+		-> obj   -- ^ Resulting object
+	
+	-- | Rounded difference
+	differenceR :: 
+		ℝ        -- ^ The radius of rounding
+		-> [obj] -- ^ Objects to difference 
+		-> obj   -- ^ Resulting object
+
+	-- | Outset an object.
+	outset :: 
+		ℝ        -- ^ distance to outset
+		-> obj   -- ^ object to outset
+		-> obj   -- ^ resulting object
+
+	-- | Make a shell of an object.
+	shell :: 
+		ℝ        -- ^ width of shell
+		-> obj   -- ^ object to take shell of
+		-> obj   -- ^ resulting shell
+
+	-- | Get the bounding box an object
+	getBox :: 
+		obj           -- ^ Object to get box of
+		-> (vec, vec) -- ^ Bounding box
+
+	-- | Get the implicit function for an object
+	getImplicit :: 
+		obj           -- ^ Object to get implicit function of
+		-> (vec -> ℝ) -- ^ Implicit function
+
+	implicit :: 
+		(vec -> ℝ)     -- ^ Implicit function
+		-> (vec, vec)  -- ^ Bounding box
+		-> obj         -- ^ Resulting object
+	
+
+instance Object SymbolicObj2 ℝ2 where
+	translate   = Translate2
+	scale       = Scale2
+	complement  = Complement2
+	unionR      = UnionR2
+	intersectR  = IntersectR2
+	differenceR = DifferenceR2
+	outset      = Outset2
+	shell       = Shell2
+	getBox      = getBox2
+	getImplicit = getImplicit2
+	implicit a b= EmbedBoxedObj2 (a,b)
+
+instance Object SymbolicObj3 ℝ3 where
+	translate   = Translate3
+	scale       = Scale3
+	complement  = Complement3
+	unionR      = UnionR3
+	intersectR  = IntersectR3
+	differenceR = DifferenceR3
+	outset      = Outset3
+	shell       = Shell3
+	getBox      = getBox3
+	getImplicit = getImplicit3
+	implicit a b= EmbedBoxedObj3 (a,b)
+
+union = unionR 0
+difference = differenceR 0
+intersect = intersectR 0
+
+-- 3D operations
+
+extrudeR = ExtrudeR
+
+extrudeRM = ExtrudeRM
+
+extrudeOnEdgeOf = ExtrudeOnEdgeOf
+
+rotate3 = Rotate3
+
+
+pack3 :: ℝ2 -> ℝ -> [SymbolicObj3] -> Maybe SymbolicObj3
+pack3 (dx, dy) sep objs = 
+	let
+		boxDropZ ((a,b,c),(d,e,f)) = ((a,b),(d,e))
+		withBoxes :: [(Box2, SymbolicObj3)]
+		withBoxes = map (\obj -> ( boxDropZ $ getBox3 obj, obj)) objs
+	in case pack ((0,0),(dy,dy)) sep withBoxes of
+			(a, []) -> Just $ union $ map (\((x,y),obj) -> translate (x,y,0) obj) a
+			_ -> Nothing
+				
+
+-- 2D operations
+
+rotate = Rotate2
+
+
+pack2 :: ℝ2 -> ℝ -> [SymbolicObj2] -> Maybe SymbolicObj2
+pack2 (dx, dy) sep objs = 
+	let
+		withBoxes :: [(Box2, SymbolicObj2)]
+		withBoxes = map (\obj -> ( getBox2 obj, obj)) objs
+	in case pack ((0,0),(dy,dy)) sep withBoxes of
+			(a, []) -> Just $ union $ map (\((x,y),obj) -> translate (x,y) obj) a
+			_ -> Nothing
+
diff --git a/Graphics/Implicit/Primitives/BoxedObj2.hs b/Graphics/Implicit/Primitives/BoxedObj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/BoxedObj2.hs
+++ /dev/null
@@ -1,20 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Primitives.BoxedObj2 where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Primitives.Definitions
-import Graphics.Implicit.Primitives.Obj2
-
-
-instance PrimitiveSupporter2 (Boxed2 Obj2) where
-	circle r = (circle r, ((-r, -r), (r,r)) )
-	rectR r a b = (rectR r a b, ( a,b ) )
-	polygonR r points = (polygonR r points, ((minimum xs, minimum ys), (maximum xs, maximum ys)) ) where
-		(xs, ys) = unzip points
-
-
diff --git a/Graphics/Implicit/Primitives/BoxedObj3.hs b/Graphics/Implicit/Primitives/BoxedObj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/BoxedObj3.hs
+++ /dev/null
@@ -1,18 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Primitives.BoxedObj3 where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Primitives.Definitions
-import Graphics.Implicit.Primitives.Obj3
-
-
-instance PrimitiveSupporter3 (Boxed3 Obj3) where
-	sphere r = (sphere r, ((-r, -r, -r), (r,r,r)) )
-	rect3R r a b = (rect3R r a b, ( a, b) )
-	cylinder2 r1 r2 h = (cylinder2 r1 r2 h, ( (-r,-r,0), (r,r,h) ) ) where r = max r1 r2
-
-
diff --git a/Graphics/Implicit/Primitives/Definitions.hs b/Graphics/Implicit/Primitives/Definitions.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/Definitions.hs
+++ /dev/null
@@ -1,46 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Primitives.Definitions where
-
-import Graphics.Implicit.Definitions
-
-
--- Basic Primitive 3D Objects; We can make the others from here.
-class PrimitiveSupporter3 obj where
-	sphere ::
-		ℝ         -- ^ Radius of the sphere
-		-> obj    -- ^ Resulting sphere
-	rect3R ::
-		ℝ        -- ^ Rounding of corners
-		-> ℝ3    -- ^ Bottom// corner
-		-> ℝ3    -- ^ Top right... corner
-		-> obj   -- ^ Resuting cube - (0,0,0) is bottom left...
-	cylinder2 ::
-		ℝ         -- ^ Radius of the cylinder	
-		-> ℝ      -- ^ Second radius of the cylinder
-		-> ℝ      -- ^ Height of the cylinder
-		-> obj    -- ^ Resulting cylinder
-
-
-class PrimitiveSupporter2 obj where
-
-	circle ::
-		ℝ        -- ^ radius of the circle
-		-> obj   -- ^ resulting circle
-	rectR ::
-		ℝ
-		-> ℝ2     -- ^ Bottom left corner
-		-> ℝ2     -- ^ Top right corner
-		-> obj    -- ^ Resulting square (bottom right = (0,0) )
-	polygonR ::
-		ℝ         -- ^ Rouding of the polygon
-		-> [ℝ2]   -- ^ Verticies of the polygon
-		 -> obj   -- ^ Resulting polygon
-
-
-
-
diff --git a/Graphics/Implicit/Primitives/Obj2.hs b/Graphics/Implicit/Primitives/Obj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/Obj2.hs
+++ /dev/null
@@ -1,49 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Primitives.Obj2 where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.Primitives.Definitions
-import qualified Graphics.Implicit.SaneOperators as S
-
-
-instance PrimitiveSupporter2 Obj2 where
-
-	circle r = \(x,y) -> sqrt (x**2 + y**2) - r
-
-	rectR r (x1,y1) (x2,y2) = 
-		\(x,y) -> rmaximum  r [abs (x- dx/2.0 -x1) -dx/2.0, abs (y- dy/2.0 -y1) - dy/2.0]
-			where (dx,dy) = (x2-x1,y2-y1)
-	polygonR 0 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)
-
diff --git a/Graphics/Implicit/Primitives/Obj3.hs b/Graphics/Implicit/Primitives/Obj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/Obj3.hs
+++ /dev/null
@@ -1,21 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Primitives.Obj3 where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.MathUtil
-import Graphics.Implicit.Primitives.Definitions
-
-instance PrimitiveSupporter3 Obj3 where
-	sphere r = \(x,y,z) -> sqrt (x**2 + y**2 + z**2) - r
-	rect3R r (x1,y1,z1) (x2,y2,z2) = 
-		\(x,y,z) -> rmaximum r
-			[abs (x-dx/2.0-x1) - dx/2.0, abs (y-dy/2.0-y1) - dy/2.0, abs (z-dz/2.0-z1) - dz/2.0]
-				where (dx, dy, dz) = (x2-x1, y2-y1, z2-z1)
-	cylinder2 r1 r2 h 
-		| r1 == r2  = \(x,y,z) -> max (sqrt(x^2+y^2) - r1) (abs(z-h/2.0) - h/2.0)
-		| otherwise = \(x,y,z) -> max (sqrt(x^2+y^2) - r1*(1.0 - z/2.0) - r2*z/2.0) (abs(z-h/2.0) - h/2.0)
-
diff --git a/Graphics/Implicit/Primitives/SymbolicObj2.hs b/Graphics/Implicit/Primitives/SymbolicObj2.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/SymbolicObj2.hs
+++ /dev/null
@@ -1,17 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-
-module Graphics.Implicit.Primitives.SymbolicObj2 where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Primitives.Definitions
-
-
-instance PrimitiveSupporter2 SymbolicObj2 where
-	circle   = Circle
-	rectR    = RectR
-	polygonR = PolygonR
-
diff --git a/Graphics/Implicit/Primitives/SymbolicObj3.hs b/Graphics/Implicit/Primitives/SymbolicObj3.hs
deleted file mode 100644
--- a/Graphics/Implicit/Primitives/SymbolicObj3.hs
+++ /dev/null
@@ -1,18 +0,0 @@
--- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
--- Released under the GNU GPL, see LICENSE
-
-{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, FlexibleContexts, TypeSynonymInstances, UndecidableInstances #-}
-
-module Graphics.Implicit.Primitives.SymbolicObj3 where
-
-import Graphics.Implicit.Definitions
-import Graphics.Implicit.Primitives.Definitions
-import Graphics.Implicit.Primitives.BoxedObj3
-
-
-instance PrimitiveSupporter3 SymbolicObj3 where
-	sphere r = Sphere r
-	rect3R = Rect3R
-	cylinder2 r1 r2 h = EmbedBoxedObj3 $ cylinder2 r1 r2 h
-
-
diff --git a/Graphics/Implicit/SaneOperators.hs b/Graphics/Implicit/SaneOperators.hs
--- a/Graphics/Implicit/SaneOperators.hs
+++ b/Graphics/Implicit/SaneOperators.hs
@@ -36,6 +36,13 @@
 class InnerProductSpace a where
 	(⋅) :: a -> a -> ℝ
 
+class ComponentWiseMultiplicative a b c | a b -> c where
+	(⋯*) :: a -> b -> c
+	infixl 7 ⋯*
+
+class ComponentWiseMultiplicativeInvertable a where
+	componentWiseMultiplicativeInverse :: 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.
 
@@ -163,4 +170,31 @@
 	(a1, a2, a3) ⋅ (b1, b2, b3) = a1*b1 + a2*b2+a3*b3
 
 
+-- ComponentWiseMultiplicative Instances
 
+instance ComponentWiseMultiplicativeInvertable ℝ where
+	componentWiseMultiplicativeInverse a = 1 P./ a
+
+instance ComponentWiseMultiplicativeInvertable ℝ2 where
+	componentWiseMultiplicativeInverse (a, b) = (1 P./ a, 1 P./ b)
+
+instance ComponentWiseMultiplicativeInvertable ℝ3 where
+	componentWiseMultiplicativeInverse (a, b, c) = (1 P./ a, 1 P./ b, 1 P./ c)
+
+instance ComponentWiseMultiplicative ℝ ℝ ℝ where
+	a ⋯* x = a*x
+
+instance ComponentWiseMultiplicative ℝ2 ℝ2 ℝ2 where
+	(a,b) ⋯* (x,y) = (a*x,b*y)
+
+instance ComponentWiseMultiplicative ℝ3 ℝ3 ℝ3 where
+	(a,b,c) ⋯* (x,y,z) = (a*x,b*y,c*z)
+
+(⋯/) :: (ComponentWiseMultiplicative a b c) => (ComponentWiseMultiplicativeInvertable b) => a -> b -> c
+x ⋯/ y = x ⋯* (componentWiseMultiplicativeInverse y)
+infixl 7 ⋯/
+
+
+(a1,a2,a3) ⨯ (b1,b2,b3) = (a2*b3-a3*b2, a3*b1-a1*b3, a1*b2-a2*b1)
+
+normalized v = v / norm v
diff --git a/extopenscad.hs b/extopenscad.hs
--- a/extopenscad.hs
+++ b/extopenscad.hs
@@ -1,14 +1,21 @@
 -- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
 -- Released under the GNU GPL, see LICENSE
 
+{-# LANGUAGE ViewPatterns #-}
+
 -- Let's make it convenient to run our extended openscad format code
 
 -- Let's be explicit about what we're getting from where :)
-import System (getArgs)
+import System.Environment (getArgs)
 import System.IO (openFile, IOMode (ReadMode), hGetContents, hClose)
-import Graphics.Implicit (runOpenscad, writeSVG, writeSTL)
+import Graphics.Implicit (runOpenscad, writeSVG, writeSTL, writeOBJ, writeSCAD3, writeSCAD2, writeGCodeHacklabLaser, writeTHREEJS)
 import Graphics.Implicit.ExtOpenScad.Definitions (OpenscadObj (ONum))
+import Graphics.Implicit.ObjectUtil (getBox2, getBox3)
+import Graphics.Implicit.Definitions (xmlErrorOn, errorMessage)
 import Data.Map as Map
+import Text.ParserCombinators.Parsec (errorPos, sourceLine)
+import Text.ParserCombinators.Parsec.Error
+import Data.IORef (writeIORef)
 
 -- | strip a .scad or .escad file to its basename.
 strip :: String -> String
@@ -17,36 +24,114 @@
 	'd':'a':'c':'s':'e':'.':xs -> reverse xs
 	_                          -> filename
 
+-- | Get the file type ending of a file
+--  eg. "foo.stl" -> "stl"
+fileType filename = reverse $ beforeFirstPeriod $ reverse filename
+	where
+		beforeFirstPeriod []       = [] 
+		beforeFirstPeriod ('.':xs) = []
+		beforeFirstPeriod (  x:xs) = x : beforeFirstPeriod xs
+
+getRes (Map.lookup "$res" -> Just (ONum res), _, _) = res
+
+getRes (_, _, obj:_) = min (minimum [x,y,z]/2) ((x*y*z)**(1/3) / 22)
+	where
+		((x1,y1,z1),(x2,y2,z2)) = getBox3 obj
+		(x,y,z) = (x2-x1, y2-y1, z2-z1)
+
+getRes (_, obj:_, _) = min (min x y/2) ((x*y)**0.5 / 30)
+	where
+		((x1,y1),(x2,y2)) = getBox2 obj
+		(x,y) = (x2-x1, y2-y1)
+
+getRes _ = 1
+
 -- | Give an openscad object to run and the basename of 
 --   the target to write to... write an object!
 executeAndExport :: String -> String -> IO ()
 executeAndExport content targetname = case runOpenscad content of
-	Left err -> putStrLn $ show $ err
+	Left err -> 
+		let
+			line = sourceLine . errorPos $ err
+			msgs = errorMessages err
+		in errorMessage line $ showErrorMessages 
+			"or" "unknown parse error" "expecting" "unexpected" "end of input"
+            (errorMessages err)
 	Right openscadProgram -> do 
 		s@(vars, obj2s, obj3s) <- openscadProgram 
-		let {
-			res = case Map.lookup "$res" vars of 
-				Nothing -> 1
-				Just (ONum n) -> n
-				Just (_) -> 1
-		} in case s of 
+		let
+			res = getRes s
+		case s of 
 			(_, [], [])   -> putStrLn "Nothing to render"
 			(_, x:xs, []) -> do
 				putStrLn $ "Rendering 2D object to " ++ targetname ++ ".svg"
+				putStrLn $ show x
 				writeSVG res (targetname ++ ".svg") x
 			(_, _, x:xs)  -> do
 				putStrLn $ "Rendering 3D object to " ++ targetname++ ".stl"
+				putStrLn $ show x
 				writeSTL res (targetname ++ ".stl") x
+
+-- | Give an openscad object to run and the basename of 
+--   the target to write to... write an object!
+executeAndExportSpecifiedTargetType :: String -> String -> String -> IO ()
+executeAndExportSpecifiedTargetType content targetname formatname = case runOpenscad content of
+	Left err -> putStrLn $ show $ err
+	Right openscadProgram -> do 
+		s@(vars, obj2s, obj3s) <- openscadProgram 
+		let
+			res = getRes s
+		case (formatname, s) of 
+			(_, (_, [], []))   -> putStrLn "Nothing to render"
+			("svg", (_, x:xs, _)) -> do
+				putStrLn $ "Rendering 2D object to " ++ targetname
+				writeSVG res targetname x
+			("ngc", (_, x:xs, _)) -> do
+				putStrLn $ "Rendering 2D object to " ++ targetname
+				writeGCodeHacklabLaser res targetname x
+			("scad", (_, x:xs, _))  -> do
+				putStrLn $ "Rendering 3D object to " ++ targetname
+				writeSCAD2 res targetname x
+			("stl", (_, _, x:xs))  -> do
+				putStrLn $ "Rendering 3D object to " ++ targetname
+				writeSTL res targetname x
+			("scad", (_, _, x:xs))  -> do
+				putStrLn $ "Rendering 3D object to " ++ targetname
+				writeSCAD3 res targetname x
+			("obj", (_, _, x:xs))  -> do
+				putStrLn $ "Rendering 3D object to " ++ targetname
+				writeOBJ res targetname x
+			("js", (_, _, x:xs))  -> do
+				putStrLn $ "Rendering 3D object to " ++ targetname
+				writeTHREEJS res targetname x
+			(otherFormat, _) -> putStrLn $ "Unrecognized format: " ++ otherFormat
+
 		
 
 main :: IO()
 main = do
 	args <- getArgs
-	case length args of
-		0 -> putStrLn "syntax: extopenscad file.escad"
-		_ -> do
-			f <- openFile (args !! 0) ReadMode
-			content <- hGetContents f 
-			executeAndExport content (strip $ args !! 0)
-			hClose f
+	if Prelude.null args || args == ["--help"] || args == ["-help"]
+		then putStrLn $ 
+			"syntax: extopenscad inputfile.escad [outputfile.format]\n"
+			++ "eg. extopenscad input.escad out.stl"
+		else do
+			let
+				args' = if head args == "-xml-error" then tail args else args
+			writeIORef xmlErrorOn (head args == "-xml-error")
+			case length args' of
+				0 -> putStrLn $ 
+					"syntax: extopenscad inputfile.escad [outputfile.format]\n"
+					++ "eg. extopenscad input.escad out.stl"
+				1 -> do
+					f <- openFile (args' !! 0) ReadMode
+					content <- hGetContents f 
+					executeAndExport content (strip $ args' !! 0)
+					hClose f
+				2 -> do
+					f <- openFile (args' !! 0) ReadMode
+					content <- hGetContents f 
+					executeAndExportSpecifiedTargetType 
+						content (args' !! 1) (fileType $ args' !! 1)
+					hClose f
 
diff --git a/implicit.cabal b/implicit.cabal
--- a/implicit.cabal
+++ b/implicit.cabal
@@ -1,5 +1,5 @@
 Name:                implicit
-Version:             0.0.1
+Version:             0.0.2
 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.
@@ -15,65 +15,96 @@
 Category:            Graphics
 
 Library
-    Build-Depends:       base >= 3 && < 5, parsec, hashmap, parallel, containers, haskell98
-    ghc-options:         -O2
-    Extensions:          MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances
+
+    Build-Depends:
+        base >= 3 && < 5,
+        parsec,
+        hashmap,
+        parallel,
+        containers,
+        plugins,
+        deepseq
+
+    ghc-options:
+        -O2 -optc-O3
+        -threaded
+        -rtsopts
+        -funfolding-use-threshold=16 
+        -fspec-constr-count=10
+
+    Extensions:
+        FlexibleContexts,
+        FlexibleInstances,
+        FunctionalDependencies,
+        GADTs,
+        IncoherentInstances,
+        KindSignatures,
+        MultiParamTypeClasses,
+        NoMonomorphismRestriction,
+        OverloadedStrings,
+        ParallelListComp,
+        RankNTypes,
+        ScopedTypeVariables,
+        TypeSynonymInstances,
+        UndecidableInstances,
+        ViewPatterns
+
     Exposed-Modules:   
         Graphics.Implicit
         Graphics.Implicit.Definitions
         Graphics.Implicit.Export
         Graphics.Implicit.MathUtil
-        Graphics.Implicit.Operations
         Graphics.Implicit.SaneOperators
+        Graphics.Implicit.ExtOpenScad
+        Graphics.Implicit.ObjectUtil
+
     Other-Modules:
         Graphics.Implicit.Primitives
-        Graphics.Implicit.Primitives.Definitions
-        Graphics.Implicit.Primitives.BoxedObj2
-        Graphics.Implicit.Primitives.BoxedObj3
-        Graphics.Implicit.Primitives.SymbolicObj2
-        Graphics.Implicit.Primitives.SymbolicObj3
-        Graphics.Implicit.Primitives.Obj2
-        Graphics.Implicit.Primitives.Obj3
-        Graphics.Implicit.Operations.Definitions
-        Graphics.Implicit.Operations.Box2
-        Graphics.Implicit.Operations.Box3
-        Graphics.Implicit.Operations.BoxPair
-        Graphics.Implicit.Operations.BoxedObj2
-        Graphics.Implicit.Operations.BoxedObj3
-        Graphics.Implicit.Operations.BoxedObjPair
-        Graphics.Implicit.Operations.SymbolicObj2
-        Graphics.Implicit.Operations.SymbolicObj3
-        Graphics.Implicit.Operations.SymbolicObjPair
-        Graphics.Implicit.Operations.Obj2
-        Graphics.Implicit.Operations.Obj3
-        Graphics.Implicit.Operations.ObjPair
-        Graphics.Implicit.ExtOpenScad
+        Graphics.Implicit.ObjectUtil.GetBox2
+        Graphics.Implicit.ObjectUtil.GetBox3
+        Graphics.Implicit.ObjectUtil.GetImplicit2
+        Graphics.Implicit.ObjectUtil.GetImplicit3
         Graphics.Implicit.ExtOpenScad.Definitions
         Graphics.Implicit.ExtOpenScad.Default
         Graphics.Implicit.ExtOpenScad.Expressions
         Graphics.Implicit.ExtOpenScad.Primitives
         Graphics.Implicit.ExtOpenScad.Statements
         Graphics.Implicit.ExtOpenScad.Util
+        Graphics.Implicit.ExtOpenScad.Util.Computation
+        Graphics.Implicit.ExtOpenScad.Util.ArgParser
         Graphics.Implicit.Export.Definitions
         Graphics.Implicit.Export.MarchingSquares
         Graphics.Implicit.Export.MarchingSquaresFill
-        Graphics.Implicit.Export.MarchingCubes
-        Graphics.Implicit.Export.BoxedObj2
-        Graphics.Implicit.Export.BoxedObj3
         Graphics.Implicit.Export.SymbolicObj2
         Graphics.Implicit.Export.SymbolicObj3
         Graphics.Implicit.Export.PolylineFormats
         Graphics.Implicit.Export.TriangleMeshFormats
+        Graphics.Implicit.Export.NormedTriangleMeshFormats
+        Graphics.Implicit.Export.SymbolicFormats
         Graphics.Implicit.Export.Util
-        Graphics.Implicit.Export.Symbolic.CoerceSymbolic2
-        Graphics.Implicit.Export.Symbolic.CoerceSymbolic3
         Graphics.Implicit.Export.Symbolic.Rebound2
         Graphics.Implicit.Export.Symbolic.Rebound3
+        Graphics.Implicit.Export.Render
+        Graphics.Implicit.Export.Render.Definitions
+        Graphics.Implicit.Export.Render.GetLoops
+        Graphics.Implicit.Export.Render.GetSegs
+        Graphics.Implicit.Export.Render.HandleSquares
+        Graphics.Implicit.Export.Render.Interpolate
+        Graphics.Implicit.Export.Render.RefineSegs
+        Graphics.Implicit.Export.Render.TesselateLoops
 
 Executable extopenscad
 
    Main-is: extopenscad.hs
+   ghc-options:
+        -O2 -optc-O3
+        -threaded
+        -rtsopts
+        -funfolding-use-threshold=16 
+        -fspec-constr-count=10
+
 source-repository head
     type:            git
     location:        https://github.com/colah/ImplicitCAD.git
+
 
