moonlight-triangulation-0.1.0.0: src-dcel/Moonlight/Triangulation/Internal/DcelOperations/Subdivide.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
-- | Insertion into an existing element: face split and edge split.
module Moonlight.Triangulation.Internal.DcelOperations.Subdivide
( insertIntoFace
, insertOnEdge
) where
import Control.Monad (unless, when)
import Control.Monad.ST (ST)
import Moonlight.Triangulation.Internal.DcelOperations.Legalize (legalizeScratch)
import Moonlight.Triangulation.Internal.DcelOperations.Twin (reverseIndex)
import Moonlight.Triangulation.Internal.Mutable
( MutableDcel
, addEdgeBlock
, addFaceBlock
, ensureCellCapacity
, faceEdges
, linkEdges
, markConnected
, payloadsPristine
, readConstraint
, readFace
, readNext
, readOrigin
, readPrevious
, resetEdgeData
, resetFaceData
, setConstraint
, setCycle3
, writeFace
, writeFaceEdge
, writeOrigin
, writeVertexOut
)
import Moonlight.Triangulation.Internal.OperationState
( Counter (..)
, OperationState
, addCounter
, writeScratch
)
import Moonlight.Triangulation.Internal.Probe (KnownProbe)
import Moonlight.Triangulation.Internal.Types (BuildError)
insertIntoFace :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s (Either BuildError ())
insertIntoFace mutable operation face vertex = do
capacity <- ensureCellCapacity mutable 3 2
case capacity of
Left obstruction -> pure (Left obstruction)
Right () -> do
insertIntoFaceWithCapacity @p mutable operation face vertex
pure (Right ())
insertIntoFaceWithCapacity :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s ()
insertIntoFaceWithCapacity mutable operation face vertex = do
(eAB, eBC, eCA) <- faceEdges mutable face
a <- readOrigin mutable eAB
b <- readOrigin mutable eBC
c <- readOrigin mutable eCA
edgeBase <- addEdgeBlock mutable 3
let !eAV = edgeBase
!eVA = edgeBase + 1
!eBV = edgeBase + 2
!eVB = edgeBase + 3
!eCV = edgeBase + 4
!eVC = edgeBase + 5
writeOrigin mutable eAV a
writeOrigin mutable eVA vertex
writeOrigin mutable eBV b
writeOrigin mutable eVB vertex
writeOrigin mutable eCV c
writeOrigin mutable eVC vertex
faceBase <- addFaceBlock mutable 2
setCycle3 mutable face eAB eBV eVA
setCycle3 mutable faceBase eBC eCV eVB
setCycle3 mutable (faceBase + 1) eCA eAV eVC
writeVertexOut mutable a eAB
writeVertexOut mutable b eBC
writeVertexOut mutable c eCA
markConnected mutable vertex eVA
-- ABC has become ABV; the other two thirds of it are fresh faces. The three
-- boundary edges keep their endpoints and so keep their labels.
resetFaceData mutable face
writeScratch operation 0 eAB
writeScratch operation 1 eBC
writeScratch operation 2 eCA
addCounter operation CounterFaceSplits 1
legalizeScratch @p mutable operation vertex 3
insertOnEdge :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s (Either BuildError ())
insertOnEdge mutable operation suppliedEdge vertex = do
suppliedFace <- readFace mutable suppliedEdge
reverseFace <- readFace mutable (reverseIndex suppliedEdge)
if suppliedFace == 0 || reverseFace == 0
then splitBoundaryEdge @p mutable operation suppliedEdge vertex
else splitInteriorEdge @p mutable operation suppliedEdge vertex
splitInteriorEdge :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s (Either BuildError ())
splitInteriorEdge mutable operation suppliedEdge vertex = do
capacity <- ensureCellCapacity mutable 3 2
case capacity of
Left obstruction -> pure (Left obstruction)
Right () -> do
splitInteriorEdgeWithCapacity @p mutable operation suppliedEdge vertex
pure (Right ())
splitInteriorEdgeWithCapacity :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s ()
splitInteriorEdgeWithCapacity mutable operation suppliedEdge vertex = do
protected <- readConstraint mutable suppliedEdge
suppliedFace <- readFace mutable suppliedEdge
let !edge = if suppliedFace == 0 then reverseIndex suppliedEdge else suppliedEdge
!reverseEdgeEdge = reverseIndex edge
leftFace <- readFace mutable edge
rightFace <- readFace mutable reverseEdgeEdge
eBC <- readNext mutable edge
eCA <- readPrevious mutable edge
eAD <- readNext mutable reverseEdgeEdge
eDB <- readPrevious mutable reverseEdgeEdge
a <- readOrigin mutable edge
b <- readOrigin mutable reverseEdgeEdge
c <- readOrigin mutable eCA
d <- readOrigin mutable eDB
writeOrigin mutable reverseEdgeEdge vertex
edgeBase <- addEdgeBlock mutable 3
let !eVB = edgeBase
!eBV = edgeBase + 1
!eVC = edgeBase + 2
!eCV = edgeBase + 3
!eVD = edgeBase + 4
!eDV = edgeBase + 5
writeOrigin mutable eVB vertex
writeOrigin mutable eBV b
writeOrigin mutable eVC vertex
writeOrigin mutable eCV c
writeOrigin mutable eVD vertex
writeOrigin mutable eDV d
faceBase <- addFaceBlock mutable 2
setCycle3 mutable leftFace edge eVC eCA
setCycle3 mutable faceBase eVB eBC eCV
setCycle3 mutable rightFace eBV eVD eDB
setCycle3 mutable (faceBase + 1) reverseEdgeEdge eAD eDV
writeVertexOut mutable a edge
writeVertexOut mutable b eBC
writeVertexOut mutable c eCA
writeVertexOut mutable d eDB
markConnected mutable vertex reverseEdgeEdge
-- AB became AV, and both incident triangles lost a corner to the new vertex.
unless (payloadsPristine mutable) $ do
resetEdgeData mutable (edge `quot` 2)
resetFaceData mutable leftFace
resetFaceData mutable rightFace
when protected $ do
_ <- setConstraint mutable eVB
pure ()
writeScratch operation 0 eCA
writeScratch operation 1 eBC
writeScratch operation 2 eDB
writeScratch operation 3 eAD
addCounter operation CounterInteriorEdgeSplits 1
legalizeScratch @p mutable operation vertex 4
splitBoundaryEdge :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s (Either BuildError ())
splitBoundaryEdge mutable operation suppliedEdge vertex = do
capacity <- ensureCellCapacity mutable 2 1
case capacity of
Left obstruction -> pure (Left obstruction)
Right () -> do
splitBoundaryEdgeWithCapacity @p mutable operation suppliedEdge vertex
pure (Right ())
splitBoundaryEdgeWithCapacity :: forall p s vertex directed undirected face. KnownProbe p => MutableDcel s vertex directed undirected face -> OperationState s -> Int -> Int -> ST s ()
splitBoundaryEdgeWithCapacity mutable operation suppliedEdge vertex = do
protected <- readConstraint mutable suppliedEdge
suppliedFace <- readFace mutable suppliedEdge
let !edge = if suppliedFace == 0 then reverseIndex suppliedEdge else suppliedEdge
!outerEdge = reverseIndex edge
innerFace <- readFace mutable edge
eBC <- readNext mutable edge
eCA <- readPrevious mutable edge
a <- readOrigin mutable edge
b <- readOrigin mutable outerEdge
c <- readOrigin mutable eCA
oldOuterPrevious <- readPrevious mutable outerEdge
oldOuterNext <- readNext mutable outerEdge
writeOrigin mutable outerEdge vertex
edgeBase <- addEdgeBlock mutable 2
let !eVB = edgeBase
!eBV = edgeBase + 1
!eVC = edgeBase + 2
!eCV = edgeBase + 3
writeOrigin mutable eVB vertex
writeOrigin mutable eBV b
writeOrigin mutable eVC vertex
writeOrigin mutable eCV c
newFace <- addFaceBlock mutable 1
setCycle3 mutable innerFace edge eVC eCA
setCycle3 mutable newFace eVB eBC eCV
writeFace mutable outerEdge 0
writeFace mutable eBV 0
linkEdges mutable oldOuterPrevious eBV
linkEdges mutable eBV outerEdge
linkEdges mutable outerEdge oldOuterNext
writeFaceEdge mutable 0 outerEdge
writeVertexOut mutable a edge
writeVertexOut mutable b eBC
writeVertexOut mutable c eCA
markConnected mutable vertex eVB
-- AB became AV and the one interior triangle lost a corner. The outer face
-- is not an element and keeps nothing to lose.
unless (payloadsPristine mutable) $ do
resetEdgeData mutable (edge `quot` 2)
resetFaceData mutable innerFace
when protected $ do
_ <- setConstraint mutable eVB
pure ()
writeScratch operation 0 eCA
writeScratch operation 1 eBC
addCounter operation CounterBoundaryEdgeSplits 1
legalizeScratch @p mutable operation vertex 2