waterfall-cad 0.1.1.1 → 0.1.2.1
raw patch · 9 files changed
+105/−13 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Waterfall.Path: fromPath2D :: Path2D -> Path
+ Waterfall.Solids: centeredCylinder :: Solid
+ Waterfall.Solids: unitCone :: Solid
+ Waterfall.Transforms: mirror :: Transformable a => V3 Double -> a -> a
+ Waterfall.TwoD.Transforms: mirror2D :: Transformable2D a => V2 Double -> a -> a
Files
- CHANGELOG.md +13/−0
- src/Waterfall/Internal/Edges.hs +5/−5
- src/Waterfall/Offset.hs +7/−1
- src/Waterfall/Path.hs +5/−1
- src/Waterfall/Solids.hs +16/−1
- src/Waterfall/Sweep.hs +2/−2
- src/Waterfall/Transforms.hs +26/−1
- src/Waterfall/TwoD/Transforms.hs +30/−1
- waterfall-cad.cabal +1/−1
CHANGELOG.md view
@@ -9,6 +9,19 @@ ## Unreleased +## 0.1.2.1 - 2024-01-09 ++### Added++- Added `mirror` to `Transformable` typeclass, and `mirror2D` to `Transformable2D`+- Added `fromPath2D` to `Waterfall.Path` to make 2D paths into 3D ones.+- Added `centeredCylinder` and `unitCone` to `Waterfall.Solids`++### Fixed++- Handle offsetting by zero (return the unmodified shape)+- Fix rotation of endcaps in a `sweep`+ ## 0.1.1.1 - 2023-12-12 ## 0.1.1.0 - 2023-12-12
src/Waterfall/Internal/Edges.hs view
@@ -25,10 +25,10 @@ gpVecToV3 vec = V3 <$> GP.Vec.getX vec <*> GP.Vec.getY vec <*> GP.Vec.getZ vec edgeEndpoints :: Ptr TopoDS.Edge -> IO (V3 Double, V3 Double)-edgeEndpoints e = (`with` pure) $ do- curve <- BRep.Tool.curve e- p1 <- liftIO . BRep.Tool.curveParamFirst $ e- p2 <- liftIO . BRep.Tool.curveParamLast $ e+edgeEndpoints edge = (`with` pure) $ do+ curve <- BRep.Tool.curve edge+ p1 <- liftIO . BRep.Tool.curveParamFirst $ edge+ p2 <- liftIO . BRep.Tool.curveParamLast $ edge s <- (liftIO . gpPntToV3) =<< Geom.Curve.value curve p1 e <- (liftIO . gpPntToV3) =<< Geom.Curve.value curve p2 return (s, e)@@ -39,7 +39,7 @@ (s, _) <- edgeEndpoints v1 let runToEnd = do edge <- WireExplorer.current explorer- (s, e') <- edgeEndpoints edge+ (_s, e') <- edgeEndpoints edge WireExplorer.next explorer more <- WireExplorer.more explorer if more
src/Waterfall/Offset.hs view
@@ -10,6 +10,7 @@ import qualified OpenCascade.BRepOffset.Mode as Mode import qualified OpenCascade.GeomAbs.JoinType as GeomAbs.JoinType import qualified OpenCascade.BRepBuilderAPI.MakeSolid as MakeSolid+import Linear.Epsilon (nearZero) -- | Expand or contract a `Solid` by a certain amount. -- @@ -19,7 +20,12 @@ -> Double -- ^ Tolerance, this can be relatively small -> Solid -- ^ the `Solid` to offset -> Solid-offset value tolerance (Solid run) = Solid $ do+offset value tolerance (Solid run)+ | nearZero value = Solid run+ | otherwise = + Solid $ do++ builder <- MakeOffsetShape.new s <- run --liftIO $ MakeOffsetShape.performBySimple builder s value
src/Waterfall/Path.hs view
@@ -4,6 +4,7 @@ module Waterfall.Path ( Path , module Waterfall.Path.Common+, fromPath2D -- $ reexports , line3D , lineTo3D@@ -22,9 +23,12 @@ import Waterfall.Path.Common+import Waterfall.TwoD.Internal.Path2D (Path2D (..)) import Linear (V3) -+-- | convert a `Path2D` into a `Path` on the \( xy \) plane (with \( z = 0 \) )+fromPath2D :: Path2D -> Path+fromPath2D (Path2D run) = Path run -- $reexports --
src/Waterfall/Solids.hs view
@@ -6,18 +6,22 @@ , box , unitSphere , unitCylinder+, centeredCylinder+, unitCone , prism ) where import Waterfall.Internal.Solid(Solid(..), nowhere) import Waterfall.TwoD.Internal.Shape (runShape)+import Waterfall.Transforms (translate) import qualified Waterfall.TwoD.Shape as TwoD.Shape import qualified OpenCascade.BRepPrimAPI.MakeBox as MakeBox import qualified OpenCascade.BRepPrimAPI.MakeSphere as MakeSphere import qualified OpenCascade.BRepPrimAPI.MakeCylinder as MakeCylinder+import qualified OpenCascade.BRepPrimAPI.MakeCone as MakeCone import qualified OpenCascade.GP as GP-import Linear (V3 (..))+import Linear (V3 (..), unit, _z, (^*)) import qualified OpenCascade.GP.Pnt as GP.Pnt import qualified OpenCascade.GP.Vec as GP.Vec import qualified OpenCascade.BRepPrimAPI.MakePrism as MakePrism@@ -56,6 +60,17 @@ -- the other centered on \( (0, 0, 1) \) unitCylinder :: Solid unitCylinder = Solid $ Inheritance.upcast <$> MakeCylinder.fromRadiusAndHeight 1 1++-- | A cylinder with radius 1, length 1,+-- centered on the origin,+centeredCylinder :: Solid+centeredCylinder = translate (unit _z ^* (-0.5)) $ unitCylinder++-- | A cone +-- With a point at the origin +-- and a circular face with Radius 1, centered on \( (0, 1, 1) \)+unitCone :: Solid+unitCone = Solid $ Inheritance.upcast <$> MakeCone.fromTwoRadiiAndHeight 0 1 1 -- | Extruded a 2D face into a prism with a given length \(len\). --
src/Waterfall/Sweep.hs view
@@ -23,8 +23,8 @@ in if nearZero (vn - z) then pure face else- let axis = if nearZero (vn + z) then unit _x else cross vn z- angle = acos (dot vn z) + let axis = if nearZero (vn + z) then unit _x else z `cross` vn+ angle = acos (vn `dot` z) in runSolid . rotate axis angle . Solid . pure $ face positionFace :: V3 Double -> Ptr TopoDS.Shape -> Acquire (Ptr TopoDS.Shape)
src/Waterfall/Transforms.hs view
@@ -6,15 +6,17 @@ , uScale , rotate , translate+, mirror ) where import Waterfall.Internal.Solid (Solid(..)) import Linear.V3 (V3 (..))-import Linear ((*^))+import Linear ((*^), normalize, dot ) import qualified Linear.Quaternion as Quaternion import qualified OpenCascade.GP.Trsf as GP.Trsf import qualified OpenCascade.GP as GP import qualified OpenCascade.GP.GTrsf as GP.GTrsf import qualified OpenCascade.GP.Ax1 as GP.Ax1+import qualified OpenCascade.GP.Ax2 as GP.Ax2 import qualified OpenCascade.GP.Dir as GP.Dir import qualified OpenCascade.GP.Vec as GP.Vec import qualified OpenCascade.BRepBuilderAPI.Transform as BRepBuilderAPI.Transform@@ -36,6 +38,8 @@ rotate :: V3 Double -> Double -> a -> a -- | Translate by a vector in 3D space translate :: V3 Double -> a -> a+ -- | Mirror in the plane, which passes through the origin, tangent to the specified vector+ mirror :: V3 Double -> a -> a fromTrsfSolid :: Acquire (Ptr GP.Trsf) -> Solid -> Solid@@ -96,6 +100,16 @@ vec <- GP.Vec.new x y z liftIO $ GP.Trsf.setTranslation trsf vec return trsf++mirrorTrsf :: V3 Double -> Acquire (Ptr GP.Trsf)+mirrorTrsf (V3 x y z) = do+ trsf <- GP.Trsf.new+ dir <- GP.Dir.new x y z+ axis <- GP.xoy+ liftIO $ do + GP.Ax2.setDirection axis dir+ GP.Trsf.setMirrorAboutAx2 trsf axis+ return trsf instance Transformable Solid where scale :: V3 Double -> Solid -> Solid@@ -110,6 +124,9 @@ translate :: V3 Double -> Solid -> Solid translate = fromTrsfSolid . translateTrsf + mirror :: V3 Double -> Solid -> Solid+ mirror = fromTrsfSolid . mirrorTrsf+ instance Transformable Path where scale :: V3 Double -> Path -> Path scale = fromGTrsfPath . scaleTrsf@@ -122,6 +139,9 @@ translate :: V3 Double -> Path -> Path translate = fromTrsfPath . translateTrsf+ + mirror :: V3 Double -> Path -> Path+ mirror = fromTrsfPath . mirrorTrsf instance Transformable (V3 Double) where@@ -137,4 +157,9 @@ translate :: V3 Double -> V3 Double -> V3 Double translate = (+)++ mirror :: V3 Double -> V3 Double -> V3 Double + mirror mirrorVec toMirror = + let nm = normalize mirrorVec+ in toMirror - (2 * (nm `dot` toMirror) *^ nm)
src/Waterfall/TwoD/Transforms.hs view
@@ -6,15 +6,17 @@ , scale2D , uScale2D , translate2D+, mirror2D ) where import Waterfall.TwoD.Internal.Path2D (Path2D (..)) import Linear.V2 (V2 (..))-import Linear ((*^))+import Linear ((*^), normalize, dot) import qualified OpenCascade.GP.Trsf as GP.Trsf import qualified OpenCascade.GP as GP import qualified OpenCascade.GP.GTrsf as GP.GTrsf import qualified OpenCascade.GP.Ax1 as GP.Ax1+import qualified OpenCascade.GP.Ax2 as GP.Ax2 import qualified OpenCascade.GP.Dir as GP.Dir import qualified OpenCascade.GP.Vec as GP.Vec import qualified OpenCascade.BRepBuilderAPI.Transform as BRepBuilderAPI.Transform@@ -35,6 +37,11 @@ uScale2D :: Double -> a -> a -- | Translate by a distance in 2D space translate2D :: V2 Double -> a -> a+ -- | Mirror in the line, which passes through the origin, tangent to the specified vector+ -- + -- Note that in order to maintain consistency with 'Waterfall.Transforms.Transformable',+ -- the mirror is in the line / tangent / to the vector, not in the line / parallel / to the vector+ mirror2D :: V2 Double -> a -> a fromTrsfPath :: Acquire (Ptr GP.Trsf) -> Path2D -> Path2D fromTrsfPath mkTrsf (Path2D run) = Path2D $ do @@ -93,6 +100,16 @@ vec <- GP.Vec.new x y 0 liftIO $ GP.Trsf.setTranslation trsf vec return trsf+ +mirrorTrsf :: V2 Double -> Acquire (Ptr GP.Trsf)+mirrorTrsf (V2 x y) = do + trsf <- GP.Trsf.new+ dir <- GP.Dir.new x y 0+ axis <- GP.xoy+ liftIO $ do+ GP.Ax2.setDirection axis dir+ GP.Trsf.setMirrorAboutAx2 trsf axis+ return trsf instance Transformable2D Path2D where rotate2D :: Double -> Path2D -> Path2D@@ -107,7 +124,11 @@ translate2D :: V2 Double -> Path2D -> Path2D translate2D = fromTrsfPath .translateTrsf + mirror2D :: V2 Double -> Path2D -> Path2D+ mirror2D = fromTrsfPath . mirrorTrsf+ + instance Transformable2D Shape where rotate2D :: Double -> Shape -> Shape rotate2D = fromTrsfShape . rotateTrsf @@ -121,6 +142,9 @@ translate2D :: V2 Double -> Shape -> Shape translate2D = fromTrsfShape .translateTrsf + mirror2D :: V2 Double -> Shape -> Shape+ mirror2D = fromTrsfShape . mirrorTrsf+ instance Transformable2D (V2 Double) where scale2D :: V2 Double -> V2 Double -> V2 Double scale2D = (*)@@ -137,3 +161,8 @@ translate2D :: V2 Double -> V2 Double -> V2 Double translate2D = (+)++ mirror2D :: V2 Double -> V2 Double -> V2 Double + mirror2D mirrorVec toMirror = + let nm = normalize mirrorVec+ in toMirror - (2 * (nm `dot` toMirror) *^ nm)
waterfall-cad.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: waterfall-cad-version: 0.1.1.1+version: 0.1.2.1 synopsis: Declarative CAD/Solid Modeling Library description: Please see the README on GitHub at <https://github.com/joe-warren/opencascade-hs#readme> category: Graphics