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))
new ∷ QEDS a
new = GV.empty
mutate ∷ QEDS a → (forall s. MQEDS s a → ST s ()) → QEDS a
mutate q f = GV.modify f q
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)
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
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 }
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
edges ∷ QEDS a → IV.Vector (Edge a)
edges = GV.map fromJust . GV.filter isJust
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)
getEdge ∷ QEDS a → EdgeRef → Edge a
getEdge q (i,_,_) = let Just e = q GV.! i
in e
getAttr ∷ QEDS a → EdgeRef → a
getAttr q e = attributes (getEdge q e)
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
isValid ∷ QEDS a → EdgeRef → Bool
isValid q (i,_,_) = isJust $ q GV.! i
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})
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
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
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)
oprev ∷ QEDS a → EdgeRef → EdgeRef
oprev = rot `comp` rot
lnext ∷ QEDS a → EdgeRef → EdgeRef
lnext = rot `comp` rotInv
lprev ∷ QEDS a → EdgeRef → EdgeRef
lprev = sym `comp` id
rnext ∷ QEDS a → EdgeRef → EdgeRef
rnext = rotInv `comp` rot
rprev ∷ QEDS a → EdgeRef → EdgeRef
rprev = id `comp` sym
dnext ∷ QEDS a → EdgeRef → EdgeRef
dnext = sym `comp` sym
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
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