{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE PartialTypeSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} module Data.Geometry.PlanarSubdivision( module Data.Geometry.PlanarSubdivision.Basic , fromPolygon, fromPolygons ) where -- import Algorithms.Geometry.PolygonTriangulation.Triangulate import Control.Lens hiding (holes, holesOf, (.=)) import qualified Data.CircularSeq as CSeq import Data.Ext import qualified Data.Foldable as F import Data.Geometry.Box import Data.Geometry.PlanarSubdivision.Basic import Data.Geometry.Polygon import Data.Geometry.Vector import qualified Data.Geometry.Vector as Vec import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.Vector as V import qualified Data.PlaneGraph as PG import Data.Proxy -- | Construct a planar subdivision from a polygon. Since our PlanarSubdivision -- models only connected planar subdivisions, this may add dummy/invisible -- edges. -- -- running time: \(O(n)\) for a simple polygon, \(O(n\log n)\) for a polygon -- with holes. fromPolygon :: forall proxy t p f r s. (Ord r, Fractional r) => proxy s -> Polygon t p r -> f -- ^ data inside -> f -- ^ data outside the polygon -> PlanarSubdivision s p () f r fromPolygon p pg@(SimplePolygon _) iD oD = fromSimplePolygon p pg iD oD fromPolygon _ (MultiPolygon vs hs) iD oD = PlanarSubdivision cs vd dd fd where wp = Proxy :: Proxy (Wrap s) -- the components cs = undefined cs' = PG.fromSimplePolygon wp (SimplePolygon vs) iD oD : map (\h -> PG.fromSimplePolygon wp h oD iD) hs vd = undefined dd = undefined fd = undefined -- | Given a list of *disjoint* polygons, construct a planarsubdivsion -- representing them. This may create dummy vertices which have no vertex data, -- hence the 'Maybe p' data type for the vertices. -- -- running time: \(O(n\log n)\) fromPolygons :: (Ord r, Fractional r) => proxy s -> NonEmpty (SimplePolygon p r :+ f) -> f -- ^ data outside the polygons -> PlanarSubdivision s (Maybe p) () f r fromPolygons px pgs oD = undefined -- subd&planeGraph.faceData .~ faceData' -- &planeGraph.vertexData.traverse %~ getP -- where -- faceData' = fmap (\(fi, FaceData hs _) -> FaceData hs (getFData fi)) . faces $ subd -- -- given a faceId lookup the -- getFData fi = let v = boundaryVertices fi subd V.! 0 -- in subd^.dataOf v.to holeData -- -- note that we intentionally reverse the order of iDd and oD in the call below, -- -- as our holes are now outside -- subd = fromPolygon px (MultiPolygon (CSeq.fromList [a,b,c,d]) holes') (Just oD) Nothing -- -- for every polygon, construct a hole. -- holes' = map withF . F.toList $ pgs -- -- add the facedata to the vertex data -- withF (pg :+ f) = bimap (\p -> Hole f p) id pg -- -- corners of the slightly enlarged boundingbox -- (a,b,c,d) = corners . bimap (const $ Outer oD) id -- . grow 1 . boundingBoxList . fmap (^.core) $ pgs --TODO: We need to mark the edges of the outer square as invisible. -- Main Idea: Assign the vertices the hole-number on which they occur. For -- each face we then find an incident vertex to find the data corresponding -- to that face. data HoleData f p = Outer !f | Hole !f !p deriving (Show,Eq) holeData :: HoleData f p -> f holeData (Outer f) = f holeData (Hole f _) = f getP :: HoleData f p -> Maybe p getP (Outer _) = Nothing getP (Hole _ p) = Just p -- | grows the box by x on all sides grow :: (Num r, Arity d) => r -> Box d p r -> Box d p r grow x b = let mi = minPoint b ma = maxPoint b v = Vec.replicate x in box (mi&core %~ (.+^ ((-1) *^ v))) (ma&core %~ (.+^ v))