context-free-art 0.2.0.3 → 0.3.0.0
raw patch · 16 files changed
+386/−291 lines, 16 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Art.ContextFree: Circle :: Float -> Symbol
- Art.ContextFree: Color :: String -> Modifier
- Art.ContextFree: Mod :: [Modifier] -> Symbol -> Symbol
- Art.ContextFree: Move :: Vec -> Modifier
- Art.ContextFree: NonTerminal :: NonEmpty Production -> Symbol
- Art.ContextFree: Poly :: [Vec] -> Symbol
- Art.ContextFree: Rotate :: Float -> Modifier
- Art.ContextFree: Scale :: Float -> Modifier
- Art.ContextFree: data Modifier
- Art.ContextFree: data Symbol
- Art.ContextFree: interpret :: Symbol -> IO Svg
- Art.ContextFree: type Production = (Float, Symbol)
- Art.ContextFree: type Vec = (Float, Float)
+ Art.ContextFree.Definite: Branch :: NonEmpty Symbol -> Symbol
+ Art.ContextFree.Definite: Circle :: Float -> Symbol
+ Art.ContextFree.Definite: Color :: String -> Modifier
+ Art.ContextFree.Definite: Mod :: [Modifier] -> Symbol -> Symbol
+ Art.ContextFree.Definite: Move :: Vec -> Modifier
+ Art.ContextFree.Definite: Poly :: [Vec] -> Symbol
+ Art.ContextFree.Definite: Rotate :: Float -> Modifier
+ Art.ContextFree.Definite: Scale :: Float -> Modifier
+ Art.ContextFree.Definite: data Modifier
+ Art.ContextFree.Definite: data Symbol
+ Art.ContextFree.Definite: render :: Symbol -> Svg
+ Art.ContextFree.Definite: type Vec = (Float, Float)
+ Art.ContextFree.Probabilistic: Circle :: Float -> Symbol
+ Art.ContextFree.Probabilistic: Color :: String -> Modifier
+ Art.ContextFree.Probabilistic: Mod :: [Modifier] -> Symbol -> Symbol
+ Art.ContextFree.Probabilistic: Move :: Vec -> Modifier
+ Art.ContextFree.Probabilistic: NonTerminal :: NonEmpty Production -> Symbol
+ Art.ContextFree.Probabilistic: Poly :: [Vec] -> Symbol
+ Art.ContextFree.Probabilistic: Rotate :: Float -> Modifier
+ Art.ContextFree.Probabilistic: Scale :: Float -> Modifier
+ Art.ContextFree.Probabilistic: data Modifier
+ Art.ContextFree.Probabilistic: data Symbol
+ Art.ContextFree.Probabilistic: render :: Symbol -> IO (Maybe Svg)
+ Art.ContextFree.Probabilistic: type Vec = (Float, Float)
Files
- Art/ContextFree.hs +0/−22
- Art/ContextFree/Definite.hs +22/−0
- Art/ContextFree/Definite/Grammar.hs +21/−0
- Art/ContextFree/Definite/Render.hs +123/−0
- Art/ContextFree/Geometry.hs +33/−0
- Art/ContextFree/Modifier.hs +10/−0
- Art/ContextFree/Probabilistic.hs +22/−0
- Art/ContextFree/Probabilistic/Grammar.hs +26/−0
- Art/ContextFree/Probabilistic/Render.hs +36/−0
- Art/ContextFree/Util.hs +13/−0
- Art/Geometry.hs +0/−33
- Art/Grammar.hs +0/−32
- Art/Interpreter.hs +0/−140
- Art/Util.hs +0/−13
- Tests.hs +15/−14
- context-free-art.cabal +65/−37
− Art/ContextFree.hs
@@ -1,22 +0,0 @@-{-|-Module : Art.ContextFree-Description : Generate art from context-free grammars-Copyright : (c) Owen Shepherd, 2019-License : BSD-3-Clause-Maintainer : 414owen@gmail.com-Stability : experimental--Create art via context free grammar production rules.--}--module Art.ContextFree- ( Modifier(..)- , Symbol(..)- , Vec- , Production- , interpret- ) where--import Art.Grammar-import Art.Interpreter-import Art.Geometry
+ Art/ContextFree/Definite.hs view
@@ -0,0 +1,22 @@+{-|+Module : Art.ContextFree.Definite+Description : Generate art from definite context-free grammars+Copyright : (c) Owen Shepherd, 2019+License : BSD-3-Clause+Maintainer : 414owen@gmail.com+Stability : experimental++Create art via definite context free grammar production rules.+-}++module Art.ContextFree.Definite+ ( Modifier(..)+ , Symbol(..)+ , Vec+ , render+ ) where++import Art.ContextFree.Definite.Grammar+import Art.ContextFree.Definite.Render+import Art.ContextFree.Geometry+import Art.ContextFree.Modifier
+ Art/ContextFree/Definite/Grammar.hs view
@@ -0,0 +1,21 @@+module Art.ContextFree.Definite.Grammar where++import Data.List.NonEmpty+import Art.ContextFree.Modifier+import Art.ContextFree.Geometry (Vec)++-- | A terminal or non-terminal symbol.+data Symbol++ -- | A non-terminal symbol.+ = Branch (NonEmpty Symbol)++ -- | Apply modifications to sub-productions.+ | Mod [Modifier] Symbol++ -- | Produce a circle with a radius.+ | Circle Float++ -- | Produce a polygon by relative points.+ -- Starts and ends at (0, 0).+ | Poly [Vec]
+ Art/ContextFree/Definite/Render.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE FlexibleInstances #-}++module Art.ContextFree.Definite.Render ( render ) where++import Data.List+import Data.List.NonEmpty hiding (reverse)+import Data.Maybe+import Text.Blaze+import Text.Blaze.Svg11 ((!))+import qualified Text.Blaze.Svg11 as S+import qualified Text.Blaze.Svg11.Attributes as A++import Art.ContextFree.Geometry+import Art.ContextFree.Definite.Grammar+import Art.ContextFree.Modifier+import Art.ContextFree.Util++type Bound = (Float, Float, Float, Float)+type Res = (Bound, S.Svg)+type State = Vec++combineBounds :: [Bound] -> Bound+combineBounds bounds =+ let (x1, y1, x2, y2) = unzip4 bounds+ in (minimum x1, minimum y1, maximum x2, maximum y2)++-- pos, path+poly :: State -> [Vec] -> Res+poly pos pts =+ let newPts = pos : pts+ (x, y) = pos+ (_, b) = foldl nextRes (pos, (x, y, x, y)) newPts+ in (b, S.path ! A.d (toValue $ toPath newPts))+ where+ nextRes ((x, y), b) (dx, dy)+ = let (i, j) = (x + dx, y + dy)+ in ( (i, j)+ , combineBounds [b, (i, j, i, j)]+ )++-- rad, pos+circle :: Float -> Vec -> Res+circle rad (x, y)+ = ( (x - rad, y - rad, x + rad, y + rad)+ , S.circle+ ! A.r (toValue rad)+ ! A.cx (toValue x)+ ! A.cy (toValue y))++modifyGroup :: Modifier -> Maybe (S.Svg -> S.Svg)+modifyGroup = \case+ Color c -> Just (! A.fill (toValue c))+ _ -> Nothing++modifyState :: State -> Modifier -> State+modifyState pos = \case+ Move p -> addVecs pos p+ _ -> pos++modifySubs :: Modifier -> Symbol -> Symbol+modifySubs (Move _) subs = subs+modifySubs (Scale s) (Circle r) = Circle $ s * r+modifySubs (Scale s) (Poly vs) = Poly $ scaleVec s <$> vs+modifySubs (Rotate r) (Poly vs) = Poly $ rotateZero r <$> vs+modifySubs m (Branch prods)+ = Branch $ modifySubs m <$> prods+modifySubs mo (Mod ms a)+ = Mod (modifyMod mo <$> ms) $ modifySubs mo a+ where+ modifyMod (Scale s) (Move m) = Move $ scaleVec s m+ modifyMod (Rotate r) (Move m) = Move $ rotateZero r m+ modifyMod _ m = m+modifySubs _ subs = subs++joinRes :: Res -> Res -> Res+joinRes (b1, s1) (b2, s2) = (combineBounds [b1, b2], s1 >> s2)++sequenceRes :: Traversable t => Res -> t Res -> Res+sequenceRes = foldl joinRes++renderSymbol :: State -> Symbol -> Res+renderSymbol state = \case+ Branch (x :| []) -> renderSymbol state x+ Branch (x :| (y: ys)) ->+ sequenceRes (renderSymbol state x) (renderSymbol state <$> (y : ys))+ Circle r -> circle r state+ Poly pts -> poly state pts+ Mod [] sym -> renderSymbol state sym+ Mod ms sym ->+ let groupMods = catMaybes $ modifyGroup <$> ms+ ed = if null groupMods then id else foldl (flip fmap) S.g groupMods+ sub = renderMods state ms sym+ in ed <$> sub+ where+ renderMods state' [] sym = renderSymbol state' sym+ renderMods state' (m : ms) sym =+ let newState = modifyState state' m+ newMods = modifySubs m $ Mod ms sym+ in renderSymbol newState newMods++fourTupLst :: (a, a, a, a) -> [a]+fourTupLst (a, b, c, d) = [a, b, c, d]++toSVG :: Bound -> S.Svg -> S.Svg+toSVG bound+ = S.docTypeSvg+ ! A.version "1.1"+ ! A.viewbox (toValue $ unwords $ show <$> fourTupLst bound)++boundsToViewBox :: Bound -> Bound+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'.+render :: Symbol -> S.Svg+render sym =+ finalise $ renderSymbol (0, 0) sym+ where+ finalise :: Res -> S.Svg+ finalise (bounds, svg) = toSVG (boundsToViewBox bounds) svg
+ Art/ContextFree/Geometry.hs view
@@ -0,0 +1,33 @@+module Art.ContextFree.Geometry where++import Data.Biapplicative++-- | A vector in 2d euclidian space.+type Vec = (Float, Float)++both :: (a -> b) -> (a, a) -> (b, b)+both f (a, b) = (f a, f b)++addVecs :: Vec -> Vec -> Vec+addVecs = biliftA2 (+) (+)++reflectVec :: Vec -> Vec+reflectVec = both negate++subVecs :: Vec -> Vec -> Vec+subVecs v1 v2 = addVecs v1 $ reflectVec v2++scaleVec :: Float -> Vec -> Vec+scaleVec n = both (* n)++radDegRatio :: Float+radDegRatio = pi / 180++degToRad :: Float -> Float+degToRad = (* radDegRatio)++rotateZero :: Float -> Vec -> Vec+rotateZero amtd (x, y)+ = (x * cos amt - y * sin amt, y * cos amt + x * sin amt)+ where+ amt = degToRad amtd
+ Art/ContextFree/Modifier.hs view
@@ -0,0 +1,10 @@+module Art.ContextFree.Modifier where++import Art.ContextFree.Geometry (Vec)++-- | Change the style applied to all downstream terminal symbols.+data Modifier+ = Color String+ | Scale Float+ | Move Vec+ | Rotate Float
+ Art/ContextFree/Probabilistic.hs view
@@ -0,0 +1,22 @@+{-|+Module : Art.ContextFree.Probabilistic+Description : Generate art from probabilistic context-free grammars+Copyright : (c) Owen Shepherd, 2019+License : BSD-3-Clause+Maintainer : 414owen@gmail.com+Stability : experimental++Create art via probabilistic context free grammar production rules.+-}++module Art.ContextFree.Probabilistic+ ( Modifier(..)+ , Symbol(..)+ , Vec+ , render+ ) where++import Art.ContextFree.Probabilistic.Grammar+import Art.ContextFree.Probabilistic.Render+import Art.ContextFree.Geometry+import Art.ContextFree.Modifier
+ Art/ContextFree/Probabilistic/Grammar.hs view
@@ -0,0 +1,26 @@+module Art.ContextFree.Probabilistic.Grammar where++import Data.List.NonEmpty+import Art.ContextFree.Modifier+import Art.ContextFree.Geometry (Vec)++-- | 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, 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++ -- | Produce a polygon by relative points.+ -- Starts and ends at (0, 0).+ | Poly [Vec]
+ Art/ContextFree/Probabilistic/Render.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE LambdaCase #-} ++module Art.ContextFree.Probabilistic.Render ( render ) where++import Data.List.NonEmpty+import Data.Maybe+import System.Random+import qualified Art.ContextFree.Definite.Grammar as DG+import qualified Art.ContextFree.Definite.Render as DR+import qualified Art.ContextFree.Probabilistic.Grammar as PG+import qualified Text.Blaze.Svg11 as S++in100 :: Int -> Int+in100 = (`mod` 100) . abs++applyProb :: (Float, PG.Symbol) -> IO (Maybe DG.Symbol)+applyProb (n, g) = randomIO >>= toSym+ where+ toSym num = if in100 num < round n then convert g else pure Nothing++pureJ :: a -> IO (Maybe a)+pureJ = pure . Just++convert :: PG.Symbol -> IO (Maybe DG.Symbol)+convert (PG.NonTerminal syms)+ = let convertsM = (sequence $ applyProb <$> toList syms) :: IO [Maybe DG.Symbol]+ converts = (catMaybes <$> convertsM) :: IO [DG.Symbol]+ in converts >>= \case+ [] -> pure Nothing+ (s : ss) -> pureJ $ DG.Branch $ s :| ss+convert (PG.Mod mods sym) = fmap (DG.Mod mods) <$> convert sym+convert (PG.Circle r) = pureJ $ DG.Circle r+convert (PG.Poly vecs) = pureJ $ DG.Poly vecs++render :: PG.Symbol -> IO (Maybe S.Svg)+render sym = fmap DR.render <$> convert sym
+ Art/ContextFree/Util.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE OverloadedStrings #-}++module Art.ContextFree.Util where++import qualified Data.Text as T+import TextShow+import Art.ContextFree.Geometry++tupLst :: (a, a) -> [a]+tupLst (a, b) = [a, b]++toPath :: [Vec] -> T.Text+toPath pts = T.intercalate " l" (T.unwords . tupLst . both showt <$> pts) <> "Z"
− Art/Geometry.hs
@@ -1,33 +0,0 @@-module Art.Geometry where--import Data.Biapplicative---- | A vector in 2d euclidian space.-type Vec = (Float, Float)--both :: (a -> b) -> (a, a) -> (b, b)-both f (a, b) = (f a, f b)--addVecs :: Vec -> Vec -> Vec-addVecs = biliftA2 (+) (+)--reflectVec :: Vec -> Vec-reflectVec = both negate--subVecs :: Vec -> Vec -> Vec-subVecs v1 v2 = addVecs v1 $ reflectVec v2--scaleVec :: Float -> Vec -> Vec-scaleVec n = both (* n)--radDegRatio :: Float-radDegRatio = pi / 180--degToRad :: Float -> Float-degToRad = (* radDegRatio)--rotateZero :: Float -> Vec -> Vec-rotateZero amtd (x, y)- = (x * cos amt - y * sin amt, y * cos amt + x * sin amt)- where- amt = degToRad amtd
− Art/Grammar.hs
@@ -1,32 +0,0 @@-module Art.Grammar where--import Data.List.NonEmpty-import Art.Geometry---- | Change the style applied to all downstream terminal symbols.-data Modifier- = Color String- | Scale Float- | Move Vec- | Rotate Float---- | 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, 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-- -- | Produce a polygon by relative points.- -- Starts and ends at (0, 0).- | Poly [Vec]
− Art/Interpreter.hs
@@ -1,140 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE FlexibleInstances #-}--module Art.Interpreter ( interpret ) where--import Control.Arrow-import Data.List-import Data.List.NonEmpty hiding (reverse)-import Data.Maybe-import System.Random-import Text.Blaze-import Text.Blaze.Svg11 ((!))-import qualified Text.Blaze.Svg11 as S-import qualified Text.Blaze.Svg11.Attributes as A--import Art.Geometry-import Art.Grammar-import Art.Util--type Bound = (Float, Float, Float, Float)-type BoundRes = Maybe Bound-type Res = (BoundRes, S.Svg)-type State = Vec--emptyRes :: Res-emptyRes = (Nothing, mempty)--combineBounds :: [BoundRes] -> BoundRes-combineBounds boundsM =- let bounds = catMaybes boundsM- (x1, y1, x2, y2) = unzip4 bounds- in if null bounds then Nothing else- Just (minimum x1, minimum y1, maximum x2, maximum y2)---- pos, path-poly :: State -> [Vec] -> Res-poly pos pts =- let newPts = pos : pts- (x, y) = pos- (_, b) = foldl nextRes (pos, Just (x, y, x, y)) newPts- in (b, S.path ! A.d (toValue $ toPath newPts))- where- nextRes ((x, y), b) (dx, dy)- = let (i, j) = (x + dx, y + dy)- in ( (i, j)- , combineBounds [b, Just (i, j, i, j)]- )---- rad, pos-circle :: Float -> Vec -> Res-circle rad (x, y)- = ( Just (x - rad, y - rad, x + rad, y + rad)- , S.circle- ! A.r (toValue rad)- ! A.cx (toValue x)- ! A.cy (toValue y))--modifyGroup :: Modifier -> Maybe (S.Svg -> S.Svg)-modifyGroup = \case- Color c -> Just (! A.fill (toValue c))- _ -> Nothing--modifyState :: State -> Modifier -> State-modifyState pos = \case- Move p -> addVecs pos p- _ -> pos--modifySubs :: Modifier -> Symbol -> Symbol-modifySubs (Move _) subs = subs-modifySubs (Scale s) (Circle r) = Circle $ s * r-modifySubs (Scale s) (Poly vs) = Poly $ scaleVec s <$> vs-modifySubs (Rotate r) (Poly vs) = Poly $ rotateZero r <$> vs-modifySubs m (NonTerminal prods)- = NonTerminal $ second (modifySubs m) <$> prods-modifySubs mo (Mod ms a)- = Mod (modifyMod mo <$> ms) $ modifySubs mo a- where- modifyMod (Scale s) (Move m) = Move $ scaleVec s m- modifyMod (Rotate r) (Move m) = Move $ rotateZero r m- modifyMod _ m = m-modifySubs _ subs = subs--in100 :: Int -> Int-in100 = (`mod` 100) . abs--joinRes :: Res -> Res -> Res-joinRes (b1, s1) (b2, s2) = (combineBounds [b1, b2], s1 >> s2)--sequenceRes :: (Monad m, Traversable t) => t (m Res) -> m Res-sequenceRes rs = foldl joinRes emptyRes <$> sequence rs--interpretNonTerminal :: State -> Production -> IO Res-interpretNonTerminal state (prob, sym)- = (< prob) . fromIntegral . in100 <$> randomIO- >>= \case- True -> interpretSymbol state sym- False -> pure emptyRes--interpretSymbol :: State -> Symbol -> IO Res-interpretSymbol state = \case- NonTerminal (x :| []) -> interpretNonTerminal state x- NonTerminal (x :| (y: ys)) ->- sequenceRes (interpretNonTerminal state <$> (x :| y : ys))- Circle r -> pure $ circle r state- Poly pts -> pure $ poly state pts- Mod [] sym -> interpretSymbol state sym- Mod ms sym ->- let groupMods = catMaybes $ modifyGroup <$> ms- ed = if null groupMods then id else foldl (flip fmap) S.g groupMods- sub = interpretMods state ms sym- in second ed <$> sub- where- interpretMods state' [] sym = interpretSymbol state' sym- interpretMods state' (m : ms) sym =- let newState = modifyState state' m- newMods = modifySubs m $ Mod ms sym- in interpretSymbol newState newMods--fourTupLst :: (a, a, a, a) -> [a]-fourTupLst (a, b, c, d) = [a, b, c, d]--toSVG :: Bound -> S.Svg -> S.Svg-toSVG bound- = S.docTypeSvg- ! A.version "1.1"- ! A.viewbox (toValue $ unwords $ show <$> fourTupLst bound)--boundsToViewBox :: Bound -> Bound-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 (0, 0) sym- where- finalise :: Res -> S.Svg- finalise (bounds, svg) = toSVG (boundsToViewBox (fromMaybe (0, 0, 0, 0) bounds)) svg
− Art/Util.hs
@@ -1,13 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Art.Util where--import qualified Data.Text as T-import TextShow-import Art.Geometry--tupLst :: (a, a) -> [a]-tupLst (a, b) = [a, b]--toPath :: [Vec] -> T.Text-toPath pts = T.intercalate " l" (T.unwords . tupLst . both showt <$> pts) <> "Z"
Tests.hs view
@@ -8,10 +8,11 @@ import qualified Text.Blaze.Svg11.Attributes as A import Text.Blaze.Svg.Renderer.Text (renderSvg) -import Art.Grammar-import Art.Geometry-import Art.Interpreter-import Art.Util+import Art.ContextFree.Definite.Grammar+import Art.ContextFree.Modifier+import Art.ContextFree.Definite.Render+import Art.ContextFree.Geometry+import Art.ContextFree.Util toSvg :: [Float] -> S.Svg -> S.Svg toSvg bound = S.docTypeSvg@@ -19,9 +20,8 @@ ! A.viewbox (toValue $ unwords $ show <$> bound) testRender :: String -> Symbol -> [Float] -> S.Svg -> Test-testRender desc start bound expected = TestCase $ do- result <- interpret start- assertEqual desc (renderSvg $ toSvg bound expected) (renderSvg result)+testRender desc start bound expected = TestCase $+ assertEqual desc (renderSvg $ toSvg bound expected) (renderSvg $ render start) circle :: Float -> Vec -> S.Svg circle r (x, y)@@ -88,7 +88,7 @@ b = Circle 1 c = Mod [Scale 2, Move (4, 4)] d d = Circle 0.5- e = NonTerminal $ (100, b) :| [(100, c)]+ e = Branch $ b :| [c] rendersPoly :: Test rendersPoly@@ -150,7 +150,7 @@ = testRender "rotate and move" a [0, -1, 2, 3] $ circle 1 (1, 0) >> circle 1 (1, 1) where- a = modif $ NonTerminal $ (100, Circle 1) :| [(100, modif $ Circle 1)]+ a = modif $ Branch $ Circle 1 :| [modif $ Circle 1] modif = Mod [Rotate 90, Move (0, -1)] assertClose :: String -> Float -> Float -> Assertion@@ -171,10 +171,10 @@ testSubVecs = TestCase $ assertEqual "sub vec" (1, 2) $ subVecs (2, 4) (1, 2) +{- svgToText :: Test-svgToText = TestCase $ do- res <- renderSvg <$> interpret (Circle 1)- assertEqual "svg text generation" res $+svgToText = TestCase $+ assertEqual "svg text generation" (renderSvg <$> render (Circle 1)) $ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" <> "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n" <> " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"@@ -182,11 +182,12 @@ <> "xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" " <> "viewBox=\"-1.0 -1.0 2.0 2.0\"><circle r=\"1.0\"" <> " cx=\"0.0\" cy=\"0.0\" /></svg>"+-} tests :: Test tests = TestList- [ svgToText- , rendersCircle+ [ rendersCircle+ -- , svgToText , rendersCircleWithRadius , scaledCircle , translatedCircle
context-free-art.cabal view
@@ -4,7 +4,7 @@ -- http://haskell.org/cabal/users-guide/ name: context-free-art-version: 0.2.0.3+version: 0.3.0.0 synopsis: Generate art from context-free grammars description: .@@ -23,20 +23,40 @@ . == Example .- > import Art.ContextFree+ > import Art.ContextFree.Probabilistic > 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 (Maybe 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+ > graphic1 = render $ Circle 1 > > -- let's create a non-terminal, 'a', which renders a terminal, 'Circle 1'- > -- and has an 85% chance of rendering another circle, placed to its right+ > -- and has an 85% chance of rendering itself, placed to its right > a = NonTerminal $ (100, Circle 1) :| [(85, b)] > b = Mod [Move (2, 0)] a+ .+ > import Art.ContextFree.Definite+ > import Data.List.NonEmpty+ >+ > move = Mod [Move (0, -1.8), Scale 0.8]+ >+ > armN :: Int -> Symbol+ > armN 0 = move $ Circle 1+ > armN n = move $ NonTerminal $+ > Circle 1 :| [Mod [Rotate 10] $ armN (n - 1)]+ >+ > arm :: Symbol+ > arm = armN 20+ >+ > spiral = NonTerminal $+ > Circle 1 :| [arm, Mod [Rotate 120] arm, Mod [Rotate 240] arm]+ .+ The latter produces this graphic:+ .+ <<https://owen.cafe/res/context-free/spiral.svg>> homepage: https://github.com/414owen/context-free-art -- bug-reports:@@ -48,36 +68,44 @@ category: Graphics extra-source-files: CHANGELOG.md -executable tests- main-is: Tests.hs- other-modules: Art.Interpreter- , Art.Geometry- , Art.Grammar- , Art.Util- build-depends: base >= 4.12 && < 5- , blaze-svg >= 0.3.6- , random >= 1.1- , blaze-markup- , bifunctors >= 5.5- , text-show >= 3.8- , text >= 1.2- , HUnit >= 1.6- , safe- ghc-options: -Wall -fwarn-incomplete-patterns- default-language: Haskell2010+test-suite tests+ type: exitcode-stdio-1.0+ main-is: Tests.hs+ other-modules: Art.ContextFree.Geometry+ , Art.ContextFree.Definite.Grammar+ , Art.ContextFree.Probabilistic.Grammar+ , Art.ContextFree.Definite.Render+ , Art.ContextFree.Modifier+ , Art.ContextFree.Probabilistic.Render+ , Art.ContextFree.Util+ build-depends: base >= 4.12 && < 5+ , blaze-svg >= 0.3.6+ , random >= 1.1+ , blaze-markup+ , bifunctors >= 5.5+ , text-show >= 3.8+ , text >= 1.2+ , HUnit >= 1.6+ , safe+ ghc-options: -Wall -fwarn-incomplete-patterns+ default-language: Haskell2010 library- exposed-modules: Art.ContextFree- other-modules: Art.Geometry- , Art.Util- , Art.Interpreter- , Art.Grammar- build-depends: base >= 4.12 && < 5- , blaze-svg >= 0.3.6- , random >= 1.1- , blaze-markup- , bifunctors >= 5.5- , text-show >= 3.8- , text >= 1.2- , safe- default-language: Haskell2010+ exposed-modules: Art.ContextFree.Definite+ , Art.ContextFree.Probabilistic+ other-modules: Art.ContextFree.Geometry+ , Art.ContextFree.Definite.Grammar+ , Art.ContextFree.Probabilistic.Grammar+ , Art.ContextFree.Definite.Render+ , Art.ContextFree.Modifier+ , Art.ContextFree.Probabilistic.Render+ , Art.ContextFree.Util+ build-depends: base >= 4.12 && < 5+ , blaze-svg >= 0.3.6+ , random >= 1.1+ , blaze-markup+ , bifunctors >= 5.5+ , text-show >= 3.8+ , text >= 1.2+ , safe+ default-language: Haskell2010