packages feed

diagrams-contrib 0.1.1.1 → 0.6

raw patch · 12 files changed

+774/−276 lines, 12 filesdep +HUnitdep +QuickCheckdep +lensdep ~basedep ~containersdep ~data-defaultPVP ok

version bump matches the API change (PVP)

Dependencies added: HUnit, QuickCheck, lens, test-framework, test-framework-hunit, test-framework-quickcheck2

Dependency ranges changed: base, containers, data-default, diagrams-lib, force-layout

API changes (from Hackage documentation)

- Diagrams.TwoD.Path.Turtle.Aliases: fd, rt, lt, bk :: Double -> Turtle ()
- Diagrams.TwoD.Path.Turtle.Aliases: pu, pd :: Turtle ()
- Diagrams.TwoD.Tilings: rt2, rt6, rt3 :: Q236
- Diagrams.TwoD.Tilings: t33434, t33336R, t33336L, t33344 :: Tiling
+ Diagrams.TwoD.Layout.Tree: renderTree' :: Monoid' m => (a -> QDiagram b R2 m) -> ((a, P2) -> (a, P2) -> QDiagram b R2 m) -> Tree (a, P2) -> QDiagram b R2 m
+ Diagrams.TwoD.Path.Turtle: setPenColor :: Monad m => Colour Double -> TurtleT m ()
+ Diagrams.TwoD.Path.Turtle: setPenWidth :: Monad m => Double -> TurtleT m ()
+ Diagrams.TwoD.Path.Turtle.Aliases: bk :: Double -> Turtle ()
+ Diagrams.TwoD.Path.Turtle.Aliases: fd :: Double -> Turtle ()
+ Diagrams.TwoD.Path.Turtle.Aliases: lt :: Double -> Turtle ()
+ Diagrams.TwoD.Path.Turtle.Aliases: pd :: Turtle ()
+ Diagrams.TwoD.Path.Turtle.Aliases: pu :: Turtle ()
+ Diagrams.TwoD.Path.Turtle.Aliases: rt :: Double -> Turtle ()
+ Diagrams.TwoD.Path.Turtle.Internal: PenStyle :: Double -> Colour Double -> PenStyle
+ Diagrams.TwoD.Path.Turtle.Internal: Turtle :: Bool -> P2 -> Deg -> (P2, Trail R2) -> PenStyle -> [TurtlePath] -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: TurtlePath :: PenStyle -> (P2, Trail R2) -> TurtlePath
+ Diagrams.TwoD.Path.Turtle.Internal: backward :: Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: closeCurrent :: Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: currPenStyle :: Turtle -> PenStyle
+ Diagrams.TwoD.Path.Turtle.Internal: currTrail :: Turtle -> (P2, Trail R2)
+ Diagrams.TwoD.Path.Turtle.Internal: data PenStyle
+ Diagrams.TwoD.Path.Turtle.Internal: data Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: data TurtlePath
+ Diagrams.TwoD.Path.Turtle.Internal: forward :: Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: getTurtleDiagram :: Renderable (Path R2) b => Turtle -> Diagram b R2
+ Diagrams.TwoD.Path.Turtle.Internal: heading :: Turtle -> Deg
+ Diagrams.TwoD.Path.Turtle.Internal: instance Show PenStyle
+ Diagrams.TwoD.Path.Turtle.Internal: instance Show Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: instance Show TurtlePath
+ Diagrams.TwoD.Path.Turtle.Internal: isPenDown :: Turtle -> Bool
+ Diagrams.TwoD.Path.Turtle.Internal: left :: Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: paths :: Turtle -> [TurtlePath]
+ Diagrams.TwoD.Path.Turtle.Internal: penColor :: PenStyle -> Colour Double
+ Diagrams.TwoD.Path.Turtle.Internal: penDown :: Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: penHop :: Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: penPos :: Turtle -> P2
+ Diagrams.TwoD.Path.Turtle.Internal: penStyle :: TurtlePath -> PenStyle
+ Diagrams.TwoD.Path.Turtle.Internal: penUp :: Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: penWidth :: PenStyle -> Double
+ Diagrams.TwoD.Path.Turtle.Internal: right :: Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: setHeading :: Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: setPenColor :: Colour Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: setPenColour :: Colour Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: setPenPos :: P2 -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: setPenWidth :: Double -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: startTurtle :: Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: towards :: P2 -> Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: traceTurtle :: Turtle -> Turtle
+ Diagrams.TwoD.Path.Turtle.Internal: turtleTrail :: TurtlePath -> (P2, Trail R2)
+ Diagrams.TwoD.Tilings: rt2 :: Q236
+ Diagrams.TwoD.Tilings: rt3 :: Q236
+ Diagrams.TwoD.Tilings: rt6 :: Q236
+ Diagrams.TwoD.Tilings: t33336L :: Tiling
+ Diagrams.TwoD.Tilings: t33336R :: Tiling
+ Diagrams.TwoD.Tilings: t33344 :: Tiling
+ Diagrams.TwoD.Tilings: t33434 :: Tiling
- Diagrams.TwoD.Layout.Tree: renderTree :: (a -> Diagram b R2) -> (P2 -> P2 -> Diagram b R2) -> Tree (a, P2) -> Diagram b R2
+ Diagrams.TwoD.Layout.Tree: renderTree :: Monoid' m => (a -> QDiagram b R2 m) -> (P2 -> P2 -> QDiagram b R2 m) -> Tree (a, P2) -> QDiagram b R2 m
- Diagrams.TwoD.Path.Turtle: runTurtle :: Turtle a -> Path R2
+ Diagrams.TwoD.Path.Turtle: runTurtle :: Renderable (Path R2) b => Turtle a -> Diagram b R2
- Diagrams.TwoD.Path.Turtle: runTurtleT :: (Monad m, Functor m) => TurtleT m a -> m (Path R2)
+ Diagrams.TwoD.Path.Turtle: runTurtleT :: (Monad m, Functor m, Renderable (Path R2) b) => TurtleT m a -> m (Diagram b R2)
- Diagrams.TwoD.Path.Turtle: type TurtleT = StateT TState
+ Diagrams.TwoD.Path.Turtle: type TurtleT = StateT Turtle

Files

