moonlight-triangulation-1.0.0.0: src-dual/Moonlight/Triangulation/Voronoi/Handles.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
-- | Zero-copy Voronoi views that retain the owning triangulation.
module Moonlight.Triangulation.Voronoi.Handles
( VoronoiFaceHandle
, DirectedVoronoiEdgeHandle
, UndirectedVoronoiEdgeHandle
, VoronoiVertexHandle
, voronoiFaceHandle
, directedVoronoiEdgeHandle
, undirectedVoronoiEdgeHandle
, vertexAsVoronoiFaceH
, directedEdgeAsVoronoiH
, undirectedEdgeAsVoronoiH
, innerFaceAsVoronoiVertexH
, fixVoronoiFace
, fixDirectedVoronoiEdge
, fixUndirectedVoronoiEdge
, fixVoronoiVertex
, voronoiEdgeReverseH
, voronoiEdgeNextH
, voronoiEdgePreviousH
, voronoiEdgeFromH
, voronoiEdgeToH
, voronoiEdgeFaceH
, voronoiEdgeAsUndirectedH
, voronoiEdgeAsDelaunayH
, voronoiFaceSiteH
, voronoiFaceAdjacentEdgesH
, voronoiVertexPositionH
, voronoiVertexOutEdgesH
, voronoiVertexAsDelaunayFaceH
, voronoiVertexAsOuterEdgeH
, voronoiEdgeDirectionH
, voronoiEdgeGeometryH
) where
import Moonlight.Triangulation.Handles.Dynamic
import Moonlight.Triangulation.Math (midpoint)
import Moonlight.Triangulation.Types
import Moonlight.Triangulation.Voronoi
-- | Zero-copy dual handles. Each dual value contains exactly one primal handle,
-- so it cannot accidentally combine an identifier from one triangulation with
-- the storage of another.
newtype VoronoiFaceHandle mode vertex directed undirected face =
VoronoiFaceHandle (VertexHandle mode vertex directed undirected face)
-- | An owning handle to a directed dual edge.
newtype DirectedVoronoiEdgeHandle mode vertex directed undirected face =
DirectedVoronoiEdgeHandle (DirectedEdgeHandle mode vertex directed undirected face)
-- | An owning handle to an undirected dual edge.
newtype UndirectedVoronoiEdgeHandle mode vertex directed undirected face =
UndirectedVoronoiEdgeHandle (UndirectedEdgeHandle mode vertex directed undirected face)
-- | An owning handle to a finite or ideal dual vertex.
data VoronoiVertexHandle mode vertex directed undirected face
= InnerVoronoiVertexHandle
!(FaceHandle InnerTag mode vertex directed undirected face)
| OuterVoronoiVertexHandle
!(DirectedVoronoiEdgeHandle mode vertex directed undirected face)
instance Show (VoronoiFaceHandle mode vertex directed undirected face) where
showsPrec precedence = showsPrec precedence . fixVoronoiFace
instance Show (DirectedVoronoiEdgeHandle mode vertex directed undirected face) where
showsPrec precedence = showsPrec precedence . fixDirectedVoronoiEdge
instance Show (UndirectedVoronoiEdgeHandle mode vertex directed undirected face) where
showsPrec precedence = showsPrec precedence . fixUndirectedVoronoiEdge
instance Show (VoronoiVertexHandle mode vertex directed undirected face) where
showsPrec precedence = showsPrec precedence . fixVoronoiVertex
-- | Admit a fixed Voronoi face identifier into a triangulation.
voronoiFaceHandle
:: Triangulation mode vertex directed undirected face
-> VoronoiFaceId
-> Maybe (VoronoiFaceHandle mode vertex directed undirected face)
voronoiFaceHandle triangulation (VoronoiFaceId site) =
VoronoiFaceHandle <$> vertexHandle triangulation site
-- | View an admitted primal vertex as its Voronoi face.
vertexAsVoronoiFaceH
:: VertexHandle mode vertex directed undirected face
-> VoronoiFaceHandle mode vertex directed undirected face
vertexAsVoronoiFaceH = VoronoiFaceHandle
-- | Admit a fixed directed Voronoi edge identifier into a triangulation.
directedVoronoiEdgeHandle
:: Triangulation mode vertex directed undirected face
-> DirectedVoronoiEdgeId
-> Maybe (DirectedVoronoiEdgeHandle mode vertex directed undirected face)
directedVoronoiEdgeHandle triangulation (DirectedVoronoiEdgeId edge) =
DirectedVoronoiEdgeHandle <$> directedEdgeHandle triangulation edge
-- | View an admitted primal directed edge in the dual handle family.
directedEdgeAsVoronoiH
:: DirectedEdgeHandle mode vertex directed undirected face
-> DirectedVoronoiEdgeHandle mode vertex directed undirected face
directedEdgeAsVoronoiH = DirectedVoronoiEdgeHandle
-- | Admit a fixed undirected Voronoi edge identifier into a triangulation.
undirectedVoronoiEdgeHandle
:: Triangulation mode vertex directed undirected face
-> UndirectedVoronoiEdgeId
-> Maybe (UndirectedVoronoiEdgeHandle mode vertex directed undirected face)
undirectedVoronoiEdgeHandle triangulation (UndirectedVoronoiEdgeId edge) =
UndirectedVoronoiEdgeHandle <$> undirectedEdgeHandle triangulation edge
-- | View an admitted primal undirected edge in the dual handle family.
undirectedEdgeAsVoronoiH
:: UndirectedEdgeHandle mode vertex directed undirected face
-> UndirectedVoronoiEdgeHandle mode vertex directed undirected face
undirectedEdgeAsVoronoiH = UndirectedVoronoiEdgeHandle
-- | View an admitted bounded primal face as a finite dual vertex.
innerFaceAsVoronoiVertexH
:: FaceHandle InnerTag mode vertex directed undirected face
-> VoronoiVertexHandle mode vertex directed undirected face
innerFaceAsVoronoiVertexH = InnerVoronoiVertexHandle
-- | Forget ownership and recover a fixed Voronoi face identifier.
fixVoronoiFace :: VoronoiFaceHandle mode vertex directed undirected face -> VoronoiFaceId
fixVoronoiFace (VoronoiFaceHandle site) = VoronoiFaceId (fixVertex site)
{-# INLINE fixVoronoiFace #-}
-- | Forget ownership and recover a fixed directed dual edge identifier.
fixDirectedVoronoiEdge
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> DirectedVoronoiEdgeId
fixDirectedVoronoiEdge (DirectedVoronoiEdgeHandle edge) =
DirectedVoronoiEdgeId (fixDirectedEdge edge)
{-# INLINE fixDirectedVoronoiEdge #-}
-- | Forget ownership and recover a fixed undirected dual edge identifier.
fixUndirectedVoronoiEdge
:: UndirectedVoronoiEdgeHandle mode vertex directed undirected face
-> UndirectedVoronoiEdgeId
fixUndirectedVoronoiEdge (UndirectedVoronoiEdgeHandle edge) =
UndirectedVoronoiEdgeId (fixUndirectedEdge edge)
{-# INLINE fixUndirectedVoronoiEdge #-}
-- | Forget ownership and recover a fixed dual vertex identifier.
fixVoronoiVertex
:: VoronoiVertexHandle mode vertex directed undirected face
-> VoronoiVertexId
fixVoronoiVertex (InnerVoronoiVertexHandle face) =
InnerVoronoiVertex (fixedFaceId (fixFace face))
fixVoronoiVertex (OuterVoronoiVertexHandle edge) =
OuterVoronoiVertex (fixDirectedVoronoiEdge edge)
{-# INLINE fixVoronoiVertex #-}
-- | Reverse an admitted directed dual edge.
voronoiEdgeReverseH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> DirectedVoronoiEdgeHandle mode vertex directed undirected face
voronoiEdgeReverseH (DirectedVoronoiEdgeHandle edge) =
DirectedVoronoiEdgeHandle (directedEdgeReverse edge)
-- | Next admitted dual edge around its Voronoi face.
voronoiEdgeNextH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> DirectedVoronoiEdgeHandle mode vertex directed undirected face
voronoiEdgeNextH (DirectedVoronoiEdgeHandle edge) =
DirectedVoronoiEdgeHandle (directedEdgeCounterClockwise edge)
-- | Previous admitted dual edge around its Voronoi face.
voronoiEdgePreviousH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> DirectedVoronoiEdgeHandle mode vertex directed undirected face
voronoiEdgePreviousH (DirectedVoronoiEdgeHandle edge) =
DirectedVoronoiEdgeHandle (directedEdgeClockwise edge)
-- | Origin finite or ideal vertex of an admitted dual edge.
voronoiEdgeFromH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> VoronoiVertexHandle mode vertex directed undirected face
voronoiEdgeFromH edge@(DirectedVoronoiEdgeHandle primal) =
case faceAsInner (directedEdgeFace primal) of
Just inner -> InnerVoronoiVertexHandle inner
Nothing -> OuterVoronoiVertexHandle edge
-- | Destination finite or ideal vertex of an admitted dual edge.
voronoiEdgeToH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> VoronoiVertexHandle mode vertex directed undirected face
voronoiEdgeToH = voronoiEdgeFromH . voronoiEdgeReverseH
-- | Voronoi face to the left of an admitted directed dual edge.
voronoiEdgeFaceH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> VoronoiFaceHandle mode vertex directed undirected face
voronoiEdgeFaceH (DirectedVoronoiEdgeHandle edge) =
VoronoiFaceHandle (directedEdgeFrom edge)
-- | Forget orientation while retaining ownership.
voronoiEdgeAsUndirectedH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> UndirectedVoronoiEdgeHandle mode vertex directed undirected face
voronoiEdgeAsUndirectedH (DirectedVoronoiEdgeHandle edge) =
UndirectedVoronoiEdgeHandle (directedEdgeAsUndirected edge)
-- | Recover the owning primal directed-edge handle.
voronoiEdgeAsDelaunayH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> DirectedEdgeHandle mode vertex directed undirected face
voronoiEdgeAsDelaunayH (DirectedVoronoiEdgeHandle edge) = edge
-- | Recover the owning primal site handle.
voronoiFaceSiteH
:: VoronoiFaceHandle mode vertex directed undirected face
-> VertexHandle mode vertex directed undirected face
voronoiFaceSiteH (VoronoiFaceHandle site) = site
-- | Admitted directed boundary of a Voronoi face.
voronoiFaceAdjacentEdgesH
:: VoronoiFaceHandle mode vertex directed undirected face
-> [DirectedVoronoiEdgeHandle mode vertex directed undirected face]
voronoiFaceAdjacentEdgesH (VoronoiFaceHandle site) =
map DirectedVoronoiEdgeHandle (vertexHandleOutEdges site)
-- | Position of a finite admitted dual vertex.
voronoiVertexPositionH
:: VoronoiVertexHandle mode vertex directed undirected face
-> Maybe (Point)
voronoiVertexPositionH (InnerVoronoiVertexHandle face) = innerFaceCircumcenter face
voronoiVertexPositionH (OuterVoronoiVertexHandle _) = Nothing
-- | Directed dual edges leaving a finite admitted dual vertex.
voronoiVertexOutEdgesH
:: VoronoiVertexHandle mode vertex directed undirected face
-> Maybe [DirectedVoronoiEdgeHandle mode vertex directed undirected face]
voronoiVertexOutEdgesH (InnerVoronoiVertexHandle face) =
Just (map DirectedVoronoiEdgeHandle (faceAdjacentEdges face))
voronoiVertexOutEdgesH (OuterVoronoiVertexHandle _) = Nothing
-- | Recover the primal bounded face underlying a finite dual vertex.
voronoiVertexAsDelaunayFaceH
:: VoronoiVertexHandle mode vertex directed undirected face
-> Maybe (FaceHandle InnerTag mode vertex directed undirected face)
voronoiVertexAsDelaunayFaceH (InnerVoronoiVertexHandle face) = Just face
voronoiVertexAsDelaunayFaceH (OuterVoronoiVertexHandle _) = Nothing
-- | Recover the primal hull edge underlying an ideal dual vertex.
voronoiVertexAsOuterEdgeH
:: VoronoiVertexHandle mode vertex directed undirected face
-> Maybe (DirectedVoronoiEdgeHandle mode vertex directed undirected face)
voronoiVertexAsOuterEdgeH (InnerVoronoiVertexHandle _) = Nothing
voronoiVertexAsOuterEdgeH (OuterVoronoiVertexHandle edge) = Just edge
-- | Unit direction of the dual edge orthogonal to the primal edge.
voronoiEdgeDirectionH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> Point
voronoiEdgeDirectionH (DirectedVoronoiEdgeHandle primal) =
let (Point ax ay, Point bx by) = directedEdgePositions primal
in Point (ay - by) (bx - ax)
-- | Geometric realization of an admitted dual edge.
voronoiEdgeGeometryH
:: DirectedVoronoiEdgeHandle mode vertex directed undirected face
-> Maybe (VoronoiEdgeGeometry)
voronoiEdgeGeometryH edge@(DirectedVoronoiEdgeHandle primal) =
case (voronoiEdgeFromH edge, voronoiEdgeToH edge) of
(InnerVoronoiVertexHandle fromFace, InnerVoronoiVertexHandle toFace) ->
VoronoiSegment <$> innerFaceCircumcenter fromFace <*> innerFaceCircumcenter toFace
(InnerVoronoiVertexHandle fromFace, OuterVoronoiVertexHandle _) -> do
start <- innerFaceCircumcenter fromFace
pure (VoronoiRay start (normalizePoint (voronoiEdgeDirectionH edge)))
(OuterVoronoiVertexHandle _, InnerVoronoiVertexHandle toFace) -> do
end <- innerFaceCircumcenter toFace
pure (VoronoiRay end (normalizePoint (negatePoint (voronoiEdgeDirectionH edge))))
(OuterVoronoiVertexHandle _, OuterVoronoiVertexHandle _) ->
let (from, to) = directedEdgePositions primal
in Just (VoronoiLine (midpoint from to) (normalizePoint (voronoiEdgeDirectionH edge)))
normalizePoint :: Point -> Point
normalizePoint (Point x y)
| scale == 0 = Point 0 0
| otherwise =
let !scaledX = x / scale
!scaledY = y / scale
!length' = sqrt (scaledX * scaledX + scaledY * scaledY)
in Point (scaledX / length') (scaledY / length')
where
!scale = max (abs x) (abs y)
negatePoint :: Point -> Point
negatePoint (Point x y) = Point (-x) (-y)
-- The handle verbs cross the same component boundary as the fixed-index ones
-- and carry their unfoldings for the same reason. 'voronoiVertexPositionH'
-- reaches its arithmetic through 'innerFaceCircumcenter', whose own worker
-- publishes no unfolding, so it stops at that call until the dcel layer says
-- otherwise.