module Data.Geometry.PlanarSubdivision.Merge( merge
, mergeWith
, mergeAllWith
, embedAsHoleIn
, embedAsHolesIn
) where
import Algorithms.DivideAndConquer
import Control.Lens hiding (holes)
import Data.Ext
import Data.Geometry.PlanarSubdivision.Basic
import Data.Geometry.PlanarSubdivision.Raw
import Data.Geometry.Point
import Data.Geometry.Polygon
import Data.PlanarGraph.Dart
import Data.PlaneGraph ( Dart, VertexId(..), FaceId(..)
, VertexId', FaceId'
)
import qualified Data.PlaneGraph as PG
import Data.Semigroup.Foldable
import qualified Data.Vector as V
import Unsafe.Coerce (unsafeCoerce)
embedAsHolesIn :: forall t s h v e f r. (Foldable1 t, Functor t)
=> t (PlanarSubdivision h v e f r)
-> (t f -> f -> f)
-> FaceId' s
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
embedAsHolesIn hs f = embedAsHoleIn ph' g
where
ph' = mergeAllWith const hs
g _ = f (fmap (\h -> h^.dataOf (outerFaceId h)) hs)
embedAsHoleIn :: forall s h v e f r.
PlanarSubdivision h v e f r
-> (f -> f -> f)
-> FaceId' s
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
embedAsHoleIn ph' f i ps = mergeWith' mergeFaces ps ph
where
ph :: PlanarSubdivision s v e f r
ph = unsafeCoerce ph'
mergeFaces fs1 fs2 = update fs1 i (V.head fs2) <> V.tail fs2
update fs (FaceId (VertexId j)) h2 = let FaceData hs' x' = h2^.faceDataVal
g (FaceData hs x) = FaceData (hs' <> hs) (f x' x)
in fs&ix j.faceDataVal %~ g
mergeAllWith :: Foldable1 t
=> (f -> f -> f)
-> t (PlanarSubdivision s v e f r)
-> PlanarSubdivision s v e f r
mergeAllWith f = divideAndConquer1With (mergeWith f) id . toNonEmpty
merge :: PlanarSubdivision s v e f r -> PlanarSubdivision s v e f r -> PlanarSubdivision s v e f r
merge = mergeWith const
mergeWith :: (f -> f -> f)
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
mergeWith f = mergeWith' (mergeFaceData f)
mergeWith' :: (V.Vector (RawFace s f) -> V.Vector (RawFace s f) -> V.Vector (RawFace s f))
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
mergeWith' mergeFaces p1 p2 = PlanarSubdivision cs vd rd rf
where
p2' = shift (numComponents p1) (numVertices p1) (numDarts p1 `div` 2) (numFaces p1 - 1) p2
cs = p1^.components <> p2'^.components
vd = p1^.rawVertexData <> p2'^.rawVertexData
rd = p1^.rawDartData <> p2'^.rawDartData
rf = (p1^.rawFaceData) `mergeFaces` (p2'^.rawFaceData)
mergeFaceData :: (f -> f -> f)
-> V.Vector (RawFace s f)
-> V.Vector (RawFace s f)
-> V.Vector (RawFace s f)
mergeFaceData f vs1 vs2 = V.cons h ts
where
ts = V.tail vs1 <> V.tail vs2
h = let FaceData hs1 x1 = vs1^.to V.head.faceDataVal
FaceData hs2 x2 = vs2^.to V.head.faceDataVal
in RawFace Nothing $ FaceData (hs1 <> hs2) (f x1 x2)
shift :: forall s v e f r.
Int -> Int -> Int -> Int
-> PlanarSubdivision s v e f r
-> PlanarSubdivision s v e f r
shift nc nv nd nf (PlanarSubdivision cs vd rd rf) = PlanarSubdivision cs' vd' rd' rf'
where
cs' = (\pg -> pg&PG.vertexData.traverse %~ incV
&PG.rawDartData.traverse %~ incD
&PG.faceData.traverse %~ incFi
) <$> cs
vd' = (\(Raw ci i x) -> Raw (incC ci) i x) <$> vd
rd' = (\(Raw ci i x) -> Raw (incC ci) i x) <$> rd
rf' = (\(RawFace fidx fd) -> RawFace (incFIdx <$> fidx) (incF fd)) <$> rf
incC :: ComponentId s -> ComponentId s
incC (ComponentId i) = ComponentId $ i + nc
incV :: VertexId' s -> VertexId' s
incV (VertexId i) = VertexId $ i + nv
incD :: Dart s -> Dart s
incD (Dart (Arc a) p) = Dart (Arc $ a + nd) p
incFIdx (ci,fi) = (incC ci, fi)
incF :: FaceData (Dart s) f -> FaceData (Dart s) f
incF (FaceData hs f) = FaceData (incD <$> hs) f
incFi :: FaceId' s -> FaceId' s
incFi (FaceId (VertexId i)) = FaceId . VertexId $ i + nf
data Test = Test
data Id a = Id a
triangle1 :: PlanarSubdivision Test () () Int Rational
triangle1 = (\pg -> fromSimplePolygon (Id Test) pg 1 0)
$ trianglePG1
trianglePG1 = fromPoints . map ext $ [origin, Point2 200 0, Point2 200 200]
triangle2 :: PlanarSubdivision Test () () Int Rational
triangle2 = (\pg -> fromSimplePolygon (Id Test) pg 2 0)
$ trianglePG2
trianglePG2 = fromPoints . map ext $ [Point2 0 30, Point2 10 30, Point2 10 40]
triangle4 :: PlanarSubdivision Test () () Int Rational
triangle4 = (\pg -> fromSimplePolygon (Id Test) pg 1 0)
$ trianglePG4
trianglePG4 = fromPoints . map ext $ [Point2 400 400, Point2 600 400, Point2 600 600]
triangle3 :: PlanarSubdivision Test () () Int Rational
triangle3 = (\pg -> fromSimplePolygon (Id Test) pg 3 0)
$ trianglePG3
trianglePG3 = fromPoints . map ext $ [Point2 401 530, Point2 410 530, Point2 410 540]
myPS = embedAsHoleIn triangle2 const (mkFI 1) triangle1
`merge`
embedAsHoleIn triangle3 const (mkFI 1) triangle4
mkFI :: Int -> FaceId' Test
mkFI = FaceId . VertexId