diff --git a/Data/QuadEdge.hs b/Data/QuadEdge.hs
new file mode 100644
--- /dev/null
+++ b/Data/QuadEdge.hs
@@ -0,0 +1,292 @@
+{-# LANGUAGE RankNTypes, UnicodeSyntax, FlexibleContexts #-}
+
+{- | The quad-edge data structure is commonly used in computational geometry for representing triangulations.
+     It represents simultaneously both the map, its dual and mirror image.
+     
+     The fundamental idea behind the quad-edge structure is the recognition that a single edge, in a closed
+     polygonal mesh topology, sits between exactly two faces and exactly two vertices. Thus, it can represent
+     a dual of the graph simply by reversing the convention on what is a vertex and what is a face.
+
+     The quad-edge data structure is described in the paper by Leonidas J. Guibas and Jorge Stolfi,
+     \"Primitives for the manipulation of general subdivisions and the computation of Voronoi diagrams\",
+     ACM Transactions on Graphics, 4(2), 1985, 75-123.
+
+     This implementation is based on Stream Fusion and seems to yield similar performance to mutable implementations
+     in the ST monad.
+-}
+
+module Data.QuadEdge (module Data.QuadEdge, module Data.QuadEdge.Base) where
+import Data.QuadEdge.Base
+import Prelude hiding (flip, lookup)
+import Control.Monad.ST (ST)
+import Data.Maybe
+
+import qualified Data.Vector as IV
+import qualified Data.Vector.Mutable as MV
+import qualified Data.Vector.Generic as GV
+import qualified Data.Vector.Generic.Mutable as MGV
+import qualified Data.Vector.Fusion.Stream as S
+
+import System.Random 
+
+type QEDS  a   = IV.Vector    (Maybe (Edge a))
+type MQEDS s a = MV.MVector s (Maybe (Edge a))
+
+------------------------------------------------------------------------------
+-- * Creation
+
+-- | Create an empty QEDS
+
+new ∷ QEDS a
+new = GV.empty
+
+
+------------------------------------------------------------------------------
+-- * Topological modification 
+
+-- | Opens up the QEDS for in-place toplogical modification
+
+mutate ∷ QEDS a → (forall s. MQEDS s a → ST s ()) → QEDS a 
+mutate q f = GV.modify f q 
+
+
+-- | Create a group of new edges and open up the QEDS 
+
+mutateNEs ∷ QEDS a → [a] → ([EdgeRef] → forall s. MQEDS s a → ST s ()) → (QEDS a, [EdgeRef])
+mutateNEs q xs f = (GV.modify (f es) q2, es)
+    where
+      es       = S.toList es'
+      (q2,es') = makeEdges q (S.fromList xs)
+
+
+-- | Create a new edge and open up the QEDS
+
+mutateNE ∷ QEDS a → a → (EdgeRef → forall s. MQEDS s a → ST s ()) → (QEDS a, EdgeRef)
+mutateNE q x f = (GV.modify (f e) q2, e)
+    where
+      (q2,e) = makeEdge q x
+
+
+-- | The QuadEdge splice operator
+
+spliceM ∷ MQEDS s a → EdgeRef → EdgeRef → ST s ()
+spliceM q a b
+  | (isPrimal a && isPrimal b) || (isDual a && isDual b) 
+  = do oa ← onextM q a
+       if b == flip oa
+	  then return ()
+          else do 
+               ob ← onextM q b
+	       let x  = rot oa
+                   y  = rot ob
+	       ox ← onextM q x
+               oy ← onextM q y
+	       update a y ob 
+               update b x oa
+	       update x b oy
+               update y a ox
+
+  | otherwise = error "QuadEdge.splice: one primal and one dual edge"
+
+  where
+
+  update (i,r,Normal) _ n = do Just e ← MGV.read q i
+                               MGV.write q i (Just $ updET e r n)
+
+  update (i,r,Flipped) z _  = do Just e ← MGV.read q i
+	                         MGV.write q i (Just $ updET e (incrDir r) (flip z))
+
+  updET e r v = e { edgeTable = updateET (edgeTable e) r v }
+
+
+
+-- | Delete an edge while in mutate mode
+
+deleteEdgeM ∷ MQEDS s a → EdgeRef → ST s ()
+deleteEdgeM q e@(i,_,_) = do
+                          spliceM q e =<< oprevM q e
+                          spliceM q s =<< oprevM q s
+                          MGV.write q i Nothing
+
+    where s = sym e
+
+
+------------------------------------------------------------------------------
+-- * Edge queries
+
+-- | Return all valid edges in the QEDS
+
+edges ∷ QEDS a → IV.Vector (Edge a)
+edges = GV.map fromJust . GV.filter isJust 
+
+
+-- | Return all valid edge references in the QEDS
+
+edgerefs ∷ QEDS a → IV.Vector EdgeRef
+edgerefs q = GV.unfoldr f 0 
+    where
+      f i | i >= GV.length q = Nothing
+          | isValid q r      = Just (r,i+1)
+          | otherwise        = f (i+1)
+
+          where
+            r = (i,Rot0,Normal)
+
+-- | Look up an edge. The edge must be valid.
+
+getEdge	∷ QEDS a → EdgeRef → Edge a
+getEdge q (i,_,_) = let Just e = q GV.! i
+                    in e
+
+-- | Look up the attributes of an edge. The edge must be valid.
+
+getAttr ∷ QEDS a → EdgeRef → a
+getAttr q e = attributes (getEdge q e)
+
+
+-- | Return a random valid EdgeRef
+
+randomEdgeRef ∷ RandomGen g => QEDS a → g → (EdgeRef, g)
+randomEdgeRef cdt g1 = 
+  case cdt GV.! r of
+    Just _  → ((r,Rot0,Normal),g2)
+    Nothing → randomEdgeRef cdt g2 
+
+  where
+    (r,g2) = randomR (0, (GV.length cdt) - 1) g1
+
+
+-- | Check if an EdgeRef points to an active Edge
+
+isValid ∷ QEDS a → EdgeRef → Bool
+isValid q (i,_,_) = isJust $ q GV.! i
+
+
+------------------------------------------------------------------------------
+-- * Edge updating
+
+updateEdge ∷ QEDS a → EdgeRef → Edge a → QEDS a
+updateEdge q (i,_,_) e = GV.modify f q 
+    where
+      f v = MGV.write v i (Just e)
+
+updateAttr ∷ QEDS a → EdgeRef → a → QEDS a
+updateAttr q (i,_,_) a = GV.modify f q
+    where
+      f v = do
+            Just x ← MGV.read v i
+            MGV.write v i (Just x{attributes=a})
+
+------------------------------------------------------------------------------
+-- * Alternate edge creation/deletion routines
+
+-- | Delete a set of edges in one pass, using mutate and deleteEdgeM
+
+deleteEdges ∷ QEDS a → S.Stream EdgeRef → QEDS a
+deleteEdges q xs = mutate q (\v → S.mapM_ (deleteEdgeM v) xs)
+
+
+makeEdges ∷ QEDS a → S.Stream a → (QEDS a, S.Stream EdgeRef)
+makeEdges z xs = (qeds, S.fromList $ reverse zs)
+    where
+      (qeds,zs) = S.foldl f (z,[]) xs
+          where
+            f (q,es) a = (q2,e:es)
+                where 
+                  (q2,e) = makeEdge q a
+
+
+makeEdge ∷ QEDS a → a → (QEDS a, EdgeRef)
+makeEdge q a = (q2,e)
+    where
+      (i,q2) = append $ \x → Edge{edgeTable=emptyET x, attributes=a}
+      e      = (i, Rot0, Normal)
+
+      append f = (index, GV.snoc q (Just $ f index))
+          where
+            index = GV.length q
+
+
+------------------------------------------------------------------------------
+-- * Adjacency Rings
+
+-- | Returns a stream of adjacent edges using the given Adjacency Operator
+
+ring ∷ QEDS a → (QEDS a → EdgeRef → EdgeRef) → EdgeRef → (S.Stream EdgeRef)
+ring q f start@(i,_,_) = S.unfoldr g (Just start)
+    where
+      g Nothing = Nothing
+      g (Just e) | j /= i    = Just (e,Just e')
+                 | otherwise = Just (e, Nothing)
+                 where
+                   e'@(j,_,_) = f q e
+            
+
+------------------------------------------------------------------------------
+-- * Adjacency Operators
+
+-- | CCW around the origin
+
+onext ∷ QEDS a → EdgeRef → EdgeRef
+onext q er@(_,r,f)
+    | f == Normal = lookupET r t
+    | otherwise   = flip . rot $ lookupET (incrDir r) t
+    where
+       t = edgeTable (getEdge q er)
+
+-- | CW around the origin
+
+oprev ∷ QEDS a → EdgeRef → EdgeRef
+oprev = rot `comp` rot       
+
+-- | CCW around the left face
+lnext ∷ QEDS a → EdgeRef → EdgeRef
+lnext = rot `comp` rotInv    
+
+-- | CW around the left face
+lprev ∷ QEDS a → EdgeRef → EdgeRef
+lprev = sym `comp` id        
+
+-- | CCW around the right face
+rnext ∷ QEDS a → EdgeRef → EdgeRef
+rnext = rotInv `comp` rot    
+
+-- | CW around the right face
+rprev ∷ QEDS a → EdgeRef → EdgeRef
+rprev = id `comp` sym        
+
+-- | CCW around the destination
+dnext ∷ QEDS a → EdgeRef → EdgeRef
+dnext = sym `comp` sym       
+
+-- | CW around the destination
+dprev ∷ QEDS a → EdgeRef → EdgeRef
+dprev = rotInv `comp` rotInv 
+
+comp ∷ (EdgeRef → a) → (b → EdgeRef) → QEDS d → b → a
+comp g f qeds x = g . onext qeds $ f x
+
+------------------------------------------------------------------------------
+-- * Adjacency Operators (ST)
+
+onextM,oprevM,lnextM,lprevM,rnextM,rprevM,dnextM,dprevM ∷ MQEDS s a → EdgeRef → ST s EdgeRef
+
+onextM q (i, r, f) = do Just e ← MGV.read q i
+                        let t = edgeTable e
+                        return $ if f == Normal 
+                                   then lookupET r t
+                                   else flip (rot (lookupET (incrDir r) t))
+
+compM ∷ (EdgeRef → b) → (t → EdgeRef) → MQEDS s a → t → ST s b
+compM g f qeds x = do e ← onextM qeds (f x)
+                      return (g e)
+
+oprevM = rot `compM` rot
+lnextM = rot `compM` rotInv
+lprevM = sym `compM` id
+rnextM = rotInv `compM` rot
+rprevM = id `compM` sym
+dnextM = sym `compM` sym
+dprevM = rotInv `compM` rotInv 
+
+-------
diff --git a/Data/QuadEdge/Base.hs b/Data/QuadEdge/Base.hs
new file mode 100644
--- /dev/null
+++ b/Data/QuadEdge/Base.hs
@@ -0,0 +1,67 @@
+-------------------------------------------------------------------------------
+-- Copyright (C) 1997, 1998, 2008 Joern Dinkla, www.dinkla.net
+-------------------------------------------------------------------------------
+
+module Data.QuadEdge.Base where
+
+import Prelude hiding (flip)
+
+
+
+type Index = Int
+
+data Edge a = Edge { edgeTable :: EdgeTable, 
+                     attributes :: a } deriving (Eq, Show, Read)
+
+type EdgeRef = (Index, Direction, Orientation)
+type EdgeTable = (EdgeRef, EdgeRef, EdgeRef, EdgeRef)
+
+data Direction = Rot0 | Rot1 | Rot2 | Rot3  deriving (Eq, Ord, Enum, Show, Read)
+data Orientation = Normal | Flipped deriving (Eq, Ord, Enum, Show, Read)
+
+
+incrDir, decrDir              :: Direction -> Direction
+incrDir x		      = case x of { Rot0 -> Rot1; Rot1 -> Rot2; 
+					    Rot2 -> Rot3; Rot3 -> Rot0 }
+decrDir x		      = case x of { Rot0 -> Rot3; Rot1 -> Rot0; 
+					    Rot2 -> Rot1; Rot3 -> Rot2 }
+
+edgesET			      :: EdgeTable -> [EdgeRef]
+edgesET (a,b,c,d)	      = [a,b,c,d]
+
+emptyET                       :: Index -> EdgeTable
+emptyET i		      = (mk Rot0, mk Rot3, mk Rot2, mk Rot1)
+  where mk r		      = (i, r, Normal)
+
+lookupET		      :: Direction -> EdgeTable -> EdgeRef
+lookupET Rot0 (x,_,_,_)       = x
+lookupET Rot1 (_,x,_,_)       = x
+lookupET Rot2 (_,_,x,_)       = x
+lookupET Rot3 (_,_,_,x)       = x
+
+updateET		      :: EdgeTable -> Direction -> EdgeRef -> EdgeTable
+updateET (_,b,c,d) Rot0	v     = (v,b,c,d)
+updateET (a,_,c,d) Rot1 v     = (a,v,c,d)
+updateET (a,b,_,d) Rot2 v     = (a,b,v,d)
+updateET (a,b,c,_) Rot3 v     = (a,b,c,v)
+
+isPrimal, isDual              :: EdgeRef -> Bool
+isPrimal (_, r, _)            = r == Rot0 || r == Rot2
+isDual (_, r, _)              = r == Rot1 || r == Rot3
+
+isFlipped                     :: EdgeRef -> Bool
+isFlipped (_, _, f)           = f == Flipped
+
+rot, sym, rotInv, flip        :: EdgeRef -> EdgeRef
+rot (e, r, Normal)	      = (e, incrDir r, Normal)
+rot (e, r, Flipped)	      = (e, decrDir r, Flipped)
+
+rotInv (i, r, Normal)	      = (i, decrDir r, Normal)
+rotInv (i, r, Flipped)        = (i, incrDir r, Flipped)
+
+sym			      = rot . rot
+
+flip (e, r, Normal)	      = (e, r, Flipped)
+flip (e, r, Flipped)	      = (e, r, Normal)
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2010, Neal Alexander <NHAlxr@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/QuadEdge.cabal b/QuadEdge.cabal
new file mode 100644
--- /dev/null
+++ b/QuadEdge.cabal
@@ -0,0 +1,20 @@
+Name:                QuadEdge
+Version:             0.2
+Synopsis:            QuadEdge structure for representing triangulations
+License:             BSD3
+License-file:        LICENSE
+Author:              Neal Alexander
+Maintainer:          NHAlxr@gmail.com
+Category:            Data
+Build-Type:          Simple
+Cabal-Version:       >=1.6
+   
+Library
+  Build-Depends:     base >= 3 && < 5, random >= 1, vector >= 0.6
+  Exposed-modules:   Data.QuadEdge, Data.QuadEdge.Base
+  ghc-options:       -Wall -Odph
+
+source-repository head
+  type:     darcs
+  location: http://code.haskell.org/~hexpuem/QuadEdge
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
