context-free-art 0.1.0.0 → 0.2.0.0
raw patch · 4 files changed
+38/−22 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Art.ContextFree: Mod :: [Modifier] -> Symbol -> Symbol
- Art.ContextFree: type Production = (Float, [Modifier], NonEmpty Symbol)
+ Art.ContextFree: type Production = (Float, Symbol)
Files
- Art/Grammar.hs +7/−2
- Art/Interpreter.hs +7/−4
- Tests.hs +15/−10
- context-free-art.cabal +9/−6
Art/Grammar.hs view
@@ -12,11 +12,16 @@ -- | A production rule, including a starting probability of generation, -- a list of styles to be applied to sub-grammars, and a non-empty list of -- symbols to produce.-type Production = (Float, [Modifier], NonEmpty Symbol)+type Production = (Float, Symbol) --- | A Terminal or non-terminal symbol.+-- | A terminal or non-terminal symbol. data Symbol++ -- | A non-terminal symbol. = NonTerminal (NonEmpty Production)++ -- | Apply modifications to sub-productions.+ | Mod [Modifier] Symbol -- | Produce a circle with a radius. | Circle Float
Art/Interpreter.hs view
@@ -102,12 +102,10 @@ sequenceRes rs = foldl joinRes emptyRes <$> sequence rs interpretNonTerminal :: State -> Production -> IO Res-interpretNonTerminal state prod@(prob, mods, syms)+interpretNonTerminal state prod@(prob, sym) = (< prob) . fromIntegral . in100 <$> randomIO >>= \case- True ->- let (newState, layerMod) = foldMods state mods- in second layerMod <$> sequenceRes (interpretSymbol newState <$> syms)+ True -> interpretSymbol state sym False -> pure emptyRes interpretSymbol :: State -> Symbol -> IO Res@@ -118,6 +116,9 @@ sequenceRes (interpretNonTerminal state <$> (x :| y : ys)) Circle r -> pure $ circle (r * scale) pos Poly pts -> pure $ poly state pts+ Mod mods sym ->+ let (newState, layerMod) = foldMods state mods+ in second layerMod <$> interpretSymbol newState sym fourTupLst :: (a, a, a, a) -> [a] fourTupLst (a, b, c, d) = [a, b, c, d]@@ -132,6 +133,8 @@ boundsToViewBox (x1, y1, x2, y2) = (x1, y1, x2 - x1, y2 - y1) -- | Create a drawing from a grammar.+-- In order to get a string representation, you'll need to use one of+-- blaze-svg's render functions, for example 'renderSvg'. interpret :: Symbol -> IO S.Svg interpret sym = finalise <$> interpretSymbol emptyState sym
Tests.hs view
@@ -51,38 +51,39 @@ = testRender "translated circle" a [5, 5, 2, 2] $ circle 1 (6, 6) where- a = NonTerminal $ (100, [Move (6, 6)], b :| []) :| []+ a = Mod [Move (6, 6)] b b = Circle 1 scaledCircle = testRender "scaled circle" a [-0.5, -0.5, 1, 1] $ circle 0.5 (0, 0) where- a = NonTerminal $ (100, [Scale 0.5], b :| []) :| []+ a = Mod [Scale 0.5] b b = Circle 1 translatedScaledCircle = testRender "translated scaled circle" a [10, 10, 4, 4] $ circle 2 (12, 12) where- a = NonTerminal $ (100, [Scale 2, Move (6, 6)], b :| []) :| []+ a = Mod [Scale 2, Move (6, 6)] b b = Circle 1 scaledTranslatedCircle = testRender "scaled translated circle" a [4, 4, 4, 4] $ circle 2 (6, 6) where- a = NonTerminal $ (100, [Move (6, 6), Scale 2], b :| []) :| []+ a = Mod [Move (6, 6), Scale 2] b b = Circle 1 multipleScaledTranslatedCircles = testRender "multiple symbols under one non-terminal" a [10, 10, 20, 20] $ circle 2 (12, 12) >> circle 2 (28, 28) where- a = NonTerminal $ (100, [Scale 2, Move (6, 6)], b :| [c]) :| []+ a = Mod [Scale 2, Move (6, 6)] e b = Circle 1- c = NonTerminal $ (100, [Scale 2, Move (4, 4)], d :| []) :| []+ c = Mod [Scale 2, Move (4, 4)] d d = Circle 0.5+ e = NonTerminal $ (100, b) :| [(100, c)] rendersPoly = testRender "poly" a [0, 0, 2, 1]@@ -94,25 +95,29 @@ = testRender "translated poly" a [1, 1, 3, 2] $ path [(1, 1), (1, 1), (1, 0)] where- a = NonTerminal $ (100, [Move (1, 1)], Poly [(1, 1), (1, 0)] :| []) :| []+ a = Mod [Move (1, 1)] b+ b = Poly [(1, 1), (1, 0)] rendersPolyScaled = testRender "scaled poly" a [0, -3, 6, 6] $ path [(0, 0), (3, 3), (3, -6)] where- a = NonTerminal $ (100, [Scale 3], Poly [(1, 1), (1, -2)] :| []) :| []+ a = Mod [Scale 3] b+ b = Poly [(1, 1), (1, -2)] rendersPolyScaled2 = testRender "another scaled poly" a [-4, 0, 4, 4] $ path [(0, 0), (-4, 4), (2, -4)] where- a = NonTerminal $ (100, [Scale 2], Poly [(-2, 2), (1, -2)] :| []) :| []+ a = Mod [Scale 2] b+ b = Poly [(-2, 2), (1, -2)] fill = testRender "another scaled poly" a [-1, -1, 2, 2] $ S.g ! A.fill "green" $ circle 1 (0, 0) where- a = NonTerminal $ (100, [Color "green"], Circle 1 :| []) :| []+ a = Mod [Color "green"] b+ b = Circle 1 svgToText = TestCase $ do res <- renderSvg <$> interpret (Circle 1)
context-free-art.cabal view
@@ -4,7 +4,7 @@ -- http://haskell.org/cabal/users-guide/ name: context-free-art-version: 0.1.0.0+version: 0.2.0.0 synopsis: Generate art from context-free grammars description: .@@ -27,16 +27,19 @@ > import Art.ContextFree > import Data.List.NonEmpty >- > -- let's define a Production rule+ > -- Let's define a Production rule > a = Circle 1 >- > -- this will produce an IO Svg from the blaze-svg package+ > -- This will produce an IO Svg from the blaze-svg package > -- to turn it into a string we can use one of the `blaze-svg` renderers > graphic1 = interpret $ Circle 1 >- > -- let's create a non-terminal, at every layer,- > -- this will have an 85% chance of rendering another circle- > circles = NonTerminal $ (85, [Move (2, 0)], Circle 1 :| [circles]) :| []+ > -- Let's create a non-terminal.+ > -- At every layer, this will have an 85% chance+ > -- of rendering another circle+ > a = Mod [Move (2, 0)] b+ > b = NonTerminal $ (85, c) :| []+ > c = NonTerminal $ (100, Circle 1) :| [(100, a)] homepage: https://github.com/414owen/context-free-art -- bug-reports: