packages feed

waterfall-cad-0.7.0.0: src/Waterfall/Internal/PaintHistory.hs

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TupleSections #-}
module Waterfall.Internal.PaintHistory
( remapWithBlendFunction
) where

import qualified OpenCascade.TopoDS.Types as TopoDS
import Foreign.Ptr (Ptr)
import Data.Acquire (Acquire)
import Waterfall.Paint (Paint)
import Control.Monad.IO.Class (liftIO)
import Waterfall.Internal.Solid (remapPaints, History (historyGenerated), fromAcquirePaints, PaintMap (FacePaints, UniformPaint), materialiseFacePaints, acquireFacePaints)
import OpenCascade.Inheritance (SubTypeOf(upcast), unsafeDowncast)
import qualified OpenCascade.NCollection as NCollection
import qualified Waterfall.Internal.ShapeMap as ShapeMap
import Waterfall.Internal.Edges (allSubShapesWithCopy)
import Data.Foldable (toList)
import qualified OpenCascade.NCollection.IndexedDataMap as NCollection.IndexedDataMap
import qualified OpenCascade.TopExp as TopExp
import Control.Arrow (first)
import Data.Maybe (catMaybes)
import qualified Data.List.NonEmpty as NE
import qualified OpenCascade.TopAbs.ShapeEnum as ShapeEnum
import qualified OpenCascade.TopoDS.Shape as TopoDS.Shape
import Control.Monad (filterM)
import Waterfall.Internal.FromOpenCascade (shapesFromListOfShape)

getUniqueVertexes :: [Ptr TopoDS.Edge] -> Acquire [Ptr TopoDS.Vertex]
getUniqueVertexes edges = 
    let vertsForEdge e = traverse (liftIO . unsafeDowncast) =<< allSubShapesWithCopy ShapeEnum.Vertex (upcast e)
        dup a = (upcast a, a)
        in fmap toList . liftIO . ShapeMap.fromList . fmap dup . concat  =<< traverse vertsForEdge edges

makeAncestorMap :: Ptr TopoDS.Shape -> Acquire (Ptr (NCollection.IndexedDataMap TopoDS.Shape (NCollection.List TopoDS.Shape)))
makeAncestorMap s = do
    m <- NCollection.IndexedDataMap.newShapeListOfShapeMap
    liftIO $ TopExp.mapShapesAndAncestors s ShapeEnum.Edge ShapeEnum.Face m
    liftIO $ TopExp.mapShapesAndAncestors s ShapeEnum.Vertex ShapeEnum.Face m
    return m

remapWithBlendFunction' :: (NE.NonEmpty Paint -> Paint) -> Ptr TopoDS.Shape -> [Ptr TopoDS.Edge] -> History -> [(Ptr TopoDS.Face, Paint)] -> Acquire PaintMap
remapWithBlendFunction' paintFunction s edges history paints = do
    mappedPaints <- liftIO $ remapPaints history paints

    ancestorMap <- makeAncestorMap s
    paintMap <- liftIO $ ShapeMap.fromList (fmap (first upcast) paints)

    let filletSurfacesFor :: Ptr TopoDS.Shape -> Acquire [(Ptr TopoDS.Face, Paint)]
        filletSurfacesFor edge = do
            faces <- liftIO . filterM (fmap (== ShapeEnum.Face) . TopoDS.Shape.shapeType)
                =<< shapesFromListOfShape 
                =<< historyGenerated history edge
            if null faces then pure [] else do
                neighbours <- shapesFromListOfShape =<<
                    NCollection.IndexedDataMap.findFromKeyShapeListOfShapeMap ancestorMap edge
                neighbouringPaints <- liftIO . fmap catMaybes $ traverse (ShapeMap.lookup paintMap) neighbours
                case NE.nonEmpty neighbouringPaints of 
                    Nothing -> pure []
                    Just ps -> 
                        let newPaint = paintFunction (NE.nub . NE.sort $ ps)
                        in traverse (fmap (, newPaint) . liftIO . unsafeDowncast) faces

    filletSurfacesEdges <- liftIO . fromAcquirePaints $ concat <$> traverse (filletSurfacesFor . upcast) edges
    verts <- getUniqueVertexes edges
    filletSurfacesVerts <-liftIO . fromAcquirePaints $ concat <$> traverse (filletSurfacesFor . upcast) verts

    return $ FacePaints (mappedPaints <> filletSurfacesEdges <> filletSurfacesVerts)


remapWithBlendFunction :: (NE.NonEmpty Paint -> Paint) -> Ptr TopoDS.Shape -> [Ptr TopoDS.Edge] -> History -> PaintMap -> Acquire PaintMap
remapWithBlendFunction paintFunction s edges history (FacePaints paints) = 
    remapWithBlendFunction' paintFunction s edges history =<< acquireFacePaints paints
remapWithBlendFunction paintFunction s edges history (UniformPaint paint) 
    | paintFunction (NE.singleton paint) == paint = pure $ UniformPaint paint
    | otherwise = remapWithBlendFunction' paintFunction s edges history =<< materialiseFacePaints s (UniformPaint paint)