Rasterific 0.5.0.3 → 0.5.1
raw patch · 8 files changed
+184/−94 lines, 8 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Graphics.Rasterific: class Geometry a where listToPrims = concatMap toPrimitives . toList
+ Graphics.Rasterific: class Primitivable a
+ Graphics.Rasterific: listToPrims :: (Geometry a, Foldable f) => f a -> [Primitive]
+ Graphics.Rasterific: toPrim :: Primitivable a => a -> Primitive
+ Graphics.Rasterific: toPrimitives :: Geometry a => a -> [Primitive]
- Graphics.Rasterific: dashedStroke :: DashPattern -> Float -> Join -> (Cap, Cap) -> [Primitive] -> Drawing px ()
+ Graphics.Rasterific: dashedStroke :: Geometry geom => DashPattern -> Float -> Join -> (Cap, Cap) -> geom -> Drawing px ()
- Graphics.Rasterific: dashedStrokeWithOffset :: Float -> DashPattern -> Float -> Join -> (Cap, Cap) -> [Primitive] -> Drawing px ()
+ Graphics.Rasterific: dashedStrokeWithOffset :: Geometry geom => Float -> DashPattern -> Float -> Join -> (Cap, Cap) -> geom -> Drawing px ()
- Graphics.Rasterific: fill :: [Primitive] -> Drawing px ()
+ Graphics.Rasterific: fill :: Geometry geom => geom -> Drawing px ()
- Graphics.Rasterific: fillWithMethod :: FillMethod -> [Primitive] -> Drawing px ()
+ Graphics.Rasterific: fillWithMethod :: Geometry geom => FillMethod -> geom -> Drawing px ()
- Graphics.Rasterific: stroke :: Float -> Join -> (Cap, Cap) -> [Primitive] -> Drawing px ()
+ Graphics.Rasterific: stroke :: Geometry geom => Float -> Join -> (Cap, Cap) -> geom -> Drawing px ()
- Graphics.Rasterific.Outline: dashedStrokize :: Float -> DashPattern -> StrokeWidth -> Join -> (Cap, Cap) -> [Primitive] -> [[Primitive]]
+ Graphics.Rasterific.Outline: dashedStrokize :: Geometry geom => Float -> DashPattern -> StrokeWidth -> Join -> (Cap, Cap) -> geom -> [[Primitive]]
- Graphics.Rasterific.Outline: strokize :: StrokeWidth -> Join -> (Cap, Cap) -> [Primitive] -> [Primitive]
+ Graphics.Rasterific.Outline: strokize :: Geometry geom => StrokeWidth -> Join -> (Cap, Cap) -> geom -> [Primitive]
Files
- Rasterific.cabal +3/−3
- changelog +5/−0
- docimages/sampled_texture_reflect.png binary
- exec-src/docImageGenerator.hs +45/−36
- src/Graphics/Rasterific.hs +28/−21
- src/Graphics/Rasterific/Outline.hs +6/−6
- src/Graphics/Rasterific/StrokeInternal.hs +11/−11
- src/Graphics/Rasterific/Types.hs +86/−17
Rasterific.cabal view
@@ -1,7 +1,7 @@ -- Initial Rasterific.cabal generated by cabal init. For further -- documentation, see http://haskell.org/cabal/users-guide/ name: Rasterific -version: 0.5.0.3 +version: 0.5.1 synopsis: A pure haskell drawing engine. -- A longer description of the package. description: @@ -37,7 +37,7 @@ Source-Repository this Type: git Location: git://github.com/Twinside/Rasterific.git - Tag: v0.5.0.3 + Tag: v0.5.1 flag embed_linear description: Embed a reduced version of Linear avoiding a (huge) dep @@ -69,7 +69,7 @@ ghc-options: -O3 -Wall -- -ddump-simpl -ddump-to-file -dsuppress-module-prefixes -dsuppress-uniques - ghc-prof-options: -Wall -prof -auto-all + ghc-prof-options: -Wall -prof default-language: Haskell2010 build-depends: base >= 4.6 && < 4.9 , free >= 4.7
changelog view
@@ -1,5 +1,10 @@ -*-change-log-*- +v0.5.1 March 2015 + * Enhancement: Generalizing geometry description, with automatic + conversion, reducing the need of type constructor from Primitive, + and directly filling Path. + v0.5.0.3 February 2015 * Fix: hackage documentation
docimages/sampled_texture_reflect.png view
binary file changed (64682 → 64813 bytes)
exec-src/docImageGenerator.hs view
@@ -24,7 +24,7 @@ logo :: Int -> Bool -> Vector -> [Primitive] logo size inv offset = - map BezierPrim . bezierFromPath . way $ map (^+^ offset) + toPrimitives . bezierFromPath . way $ map (^+^ offset) [ (V2 0 is) , (V2 0 0) , (V2 is 0) @@ -71,7 +71,7 @@ withTexture accentTexture $ stroke 2 join (CapRound, CapRound) base_stroke where - base_stroke = LinePrim <$> + base_stroke = [ Line (V2 0 200) (V2 100 100) , Line (V2 100 100) (V2 200 200) ] @@ -104,10 +104,25 @@ writePng (outFolder </> "module_example.png") img +arialFont :: FilePath +arialFont = +#ifdef __WIN32__ + "C:/Windows/Fonts/arial.ttf" +#else + "/usr/share/fonts/truetype/msttcorefonts/arial.ttf" +#endif +monospaceFont :: FilePath +monospaceFont = +#ifdef __WIN32__ + "C:/Windows/Fonts/consola.ttf" +#else + "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf" +#endif + textOnPathExample :: IO () textOnPathExample = do - fontErr <- loadFontFile "C:/Windows/Fonts/arial.ttf" + fontErr <- loadFontFile arialFont case fontErr of Left err -> putStrLn err Right font -> @@ -115,8 +130,7 @@ [PathCubicBezierCurveTo (V2 20 20) (V2 170 20) (V2 300 200)] in produceDocImage (outFolder </> "text_on_path.png") $ do - stroke 3 JoinRound (CapStraight 0, CapStraight 0) $ - pathToPrimitives path + stroke 3 JoinRound (CapStraight 0, CapStraight 0) path withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ do withPathOrientation path 0 $ @@ -124,7 +138,7 @@ geometryOnPath :: IO () geometryOnPath = do - fontErr <- loadFontFile "C:/Windows/Fonts/arial.ttf" + fontErr <- loadFontFile arialFont case fontErr of Left err -> putStrLn err Right font -> @@ -132,8 +146,7 @@ let path = Path (V2 100 180) False [PathCubicBezierCurveTo (V2 20 20) (V2 170 20) (V2 300 200)] withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ - stroke 3 JoinRound (CapStraight 0, CapStraight 0) $ - pathToPrimitives path + stroke 3 JoinRound (CapStraight 0, CapStraight 0) path withPathOrientation path 0 $ do printTextAt font (PointSize 24) (V2 0 0) "TX" @@ -144,7 +157,7 @@ textExample :: IO () textExample = do - fontErr <- loadFontFile "C:/Windows/Fonts/arial.ttf" + fontErr <- loadFontFile arialFont case fontErr of Left err -> putStrLn err Right font -> @@ -155,8 +168,8 @@ textMultipleExample :: IO () textMultipleExample = do - eitherFont1 <- loadFontFile "C:/Windows/Fonts/arial.ttf" - eitherFont2 <- loadFontFile "C:/Windows/Fonts/consola.ttf" + eitherFont1 <- loadFontFile arialFont + eitherFont2 <- loadFontFile monospaceFont case (,) <$> eitherFont1 <*> eitherFont2 of Left err -> putStrLn err Right (font1, font2) -> @@ -175,7 +188,7 @@ coordinateSystem :: IO () coordinateSystem = do - fontErr <- loadFontFile "C:/Windows/Fonts/arial.ttf" + fontErr <- loadFontFile arialFont case fontErr of Left err -> putStrLn err Right font -> @@ -186,23 +199,21 @@ white = PixelRGBA8 255 255 255 255 black = PixelRGBA8 0 0 0 255 stroker = stroke 4 JoinRound (CapStraight 0, CapStraight 0) - filler = fill . pathToPrimitives create font = withTexture (uniformTexture black) $ do stroker $ line (V2 10 40) (V2 190 40) stroker $ line (V2 40 10) (V2 40 190) printTextAt font (PointSize 12) (V2 4 37) "(0,0)" printTextAt font (PointSize 12) (V2 100 37) "(width, 0)" printTextAt font (PointSize 12) (V2 57 190) "(0, height)" - filler $ Path (V2 170 30) True + fill $ Path (V2 170 30) True [PathLineTo (V2 195 40), PathLineTo (V2 170 50)] - filler $ Path (V2 30 170) True + fill $ Path (V2 30 170) True [PathLineTo (V2 40 195), PathLineTo (V2 50 170)] fillingSample :: FillMethod -> Drawing px () fillingSample fillMethod = fillWithMethod fillMethod geometry where geometry = transform (applyTransformation $ scale 0.35 0.4 <> translate (V2 (-80) (-180))) - $ concatMap pathToPrimitives [ Path (V2 484 499) True [ PathCubicBezierCurveTo (V2 681 452) (V2 639 312) (V2 541 314) , PathCubicBezierCurveTo (V2 327 337) (V2 224 562) (V2 484 499) @@ -298,18 +309,16 @@ produceDocImage (outFolder </> "strokize_path.png") $ stroke 3 (JoinMiter 0) (CapStraight 0, CapStraight 0) $ - strokize 40 JoinRound (CapRound, CapRound) - [CubicBezierPrim $ - CubicBezier (V2 40 160) (V2 40 40) - (V2 160 40) (V2 160 160)] + strokize 40 JoinRound (CapRound, CapRound) $ + CubicBezier (V2 40 160) (V2 40 40) + (V2 160 40) (V2 160 160) produceDocImage (outFolder </> "strokize_dashed_path.png") $ mapM_ (stroke 3 (JoinMiter 0) (CapStraight 0, CapStraight 0)) $ dashedStrokize 0 [10, 5] 40 JoinRound (CapStraight 0, CapStraight 0) - [CubicBezierPrim $ - CubicBezier (V2 40 160) (V2 40 40) - (V2 160 40) (V2 160 160)] + [CubicBezier (V2 40 160) (V2 40 40) + (V2 160 40) (V2 160 160)] produceDocImage (outFolder </> "with_clipping.png") $ withClipping (fill $ circle (V2 100 100) 75) $ @@ -356,28 +365,28 @@ produceDocImage (outFolder </> "cubic_bezier.png") $ stroke 5 JoinRound (CapRound, CapRound) $ - [CubicBezierPrim $ CubicBezier (V2 0 10) (V2 205 250) - (V2 (-10) 250) (V2 160 35)] + CubicBezier (V2 0 10) (V2 205 250) + (V2 (-10) 250) (V2 160 35) produceDocImage (outFolder </> "quadratic_bezier.png") $ - fill $ BezierPrim <$> [Bezier (V2 10 10) (V2 200 50) (V2 200 100) - ,Bezier (V2 200 100) (V2 150 200) (V2 120 175) - ,Bezier (V2 120 175) (V2 30 100) (V2 10 10)] + fill [ Bezier (V2 10 10) (V2 200 50) (V2 200 100) + , Bezier (V2 200 100) (V2 150 200) (V2 120 175) + , Bezier (V2 120 175) (V2 30 100) (V2 10 10)] produceDocImage (outFolder </> "simple_line.png") $ - fill $ LinePrim <$> [ Line (V2 10 10) (V2 190 10) - , Line (V2 190 10) (V2 95 170) - , Line (V2 95 170) (V2 10 10)] + fill [ Line (V2 10 10) (V2 190 10) + , Line (V2 190 10) (V2 95 170) + , Line (V2 95 170) (V2 10 10) ] produceDocImage (outFolder </> "primitive_mixed.png") $ fill - [ CubicBezierPrim $ CubicBezier (V2 50 20) (V2 90 60) - (V2 5 100) (V2 50 140) - , LinePrim $ Line (V2 50 140) (V2 120 80) - , LinePrim $ Line (V2 120 80) (V2 50 20) ] + [ toPrim $ CubicBezier (V2 50 20) (V2 90 60) + (V2 5 100) (V2 50 140) + , toPrim $ Line (V2 50 140) (V2 120 80) + , toPrim $ Line (V2 120 80) (V2 50 20) ] produceDocImage (outFolder </> "path_example.png") $ - fill . pathToPrimitives $ Path (V2 50 20) True + fill $ Path (V2 50 20) True [ PathCubicBezierCurveTo (V2 90 60) (V2 5 100) (V2 50 140) , PathLineTo (V2 120 80) ]
src/Graphics/Rasterific.hs view
@@ -77,6 +77,12 @@ , Primitive( .. ) , Path( .. ) , PathCommand( .. ) + + -- * Generic geometry description + , Primitivable( .. ) + , Geometry( .. ) + + -- * Generic geometry manipulation , Transformable( .. ) , PointFoldable( .. ) , PlaneBoundable( .. ) @@ -116,7 +122,6 @@ -- * Debugging helper , dumpDrawing - ) where #if !MIN_VERSION_base(4,8,0) @@ -188,8 +193,7 @@ -- -- > let path = Path (V2 100 180) False -- > [PathCubicBezierCurveTo (V2 20 20) (V2 170 20) (V2 300 200)] in --- > stroke 3 JoinRound (CapStraight 0, CapStraight 0) $ --- > pathToPrimitives path +-- > stroke 3 JoinRound (CapStraight 0, CapStraight 0) path -- > withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ -- > withPathOrientation path 0 $ -- > printTextAt font (PointSize 24) (V2 0 0) "Text on path" @@ -205,8 +209,7 @@ -- > let path = Path (V2 100 180) False -- > [PathCubicBezierCurveTo (V2 20 20) (V2 170 20) (V2 300 200)] -- > withTexture (uniformTexture $ PixelRGBA8 0 0 0 255) $ --- > stroke 3 JoinRound (CapStraight 0, CapStraight 0) $ --- > pathToPrimitives path +-- > stroke 3 JoinRound (CapStraight 0, CapStraight 0) path -- > -- > withPathOrientation path 0 $ do -- > printTextAt font (PointSize 24) (V2 0 0) "TX" @@ -234,15 +237,16 @@ -- -- <<docimages/fill_circle.png>> -- -fill :: [Primitive] -> Drawing px () -fill prims = liftF $ Fill FillWinding prims () +fill :: Geometry geom => geom -> Drawing px () +fill prims = liftF $ Fill FillWinding (toPrimitives prims) () -- | This function let you choose how to fill the primitives -- in case of self intersection. See `FillMethod` documentation -- for more information. -fillWithMethod :: FillMethod -> [Primitive] -> Drawing px () +fillWithMethod :: Geometry geom + => FillMethod -> geom -> Drawing px () fillWithMethod method prims = - liftF $ Fill method prims () + liftF $ Fill method (toPrimitives prims) () -- | Draw some geometry using a clipping path. -- @@ -268,13 +272,14 @@ -- -- <<docimages/stroke_circle.png>> -- -stroke :: Float -- ^ Stroke width +stroke :: (Geometry geom) + => Float -- ^ Stroke width -> Join -- ^ Which kind of join will be used -> (Cap, Cap) -- ^ Start and end capping. - -> [Primitive] -- ^ List of elements to render + -> geom -- ^ List of elements to render -> Drawing px () stroke width join caping prims = - liftF $ Stroke width join caping prims () + liftF $ Stroke width join caping (toPrimitives prims) () -- | Draw a string at a given position. -- Text printing imply loading a font, there is no default @@ -490,17 +495,18 @@ -- | With stroke geometry with a given stroke width, using -- a dash pattern. -- --- > dashedStroke [5, 10, 5] 3 JoinRound (CapRound, CapStraight 0) --- > [line (V2 0 100) (V2 200 100)] +-- > dashedStroke [5, 10, 5] 3 JoinRound (CapRound, CapStraight 0) $ +-- > line (V2 0 100) (V2 200 100) -- -- <<docimages/dashed_stroke.png>> -- dashedStroke - :: DashPattern -- ^ Dashing pattern to use for stroking + :: Geometry geom + => DashPattern -- ^ Dashing pattern to use for stroking -> Float -- ^ Stroke width -> Join -- ^ Which kind of join will be used -> (Cap, Cap) -- ^ Start and end capping. - -> [Primitive] -- ^ List of elements to render + -> geom -- ^ List of elements to render -> Drawing px () dashedStroke = dashedStrokeWithOffset 0.0 @@ -508,23 +514,24 @@ -- a dash pattern. The offset is there to specify the starting -- point into the pattern, the value can be negative. -- --- > dashedStrokeWithOffset 3 [5, 10, 5] 3 JoinRound (CapRound, CapStraight 0) --- > [line (V2 0 100) (V2 200 100)] +-- > dashedStrokeWithOffset 3 [5, 10, 5] 3 JoinRound (CapRound, CapStraight 0) $ +-- > line (V2 0 100) (V2 200 100) -- -- <<docimages/dashed_stroke_with_offset.png>> -- dashedStrokeWithOffset - :: Float -- ^ Starting offset + :: Geometry geom + => Float -- ^ Starting offset -> DashPattern -- ^ Dashing pattern to use for stroking -> Float -- ^ Stroke width -> Join -- ^ Which kind of join will be used -> (Cap, Cap) -- ^ Start and end capping. - -> [Primitive] -- ^ List of elements to render + -> geom -- ^ List of elements to render -> Drawing px () dashedStrokeWithOffset _ [] width join caping prims = stroke width join caping prims dashedStrokeWithOffset offset dashing width join caping prims = - liftF $ DashedStroke offset dashing width join caping prims () + liftF $ DashedStroke offset dashing width join caping (toPrimitives prims) () -- | Generate a list of primitive representing a circle. --
src/Graphics/Rasterific/Outline.hs view
@@ -14,17 +14,17 @@ -- given a path. You can then stroke it. -- -- > stroke 3 (JoinMiter 0) (CapStraight 0, CapStraight 0) $ --- > strokize 40 JoinRound (CapRound, CapRound) --- > [CubicBezierPrim $ --- > CubicBezier (V2 40 160) (V2 40 40) --- > (V2 160 40) (V2 160 160)] +-- > strokize 40 JoinRound (CapRound, CapRound) $ +-- > CubicBezier (V2 40 160) (V2 40 40) +-- > (V2 160 40) (V2 160 160) -- -- <<docimages/strokize_path.png>> -- -strokize :: StrokeWidth -- ^ Stroke width +strokize :: Geometry geom + => StrokeWidth -- ^ Stroke width -> Join -- ^ Which kind of join will be used -> (Cap, Cap) -- ^ Start and end capping. - -> [Primitive] -- ^ List of elements to strokize + -> geom -- ^ List of elements to strokize -> [Primitive] strokize w j c = listOfContainer . S.strokize w j c
src/Graphics/Rasterific/StrokeInternal.hs view
@@ -189,13 +189,14 @@ sanitize (BezierPrim b) = sanitizeBezier b sanitize (CubicBezierPrim c) = sanitizeCubicBezier c -strokize :: StrokeWidth -> Join -> (Cap, Cap) -> [Primitive] +strokize :: Geometry geom + => StrokeWidth -> Join -> (Cap, Cap) -> geom -> Container Primitive -strokize width join (capStart, capEnd) beziers = +strokize width join (capStart, capEnd) geom = offseter capEnd sanitized <> offseter capStart (reverse $ reversePrimitive <$> sanitized) where - sanitized = foldMap (listOfContainer . sanitize) beziers + sanitized = foldMap (listOfContainer . sanitize) $ toPrimitives geom offseter = offsetAndJoin (width / 2) join flattenPrimitive :: Primitive -> Container Primitive @@ -280,21 +281,20 @@ -- -- > mapM_ (stroke 3 (JoinMiter 0) (CapStraight 0, CapStraight 0)) $ -- > dashedStrokize 0 [10, 5] --- > 40 JoinRound (CapStraight 0, CapStraight 0) --- > [CubicBezierPrim $ --- > CubicBezier (V2 40 160) (V2 40 40) --- > (V2 160 40) (V2 160 160)] +-- > 40 JoinRound (CapStraight 0, CapStraight 0) $ +-- > CubicBezier (V2 40 160) (V2 40 40) (V2 160 40) (V2 160 160) -- -- <<docimages/strokize_dashed_path.png>> -- -dashedStrokize :: Float -- ^ Starting offset +dashedStrokize :: Geometry geom + => Float -- ^ Starting offset -> DashPattern -- ^ Dashing pattern to use for stroking -> StrokeWidth -- ^ Stroke width -> Join -- ^ Which kind of join will be used -> (Cap, Cap) -- ^ Start and end capping. - -> [Primitive] -- ^ List of elements to transform + -> geom -- ^ Elements to transform -> [[Primitive]] -dashedStrokize offset dashPattern width join capping beziers = +dashedStrokize offset dashPattern width join capping geom = listOfContainer . strokize width join capping - <$> dashize offset dashPattern beziers + <$> dashize offset dashPattern (toPrimitives geom)
src/Graphics/Rasterific/Types.hs view
@@ -12,6 +12,10 @@ , Bezier( .. ) , CubicBezier( .. ) , Primitive( .. ) + + , Primitivable( .. ) + , Geometry( .. ) + , Producer , Container , containerOfList @@ -39,14 +43,16 @@ , lastTangeantOf , firstPointOf , lastPointOf + ) where -import Data.DList( DList, fromList, toList ) +import Data.DList( DList, fromList ) #if !MIN_VERSION_base(4,8,0) import Data.Foldable( Foldable ) #endif -import Data.Foldable( foldl' ) +import Data.Foldable( foldl', toList ) +import qualified Data.Foldable as F import Graphics.Rasterific.Linear( V2( .. ), (^-^), nearZero ) import Foreign.Ptr( castPtr ) @@ -116,7 +122,6 @@ -- > fillingSample fillMethod = fillWithMethod fillMethod geometry where -- > geometry = transform (applyTransformation $ scale 0.35 0.4 -- > <> translate (V2 (-80) (-180))) --- > $ concatMap pathToPrimitives -- > [ Path (V2 484 499) True -- > [ PathCubicBezierCurveTo (V2 681 452) (V2 639 312) (V2 541 314) -- > , PathCubicBezierCurveTo (V2 327 337) (V2 224 562) (V2 484 499) @@ -213,19 +218,21 @@ -- the primitive. foldPoints :: (b -> Point -> b) -> b -> a -> b +-- | Just apply the function instance Transformable Point where {-# INLINE transform #-} transform f = f +-- | Just apply the function instance PointFoldable Point where {-# INLINE foldPoints #-} foldPoints f = f -- | Describe a simple 2D line between two points. -- --- > fill $ LinePrim <$> [ Line (V2 10 10) (V2 190 10) --- > , Line (V2 190 10) (V2 95 170) --- > , Line (V2 95 170) (V2 10 10)] +-- > fill [ Line (V2 10 10) (V2 190 10) +-- > , Line (V2 190 10) (V2 95 170) +-- > , Line (V2 95 170) (V2 10 10)] -- -- <<docimages/simple_line.png>> -- @@ -251,9 +258,9 @@ -- | Describe a quadratic bezier spline, described -- using 3 points. -- --- > fill $ BezierPrim <$> [Bezier (V2 10 10) (V2 200 50) (V2 200 100) --- > ,Bezier (V2 200 100) (V2 150 200) (V2 120 175) --- > ,Bezier (V2 120 175) (V2 30 100) (V2 10 10)] +-- > fill [Bezier (V2 10 10) (V2 200 50) (V2 200 100) +-- > ,Bezier (V2 200 100) (V2 150 200) (V2 120 175) +-- > ,Bezier (V2 120 175) (V2 30 100) (V2 10 10)] -- -- <<docimages/quadratic_bezier.png>> -- @@ -286,8 +293,7 @@ -- using 4 points. -- -- > stroke 4 JoinRound (CapRound, CapRound) $ --- > [CubicBezierPrim $ CubicBezier (V2 0 10) (V2 205 250) --- > (V2 (-10) 250) (V2 160 35)] +-- > CubicBezier (V2 0 10) (V2 205 250) (V2 (-10) 250) (V2 160 35) -- -- <<docimages/cubic_bezier.png>> -- @@ -325,11 +331,10 @@ -- on some specific algorithms. You can mix the different -- primitives in a single call : -- --- > fill --- > [ CubicBezierPrim $ CubicBezier (V2 50 20) (V2 90 60) --- > (V2 5 100) (V2 50 140) --- > , LinePrim $ Line (V2 50 140) (V2 120 80) --- > , LinePrim $ Line (V2 120 80) (V2 50 20) ] +-- > fill [ toPrim $ CubicBezier (V2 50 20) (V2 90 60) +-- > (V2 5 100) (V2 50 140) +-- > , toPrim $ Line (V2 50 140) (V2 120 80) +-- > , toPrim $ Line (V2 120 80) (V2 50 20) ] -- -- <<docimages/primitive_mixed.png>> -- @@ -339,6 +344,70 @@ | CubicBezierPrim !CubicBezier -- ^ Primitive used for cubic bezier curve deriving (Eq, Show) +-- | Generalizing constructors of the `Primitive` type to work +-- generically. +class Primitivable a where + toPrim :: a -> Primitive + +-- | @toPrim = id@ +instance Primitivable Primitive where toPrim = id + +-- | @toPrim = LinePrim@ +instance Primitivable Line where toPrim = LinePrim + +-- | @toPrim = BezierPrim@ +instance Primitivable Bezier where toPrim = BezierPrim + +-- | @toPrim = CubicBezierPrim@ +instance Primitivable CubicBezier where toPrim = CubicBezierPrim + +-- | All the rasterization works on lists of primitives, +-- in order to ease the use of the library, the Geometry +-- type class provides conversion facility, which help +-- generalising the geometry definition and avoid applying +-- Primitive constructor. +-- +-- Also streamline the Path conversion. +class Geometry a where + -- | Convert an element to a list of primitives + -- to be rendered. + toPrimitives :: a -> [Primitive] + + -- | Helper method to avoid overlaping instances. + -- You shouldn't use it directly. + listToPrims :: (Foldable f) => f a -> [Primitive] + {-# INLINE listToPrims #-} + listToPrims = F.concatMap toPrimitives . F.toList + +instance Geometry Path where + {-# INLINE toPrimitives #-} + toPrimitives = pathToPrimitives + +instance Geometry Primitive where + toPrimitives e = [e] + {-# INLINE listToPrims #-} + listToPrims = F.toList -- Open question, is it optimised as `id`? + +instance Geometry Line where + {-# INLINE toPrimitives #-} + toPrimitives e = [toPrim e] + +instance Geometry Bezier where + {-# INLINE toPrimitives #-} + toPrimitives e = [toPrim e] + +instance Geometry CubicBezier where + {-# INLINE toPrimitives #-} + toPrimitives e = [toPrim e] + +-- | Generalize the geometry to any foldable container, +-- so you can throw any container to the the 'fill' or +-- 'stroke' function. +instance (Foldable f, Geometry a) => Geometry (f a) where + {-# INLINE toPrimitives #-} + toPrimitives = listToPrims + + instance Transformable Primitive where {-# INLINE transform #-} transform f (LinePrim l) = LinePrim $ transform f l @@ -378,7 +447,7 @@ -- it for the next "move" -- For example the example from Primitive could be rewritten: -- --- > fill . pathToPrimitives $ Path (V2 50 20) True +-- > fill $ Path (V2 50 20) True -- > [ PathCubicBezierCurveTo (V2 90 60) (V2 5 100) (V2 50 140) -- > , PathLineTo (V2 120 80) ] --