moonlight-triangulation-1.4.0.3: ffi/abi/Moonlight/Triangulation/Foreign/Mesh.hs
module Moonlight.Triangulation.Foreign.Mesh
( delaunayF64
, insertGeometryBatch
, meshCopyTrianglesU32
, meshCopyVerticesF64
, meshFree
, meshInsertManyF64
, meshSiteDifference
, meshSiteIntersection
, meshSiteSymmetricDifference
, meshSiteUnion
, meshTriangleCount
, meshVertexCount
) where
import Control.Monad (void)
import Data.Bifunctor (first)
import Data.Word (Word32)
import Foreign.C.Types (CDouble (..), CSize, CUInt)
import Foreign.Ptr (Ptr)
import Foreign.Storable (poke, pokeElemOff)
import qualified Data.Vector as V
import qualified Moonlight.Triangulation as T
import Moonlight.Triangulation.Foreign.Boundary
( GeometryMesh
, HandleValue
, checkedCount
, dereferenceHandle
, freeHandle
, produceHandle
, readPoints
, requireOutputCapacity
, requirePointer
, runBoundary
)
import Moonlight.Triangulation.Foreign.Contract (CMesh, CObstruction)
import Moonlight.Triangulation.Foreign.Obstruction (buildFailure)
import Moonlight.Triangulation.Math (validatePoint)
import qualified Moonlight.Triangulation.Internal.Session as Session
delaunayF64 :: Ptr CDouble -> CSize -> Ptr (Ptr CMesh) -> Ptr CObstruction -> IO CUInt
delaunayF64 coordinates rawCount output obstructionPointer =
runBoundary obstructionPointer $ produceHandle output $ do
case checkedCount 2 rawCount of
Left failure -> pure (Left failure)
Right count -> do
points <- readPoints coordinates count
pure (points >>= first buildFailure . T.delaunayGeometry)
meshInsertManyF64 :: Ptr CMesh -> Ptr CDouble -> CSize -> Ptr (Ptr CMesh) -> Ptr CObstruction -> IO CUInt
meshInsertManyF64 meshPointer coordinates rawCount output obstructionPointer =
runBoundary obstructionPointer $ produceHandle output $ do
case requirePointer "mesh" meshPointer >> checkedCount 2 rawCount of
Left failure -> pure (Left failure)
Right count -> do
points <- readPoints coordinates count
case points of
Left failure -> pure (Left failure)
Right admitted -> do
mesh <- dereferenceHandle meshPointer
pure (first buildFailure (insertGeometryBatch mesh admitted))
-- | Admit the complete batch before opening the immutable insertion session.
insertGeometryBatch :: GeometryMesh -> V.Vector T.Point -> Either T.BuildError GeometryMesh
insertGeometryBatch mesh points = do
admittedPoints <- V.imapM (\index point -> validatePoint (Just index) point) points
(_, revised, _) <-
Session.withSession
mesh
(V.length points)
( V.mapM_
( \point ->
void
( Session.insertAdmittedVertexAtCombining
(\_ replacement -> replacement)
point
()
)
)
admittedPoints
)
pure revised
meshSiteUnion, meshSiteIntersection, meshSiteDifference, meshSiteSymmetricDifference :: Ptr CMesh -> Ptr CMesh -> Ptr (Ptr CMesh) -> Ptr CObstruction -> IO CUInt
meshSiteUnion = binaryMeshOperation T.union
meshSiteIntersection = binaryMeshOperation T.intersection
meshSiteDifference = binaryMeshOperation T.difference
meshSiteSymmetricDifference = binaryMeshOperation T.symmetricDifference
binaryMeshOperation
:: (GeometryMesh -> GeometryMesh -> Either T.BuildError GeometryMesh)
-> Ptr CMesh
-> Ptr CMesh
-> Ptr (Ptr CMesh)
-> Ptr CObstruction
-> IO CUInt
binaryMeshOperation operation leftPointer rightPointer output obstructionPointer =
runBoundary obstructionPointer $ produceHandle output $ do
case requirePointer "left mesh" leftPointer >> requirePointer "right mesh" rightPointer of
Left failure -> pure (Left failure)
Right () -> do
left <- dereferenceHandle leftPointer
right <- dereferenceHandle rightPointer
pure (first buildFailure (operation left right))
meshVertexCount, meshTriangleCount :: Ptr CMesh -> Ptr CSize -> Ptr CObstruction -> IO CUInt
meshVertexCount = handleCount "mesh" T.numVertices
meshTriangleCount = handleCount "mesh" (V.length . T.innerFaceVertexTriples)
handleCount
:: String
-> (HandleValue carrier -> Int)
-> Ptr carrier
-> Ptr CSize
-> Ptr CObstruction
-> IO CUInt
handleCount handleLabel observe handlePointer output obstructionPointer =
runBoundary obstructionPointer $
case requirePointer handleLabel handlePointer >> requirePointer "count" output of
Left failure -> pure (Left failure)
Right () -> do
value <- dereferenceHandle handlePointer
poke output (fromIntegral (observe value))
pure (Right ())
meshCopyVerticesF64 :: Ptr CMesh -> Ptr CDouble -> CSize -> Ptr CSize -> Ptr CObstruction -> IO CUInt
meshCopyVerticesF64 =
copyHandleProjection
"mesh"
"points_written"
"coordinates"
T.vertexPoints
( \output index (T.Point x y) -> do
pokeElemOff output (index * 2) (CDouble x)
pokeElemOff output (index * 2 + 1) (CDouble y)
)
meshCopyTrianglesU32 :: Ptr CMesh -> Ptr Word32 -> CSize -> Ptr CSize -> Ptr CObstruction -> IO CUInt
meshCopyTrianglesU32 =
copyHandleProjection
"mesh"
"triangles_written"
"triangles"
T.innerFaceVertexTriples
( \output index (firstVertex, secondVertex, thirdVertex) -> do
pokeElemOff output (index * 3) (T.unVertexId firstVertex)
pokeElemOff output (index * 3 + 1) (T.unVertexId secondVertex)
pokeElemOff output (index * 3 + 2) (T.unVertexId thirdVertex)
)
copyHandleProjection
:: String
-> String
-> String
-> (HandleValue carrier -> V.Vector item)
-> (Ptr element -> Int -> item -> IO ())
-> Ptr carrier
-> Ptr element
-> CSize
-> Ptr CSize
-> Ptr CObstruction
-> IO CUInt
{-# INLINE copyHandleProjection #-}
copyHandleProjection handleLabel writtenLabel outputLabel project writeItem handlePointer output rawCapacity written obstructionPointer =
runBoundary obstructionPointer $
case requirePointer handleLabel handlePointer >> requirePointer writtenLabel written >> checkedCount 1 rawCapacity of
Left failure -> pure (Left failure)
Right capacity -> do
value <- dereferenceHandle handlePointer
let items = project value
required = V.length items
poke written (fromIntegral required)
case requireOutputCapacity outputLabel output required capacity of
Left failure -> pure (Left failure)
Right () -> V.imapM_ (writeItem output) items >> pure (Right ())
meshFree :: Ptr CMesh -> IO ()
meshFree = freeHandle