− CHANGES
@@ -1,27 +0,0 @@-0.1.1.1: 13 May 2012--  * bump mtl (< 2.2) and data-default (< 0.5) upper bounds--0.1.1.0: 16 March 2012--  * Add Andrew Kennedy's symmetric rose tree layout algorithm to-    Diagrams.TwoD.Layout.Tree--0.1.0.0: 9 March 2012--  Initial release, containing:--  * Diagrams.Layout.Wrap, for laying out diagrams "wrapped" inside an-    arbitrary region (Michael Sloan)--  * Diagrams.TwoD.Tilings, for generating various 2D regular tilings-    (Brent Yorgey)--  * Diagrams.TwoD.Apollonian, for generating Apollonian gaskets (Brent-    Yorgey)--  * Diagrams.TwoD.Layout.Tree, tree layout and drawing algorithms-    (Brent Yorgey)--  * Diagrams.TwoD.Path.Turtle, creation of 2D paths using a stateful-    "turtle" interface (Michael Sloan)
+ CHANGES.markdown view
@@ -0,0 +1,55 @@+0.6: 11 December 2012+---------------------++* **New features**++    - New pure implementation of Turtle library, in `Turtle.Internals`++    - `Diagrams.TwoD.Layout.Tree`: ++	- New `renderTree'` function which gives+	  the edge-drawing function access to the values stored at the+	  nodes instead of just the node positions.++	- The type of `renderTree` is generalized to work with any+	  `QDiagram b R2 m`.++* **Bug fixes**++    - Tiling generation code in `Diagrams.TwoD.Tilings` wasn't actually+      checking whether vertexes had been already visited.+      +* **Dependency/version changes**++    - Switch from `fclabels` to `lens`++0.1.1.1: 13 May 2012+--------------------++* bump `mtl` (< 2.2) and `data-default` (< 0.5) upper bounds++0.1.1.0: 16 March 2012+----------------------++* Add Andrew Kennedy's symmetric rose tree layout algorithm to+    `Diagrams.TwoD.Layout.Tree`++0.1.0.0: 9 March 2012+---------------------++Initial release, containing:++* `Diagrams.Layout.Wrap`, for laying out diagrams "wrapped" inside an+    arbitrary region (Michael Sloan)++* `Diagrams.TwoD.Tilings`, for generating various 2D regular tilings+    (Brent Yorgey)++* `Diagrams.TwoD.Apollonian`, for generating Apollonian gaskets (Brent+    Yorgey)++* `Diagrams.TwoD.Layout.Tree`, tree layout and drawing algorithms+    (Brent Yorgey)++* `Diagrams.TwoD.Path.Turtle`, creation of 2D paths using a stateful+    "turtle" interface (Michael Sloan)
− README
@@ -1,26 +0,0 @@-This package is a repository for user contributions to the diagrams-project (http://projects.haskell.org/diagrams): generation of-specialized diagrams, fun or instructive examples, half-baked ideas,-stuff which is not sufficiently polished or general to go in the-diagrams-lib package but is nonetheless worth sharing.  Any code is-welcome, as long as it conforms to a few simple standards:--  - Code must be released under a BSD3 license (see the LICENSE).--  - You must list yourself as the maintainer.--  - Try to keep external dependencies to a minimum; the goal is for-    diagrams-contrib to be easily installable by as many people as-    possible.  New dependencies will be considered on a case-by-case-    basis.  Dependencies involving the FFI will most likely be-    rejected.  If you have some cool code using diagrams which-    requires big external dependencies, you should release it as a-    separate package rather than including it in diagrams-contrib.--  - There should at minimum be a Haddock comment on the module itself,-    explaining the purpose, giving some examples of use, etc.--  - It must compile with no warnings under -Wall. This may seem a bit-    draconian, but you'll get over it.  If it makes you feel any-    better, you are welcome to turn off specific warnings for your-    module with an {-# OPTIONS_GHC -fno-warn-blah #-} pragma.
+ README.markdown view
@@ -0,0 +1,32 @@+[![Build Status](https://secure.travis-ci.org/diagrams/diagrams-contrib.png)](http://travis-ci.org/diagrams/diagrams-contrib)++This package is a repository for user contributions to the+[diagrams project](http://projects.haskell.org/diagrams): generation+of specialized diagrams, fun or instructive examples, half-baked+ideas, stuff which is not sufficiently polished or general to go in+the [diagrams-lib](http://github.com/diagrams/diagrams-lib) package+but is nonetheless worth sharing.  Any code is welcome, as long as it+conforms to a few simple standards:++* Code must be released under a BSD3 license (see the LICENSE).++* You must list yourself as the maintainer.++* Try to keep external dependencies to a minimum; the goal is for+  diagrams-contrib to be easily installable by as many people as+  possible.  New dependencies will be considered on a case-by-case+  basis.  Dependencies involving the FFI will most likely be+  rejected.  If you have some cool code using diagrams which+  requires big external dependencies, you should release it as a+  separate package rather than including it in diagrams-contrib.++* There should at minimum be a Haddock comment on the module itself,+  explaining the purpose, giving some examples of use, *etc.*++* It must compile with no warnings under `-Wall`. This may seem a bit+  draconian, but you'll get over it.  If it makes you feel any+  better, you are welcome to turn off specific warnings for your+  module with an `{-# OPTIONS_GHC -fno-warn-blah #-}` pragma.++For more general information on contributing to the diagrams project,+see the [Contributing page on the diagrams wiki](http://www.haskell.org/haskellwiki/Diagrams/Contributing).
diagrams-contrib.cabal view
@@ -1,5 +1,5 @@ name:                diagrams-contrib-version:             0.1.1.1+version:             0.6 synopsis:            Collection of user contributions to diagrams EDSL description:         A collection of user contributions for diagrams,                      an embedded domain-specific language for generation @@ -8,31 +8,62 @@ license:             BSD3 license-file:        LICENSE author:              Various-maintainer:          diagrams-discuss@googlegroups.com+maintainer:          Various; see individual modules+Bug-reports:         http://github.com/diagrams/diagrams-contrib/issues category:            Graphics build-type:          Simple-cabal-version:       >=1.8-extra-source-files:  README, CHANGES-tested-with:         GHC == 6.12.3, GHC == 7.0.4, GHC == 7.2.1, GHC == 7.4.1+cabal-version:       >=1.10+extra-source-files:  README.markdown, CHANGES.markdown+tested-with:         GHC == 7.0.4, GHC == 7.2.1, GHC == 7.4.2, GHC == 7.6.1 Source-repository head-  type:     darcs-  location: http://patch-tag.com/r/byorgey/diagrams-contrib+  type:     git+  location: http://github.com/diagrams/diagrams-contrib.git  library+  ghc-options:         -Wall   exposed-modules:     Diagrams.Layout.Wrap,                        Diagrams.TwoD.Tilings,                        Diagrams.TwoD.Apollonian,                        Diagrams.TwoD.Layout.Tree,                        Diagrams.TwoD.Path.Turtle,-                       Diagrams.TwoD.Path.Turtle.Aliases-  build-depends:       base >= 4.2 && < 4.6,+                       Diagrams.TwoD.Path.Turtle.Aliases,+                       Diagrams.TwoD.Path.Turtle.Internal+  build-depends:       base >= 4.2 && < 4.7,                        mtl >= 2.0 && < 2.2,-                       containers ==0.4.*,+                       containers > 0.4 && < 0.6,                        vector-space >= 0.7 && < 0.9,                        colour >= 2.3.1 && < 2.4,-                       diagrams-lib ==0.5.*,+                       diagrams-lib >= 0.6 && < 0.7, -                       fclabels >= 1.0.4 && < 1.2,-                       force-layout >= 0.1 && < 0.2,-                       data-default >= 0.3 && < 0.5+                       lens >= 3.7 && < 4,+                       force-layout >= 0.2 && < 0.3,+                       data-default >= 0.3 && < 0.6   hs-source-dirs:      src+  default-language:    Haskell2010++test-suite turtle-tests+  type:                exitcode-stdio-1.0+  hs-source-dirs:      src tests+  Main-is:             TestSuite.hs+  ghc-options:         -Wall++  other-modules:       Diagrams.TwoD.Path.Turtle.Tests++  build-depends:       HUnit                      >= 1.2 && < 1.3,+                       QuickCheck                 >= 2.4 && < 2.6,+                       containers                 >= 0.3 && < 0.6,+                       test-framework             >= 0.4 && < 0.7,+                       test-framework-hunit       >= 0.2 && < 0.3,+                       test-framework-quickcheck2 >= 0.2 && < 0.3,+                       -- Copied from regular dependencies+                       base >= 4.2 && < 4.7,+                       mtl >= 2.0 && < 2.2,+                       containers >= 0.4 && < 0.6,+                       vector-space >= 0.7 && < 0.9,+                       colour >= 2.3.1 && < 2.4,+                       diagrams-lib >= 0.6 && < 0.7,++                       fclabels >= 1.0.4 && < 1.2,+                       force-layout >= 0.2 && < 0.3,+                       data-default >= 0.3 && < 0.6+  default-language:    Haskell2010
src/Diagrams/TwoD/Apollonian.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE Rank2Types +{-# LANGUAGE Rank2Types            , FlexibleContexts            , ViewPatterns   #-}@@ -16,30 +16,30 @@ -- tangent to all three.  This process can be repeated, generating a -- fractal circle packing. ----- See J. Lagarias, C. Mallows, and A. Wilks, "Beyond the Descartes--- circle theorem", Amer. Math. Monthly 109 (2002), 338--361.+-- See J. Lagarias, C. Mallows, and A. Wilks, \"Beyond the Descartes+-- circle theorem\", /Amer. Math. Monthly/ 109 (2002), 338--361. -- <http://arxiv.org/abs/math/0101066>. -- ----------------------------------------------------------------------------- -module Diagrams.TwoD.Apollonian +module Diagrams.TwoD.Apollonian        ( -- * Circles-         +          Circle(..), mkCircle, center, radius-                                       -         -- * Descartes' Theorem                                       ++         -- * Descartes' Theorem        , descartes, other, initialConfig-                    +          -- * Apollonian gasket generation-                    +        , apollonian-         +          -- * Diagram generation-         +        , drawCircle        , drawGasket        , apollonianGasket-         +        ) where  import Data.Complex@@ -48,7 +48,6 @@ import Diagrams.Prelude hiding (radius, center)  import Control.Arrow (second)-import Data.Colour   (transparent)  ------------------------------------------------------------ --  Circles@@ -56,14 +55,14 @@  -- | Representation for circles that lets us quickly compute an --   Apollonian gasket.-data Circle = Circle { bend :: Double   +data Circle = Circle { bend :: Double                        -- ^ The bend is the reciprocal of signed                        --   radius: a negative radius means the                        --   outside and inside of the circle are                        --   switched.  The bends of any four mutually                        --   tangent circles satisfy Descartes'                        --   Theorem.-                     , cb   :: Complex Double  +                     , cb   :: Complex Double                        -- ^ /Product/ of bend and center represented                        --   as a complex number.  Amazingly, these                        --   products also satisfy the equation of@@ -99,7 +98,7 @@   negate = liftF negate   abs = liftF abs   fromInteger n = Circle (fromInteger n) (fromInteger n)-  + instance Fractional Circle where   (/) = liftF2 (/)   recip = liftF recip@@ -115,7 +114,7 @@ ------------------------------------------------------------  -- | Descartes' Theorem states that if @b1@, @b2@, @b3@ and @b4@ are---   the bends of four mutually tangent circles, then +--   the bends of four mutually tangent circles, then -- --   @ --     b1^2 + b2^2 + b3^2 + b4^2 = 1/2 * (b1 + b2 + b3 + b4)^2.@@ -178,19 +177,19 @@ --   Stop the recursion when encountering a circle with an (unsigned) --   radius smaller than the threshold. apollonian :: Double -> [Circle] -> [Circle]-apollonian thresh cs +apollonian thresh cs   =  cs   ++ (concat . map (\(c,cs') -> apollonian' thresh (other cs' c) cs') . select $ cs)-  + apollonian' :: Double -> Circle -> [Circle] -> [Circle] apollonian' thresh cur others   | radius cur < thresh = []-  | otherwise = cur +  | otherwise = cur               : (concat $                    map (\(c, cs') -> apollonian' thresh-                                       (other (cur:cs') c) -                                       (cur:cs') -                       ) +                                       (other (cur:cs') c)+                                       (cur:cs')+                       )                        (select others)                 ) @@ -212,7 +211,7 @@ -- | Draw an Apollonian gasket: the first argument is the threshold; --   the recursion will stop upon reaching circles with radii less than --   it. The next three arguments are bends of three circles.-apollonianGasket :: (Renderable (Path R2) b) +apollonianGasket :: (Renderable (Path R2) b)                  => Double -> Double -> Double -> Double -> Diagram b R2 apollonianGasket thresh b1 b2 b3 = drawGasket . apollonian thresh $ (initialConfig b1 b2 b3) 
src/Diagrams/TwoD/Layout/Tree.hs view
@@ -23,6 +23,7 @@ -- > {-# LANGUAGE NoMonomorphismRestriction #-} -- > import Diagrams.Prelude -- > import Diagrams.TwoD.Layout.Tree+-- > import Data.Tree -- > -- > t1 = Node 'A' [Node 'B' (map lf "CDE"), Node 'F' [Node 'G' (map lf "HIJ")]] -- >@@ -37,6 +38,7 @@ -- > {-# LANGUAGE NoMonomorphismRestriction #-} -- > import Diagrams.Prelude -- > import Diagrams.TwoD.Layout.Tree+-- > import Data.Tree -- > -- > tD = Node (rect 1 3) -- >        [ Node (circle 0.2) []@@ -99,6 +101,7 @@          -- * Rendering         , renderTree+       , renderTree'         ) where @@ -106,19 +109,19 @@  import           Control.Applicative import           Control.Arrow         (first, second, (***), (&&&))+import           Control.Lens import           Control.Monad.State  import           Data.Default import qualified Data.Foldable         as F+import           Data.Function         (on) import qualified Data.Map              as M-import           Data.Label            (mkLabels)-import qualified Data.Label            as L import           Data.List             (mapAccumL) import           Data.Maybe import qualified Data.Traversable      as T import           Data.Tree -import           Diagrams.Prelude      hiding (e)+import           Diagrams.Prelude      hiding (e, view)   @@ -155,15 +158,7 @@                }   deriving (Eq, Show) -mkLabels [''Pos]--incHoriz, up, down :: MonadState Pos m => m ()-incHoriz   = modify (L.modify horiz (+1))-up         = modLevel (subtract 1)-down       = modLevel (+1)--modLevel :: MonadState Pos m => (Int -> Int) -> m ()-modLevel f = modify (L.modify level f)+makeLenses ''Pos  pos2Point :: Double -> Double -> Pos -> P2 pos2Point cSep lSep (Pos l h) = p2 (fromIntegral h * cSep, -fromIntegral l * lSep)@@ -194,8 +189,11 @@           r' <- uniqueXLayout' r           up           return $ Just (Node (a,p) (catMaybes [l', r']))-        mkNode = get <* incHoriz+        mkNode = get <* (horiz += 1) +        down = level += 1+        up   = level -= 1+ -------------------------------------------------- -- "Symmetric" layout of rose trees. @@ -407,7 +405,7 @@ --   identifiers used in the 'Ensemble'. reconstruct :: Functor t => Ensemble R2 -> t (a, PID) -> t (a, P2) reconstruct e = (fmap . second)-                  (fromMaybe origin . fmap (L.get pos) . flip M.lookup (L.get particles e))+                  (fromMaybe origin . fmap (view pos) . flip M.lookup (e^.particles))  data ForceLayoutTreeOpts =   FLTOpts@@ -464,11 +462,21 @@  -- | Draw a tree annotated with node positions, given functions --   specifying how to draw nodes and edges.-renderTree :: (a -> Diagram b R2) -> (P2 -> P2 -> Diagram b R2)-           -> Tree (a, P2) -> Diagram b R2-renderTree renderNode renderEdge = alignT . centerX . renderTree'+renderTree :: Monoid' m+           => (a -> QDiagram b R2 m) -> (P2 -> P2 -> QDiagram b R2 m)+           -> Tree (a, P2) -> QDiagram b R2 m+renderTree n e = renderTree' n (e `on` snd)++-- | Draw a tree annotated with node positions, given functions+--   specifying how to draw nodes and edges.  Unlike 'renderTree',+--   this version gives the edge-drawing function access to the actual+--   values stored at the nodes rather than just their positions.+renderTree' :: Monoid' m+           => (a -> QDiagram b R2 m) -> ((a,P2) -> (a,P2) -> QDiagram b R2 m)+           -> Tree (a, P2) -> QDiagram b R2 m+renderTree' renderNode renderEdge = alignT . centerX . renderTreeR   where-    renderTree' (Node (a,p) cs) =+    renderTreeR (Node (a,p) cs) =          renderNode a # moveTo p-      <> mconcat (map renderTree' cs)-      <> mconcat (map (renderEdge p . snd . rootLabel) cs)+      <> mconcat (map renderTreeR cs)+      <> mconcat (map (renderEdge (a,p) . rootLabel) cs)
src/Diagrams/TwoD/Path/Turtle.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleContexts #-} ----------------------------------------------------------------------------- -- | -- Module      :  Diagrams.TwoD.Path.Turtle@@ -19,146 +20,101 @@   , forward, backward, left, right      -- * State accessors / setters-  , heading, setHeading, towards-  , pos, setPos+  , heading, setHeading, towards, isDown+  , pos, setPos, setPenWidth, setPenColor      -- * Drawing control-  , penHop, penUp, penDown, isDown-  , closeCurrent+  , penUp, penDown, penHop, closeCurrent   ) where -import Diagrams.Prelude- import qualified Control.Monad.State as ST-import Control.Monad.Identity+import Control.Monad.Identity (Identity(..)) -type TurtleT = ST.StateT TState+import Diagrams.Prelude+import qualified Diagrams.TwoD.Path.Turtle.Internal as T -type Turtle = TurtleT Identity -data TState = TState Bool Deg (Path R2)---- Unexported utilities---- The path is stored backwards to make accumulation efficient.--- TODO: consider keeping the output backwards, and always update the position?--- This would make the "position" query more efficient.-getPath :: TState -> Path R2-getPath (TState d _ (Path xs))-  = Path . reverse-  $ map (\(p, (Trail ys c)) -> (p, Trail (reverse ys) c))-  $ if d then xs else tail xs---- Adds a segment to the accumulated path.-logoseg :: Monad m => (Segment R2) -> TurtleT m ()-logoseg seg = ST.modify-  (\(TState d ang p) ->-     TState d ang $ modifyTrail-       (\(Trail xs c) -> Trail (rotate ang seg:xs) c) p)--modifyAngle :: Monad m => (Deg -> Deg) -> TurtleT m ()-modifyAngle f = ST.modify (\(TState d a p) -> TState d (f a) p)--modifyPath :: (Path R2 -> Path R2) -> TState -> TState-modifyPath f (TState d ang p) = TState d ang $ f p+type TurtleT = ST.StateT T.Turtle -modifyTrail :: (Trail v -> Trail v) -> Path v -> Path v-modifyTrail f (Path ((p, t) : ps)) = Path $ (p, f t) : ps-modifyTrail _ p = p+type Turtle = TurtleT Identity  -- | A more general way to run the turtle. Returns a computation in the -- underlying monad @m@ yielding a path consisting of the traced trails-runTurtleT :: (Monad m, Functor m) => TurtleT m a -> m (Path R2)-runTurtleT t = getPath . snd-            <$> ST.runStateT t (TState True 0 (Path [(origin, Trail [] False)]))+runTurtleT :: (Monad m, Functor m, (Renderable (Path R2) b)) => TurtleT m a -> m (Diagram b R2)+runTurtleT t = T.getTurtleDiagram . snd+           <$> ST.runStateT t T.startTurtle  -- | Run the turtle, yielding a path consisting of the traced trails.-runTurtle :: Turtle a -> Path R2-runTurtle t = getPath . snd . ST.runState t-            $ TState True 0 (Path [(origin, Trail [] False)])+runTurtle :: (Renderable (Path R2) b) => Turtle a -> Diagram b R2+runTurtle = runIdentity . runTurtleT  -- Motion commands  -- | Move the turtle forward, along the current heading. forward :: Monad m => Double -> TurtleT m ()-forward  x = logoseg $ Linear (r2 (x,          0))+forward x = ST.modify $ T.forward x  -- | Move the turtle backward, directly away from the current heading. backward :: Monad m => Double -> TurtleT m ()-backward x = logoseg $ Linear (r2 ((negate x), 0))+backward x = ST.modify $ T.backward x  -- | Modify the current heading to the left by the specified angle in degrees. left :: Monad m => Double -> TurtleT m ()-left  a = modifyAngle (+        (Deg a))+left d = ST.modify $ T.left d  -- | Modify the current heading to the right by the specified angle in degrees. right :: Monad m => Double -> TurtleT m ()-right a = modifyAngle (subtract (Deg a))----- Based on "bezierFromSweepQ1" from Diagrams.TwoD.Arc-{--smoothTurn f s =-  where (x,y) = rotate s (1, 0)-        (u,v) = ((4-x)/3, (1-x)*(3-x)/(3*y))--bezierFromSweepQ1 :: Rad -> Segment R2-bezierFromSweepQ1 s = fmap (^-^ v) . rotate (s/2) $ Cubic p2 p1 p0-        p2       = reflectY p1--}+right d = ST.modify $ T.right d  -- State accessors / setters  -- | Set the current turtle angle, in degrees. setHeading :: Monad m => Double -> TurtleT m ()-setHeading a = modifyAngle (const (Deg a))+setHeading d = ST.modify $ T.setHeading d  -- | Get the current turtle angle, in degrees. heading :: Monad m => TurtleT m Double-heading = ST.gets (\(TState _ (Deg x) _) -> x)+heading = ST.gets ((\(Deg x) -> x) . T.heading)  -- | Sets the heading towards a given location. towards :: Monad m => P2 -> TurtleT m ()-towards pt = do-  p <- pos-  setHeading . (*360) . (/tau) . uncurry atan2 . unr2 $ pt .-. p+towards pt = ST.modify $ T.towards pt  -- | Set the current turtle X/Y position. setPos :: Monad m => P2 -> TurtleT m ()-setPos p = ST.modify helper- where-  helper (TState d a (Path ps))-    = TState d a $ Path $ (p, Trail [] False)-                          : if d then ps else tail ps+setPos p = ST.modify $ T.setPenPos p  -- | Get the current turtle X/Y position. pos ::  Monad m => TurtleT m P2-pos = ST.gets f-  where f (TState _ _ (Path ((p, t) : _))) = p .+^ trailOffset t-        f _ = error "Diagrams.TwoD.Path.Turtle.pos: no path.  Please report this as a bug."+pos = ST.gets T.penPos  -- Drawing control. --- | Starts a new path at the current location.-penHop :: Monad m => TurtleT m ()-penHop = pos >>= setPos- -- | Ends the current path, and enters into "penUp" mode penUp :: Monad m => TurtleT m ()-penUp   = penHop >> ST.modify (\(TState _ a p) -> TState False a p)+penUp   = ST.modify T.penUp  -- | Ends the current path, and enters into "penDown" mode penDown :: Monad m => TurtleT m ()-penDown = penHop >> ST.modify (\(TState _ a p) -> TState True a p)+penDown = ST.modify T.penDown +-- | Start a new trail at current position+penHop :: Monad m => TurtleT m ()+penHop = ST.modify T.penHop+ -- | Queries whether the pen is currently drawing a path or not. isDown :: Monad m => TurtleT m Bool-isDown = ST.gets (\(TState d _ _) -> d)+isDown = ST.gets T.isPenDown --- | Closes the current path, to the last penDown / setPosition--- Maintains current position - does this make sense?+-- | Closes the current path , to the starting position of the current+-- trail. Has no effect when the pen position is up. closeCurrent :: Monad m => TurtleT m ()-closeCurrent = do-  p <- pos-  ST.modify $ modifyPath $ modifyTrail close-  setPos p+closeCurrent = ST.modify T.closeCurrent++-- | Sets the pen color+setPenColor :: Monad m => Colour Double -> TurtleT m ()+setPenColor c = ST.modify $ T.setPenColor c++-- | Sets the pen size+setPenWidth  :: Monad m =>  Double -> TurtleT m ()+setPenWidth s = ST.modify $ T.setPenWidth s
+ src/Diagrams/TwoD/Path/Turtle/Internal.hs view
@@ -0,0 +1,273 @@+{-# LANGUAGE FlexibleContexts, TypeSynonymInstances, FlexibleInstances #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  Diagrams.TwoD.Path.Turtle+-- Copyright   :  (c) 2011 Michael Sloan+-- License     :  BSD-style (see LICENSE)+-- Maintainer  :  Michael Sloan <mgsloan at gmail>,  Deepak Jois <deepak.jois@gmail.com>+-- Authors     :  Michael Sloan <mgsloan at gmail>, Deepak Jois <deepak.jois@gmail.com>+--+-- A module consisting of core types and functions to represent and operate on+-- a \"turtle\".+--+-- More info about turtle graphics:+-- <http://en.wikipedia.org/wiki/Turtle_graphics>+--+-----------------------------------------------------------------------------++module Diagrams.TwoD.Path.Turtle.Internal+  (+    -- * Turtle data types and accessors+    Turtle(..), TurtlePath(..), PenStyle(..)++    -- * Motion commands+  , forward, backward, left, right++    -- * Pen style commands+  , setPenColor, setPenColour, setPenWidth++    -- * State setters+  , startTurtle, setHeading, towards+  , setPenPos++    -- * Drawing control+  , penUp, penDown, penHop, closeCurrent ++    -- * Debugging+  , traceTurtle++    -- * Diagram related+  , getTurtleDiagram+  ) where++import Debug.Trace (traceShow)+import Control.Arrow (second)++import Diagrams.Prelude++-- | Style attributes associated with the turtle pen+data PenStyle = PenStyle+  { penWidth :: Double         -- ^ Width of pen. Default is 1.0+  , penColor :: Colour Double  -- ^ Color of pen. Default is @black@+  } deriving Show++-- | Turtle path type that captures a list of paths and the style attributes+-- associated with them+data TurtlePath = TurtlePath+  { penStyle    :: PenStyle        -- ^ Style+  , turtleTrail :: (P2, Trail R2)  -- ^ Path+  } deriving Show++-- | Core turtle data type. A turtle needs to keep track of its current+-- position, like its position, heading etc., and all the paths that it has+-- traversed so far.+--+-- We need to record a new path, everytime an attribute like style, pen position+-- etc changes, so that we can separately track styles for each portion of the+-- eventual path that the turtle took.+data Turtle = Turtle+  { -- | State of the pen. @False@ means that turtle movements will not draw+    -- anything+    isPenDown  :: Bool+     -- | Current position. This is updated everytime the turtle moves+  , penPos     :: P2+     -- | Orientation of the turtle in 2D space, given in degrees+  , heading    :: Deg+     -- | Path traversed by the turtle so far, without any style or pen+     -- attributes changing+  , currTrail  :: (P2, Trail R2)+     -- | Current style of the pen+  , currPenStyle  :: PenStyle+     -- | List of paths along with style information, traversed by the turtle+     -- previously+  , paths      :: [TurtlePath]+  } deriving Show++-- | Default pen style, with @penWidth@ set to 1.0 and @penColor@ set to black+defaultPenStyle :: PenStyle+defaultPenStyle = PenStyle 1.0 black++-- | The initial state of turtle. The turtle is located at the origin, at an+-- orientation of 0 degrees with its pen position down. The pen style is+-- @defaultPenStyle@.+startTurtle :: Turtle+startTurtle = Turtle True origin 0 (origin, mempty) defaultPenStyle []++-- | Draw a segment along the turtle’s path and update its position. If the pen+-- is up, only the position is updated.+moveTurtle :: Segment R2  -- ^ Segment representing the path to travel+           -> Turtle      -- ^ Turtle to move+           -> Turtle      -- ^ Resulting turtle+moveTurtle s t@(Turtle pd pos h (o, Trail xs _) _ _) =+ if pd+   -- Add segment to current trail and update position+   then t { currTrail = (o, Trail newTrail False)+          , penPos = newPenPos+          }+   -- Update position only+   else t { penPos = newPenPos }+ where+   -- Rotate segment by orientation before adding to trail+   rotatedSeg  =  rotate h s+   newTrail    =  rotatedSeg : xs+   -- Calculate the new position along the segment+   newPenPos   =  pos .+^ segOffset rotatedSeg++-- | Move the turtle forward by @x@ units+forward :: Double  -- ^ Distance to move+        -> Turtle  -- ^ Turtle to move+        -> Turtle  -- ^ Resulting turtle+forward x = moveTurtle (Linear $ r2 (x,0))++-- | Move the turtle backward by @x@ units+backward :: Double  -- ^ Distance to move+         -> Turtle  -- ^ Turtle to move+         -> Turtle  -- ^ Resulting turtle+backward x = moveTurtle (Linear $ r2 (negate x, 0))++-- | Turn the turtle by applying the given function to its current orientation+-- (in degrees)+turnTurtle :: (Deg -> Deg)  -- ^ Transformation to apply on current orientation+           -> Turtle        -- ^ Turtle to turn+           -> Turtle        -- ^ Resulting turtle+turnTurtle f t@(Turtle _ _ h _ _ _) = t { heading = f h  }++-- | Turn the turtle anti-clockwise (left)+left :: Double  -- ^ Degree of turn+     -> Turtle  -- ^ Turtle to turn+     -> Turtle  -- ^ Resulting turtle+left d = turnTurtle (+ (Deg d))++-- | Turn the turtle clockwise (right)+right :: Double  -- ^ Degree of turn+      -> Turtle  -- ^ Turtle to turn+      -> Turtle  -- ^ Resulting turtle+right d = turnTurtle (subtract (Deg d))++-- | Turn the turtle to the given orientation, in degrees+setHeading :: Double  -- ^ Degree of orientation+           -> Turtle  -- ^ Turtle to orient+           -> Turtle  -- ^ Resulting turtle+setHeading d = turnTurtle (const $ Deg d)++-- | Sets the turtle orientation towards a given location.+towards :: P2      -- ^ Point to orient turtle towards+        -> Turtle  -- ^ Turtle to orient+        -> Turtle  -- ^ Resulting turtle+towards p  = setHeading =<< (360 *) . (/ tau) . uncurry atan2 . unr2 . (p .-.) . penPos++-- | Puts the turtle pen in “Up” mode. Turtle movements will not draw anything+--+-- Does nothing if the pen was already up. Otherwise, it creates a turtle with+-- the current trail added to @paths@.+penUp :: Turtle  -- ^ Turtle to modify+      -> Turtle  -- ^ Resulting turtle+penUp t+ | isPenDown t = t # makeNewTrail #  \t' -> t' { isPenDown = False }+ | otherwise   = t++-- | Puts the turtle pen in “Down” mode. Turtle movements will cause drawing to+-- happen+--+-- Does nothing if the pen was already down. Otherwise, starts a new trail+-- starting at the current position.+penDown :: Turtle  -- ^ Turtle to modify+        -> Turtle  -- ^ Resulting turtle+penDown t+  | isPenDown t = t+  | otherwise   = t # makeNewTrail #  \t' -> t' { isPenDown = True }++-- Start a new trail at current position+penHop :: Turtle+         -> Turtle+penHop t = t # makeNewTrail++-- Closes the current path , to the starting position of the current+-- trail. Has no effect when the pen position is up+closeCurrent :: Turtle+             -> Turtle+closeCurrent t+  | isPenDown t = t # setPenPos startPos # closeTrail # makeNewTrail+  | otherwise   = t + where startPos = fst . currTrail $ t +       closeTrail t'  = t' { currTrail = second close $ currTrail t }++-- | Set the turtle X/Y position.+--+-- If pen is down and the current trail is non-empty, this will also add the+-- current trail to the @paths@ field.+setPenPos :: P2      -- ^ Position to place true+          -> Turtle  -- ^ Turtle to position+          -> Turtle  -- ^ Resulting turtle+setPenPos newPos t = t {penPos = newPos } # makeNewTrail++-- | Set a new pen width for turtle.+--+-- If pen is down, this adds the current trail to @paths@ and starts a new empty+-- trail.+setPenWidth :: Double -- ^ Width of Pen+            -> Turtle -- ^ Turtle to change+            -> Turtle -- ^ Resulting Turtle+setPenWidth w = modifyCurrStyle (\s -> s { penWidth = w })+-- | Set a new pen color for turtle.+--+-- If pen is down, this adds the current trail to @paths@ and starts a new empty+-- trail.+setPenColour :: Colour Double -- ^ Width of Pen+             -> Turtle        -- ^ Turtle to change+             -> Turtle        -- ^ Resulting Turtle+setPenColour c = modifyCurrStyle (\s -> s { penColor = c })++-- | alias of @setPenColour@+setPenColor :: Colour Double -- ^ Width of Pen+             -> Turtle        -- ^ Turtle to change+             -> Turtle        -- ^ Resulting Turtle+setPenColor = setPenColour++-- | Creates a diagram from a turtle+--+-- Applies the styles to each trails in @paths@ separately and combines them+-- into a single diagram+getTurtleDiagram :: (Renderable (Path R2) b) => Turtle+                 -> Diagram b R2+getTurtleDiagram t =+  position .+  map turtlePathToStroke .+  paths $ t # penUp -- Do a penUp to add @currTrail@ to @paths@++-- * Helper functions++-- Makes a "TurtlePath" from a "Turtle"’s @currTrail@ field+makeTurtlePath :: Turtle+               -> TurtlePath+makeTurtlePath t = TurtlePath (currPenStyle t) (currTrail t)++-- Returns a list of paths, with current trail added to a "Turtle"’s @paths@ field+addCurrTrailToPath :: Turtle+                   -> [TurtlePath]+addCurrTrailToPath t = if emptyTrail then paths t else makeTurtlePath t : paths t+ where emptyTrail = (snd . currTrail) t == mempty++-- Starts a new trail and adds current trail to path+makeNewTrail :: Turtle+             -> Turtle+makeNewTrail t = t { currTrail = (penPos t, mempty), paths = addCurrTrailToPath t  }++-- Modifies the current style after starting a new trail+modifyCurrStyle :: (PenStyle -> PenStyle)+                -> Turtle+                -> Turtle+modifyCurrStyle f t =  t # makeNewTrail # \t' -> t' { currPenStyle = (f . currPenStyle) t' }++-- Creates a diagram from a TurtlePath using the provided styles+turtlePathToStroke :: (Renderable (Path R2) b) => TurtlePath+                   -> (P2, Diagram b R2)+turtlePathToStroke (TurtlePath (PenStyle lineWidth_  lineColor_) (p,Trail xs c)) = (p,d)+ where d = lc lineColor_ .+           lw lineWidth_ .+           stroke $ pathFromTrail (Trail (reverse xs) c)++-- | Prints out turtle representation and returns it. Use for debugging+traceTurtle :: Turtle+            -> Turtle+traceTurtle t = traceShow t t
src/Diagrams/TwoD/Tilings.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE TypeFamilies -           , FlexibleContexts +{-# LANGUAGE TypeFamilies+           , FlexibleContexts            , ScopedTypeVariables            , ViewPatterns            , CPP@@ -18,57 +18,57 @@ -- ----------------------------------------------------------------------------- module Diagrams.TwoD.Tilings (-  +   -- * The ring Q[sqrt 2, sqrt 3]-  +     Q236, rt2, rt3, rt6-                  +   , toDouble-    +   , Q2, toR2, toP2-              -  -- * Regular polygons              -              -  , TilingPoly(..)              ++  -- * Regular polygons++  , TilingPoly(..)   , polySides, polyFromSides   , polyCos, polySin   , polyRotation, polyExtRotation-                  -  -- * Tilings                -                  -  -- ** Types                  ++  -- * Tilings++  -- ** Types   , Tiling(..)   , Edge, mkEdge-          +   , Polygon(..)-              +   -- ** Generation-    -  , TilingState(..), initTilingState  ++  , TilingState(..), initTilingState   , TilingM-    +   , generateTiling-    -  -- ** Pre-defined tilings  -    ++  -- ** Pre-defined tilings+   , t3, t4, t6   , mk3Tiling, t4612, t488, t31212-                            +   , t3636   , semiregular   , rot   , t3464, t33434, t33344, t33336L, t33336R-              -  -- * Diagrams  -    ++  -- * Diagrams+   , drawEdge   , drawPoly   , polyColor   , drawTiling   , drawTilingStyled-    +   ) where-    + import Control.Monad.State #if __GLASGOW_HASKELL__ >= 704 import Control.Monad.Writer hiding ((<>))@@ -102,9 +102,9 @@  -- | Convert a @Q236@ value to a @Double@. toDouble :: Q236 -> Double-toDouble (Q236 a b c d) = fromRational a -                        + fromRational b * sqrt 2 -                        + fromRational c * sqrt 3 +toDouble (Q236 a b c d) = fromRational a+                        + fromRational b * sqrt 2+                        + fromRational c * sqrt 3                         + fromRational d * sqrt 6  rt2, rt3, rt6 :: Q236@@ -123,13 +123,13 @@   abs (Q236 a b c d) = Q236 (abs a) (abs b) (abs c) (abs d)   fromInteger z = Q236 (fromInteger z) 0 0 0   signum = error "no signum for Q236"-  + instance AdditiveGroup Q236 where   zeroV = Q236 0 0 0 0-  (Q236 a1 b1 c1 d1) ^+^ (Q236 a2 b2 c2 d2) +  (Q236 a1 b1 c1 d1) ^+^ (Q236 a2 b2 c2 d2)     = Q236 (a1 + a2) (b1 + b2) (c1 + c2) (d1 + d2)   negateV (Q236 a b c d) = Q236 (-a) (-b) (-c) (-d)-  + instance VectorSpace Q236 where   type Scalar Q236 = Rational   s *^ (Q236 a b c d) = Q236 (s * a) (s * b) (s * c) (s * d)@@ -238,7 +238,7 @@  instance Eq Polygon where   (Polygon vs1) == (Polygon vs2) = sort vs1 == sort vs2-  + instance Ord Polygon where   compare = compare `on` (sort . polygonVertices) @@ -271,61 +271,61 @@                -> (Edge -> w)          -- ^ what to do with edges                -> (Polygon -> w)       -- ^ what to do with polygons                -> w-generateTiling t v d vPred e p +generateTiling t v d vPred e p   = evalState (execWriterT (generateTiling' t v d)) initTilingState where-    -  generateTiling' :: Tiling -> Q2 -> Q2 -> TilingM w ()  ++  generateTiling' :: Tiling -> Q2 -> Q2 -> TilingM w ()   generateTiling' t v d       -- stop if the current vertex fails the predicate     | not (vPred v) = return ()     | otherwise = do         ts <- get-        +         -- stop if we've seen this vertex before         when (v `S.notMember` visitedVertices ts) $ do-          -        -- otherwise, mark it as visited  -        modify (\ts -> ts { visitedVertices = v `S.insert` visitedVertices ts })-      -        -- get the neighboring vertices and the polygons surrounding-        -- this vertex, and filter out ones we've already generated-        let (neighbors, polys) = genNeighbors t v d-            edges  = S.fromList $ map (mkEdge v) neighbors-            edges' = edges `S.difference` visitedEdges ts-            polys' = polys `S.difference` visitedPolygons ts-            -        -- generate some edges and polygons-        F.mapM_ (tell . e) edges'-        F.mapM_ (tell . p) polys'-        -        -- remember that we generated them-        modify (\ts -> ts { visitedEdges = edges' `S.union` visitedEdges ts })-        modify (\ts -> ts { visitedPolygons = polys' `S.union` visitedPolygons ts })-      -        -- follow edges and continue recursively-        zipWithM_ (\d i -> generateTiling' (follow t i) (v ^+^ d) d) -          (map (^-^ v) $ neighbors) [0..] +          -- otherwise, mark it as visited+          modify (\ts -> ts { visitedVertices = v `S.insert` visitedVertices ts })++          -- get the neighboring vertices and the polygons surrounding+          -- this vertex, and filter out ones we've already generated+          let (neighbors, polys) = genNeighbors t v d+              edges  = S.fromList $ map (mkEdge v) neighbors+              edges' = edges `S.difference` visitedEdges ts+              polys' = polys `S.difference` visitedPolygons ts++          -- generate some edges and polygons+          F.mapM_ (tell . e) edges'+          F.mapM_ (tell . p) polys'++          -- remember that we generated them+          modify (\ts -> ts { visitedEdges = edges' `S.union` visitedEdges ts })+          modify (\ts -> ts { visitedPolygons = polys' `S.union` visitedPolygons ts })++          -- follow edges and continue recursively+          zipWithM_ (\d i -> generateTiling' (follow t i) (v ^+^ d) d)+            (map (^-^ v) $ neighbors) [0..]+ -- | Generate the neighboring vertices and polygons of a given vertex. genNeighbors :: Tiling -> Q2 -> Q2 -> ([Q2], S.Set Polygon) genNeighbors t v d = (neighbors, S.fromList polys) where-  (neighbors, polys) +  (neighbors, polys)     = unzip . snd-      $ mapAccumL +      $ mapAccumL           (\d' poly -> (polyRotation poly d', (v ^+^ d', genPolyVs poly v d')))           (negateV d)           (curConfig t)-  + -- | Generate the vertices of the given polygon, with one vertex at the given point --   and an adjacent vertex at the given offset.-genPolyVs :: TilingPoly +genPolyVs :: TilingPoly           -> Q2          -- ^ one vertex           -> Q2          -- ^ vector to second vertex           -> Polygon genPolyVs p v d = Polygon-                . scanl (^+^) v +                . scanl (^+^) v                 . take (polySides p - 1)-                . iterate (polyExtRotation p) +                . iterate (polyExtRotation p)                 $ d  ------------------------------------------------------------@@ -350,28 +350,28 @@  -- | Draw a tiling, with a given width and height and default colors --   for the polygons.-drawTiling :: (Renderable (Path R2) b, Backend b R2) +drawTiling :: (Renderable (Path R2) b, Backend b R2)            => Tiling -> Double -> Double -> Diagram b R2-drawTiling = -  drawTilingStyled +drawTiling =+  drawTilingStyled     (mempty # lw 0.02)-    (\p -> mempty +    (\p -> mempty            # lw 0-           # fc ( polyColor -                . polyFromSides -                . length +           # fc ( polyColor+                . polyFromSides+                . length                 . polygonVertices                 $ p                 )     )-  + -- | Draw a tiling with customizable styles for the polygons.  This is --   just an example, which you can use as the basis of your own --   tiling-drawing routine.-drawTilingStyled :: (Renderable (Path R2) b, Backend b R2) +drawTilingStyled :: (Renderable (Path R2) b, Backend b R2)                  => Style R2 -> (Polygon -> Style R2)                  -> Tiling -> Double -> Double -> Diagram b R2-drawTilingStyled eStyle pStyle t w h = +drawTilingStyled eStyle pStyle t w h =   mkDia $ generateTiling t (0,0) (1,0) inRect              -- draw the edges and polygons into separate@@ -389,7 +389,7 @@ ------------------------------------------------------------  -- Regular tilings-    + t3 :: Tiling t3 = Tiling (replicate 6 Triangle) (const t3) @@ -405,14 +405,14 @@ --   The argument is the number of sides of the polygons surrounding a vertex. mk3Tiling :: [Int] -> Tiling mk3Tiling (ps@[a,b,c])-      = Tiling +      = Tiling           (map polyFromSides ps)           (\i -> case i `mod` 3 of                    0 -> mk3Tiling (reverse ps)                    1 -> mk3Tiling [a,c,b]                    2 -> mk3Tiling [b,a,c]                    _ -> error "i `mod` 3 is not 0, 1,or 2! the sky is falling!"-          )           +          ) mk3Tiling _ = error "mk3Tiling may only be called on a list of length 3."  t4612 :: Tiling
+ tests/Diagrams/TwoD/Path/Turtle/Tests.hs view
@@ -0,0 +1,186 @@+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, ViewPatterns  #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Diagrams.TwoD.Path.Turtle.Tests+  ( tests+  ) where++import Control.Arrow ((***))++import Test.Framework+import Test.Framework.Providers.QuickCheck2+import Test.QuickCheck++import Diagrams.Prelude+import Diagrams.TwoD.Path.Turtle.Internal++tests :: [Test]+tests =+  [ testProperty "Moves forward correctly" movesForward+  , testProperty "Moves backward correctly" movesBackward+  , testProperty "Moves backward and forward correctly" movesBackwardAndForward+  , testProperty "Moves left correctly" movesLeft+  , testProperty "Moves right correctly" movesRight+  , testProperty "Current trail is empty when pen is up" trailEmptyWhenPenUp+  , testProperty "penHop creates a new path when pen is down" verifyPenHopWhenPenDown+  , testProperty "penHop does not create new path when pen is up" verifyPenHopWhenPenUp +  , testProperty "closeCurrent works correctly when no trail has started and pen is down" verifyCloseCurrent+  ]+++-- | The turtle moves forward by the right distance+movesForward :: Turtle+             -> Property+movesForward t =  isPenDown t ==>+     diffPos      == round x  -- position is set correctly+  && lenCurrTrail == round x  -- most recent trail has the right length+ where+  x            = 2.0+  t'           = t  # forward x+  diffPos :: Int+  diffPos      = round $ magnitude $ penPos t' .-. penPos t+  lenCurrTrail :: Int+  lenCurrTrail = round $ flip arcLength 0.0001 . head . trailSegments . snd . currTrail $ t'++-- | The turtle moves forward by the right distance+movesBackward :: Turtle+             -> Property+movesBackward t =  isPenDown t ==>+     diffPos      == round x  -- position is set correctly+  && lenCurrTrail == round x  -- most recent trail has the right length+ where+  x            = 2.0+  t'           = t  # backward x+  diffPos :: Int+  diffPos      = round $ magnitude $ penPos t' .-. penPos t+  lenCurrTrail :: Int+  lenCurrTrail = round $ flip arcLength 0.0001 . head . trailSegments . snd . currTrail $ t'++-- | The turtle moves forward and backward by the same distance and returns to+-- the same position+movesBackwardAndForward :: Turtle+                        -> Property+movesBackwardAndForward t = isPenDown t ==>+     abs(endX - startX) < 0.0001+  && abs(endY - startY) < 0.0001+  && totalSegmentsAdded == 2+ where+  x                          = 2.0+  t'                         = t # forward x # backward x+  (unp2 -> (startX, startY)) = penPos t+  (unp2 -> (endX, endY))     = penPos t'+  totalSegmentsAdded         = (uncurry (-)) . (getTrailLength *** getTrailLength) $ (t',t)+  getTrailLength             = (length . trailSegments . snd . currTrail)++-- | The turtle moves left four times and returns to the same position+movesLeft  :: Turtle+           -> Property+movesLeft t = isPenDown t ==>+     abs(endX - startX) < 0.0001+  && abs(endY - startY) < 0.0001+ where+  x                          = 2.0+  turn                       = 90+  t'                         = t # forward x # left turn+                                 # forward x # left turn+                                 # forward x # left turn+                                 # forward x+  (unp2 -> (startX, startY)) = penPos t+  (unp2 -> (endX, endY))     = penPos t'++-- | The turtle moves right four times and returns to the same position+movesRight  :: Turtle+            -> Property+movesRight t = isPenDown t ==>+     abs(endX - startX) < 0.0001+  && abs(endY - startY) < 0.0001+ where+  x                          = 2.0+  turn                       = 90+  t'                         = t # forward x # right turn+                                 # forward x # right turn+                                 # forward x # right turn+                                 # forward x+  (unp2 -> (startX, startY)) = penPos t+  (unp2 -> (endX, endY))     = penPos t'++-- | When the trail is empty, @currTrail@ always remains empty and no new paths+-- are added+trailEmptyWhenPenUp :: Turtle+                    -> Property+trailEmptyWhenPenUp t = isPenDown t ==> trailIsEmpty+ where+  t'           = t # penUp # forward 4 # backward 3+  trailIsEmpty = null . trailSegments . snd . currTrail $ t'++-- | Verify that the turtle adds a trail to @paths@ when pen is down+-- and @penHop@ is called.+verifyPenHopWhenPenDown :: Turtle+                        -> Property+verifyPenHopWhenPenDown t = isPenDown t ==> (numPaths t') - (numPaths t) == 1+ where +  t' = t # forward 2.0 # penHop+  numPaths = length . paths++-- | Verify that the turtle does not add a trail to @paths@ when pen is up+-- and @penHop@ is called.+verifyPenHopWhenPenUp :: Turtle+                      -> Property+verifyPenHopWhenPenUp t = not (isPenDown t) && (null . trailSegments . snd . currTrail $ t) ==>  (numPaths t') == (numPaths t)+ where +  t' = t # forward 2.0 # penHop+  numPaths = length . paths++-- | Verify that calling @closeCurrent@ updates the turtle position to the beginning to the trail+verifyCloseCurrent :: Turtle+                   -> Property+verifyCloseCurrent t = (isPenDown t)  && (null . trailSegments . snd . currTrail $ t) ==> (penPos t') == origin+ where+  t' = t # setPenPos origin # forward 2.0 # right 90 # forward 3.0 # closeCurrent+-- | Arbitrary instance for the Turtle type.+--+-- FIXME this arbitrary instance can generate+-- invalid turtle. For e.g. when pen is up, and+-- the current trail is not empty.+--+-- Currently we filter these out in the tests+instance Arbitrary Turtle where+   arbitrary =+     Turtle <$> arbitrary+            <*> arbitrary+            <*> (Deg <$> arbitrary)+            <*> arbitrary+            <*> arbitrary+            <*> arbitrary++-- | Arbitrary instance for Diagrams type P2+instance Arbitrary P2 where+  arbitrary = p2 <$> arbitrary++-- | Arbitrary instance for TurtlePath+instance Arbitrary TurtlePath where+  arbitrary = TurtlePath <$> arbitrary <*> arbitrary++-- | Arbitrary instance of PenStyle+--+-- The color of the pen is chosen from black, blue or brown only+instance Arbitrary PenStyle where+  arbitrary = do+    penWidth_ <- arbitrary+    colorCode <- choose (1,3) :: Gen Int+    case colorCode of+      1 -> return $ PenStyle penWidth_  black+      2 -> return $ PenStyle penWidth_  blue+      3 -> return $ PenStyle penWidth_  brown+      _ -> error "Should not get here"++-- | Arbitrary instance of Segment+--+-- Currently this only generates linear segments only+instance Arbitrary (Segment R2)  where+  arbitrary = do+    h <- Deg <$> arbitrary+    x <- r2 <$> arbitrary+    return $ rotate h (Linear x)++instance Arbitrary (Trail R2) where+  arbitrary = Trail <$> arbitrary <*> (return False)
+ tests/TestSuite.hs view
@@ -0,0 +1,11 @@+-- | Main module to run all tests.+--+module Main where++import Test.Framework (defaultMain, testGroup)++import qualified  Diagrams.TwoD.Path.Turtle.Tests++main :: IO ()+main = defaultMain+    [ testGroup "Diagrams.TwoD.Path.Turtle.Tests" Diagrams.TwoD.Path.Turtle.Tests.tests ]