diagrams 0.1 → 0.2
raw patch · 11 files changed
+974/−1558 lines, 11 filesdep +colourdep +containers
Dependencies added: colour, containers
Files
- CHANGELOG +14/−0
- Graphics/Rendering/Diagrams.hs +112/−36
- Graphics/Rendering/Diagrams/Attributes.hs +75/−38
- Graphics/Rendering/Diagrams/Colors.hs +0/−1338
- Graphics/Rendering/Diagrams/Engine.hs +104/−30
- Graphics/Rendering/Diagrams/Layouts.hs +171/−16
- Graphics/Rendering/Diagrams/Paths.hs +177/−0
- Graphics/Rendering/Diagrams/Shapes.hs +137/−25
- Graphics/Rendering/Diagrams/Types.hs +137/−54
- README +31/−16
- diagrams.cabal +16/−5
+ CHANGELOG view
@@ -0,0 +1,14 @@+New in version 0.2:++ * rawCairo function for creating primitive diagrams from raw Cairo code+ * line join, cap, and dashing attributes+ * bouding box visualization functions for debugging+ * new padding and positioning combinators+ * PDF, PS, and SVG output+ * experimental tree layout+ * paths, polygons, bezier curves+ * create diagrams from text+ * render on top of arbitrary background images+ * depend on colour package instead of built-in colors+ * new examples: snellen, wordcloud, dragon+ * emptyPath and pathConcat
Graphics/Rendering/Diagrams.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-} ----------------------------------------------------------------------------- -- | -- Module : Graphics.Rendering.Diagrams@@ -8,7 +9,8 @@ -- Portability : portable -- -- An embedded domain-specific language (EDSL) for creating simple--- diagrams, built on top of the Cairo rendering engine.+-- diagrams, illustrations, and other types of graphics, built on top+-- of the Cairo rendering engine. -- ----------------------------------------------------------------------------- @@ -26,9 +28,17 @@ -- ** Shapes , circle- , poly , rect+ , roundRect++ , regPolyPath+ , regPoly+ , rotRegPoly+ , shape+ , rawCairo+ , text+ , textPath -- ** Spacers @@ -36,6 +46,18 @@ , vspace , empty + -- ** Paths++ , Path+ , emptyPath+ , pathFromVertices, pathFromVectors+ , pathConcat+ , closed, isClosed+ , rotPath++ , straight+ , curved+ -- * Combinators -- $comb @@ -53,11 +75,23 @@ , hdistrib, vdistrib , hdistribA, vdistribA + , position, positionA+ , VAlignment , top, vcenter, bottom , HAlignment , left, hcenter, right + -- ** Complex layouts++ , tree++ -- ** Miscellaneous++ , pad, padA+ , showBBox, showBBoxes+ , withSize+ -- * Transformations -- $transf @@ -70,64 +104,71 @@ -- * Attributes -- $attr + -- ** Colors+ -- $color++ , Color+ , module Data.Colour.Names , fillColor, fc- , fillTransparency, ft , lineColor, lc++ -- ** Other attributes+ , lineWidth, lw - , Color- , rgb- , rgba- , module Graphics.Rendering.Diagrams.Colors+ , lineCap, LineCap(..)+ , lineJoin, LineJoin(..)+ , dashing + , typeface, tf -- * Rendering+ -- $render - , renderToPng- , compose+ , renderAs+ , OutputType(..)+ , SizeSpec(..)+ , renderOverPNG ) where import Graphics.Rendering.Diagrams.Types import Graphics.Rendering.Diagrams.Shapes+import Graphics.Rendering.Diagrams.Paths import Graphics.Rendering.Diagrams.Attributes-import Graphics.Rendering.Diagrams.Colors import Graphics.Rendering.Diagrams.Layouts import Graphics.Rendering.Diagrams.Engine+import Data.Colour.Names {- $intro "Graphics.Rendering.Diagrams" is an embedded domain-specific language-(EDSL) for creating simple diagrams. It is compositional; starting+(EDSL) for creating simple graphics. It is compositional; starting with some basic shapes, you can build up complex diagrams by combining simpler diagrams in various ways. A few fundamental concepts to keep in mind: * When constructing diagrams, there is no concept of an absolute- coordinate system; everything is relative. You cannot say \"this- diagram should go at (2,1)\"; you can only say \"this diagram should- go to the right of this other one\", or \"this diagram should go two- units to the right and one unit above where it would otherwise- be\".+ coordinate system, although each diagram does have a local+ coordinate system. * Every diagram has an associated rectangular bounding box, which determines its positioning and alignment relative to other diagrams. Usually this makes no difference but there are times- when it's nice to be aware of it. For example, translating a+ when it\'s nice to be aware of it. For example, translating a diagram works by moving the diagram relative to its bounding box; positioning the bounding box where it would have gone means the- diagram itself ends up elsewhere. Also, some shapes have- non-obvious bounding boxes; for example, regular polygons have a- bounding box that fits their circumcircle.+ diagram itself ends up elsewhere. To visualize bounding boxes,+ you can use the 'showBBox' and 'showBBoxes' functions. - * The positive y-axis points downwards.+ * The positive y-axis points downwards. This also means that+ positive rotations are clockwise. -For some simple examples, see-<http://byorgey.wordpress.com/2008/04/30/new-haskell-diagrams-library/>.+For some simple examples, see <http://code.haskell.org/diagrams/>. Enjoy! Please send comments, suggestions, bug reports, or patches to-byorgey at gmail dot com.+byorgey at cis dot upenn dot edu. -} @@ -139,6 +180,10 @@ shape :: (ShapeClass s) => s -> Diagram shape = Prim . Shape +-- | Create text with black fill, no outline, and a default font.+text :: Double -> String -> Diagram+text sz str = fc black $ lw 0 $ textPath sz str+ -- | @hspace w@ is a 'Diagram' which produces no output but takes up -- @w@ amount of space horizontally. Useful for manually creating -- horizontal separation between two diagrams. A negative value@@ -160,23 +205,54 @@ empty :: Double -> Double -> Diagram empty w h = Sized (w, h) Empty +-- $comb+-- Various ways to combine 'Diagram's into larger 'Diagram's.+ -- $transf -- Various ways to modify and transform 'Diagram's. --- | XXX comment me+-- | Explicitly set a diagram's bounding box, by giving the+-- coordinates of the upper left and lower right corners (keeping in+-- mind that the positive y-axis points downwards). Particularly+-- useful for applying to the top-level diagram in order to only+-- view a portion of it in the rendered output. view :: Point -> Point -> Diagram -> Diagram-view (x1,y1) (x2,y2) d = Sized (x2-x1, y2-y1) . translate ((x1-x2)/2) ((y1-y2)/2) $ d+view (x1,y1) (x2,y2) = Sized (x2-x1, y2-y1) . translate ((x1-x2)/2 - x1)+ ((y1-y2)/2 - y1) -- $attr -- Attributes which affect the way in which a 'Diagram' is rendered.--- For a large list of predefined 'Color' values, see--- "Graphics.Rendering.Diagrams.Colors". --- | Render a diagram to a file in PNG format.-renderToPng :: String -- ^ The name of the file to create.- -> Int -- ^ The desired width of the image, in pixels.- -> Int -- ^ The desired height of the image.- -> Diagram -- ^ The diagram to render.- -> IO ()-renderToPng name w h dia = writePng name w h $- compose (fromIntegral w) (fromIntegral h) dia+-- $color+-- Diagrams depends on the "Data.Colour" library (available on Hackage+-- as the \"colour\" package) for colo(u)r. Any functions expecting a+-- color can take any instance of the 'Color' type class, which has+-- instances for both the 'Data.Colour.Colour' and+-- 'Data.Colour.AlphaColour' types from "Data.Colour".+--+-- For normal use, you can just use color names from+-- "Data.Colour.Names", which is re-exported by+-- "Graphics.Rendering.Diagrams" for convenience. For more+-- sophisticated color manipulation, use the facilities provided by+-- the "Data.Colour" library. For example, to create a color directly+-- from RGB values, you can use the @rgb@ function from+-- "Data.Colour.SRGB.Linear".++-- $render+-- Rendering diagrams to a file is accomplished with the 'renderAs'+-- function. 'renderOverPNG' also provides a specialized rendering+-- method, which overlays a rendererd diagram on top of an existing+-- PNG.++-- | Render a diagram to a file.+renderAs :: OutputType -- ^ The output type to use (PNG, PS, PDF, or SVG)+ -> String -- ^ The name of the file to create.+ -> SizeSpec -- ^ The desired width or height of the image.+ -> Diagram -- ^ The diagram to render.+ -> IO ()+renderAs otype = renderWithBackend (chooseBackend otype)++-- | @renderOverPNG infile outfile d@ reads the PNG @infile@+-- and renders @d@ over this, saving the output as a PNG to @outfile@.+renderOverPNG :: FilePath -> FilePath -> Diagram -> IO ()+renderOverPNG srcfile dstfile dia = renderOverlayPNG srcfile dstfile dia
Graphics/Rendering/Diagrams/Attributes.hs view
@@ -12,11 +12,16 @@ -- ----------------------------------------------------------------------------- module Graphics.Rendering.Diagrams.Attributes- ( fillColor, fc- , fillTransparency, ft+ ( defaultAttributes+ , fillColor, fc , lineColor, lc , lineWidth, lw+ , lineCap, C.LineCap(..)+ , lineJoin, C.LineJoin(..)+ , dashing + , typeface, tf+ , stretch, scale, scaleX, scaleY , translate, translateX, translateY , rotate, rotateR@@ -31,40 +36,38 @@ -- Fill color ---------------------- -- | Specify the default fill color for a 'Diagram'.-newtype Fill = Fill Color deriving (Eq, Show, Read)+newtype Fill = Fill SomeColor instance AttrClass Fill where- renderAttr (Fill f) = return (setEnvFillColor f)+ renderAttr (Fill (SomeColor f)) = return (setEnvFillColor f) -- | Draw a diagram using the given fill color. Note that the new -- color only applies to parts of the diagram which are not -- otherwise colored; subdiagrams which already have an explicit -- fill color will not be affected. The default fill color is -- completely transparent.-fillColor :: Color -> Diagram -> Diagram-fillColor = Ann . Attr . Fill+fillColor :: Color c => c -> Diagram -> Diagram+fillColor = Ann . Attr . Fill . SomeColor -- | 'fc' is provided as a convenient short synonym for 'fillColor'.-fc :: Color -> Diagram -> Diagram+fc :: Color c => c -> Diagram -> Diagram fc = fillColor -- -- Stroke color ---------------------- -- | Specify the default stroke color for a 'Diagram'.-newtype Stroke = Stroke Color deriving (Eq, Show, Read)+newtype Stroke = Stroke SomeColor instance AttrClass Stroke where- renderAttr (Stroke sc) = return (setEnvStrokeColor sc)+ renderAttr (Stroke (SomeColor sc)) = return (setEnvStrokeColor sc) -- | Draw a diagram using the given color for lines. Note that the new -- color only applies to parts of the diagram which are not -- otherwise colored; subdiagrams which already have an explicit -- line color will not be affected. The default line color is black.-lineColor :: Color -> Diagram -> Diagram-lineColor = Ann . Attr . Stroke+lineColor :: Color c => c -> Diagram -> Diagram+lineColor = Ann . Attr . Stroke . SomeColor -- | 'lc' is provided as a convenient short synonym for 'lineColor'.-lc :: Color -> Diagram -> Diagram+lc :: Color c => c -> Diagram -> Diagram lc = lineColor @@ -90,32 +93,20 @@ lw :: Double -> Diagram -> Diagram lw = lineWidth ----- Transparency --------------------------------newtype FillTransparency = FT Double deriving (Eq, Show, Read)-instance AttrClass FillTransparency where- renderAttr (FT t) = return setFillAlpha- where setFillAlpha env = env { envFillColor = newFillColor env }- newFillColor env = RGBA r g b t- where (RGBA r g b _) = envFillColor env+-- Fonts ----------------------------- --- XXX improve this -- currently, you have to put it AFTER the color!--- | Set the transparency used for the fill color, from 0 (completely--- transparent) to 255 (completely opaque). Note that you can set--- the alpha channel of the fill color using 'fillColor' combined--- with 'rgba', but 'fillTransparency' allows you to set the alpha--- channel independently of the color channels. This means you can--- use it together with the colors defined in--- "Graphics.Rendering.Diagrams.Colors".-fillTransparency :: Int -> Diagram -> Diagram-fillTransparency = Ann . Attr . FT . (/255) . fromIntegral+-- | Set the typeface for a text diagram+newtype Typeface = Typeface String deriving (Eq, Show, Read)+instance AttrClass Typeface where+ renderAttr (Typeface fontname) = c $ C.selectFontFace fontname C.FontSlantNormal C.FontWeightNormal >> return id --- | 'ft' is provided as a convenient short synonym for 'fillTransparency'.-ft = fillTransparency+-- | Change the default typeface to one named.+typeface :: String -> Diagram -> Diagram+typeface fontname = Ann (Attr (Typeface fontname)) --- XXX put a line transparency attribute here+-- | Convenience function to change the typeface.+tf :: String -> Diagram -> Diagram+tf = typeface -- Rotate ---------------------------- @@ -167,7 +158,7 @@ -- respectively. newtype Scale = Scale Point deriving (Eq, Show, Read) instance AttrClass Scale where- attrSize (Scale k) s = k .* s+ attrSize (Scale k) s = k .*. s renderAttr (Scale (x,y)) = c $ C.scale x y >> return id -- | Stretch a diagram by a separate scaling factor for each axis.@@ -191,3 +182,49 @@ -- to @stretch 1 s@. scaleY :: Double -> Diagram -> Diagram scaleY sy = stretch 1 sy+++-- Stroke styles ----------------------------------++newtype LCap = LCap C.LineCap+instance AttrClass LCap where+ renderAttr (LCap lcap) = c $ C.setLineCap lcap >> return id++-- | Set the line cap style. Valid values for 'LineCap' are+-- @LineCapButt@, @LineCapRound@, and @LineCapSquare@.+lineCap :: C.LineCap -> Diagram -> Diagram+lineCap = Ann . Attr . LCap++newtype LJoin = LJoin C.LineJoin+instance AttrClass LJoin where+ renderAttr (LJoin lj) = c $ C.setLineJoin lj >> return id++-- | Set the line join style. Valid values for 'LineJoin' are+-- @LineJoinMiter@, @LineJoinRound@, and @LineJoinBevel@.+lineJoin :: C.LineJoin -> Diagram -> Diagram+lineJoin = Ann . Attr . LJoin++data Dashing = Dashing [Double] Double+instance AttrClass Dashing where+ renderAttr (Dashing ds offs) = c $ C.setDash ds offs >> return id++-- | Set the line dashing pattern.+dashing :: [Double] -- ^ a list specifying alternate lengths of on+ -- and off portions of the stroke. The empty+ -- list indicates no dashing.+ -> Double -- ^ an offset into the dash pattern at which the+ -- stroke should start+ -> Diagram -> Diagram+dashing ds offs = Ann (Attr (Dashing ds offs))++-- | Apply all the default attributes to a 'Diagram'.+defaultAttributes :: Diagram -> Diagram+defaultAttributes =+ case defaultDiaRenderEnv of+ (DREnv (SomeColor fillC) (SomeColor strokeC) strokeW) ->+ lc strokeC .+ lw strokeW .+ lineCap C.LineCapButt .+ lineJoin C.LineJoinMiter .+ dashing [] 0 .+ fc fillC
− Graphics/Rendering/Diagrams/Colors.hs
@@ -1,1338 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Graphics.Rendering.Diagrams.Colors--- Copyright : (c) Brent Yorgey 2008--- License : BSD-style (see LICENSE)--- Maintainer : byorgey@gmail.com--- Stability : experimental--- Portability : portable------ Convenient pre-defined colors for "Graphics.Rendering.Diagrams", an--- embedded domain-specific language (EDSL) for creating simple--- diagrams. Color names and definitions pulled from X11\'s list of--- colors.----------------------------------------------------------------------------------module Graphics.Rendering.Diagrams.Colors where--import Graphics.Rendering.Diagrams.Types--rgb' :: Int -> Int -> Int -> Color-rgb' r g b = rgb (fromIntegral r / 255)- (fromIntegral g / 255)- (fromIntegral b / 255)--snow :: Color-snow = rgb' 255 250 250-ghostWhite :: Color-ghostWhite = rgb' 248 248 255-whiteSmoke :: Color-whiteSmoke = rgb' 245 245 245-gainsboro :: Color-gainsboro = rgb' 220 220 220-floralWhite :: Color-floralWhite = rgb' 255 250 240-oldLace :: Color-oldLace = rgb' 253 245 230-linen :: Color-linen = rgb' 250 240 230-antiqueWhite :: Color-antiqueWhite = rgb' 250 235 215-papayaWhip :: Color-papayaWhip = rgb' 255 239 213-blanchedAlmond :: Color-blanchedAlmond = rgb' 255 235 205-bisque :: Color-bisque = rgb' 255 228 196-peachPuff :: Color-peachPuff = rgb' 255 218 185-navajoWhite :: Color-navajoWhite = rgb' 255 222 173-moccasin :: Color-moccasin = rgb' 255 228 181-cornsilk :: Color-cornsilk = rgb' 255 248 220-ivory :: Color-ivory = rgb' 255 255 240-lemonChiffon :: Color-lemonChiffon = rgb' 255 250 205-seashell :: Color-seashell = rgb' 255 245 238-honeydew :: Color-honeydew = rgb' 240 255 240-mintCream :: Color-mintCream = rgb' 245 255 250-azure :: Color-azure = rgb' 240 255 255-aliceBlue :: Color-aliceBlue = rgb' 240 248 255-lavender :: Color-lavender = rgb' 230 230 250-lavenderBlush :: Color-lavenderBlush = rgb' 255 240 245-mistyRose :: Color-mistyRose = rgb' 255 228 225-white :: Color-white = rgb' 255 255 255-black :: Color-black = rgb' 0 0 0-darkSlateGray :: Color-darkSlateGray = rgb' 47 79 79-darkSlateGrey :: Color-darkSlateGrey = rgb' 47 79 79-dimGray :: Color-dimGray = rgb' 105 105 105-dimGrey :: Color-dimGrey = rgb' 105 105 105-slateGray :: Color-slateGray = rgb' 112 128 144-slateGrey :: Color-slateGrey = rgb' 112 128 144-lightSlateGray :: Color-lightSlateGray = rgb' 119 136 153-lightSlateGrey :: Color-lightSlateGrey = rgb' 119 136 153-gray :: Color-gray = rgb' 190 190 190-grey :: Color-grey = rgb' 190 190 190-lightGrey :: Color-lightGrey = rgb' 211 211 211-lightGray :: Color-lightGray = rgb' 211 211 211-midnightBlue :: Color-midnightBlue = rgb' 25 25 112-navy :: Color-navy = rgb' 0 0 128-navyBlue :: Color-navyBlue = rgb' 0 0 128-cornflowerBlue :: Color-cornflowerBlue = rgb' 100 149 237-darkSlateBlue :: Color-darkSlateBlue = rgb' 72 61 139-slateBlue :: Color-slateBlue = rgb' 106 90 205-mediumSlateBlue :: Color-mediumSlateBlue = rgb' 123 104 238-lightSlateBlue :: Color-lightSlateBlue = rgb' 132 112 255-mediumBlue :: Color-mediumBlue = rgb' 0 0 205-royalBlue :: Color-royalBlue = rgb' 65 105 225-blue :: Color-blue = rgb' 0 0 255-dodgerBlue :: Color-dodgerBlue = rgb' 30 144 255-deepSkyBlue :: Color-deepSkyBlue = rgb' 0 191 255-skyBlue :: Color-skyBlue = rgb' 135 206 235-lightSkyBlue :: Color-lightSkyBlue = rgb' 135 206 250-steelBlue :: Color-steelBlue = rgb' 70 130 180-lightSteelBlue :: Color-lightSteelBlue = rgb' 176 196 222-lightBlue :: Color-lightBlue = rgb' 173 216 230-powderBlue :: Color-powderBlue = rgb' 176 224 230-paleTurquoise :: Color-paleTurquoise = rgb' 175 238 238-darkTurquoise :: Color-darkTurquoise = rgb' 0 206 209-mediumTurquoise :: Color-mediumTurquoise = rgb' 72 209 204-turquoise :: Color-turquoise = rgb' 64 224 208-cyan :: Color-cyan = rgb' 0 255 255-lightCyan :: Color-lightCyan = rgb' 224 255 255-cadetBlue :: Color-cadetBlue = rgb' 95 158 160-mediumAquamarine :: Color-mediumAquamarine = rgb' 102 205 170-aquamarine :: Color-aquamarine = rgb' 127 255 212-darkGreen :: Color-darkGreen = rgb' 0 100 0-darkOliveGreen :: Color-darkOliveGreen = rgb' 85 107 47-darkSeaGreen :: Color-darkSeaGreen = rgb' 143 188 143-seaGreen :: Color-seaGreen = rgb' 46 139 87-mediumSeaGreen :: Color-mediumSeaGreen = rgb' 60 179 113-lightSeaGreen :: Color-lightSeaGreen = rgb' 32 178 170-paleGreen :: Color-paleGreen = rgb' 152 251 152-springGreen :: Color-springGreen = rgb' 0 255 127-lawnGreen :: Color-lawnGreen = rgb' 124 252 0-green :: Color-green = rgb' 0 255 0-chartreuse :: Color-chartreuse = rgb' 127 255 0-mediumSpringGreen :: Color-mediumSpringGreen = rgb' 0 250 154-greenYellow :: Color-greenYellow = rgb' 173 255 47-limeGreen :: Color-limeGreen = rgb' 50 205 50-yellowGreen :: Color-yellowGreen = rgb' 154 205 50-forestGreen :: Color-forestGreen = rgb' 34 139 34-oliveDrab :: Color-oliveDrab = rgb' 107 142 35-darkKhaki :: Color-darkKhaki = rgb' 189 183 107-khaki :: Color-khaki = rgb' 240 230 140-paleGoldenrod :: Color-paleGoldenrod = rgb' 238 232 170-lightGoldenrodYellow :: Color-lightGoldenrodYellow = rgb' 250 250 210-lightYellow :: Color-lightYellow = rgb' 255 255 224-yellow :: Color-yellow = rgb' 255 255 0-gold :: Color-gold = rgb' 255 215 0-lightGoldenrod :: Color-lightGoldenrod = rgb' 238 221 130-goldenrod :: Color-goldenrod = rgb' 218 165 32-darkGoldenrod :: Color-darkGoldenrod = rgb' 184 134 11-rosyBrown :: Color-rosyBrown = rgb' 188 143 143-indianRed :: Color-indianRed = rgb' 205 92 92-saddleBrown :: Color-saddleBrown = rgb' 139 69 19-sienna :: Color-sienna = rgb' 160 82 45-peru :: Color-peru = rgb' 205 133 63-burlywood :: Color-burlywood = rgb' 222 184 135-beige :: Color-beige = rgb' 245 245 220-wheat :: Color-wheat = rgb' 245 222 179-sandyBrown :: Color-sandyBrown = rgb' 244 164 96-tan :: Color-tan = rgb' 210 180 140-chocolate :: Color-chocolate = rgb' 210 105 30-firebrick :: Color-firebrick = rgb' 178 34 34-brown :: Color-brown = rgb' 165 42 42-darkSalmon :: Color-darkSalmon = rgb' 233 150 122-salmon :: Color-salmon = rgb' 250 128 114-lightSalmon :: Color-lightSalmon = rgb' 255 160 122-orange :: Color-orange = rgb' 255 165 0-darkOrange :: Color-darkOrange = rgb' 255 140 0-coral :: Color-coral = rgb' 255 127 80-lightCoral :: Color-lightCoral = rgb' 240 128 128-tomato :: Color-tomato = rgb' 255 99 71-orangeRed :: Color-orangeRed = rgb' 255 69 0-red :: Color-red = rgb' 255 0 0-hotPink :: Color-hotPink = rgb' 255 105 180-deepPink :: Color-deepPink = rgb' 255 20 147-pink :: Color-pink = rgb' 255 192 203-lightPink :: Color-lightPink = rgb' 255 182 193-paleVioletRed :: Color-paleVioletRed = rgb' 219 112 147-maroon :: Color-maroon = rgb' 176 48 96-mediumVioletRed :: Color-mediumVioletRed = rgb' 199 21 133-violetRed :: Color-violetRed = rgb' 208 32 144-magenta :: Color-magenta = rgb' 255 0 255-violet :: Color-violet = rgb' 238 130 238-plum :: Color-plum = rgb' 221 160 221-orchid :: Color-orchid = rgb' 218 112 214-mediumOrchid :: Color-mediumOrchid = rgb' 186 85 211-darkOrchid :: Color-darkOrchid = rgb' 153 50 204-darkViolet :: Color-darkViolet = rgb' 148 0 211-blueViolet :: Color-blueViolet = rgb' 138 43 226-purple :: Color-purple = rgb' 160 32 240-mediumPurple :: Color-mediumPurple = rgb' 147 112 219-thistle :: Color-thistle = rgb' 216 191 216-snow1 :: Color-snow1 = rgb' 255 250 250-snow2 :: Color-snow2 = rgb' 238 233 233-snow3 :: Color-snow3 = rgb' 205 201 201-snow4 :: Color-snow4 = rgb' 139 137 137-seashell1 :: Color-seashell1 = rgb' 255 245 238-seashell2 :: Color-seashell2 = rgb' 238 229 222-seashell3 :: Color-seashell3 = rgb' 205 197 191-seashell4 :: Color-seashell4 = rgb' 139 134 130-antiqueWhite1 :: Color-antiqueWhite1 = rgb' 255 239 219-antiqueWhite2 :: Color-antiqueWhite2 = rgb' 238 223 204-antiqueWhite3 :: Color-antiqueWhite3 = rgb' 205 192 176-antiqueWhite4 :: Color-antiqueWhite4 = rgb' 139 131 120-bisque1 :: Color-bisque1 = rgb' 255 228 196-bisque2 :: Color-bisque2 = rgb' 238 213 183-bisque3 :: Color-bisque3 = rgb' 205 183 158-bisque4 :: Color-bisque4 = rgb' 139 125 107-peachPuff1 :: Color-peachPuff1 = rgb' 255 218 185-peachPuff2 :: Color-peachPuff2 = rgb' 238 203 173-peachPuff3 :: Color-peachPuff3 = rgb' 205 175 149-peachPuff4 :: Color-peachPuff4 = rgb' 139 119 101-navajoWhite1 :: Color-navajoWhite1 = rgb' 255 222 173-navajoWhite2 :: Color-navajoWhite2 = rgb' 238 207 161-navajoWhite3 :: Color-navajoWhite3 = rgb' 205 179 139-navajoWhite4 :: Color-navajoWhite4 = rgb' 139 121 94-lemonChiffon1 :: Color-lemonChiffon1 = rgb' 255 250 205-lemonChiffon2 :: Color-lemonChiffon2 = rgb' 238 233 191-lemonChiffon3 :: Color-lemonChiffon3 = rgb' 205 201 165-lemonChiffon4 :: Color-lemonChiffon4 = rgb' 139 137 112-cornsilk1 :: Color-cornsilk1 = rgb' 255 248 220-cornsilk2 :: Color-cornsilk2 = rgb' 238 232 205-cornsilk3 :: Color-cornsilk3 = rgb' 205 200 177-cornsilk4 :: Color-cornsilk4 = rgb' 139 136 120-ivory1 :: Color-ivory1 = rgb' 255 255 240-ivory2 :: Color-ivory2 = rgb' 238 238 224-ivory3 :: Color-ivory3 = rgb' 205 205 193-ivory4 :: Color-ivory4 = rgb' 139 139 131-honeydew1 :: Color-honeydew1 = rgb' 240 255 240-honeydew2 :: Color-honeydew2 = rgb' 224 238 224-honeydew3 :: Color-honeydew3 = rgb' 193 205 193-honeydew4 :: Color-honeydew4 = rgb' 131 139 131-lavenderBlush1 :: Color-lavenderBlush1 = rgb' 255 240 245-lavenderBlush2 :: Color-lavenderBlush2 = rgb' 238 224 229-lavenderBlush3 :: Color-lavenderBlush3 = rgb' 205 193 197-lavenderBlush4 :: Color-lavenderBlush4 = rgb' 139 131 134-mistyRose1 :: Color-mistyRose1 = rgb' 255 228 225-mistyRose2 :: Color-mistyRose2 = rgb' 238 213 210-mistyRose3 :: Color-mistyRose3 = rgb' 205 183 181-mistyRose4 :: Color-mistyRose4 = rgb' 139 125 123-azure1 :: Color-azure1 = rgb' 240 255 255-azure2 :: Color-azure2 = rgb' 224 238 238-azure3 :: Color-azure3 = rgb' 193 205 205-azure4 :: Color-azure4 = rgb' 131 139 139-slateBlue1 :: Color-slateBlue1 = rgb' 131 111 255-slateBlue2 :: Color-slateBlue2 = rgb' 122 103 238-slateBlue3 :: Color-slateBlue3 = rgb' 105 89 205-slateBlue4 :: Color-slateBlue4 = rgb' 71 60 139-royalBlue1 :: Color-royalBlue1 = rgb' 72 118 255-royalBlue2 :: Color-royalBlue2 = rgb' 67 110 238-royalBlue3 :: Color-royalBlue3 = rgb' 58 95 205-royalBlue4 :: Color-royalBlue4 = rgb' 39 64 139-blue1 :: Color-blue1 = rgb' 0 0 255-blue2 :: Color-blue2 = rgb' 0 0 238-blue3 :: Color-blue3 = rgb' 0 0 205-blue4 :: Color-blue4 = rgb' 0 0 139-dodgerBlue1 :: Color-dodgerBlue1 = rgb' 30 144 255-dodgerBlue2 :: Color-dodgerBlue2 = rgb' 28 134 238-dodgerBlue3 :: Color-dodgerBlue3 = rgb' 24 116 205-dodgerBlue4 :: Color-dodgerBlue4 = rgb' 16 78 139-steelBlue1 :: Color-steelBlue1 = rgb' 99 184 255-steelBlue2 :: Color-steelBlue2 = rgb' 92 172 238-steelBlue3 :: Color-steelBlue3 = rgb' 79 148 205-steelBlue4 :: Color-steelBlue4 = rgb' 54 100 139-deepSkyBlue1 :: Color-deepSkyBlue1 = rgb' 0 191 255-deepSkyBlue2 :: Color-deepSkyBlue2 = rgb' 0 178 238-deepSkyBlue3 :: Color-deepSkyBlue3 = rgb' 0 154 205-deepSkyBlue4 :: Color-deepSkyBlue4 = rgb' 0 104 139-skyBlue1 :: Color-skyBlue1 = rgb' 135 206 255-skyBlue2 :: Color-skyBlue2 = rgb' 126 192 238-skyBlue3 :: Color-skyBlue3 = rgb' 108 166 205-skyBlue4 :: Color-skyBlue4 = rgb' 74 112 139-lightSkyBlue1 :: Color-lightSkyBlue1 = rgb' 176 226 255-lightSkyBlue2 :: Color-lightSkyBlue2 = rgb' 164 211 238-lightSkyBlue3 :: Color-lightSkyBlue3 = rgb' 141 182 205-lightSkyBlue4 :: Color-lightSkyBlue4 = rgb' 96 123 139-slateGray1 :: Color-slateGray1 = rgb' 198 226 255-slateGray2 :: Color-slateGray2 = rgb' 185 211 238-slateGray3 :: Color-slateGray3 = rgb' 159 182 205-slateGray4 :: Color-slateGray4 = rgb' 108 123 139-lightSteelBlue1 :: Color-lightSteelBlue1 = rgb' 202 225 255-lightSteelBlue2 :: Color-lightSteelBlue2 = rgb' 188 210 238-lightSteelBlue3 :: Color-lightSteelBlue3 = rgb' 162 181 205-lightSteelBlue4 :: Color-lightSteelBlue4 = rgb' 110 123 139-lightBlue1 :: Color-lightBlue1 = rgb' 191 239 255-lightBlue2 :: Color-lightBlue2 = rgb' 178 223 238-lightBlue3 :: Color-lightBlue3 = rgb' 154 192 205-lightBlue4 :: Color-lightBlue4 = rgb' 104 131 139-lightCyan1 :: Color-lightCyan1 = rgb' 224 255 255-lightCyan2 :: Color-lightCyan2 = rgb' 209 238 238-lightCyan3 :: Color-lightCyan3 = rgb' 180 205 205-lightCyan4 :: Color-lightCyan4 = rgb' 122 139 139-paleTurquoise1 :: Color-paleTurquoise1 = rgb' 187 255 255-paleTurquoise2 :: Color-paleTurquoise2 = rgb' 174 238 238-paleTurquoise3 :: Color-paleTurquoise3 = rgb' 150 205 205-paleTurquoise4 :: Color-paleTurquoise4 = rgb' 102 139 139-cadetBlue1 :: Color-cadetBlue1 = rgb' 152 245 255-cadetBlue2 :: Color-cadetBlue2 = rgb' 142 229 238-cadetBlue3 :: Color-cadetBlue3 = rgb' 122 197 205-cadetBlue4 :: Color-cadetBlue4 = rgb' 83 134 139-turquoise1 :: Color-turquoise1 = rgb' 0 245 255-turquoise2 :: Color-turquoise2 = rgb' 0 229 238-turquoise3 :: Color-turquoise3 = rgb' 0 197 205-turquoise4 :: Color-turquoise4 = rgb' 0 134 139-cyan1 :: Color-cyan1 = rgb' 0 255 255-cyan2 :: Color-cyan2 = rgb' 0 238 238-cyan3 :: Color-cyan3 = rgb' 0 205 205-cyan4 :: Color-cyan4 = rgb' 0 139 139-darkSlateGray1 :: Color-darkSlateGray1 = rgb' 151 255 255-darkSlateGray2 :: Color-darkSlateGray2 = rgb' 141 238 238-darkSlateGray3 :: Color-darkSlateGray3 = rgb' 121 205 205-darkSlateGray4 :: Color-darkSlateGray4 = rgb' 82 139 139-aquamarine1 :: Color-aquamarine1 = rgb' 127 255 212-aquamarine2 :: Color-aquamarine2 = rgb' 118 238 198-aquamarine3 :: Color-aquamarine3 = rgb' 102 205 170-aquamarine4 :: Color-aquamarine4 = rgb' 69 139 116-darkSeaGreen1 :: Color-darkSeaGreen1 = rgb' 193 255 193-darkSeaGreen2 :: Color-darkSeaGreen2 = rgb' 180 238 180-darkSeaGreen3 :: Color-darkSeaGreen3 = rgb' 155 205 155-darkSeaGreen4 :: Color-darkSeaGreen4 = rgb' 105 139 105-seaGreen1 :: Color-seaGreen1 = rgb' 84 255 159-seaGreen2 :: Color-seaGreen2 = rgb' 78 238 148-seaGreen3 :: Color-seaGreen3 = rgb' 67 205 128-seaGreen4 :: Color-seaGreen4 = rgb' 46 139 87-paleGreen1 :: Color-paleGreen1 = rgb' 154 255 154-paleGreen2 :: Color-paleGreen2 = rgb' 144 238 144-paleGreen3 :: Color-paleGreen3 = rgb' 124 205 124-paleGreen4 :: Color-paleGreen4 = rgb' 84 139 84-springGreen1 :: Color-springGreen1 = rgb' 0 255 127-springGreen2 :: Color-springGreen2 = rgb' 0 238 118-springGreen3 :: Color-springGreen3 = rgb' 0 205 102-springGreen4 :: Color-springGreen4 = rgb' 0 139 69-green1 :: Color-green1 = rgb' 0 255 0-green2 :: Color-green2 = rgb' 0 238 0-green3 :: Color-green3 = rgb' 0 205 0-green4 :: Color-green4 = rgb' 0 139 0-chartreuse1 :: Color-chartreuse1 = rgb' 127 255 0-chartreuse2 :: Color-chartreuse2 = rgb' 118 238 0-chartreuse3 :: Color-chartreuse3 = rgb' 102 205 0-chartreuse4 :: Color-chartreuse4 = rgb' 69 139 0-oliveDrab1 :: Color-oliveDrab1 = rgb' 192 255 62-oliveDrab2 :: Color-oliveDrab2 = rgb' 179 238 58-oliveDrab3 :: Color-oliveDrab3 = rgb' 154 205 50-oliveDrab4 :: Color-oliveDrab4 = rgb' 105 139 34-darkOliveGreen1 :: Color-darkOliveGreen1 = rgb' 202 255 112-darkOliveGreen2 :: Color-darkOliveGreen2 = rgb' 188 238 104-darkOliveGreen3 :: Color-darkOliveGreen3 = rgb' 162 205 90-darkOliveGreen4 :: Color-darkOliveGreen4 = rgb' 110 139 61-khaki1 :: Color-khaki1 = rgb' 255 246 143-khaki2 :: Color-khaki2 = rgb' 238 230 133-khaki3 :: Color-khaki3 = rgb' 205 198 115-khaki4 :: Color-khaki4 = rgb' 139 134 78-lightGoldenrod1 :: Color-lightGoldenrod1 = rgb' 255 236 139-lightGoldenrod2 :: Color-lightGoldenrod2 = rgb' 238 220 130-lightGoldenrod3 :: Color-lightGoldenrod3 = rgb' 205 190 112-lightGoldenrod4 :: Color-lightGoldenrod4 = rgb' 139 129 76-lightYellow1 :: Color-lightYellow1 = rgb' 255 255 224-lightYellow2 :: Color-lightYellow2 = rgb' 238 238 209-lightYellow3 :: Color-lightYellow3 = rgb' 205 205 180-lightYellow4 :: Color-lightYellow4 = rgb' 139 139 122-yellow1 :: Color-yellow1 = rgb' 255 255 0-yellow2 :: Color-yellow2 = rgb' 238 238 0-yellow3 :: Color-yellow3 = rgb' 205 205 0-yellow4 :: Color-yellow4 = rgb' 139 139 0-gold1 :: Color-gold1 = rgb' 255 215 0-gold2 :: Color-gold2 = rgb' 238 201 0-gold3 :: Color-gold3 = rgb' 205 173 0-gold4 :: Color-gold4 = rgb' 139 117 0-goldenrod1 :: Color-goldenrod1 = rgb' 255 193 37-goldenrod2 :: Color-goldenrod2 = rgb' 238 180 34-goldenrod3 :: Color-goldenrod3 = rgb' 205 155 29-goldenrod4 :: Color-goldenrod4 = rgb' 139 105 20-darkGoldenrod1 :: Color-darkGoldenrod1 = rgb' 255 185 15-darkGoldenrod2 :: Color-darkGoldenrod2 = rgb' 238 173 14-darkGoldenrod3 :: Color-darkGoldenrod3 = rgb' 205 149 12-darkGoldenrod4 :: Color-darkGoldenrod4 = rgb' 139 101 8-rosyBrown1 :: Color-rosyBrown1 = rgb' 255 193 193-rosyBrown2 :: Color-rosyBrown2 = rgb' 238 180 180-rosyBrown3 :: Color-rosyBrown3 = rgb' 205 155 155-rosyBrown4 :: Color-rosyBrown4 = rgb' 139 105 105-indianRed1 :: Color-indianRed1 = rgb' 255 106 106-indianRed2 :: Color-indianRed2 = rgb' 238 99 99-indianRed3 :: Color-indianRed3 = rgb' 205 85 85-indianRed4 :: Color-indianRed4 = rgb' 139 58 58-sienna1 :: Color-sienna1 = rgb' 255 130 71-sienna2 :: Color-sienna2 = rgb' 238 121 66-sienna3 :: Color-sienna3 = rgb' 205 104 57-sienna4 :: Color-sienna4 = rgb' 139 71 38-burlywood1 :: Color-burlywood1 = rgb' 255 211 155-burlywood2 :: Color-burlywood2 = rgb' 238 197 145-burlywood3 :: Color-burlywood3 = rgb' 205 170 125-burlywood4 :: Color-burlywood4 = rgb' 139 115 85-wheat1 :: Color-wheat1 = rgb' 255 231 186-wheat2 :: Color-wheat2 = rgb' 238 216 174-wheat3 :: Color-wheat3 = rgb' 205 186 150-wheat4 :: Color-wheat4 = rgb' 139 126 102-tan1 :: Color-tan1 = rgb' 255 165 79-tan2 :: Color-tan2 = rgb' 238 154 73-tan3 :: Color-tan3 = rgb' 205 133 63-tan4 :: Color-tan4 = rgb' 139 90 43-chocolate1 :: Color-chocolate1 = rgb' 255 127 36-chocolate2 :: Color-chocolate2 = rgb' 238 118 33-chocolate3 :: Color-chocolate3 = rgb' 205 102 29-chocolate4 :: Color-chocolate4 = rgb' 139 69 19-firebrick1 :: Color-firebrick1 = rgb' 255 48 48-firebrick2 :: Color-firebrick2 = rgb' 238 44 44-firebrick3 :: Color-firebrick3 = rgb' 205 38 38-firebrick4 :: Color-firebrick4 = rgb' 139 26 26-brown1 :: Color-brown1 = rgb' 255 64 64-brown2 :: Color-brown2 = rgb' 238 59 59-brown3 :: Color-brown3 = rgb' 205 51 51-brown4 :: Color-brown4 = rgb' 139 35 35-salmon1 :: Color-salmon1 = rgb' 255 140 105-salmon2 :: Color-salmon2 = rgb' 238 130 98-salmon3 :: Color-salmon3 = rgb' 205 112 84-salmon4 :: Color-salmon4 = rgb' 139 76 57-lightSalmon1 :: Color-lightSalmon1 = rgb' 255 160 122-lightSalmon2 :: Color-lightSalmon2 = rgb' 238 149 114-lightSalmon3 :: Color-lightSalmon3 = rgb' 205 129 98-lightSalmon4 :: Color-lightSalmon4 = rgb' 139 87 66-orange1 :: Color-orange1 = rgb' 255 165 0-orange2 :: Color-orange2 = rgb' 238 154 0-orange3 :: Color-orange3 = rgb' 205 133 0-orange4 :: Color-orange4 = rgb' 139 90 0-darkOrange1 :: Color-darkOrange1 = rgb' 255 127 0-darkOrange2 :: Color-darkOrange2 = rgb' 238 118 0-darkOrange3 :: Color-darkOrange3 = rgb' 205 102 0-darkOrange4 :: Color-darkOrange4 = rgb' 139 69 0-coral1 :: Color-coral1 = rgb' 255 114 86-coral2 :: Color-coral2 = rgb' 238 106 80-coral3 :: Color-coral3 = rgb' 205 91 69-coral4 :: Color-coral4 = rgb' 139 62 47-tomato1 :: Color-tomato1 = rgb' 255 99 71-tomato2 :: Color-tomato2 = rgb' 238 92 66-tomato3 :: Color-tomato3 = rgb' 205 79 57-tomato4 :: Color-tomato4 = rgb' 139 54 38-orangeRed1 :: Color-orangeRed1 = rgb' 255 69 0-orangeRed2 :: Color-orangeRed2 = rgb' 238 64 0-orangeRed3 :: Color-orangeRed3 = rgb' 205 55 0-orangeRed4 :: Color-orangeRed4 = rgb' 139 37 0-red1 :: Color-red1 = rgb' 255 0 0-red2 :: Color-red2 = rgb' 238 0 0-red3 :: Color-red3 = rgb' 205 0 0-red4 :: Color-red4 = rgb' 139 0 0-deepPink1 :: Color-deepPink1 = rgb' 255 20 147-deepPink2 :: Color-deepPink2 = rgb' 238 18 137-deepPink3 :: Color-deepPink3 = rgb' 205 16 118-deepPink4 :: Color-deepPink4 = rgb' 139 10 80-hotPink1 :: Color-hotPink1 = rgb' 255 110 180-hotPink2 :: Color-hotPink2 = rgb' 238 106 167-hotPink3 :: Color-hotPink3 = rgb' 205 96 144-hotPink4 :: Color-hotPink4 = rgb' 139 58 98-pink1 :: Color-pink1 = rgb' 255 181 197-pink2 :: Color-pink2 = rgb' 238 169 184-pink3 :: Color-pink3 = rgb' 205 145 158-pink4 :: Color-pink4 = rgb' 139 99 108-lightPink1 :: Color-lightPink1 = rgb' 255 174 185-lightPink2 :: Color-lightPink2 = rgb' 238 162 173-lightPink3 :: Color-lightPink3 = rgb' 205 140 149-lightPink4 :: Color-lightPink4 = rgb' 139 95 101-paleVioletRed1 :: Color-paleVioletRed1 = rgb' 255 130 171-paleVioletRed2 :: Color-paleVioletRed2 = rgb' 238 121 159-paleVioletRed3 :: Color-paleVioletRed3 = rgb' 205 104 137-paleVioletRed4 :: Color-paleVioletRed4 = rgb' 139 71 93-maroon1 :: Color-maroon1 = rgb' 255 52 179-maroon2 :: Color-maroon2 = rgb' 238 48 167-maroon3 :: Color-maroon3 = rgb' 205 41 144-maroon4 :: Color-maroon4 = rgb' 139 28 98-violetRed1 :: Color-violetRed1 = rgb' 255 62 150-violetRed2 :: Color-violetRed2 = rgb' 238 58 140-violetRed3 :: Color-violetRed3 = rgb' 205 50 120-violetRed4 :: Color-violetRed4 = rgb' 139 34 82-magenta1 :: Color-magenta1 = rgb' 255 0 255-magenta2 :: Color-magenta2 = rgb' 238 0 238-magenta3 :: Color-magenta3 = rgb' 205 0 205-magenta4 :: Color-magenta4 = rgb' 139 0 139-orchid1 :: Color-orchid1 = rgb' 255 131 250-orchid2 :: Color-orchid2 = rgb' 238 122 233-orchid3 :: Color-orchid3 = rgb' 205 105 201-orchid4 :: Color-orchid4 = rgb' 139 71 137-plum1 :: Color-plum1 = rgb' 255 187 255-plum2 :: Color-plum2 = rgb' 238 174 238-plum3 :: Color-plum3 = rgb' 205 150 205-plum4 :: Color-plum4 = rgb' 139 102 139-mediumOrchid1 :: Color-mediumOrchid1 = rgb' 224 102 255-mediumOrchid2 :: Color-mediumOrchid2 = rgb' 209 95 238-mediumOrchid3 :: Color-mediumOrchid3 = rgb' 180 82 205-mediumOrchid4 :: Color-mediumOrchid4 = rgb' 122 55 139-darkOrchid1 :: Color-darkOrchid1 = rgb' 191 62 255-darkOrchid2 :: Color-darkOrchid2 = rgb' 178 58 238-darkOrchid3 :: Color-darkOrchid3 = rgb' 154 50 205-darkOrchid4 :: Color-darkOrchid4 = rgb' 104 34 139-purple1 :: Color-purple1 = rgb' 155 48 255-purple2 :: Color-purple2 = rgb' 145 44 238-purple3 :: Color-purple3 = rgb' 125 38 205-purple4 :: Color-purple4 = rgb' 85 26 139-mediumPurple1 :: Color-mediumPurple1 = rgb' 171 130 255-mediumPurple2 :: Color-mediumPurple2 = rgb' 159 121 238-mediumPurple3 :: Color-mediumPurple3 = rgb' 137 104 205-mediumPurple4 :: Color-mediumPurple4 = rgb' 93 71 139-thistle1 :: Color-thistle1 = rgb' 255 225 255-thistle2 :: Color-thistle2 = rgb' 238 210 238-thistle3 :: Color-thistle3 = rgb' 205 181 205-thistle4 :: Color-thistle4 = rgb' 139 123 139-gray0 :: Color-gray0 = rgb' 0 0 0-grey0 :: Color-grey0 = rgb' 0 0 0-gray1 :: Color-gray1 = rgb' 3 3 3-grey1 :: Color-grey1 = rgb' 3 3 3-gray2 :: Color-gray2 = rgb' 5 5 5-grey2 :: Color-grey2 = rgb' 5 5 5-gray3 :: Color-gray3 = rgb' 8 8 8-grey3 :: Color-grey3 = rgb' 8 8 8-gray4 :: Color-gray4 = rgb' 10 10 10-grey4 :: Color-grey4 = rgb' 10 10 10-gray5 :: Color-gray5 = rgb' 13 13 13-grey5 :: Color-grey5 = rgb' 13 13 13-gray6 :: Color-gray6 = rgb' 15 15 15-grey6 :: Color-grey6 = rgb' 15 15 15-gray7 :: Color-gray7 = rgb' 18 18 18-grey7 :: Color-grey7 = rgb' 18 18 18-gray8 :: Color-gray8 = rgb' 20 20 20-grey8 :: Color-grey8 = rgb' 20 20 20-gray9 :: Color-gray9 = rgb' 23 23 23-grey9 :: Color-grey9 = rgb' 23 23 23-gray10 :: Color-gray10 = rgb' 26 26 26-grey10 :: Color-grey10 = rgb' 26 26 26-gray11 :: Color-gray11 = rgb' 28 28 28-grey11 :: Color-grey11 = rgb' 28 28 28-gray12 :: Color-gray12 = rgb' 31 31 31-grey12 :: Color-grey12 = rgb' 31 31 31-gray13 :: Color-gray13 = rgb' 33 33 33-grey13 :: Color-grey13 = rgb' 33 33 33-gray14 :: Color-gray14 = rgb' 36 36 36-grey14 :: Color-grey14 = rgb' 36 36 36-gray15 :: Color-gray15 = rgb' 38 38 38-grey15 :: Color-grey15 = rgb' 38 38 38-gray16 :: Color-gray16 = rgb' 41 41 41-grey16 :: Color-grey16 = rgb' 41 41 41-gray17 :: Color-gray17 = rgb' 43 43 43-grey17 :: Color-grey17 = rgb' 43 43 43-gray18 :: Color-gray18 = rgb' 46 46 46-grey18 :: Color-grey18 = rgb' 46 46 46-gray19 :: Color-gray19 = rgb' 48 48 48-grey19 :: Color-grey19 = rgb' 48 48 48-gray20 :: Color-gray20 = rgb' 51 51 51-grey20 :: Color-grey20 = rgb' 51 51 51-gray21 :: Color-gray21 = rgb' 54 54 54-grey21 :: Color-grey21 = rgb' 54 54 54-gray22 :: Color-gray22 = rgb' 56 56 56-grey22 :: Color-grey22 = rgb' 56 56 56-gray23 :: Color-gray23 = rgb' 59 59 59-grey23 :: Color-grey23 = rgb' 59 59 59-gray24 :: Color-gray24 = rgb' 61 61 61-grey24 :: Color-grey24 = rgb' 61 61 61-gray25 :: Color-gray25 = rgb' 64 64 64-grey25 :: Color-grey25 = rgb' 64 64 64-gray26 :: Color-gray26 = rgb' 66 66 66-grey26 :: Color-grey26 = rgb' 66 66 66-gray27 :: Color-gray27 = rgb' 69 69 69-grey27 :: Color-grey27 = rgb' 69 69 69-gray28 :: Color-gray28 = rgb' 71 71 71-grey28 :: Color-grey28 = rgb' 71 71 71-gray29 :: Color-gray29 = rgb' 74 74 74-grey29 :: Color-grey29 = rgb' 74 74 74-gray30 :: Color-gray30 = rgb' 77 77 77-grey30 :: Color-grey30 = rgb' 77 77 77-gray31 :: Color-gray31 = rgb' 79 79 79-grey31 :: Color-grey31 = rgb' 79 79 79-gray32 :: Color-gray32 = rgb' 82 82 82-grey32 :: Color-grey32 = rgb' 82 82 82-gray33 :: Color-gray33 = rgb' 84 84 84-grey33 :: Color-grey33 = rgb' 84 84 84-gray34 :: Color-gray34 = rgb' 87 87 87-grey34 :: Color-grey34 = rgb' 87 87 87-gray35 :: Color-gray35 = rgb' 89 89 89-grey35 :: Color-grey35 = rgb' 89 89 89-gray36 :: Color-gray36 = rgb' 92 92 92-grey36 :: Color-grey36 = rgb' 92 92 92-gray37 :: Color-gray37 = rgb' 94 94 94-grey37 :: Color-grey37 = rgb' 94 94 94-gray38 :: Color-gray38 = rgb' 97 97 97-grey38 :: Color-grey38 = rgb' 97 97 97-gray39 :: Color-gray39 = rgb' 99 99 99-grey39 :: Color-grey39 = rgb' 99 99 99-gray40 :: Color-gray40 = rgb' 102 102 102-grey40 :: Color-grey40 = rgb' 102 102 102-gray41 :: Color-gray41 = rgb' 105 105 105-grey41 :: Color-grey41 = rgb' 105 105 105-gray42 :: Color-gray42 = rgb' 107 107 107-grey42 :: Color-grey42 = rgb' 107 107 107-gray43 :: Color-gray43 = rgb' 110 110 110-grey43 :: Color-grey43 = rgb' 110 110 110-gray44 :: Color-gray44 = rgb' 112 112 112-grey44 :: Color-grey44 = rgb' 112 112 112-gray45 :: Color-gray45 = rgb' 115 115 115-grey45 :: Color-grey45 = rgb' 115 115 115-gray46 :: Color-gray46 = rgb' 117 117 117-grey46 :: Color-grey46 = rgb' 117 117 117-gray47 :: Color-gray47 = rgb' 120 120 120-grey47 :: Color-grey47 = rgb' 120 120 120-gray48 :: Color-gray48 = rgb' 122 122 122-grey48 :: Color-grey48 = rgb' 122 122 122-gray49 :: Color-gray49 = rgb' 125 125 125-grey49 :: Color-grey49 = rgb' 125 125 125-gray50 :: Color-gray50 = rgb' 127 127 127-grey50 :: Color-grey50 = rgb' 127 127 127-gray51 :: Color-gray51 = rgb' 130 130 130-grey51 :: Color-grey51 = rgb' 130 130 130-gray52 :: Color-gray52 = rgb' 133 133 133-grey52 :: Color-grey52 = rgb' 133 133 133-gray53 :: Color-gray53 = rgb' 135 135 135-grey53 :: Color-grey53 = rgb' 135 135 135-gray54 :: Color-gray54 = rgb' 138 138 138-grey54 :: Color-grey54 = rgb' 138 138 138-gray55 :: Color-gray55 = rgb' 140 140 140-grey55 :: Color-grey55 = rgb' 140 140 140-gray56 :: Color-gray56 = rgb' 143 143 143-grey56 :: Color-grey56 = rgb' 143 143 143-gray57 :: Color-gray57 = rgb' 145 145 145-grey57 :: Color-grey57 = rgb' 145 145 145-gray58 :: Color-gray58 = rgb' 148 148 148-grey58 :: Color-grey58 = rgb' 148 148 148-gray59 :: Color-gray59 = rgb' 150 150 150-grey59 :: Color-grey59 = rgb' 150 150 150-gray60 :: Color-gray60 = rgb' 153 153 153-grey60 :: Color-grey60 = rgb' 153 153 153-gray61 :: Color-gray61 = rgb' 156 156 156-grey61 :: Color-grey61 = rgb' 156 156 156-gray62 :: Color-gray62 = rgb' 158 158 158-grey62 :: Color-grey62 = rgb' 158 158 158-gray63 :: Color-gray63 = rgb' 161 161 161-grey63 :: Color-grey63 = rgb' 161 161 161-gray64 :: Color-gray64 = rgb' 163 163 163-grey64 :: Color-grey64 = rgb' 163 163 163-gray65 :: Color-gray65 = rgb' 166 166 166-grey65 :: Color-grey65 = rgb' 166 166 166-gray66 :: Color-gray66 = rgb' 168 168 168-grey66 :: Color-grey66 = rgb' 168 168 168-gray67 :: Color-gray67 = rgb' 171 171 171-grey67 :: Color-grey67 = rgb' 171 171 171-gray68 :: Color-gray68 = rgb' 173 173 173-grey68 :: Color-grey68 = rgb' 173 173 173-gray69 :: Color-gray69 = rgb' 176 176 176-grey69 :: Color-grey69 = rgb' 176 176 176-gray70 :: Color-gray70 = rgb' 179 179 179-grey70 :: Color-grey70 = rgb' 179 179 179-gray71 :: Color-gray71 = rgb' 181 181 181-grey71 :: Color-grey71 = rgb' 181 181 181-gray72 :: Color-gray72 = rgb' 184 184 184-grey72 :: Color-grey72 = rgb' 184 184 184-gray73 :: Color-gray73 = rgb' 186 186 186-grey73 :: Color-grey73 = rgb' 186 186 186-gray74 :: Color-gray74 = rgb' 189 189 189-grey74 :: Color-grey74 = rgb' 189 189 189-gray75 :: Color-gray75 = rgb' 191 191 191-grey75 :: Color-grey75 = rgb' 191 191 191-gray76 :: Color-gray76 = rgb' 194 194 194-grey76 :: Color-grey76 = rgb' 194 194 194-gray77 :: Color-gray77 = rgb' 196 196 196-grey77 :: Color-grey77 = rgb' 196 196 196-gray78 :: Color-gray78 = rgb' 199 199 199-grey78 :: Color-grey78 = rgb' 199 199 199-gray79 :: Color-gray79 = rgb' 201 201 201-grey79 :: Color-grey79 = rgb' 201 201 201-gray80 :: Color-gray80 = rgb' 204 204 204-grey80 :: Color-grey80 = rgb' 204 204 204-gray81 :: Color-gray81 = rgb' 207 207 207-grey81 :: Color-grey81 = rgb' 207 207 207-gray82 :: Color-gray82 = rgb' 209 209 209-grey82 :: Color-grey82 = rgb' 209 209 209-gray83 :: Color-gray83 = rgb' 212 212 212-grey83 :: Color-grey83 = rgb' 212 212 212-gray84 :: Color-gray84 = rgb' 214 214 214-grey84 :: Color-grey84 = rgb' 214 214 214-gray85 :: Color-gray85 = rgb' 217 217 217-grey85 :: Color-grey85 = rgb' 217 217 217-gray86 :: Color-gray86 = rgb' 219 219 219-grey86 :: Color-grey86 = rgb' 219 219 219-gray87 :: Color-gray87 = rgb' 222 222 222-grey87 :: Color-grey87 = rgb' 222 222 222-gray88 :: Color-gray88 = rgb' 224 224 224-grey88 :: Color-grey88 = rgb' 224 224 224-gray89 :: Color-gray89 = rgb' 227 227 227-grey89 :: Color-grey89 = rgb' 227 227 227-gray90 :: Color-gray90 = rgb' 229 229 229-grey90 :: Color-grey90 = rgb' 229 229 229-gray91 :: Color-gray91 = rgb' 232 232 232-grey91 :: Color-grey91 = rgb' 232 232 232-gray92 :: Color-gray92 = rgb' 235 235 235-grey92 :: Color-grey92 = rgb' 235 235 235-gray93 :: Color-gray93 = rgb' 237 237 237-grey93 :: Color-grey93 = rgb' 237 237 237-gray94 :: Color-gray94 = rgb' 240 240 240-grey94 :: Color-grey94 = rgb' 240 240 240-gray95 :: Color-gray95 = rgb' 242 242 242-grey95 :: Color-grey95 = rgb' 242 242 242-gray96 :: Color-gray96 = rgb' 245 245 245-grey96 :: Color-grey96 = rgb' 245 245 245-gray97 :: Color-gray97 = rgb' 247 247 247-grey97 :: Color-grey97 = rgb' 247 247 247-gray98 :: Color-gray98 = rgb' 250 250 250-grey98 :: Color-grey98 = rgb' 250 250 250-gray99 :: Color-gray99 = rgb' 252 252 252-grey99 :: Color-grey99 = rgb' 252 252 252-gray100 :: Color-gray100 = rgb' 255 255 255-grey100 :: Color-grey100 = rgb' 255 255 255-darkGrey :: Color-darkGrey = rgb' 169 169 169-darkGray :: Color-darkGray = rgb' 169 169 169-darkBlue :: Color-darkBlue = rgb' 0 0 139-darkCyan :: Color-darkCyan = rgb' 0 139 139-darkMagenta :: Color-darkMagenta = rgb' 139 0 139-darkRed :: Color-darkRed = rgb' 139 0 0-lightGreen :: Color-lightGreen = rgb' 144 238 144
Graphics/Rendering/Diagrams/Engine.hs view
@@ -26,7 +26,10 @@ -- ** User interface , compose- , writePng+ , writePNG, writePS, writePDF, writeSVG+ , renderWithBackend+ , renderOverlayPNG+ , chooseBackend -- ** Internals @@ -36,13 +39,9 @@ ) where import Graphics.Rendering.Diagrams.Types-import Graphics.Rendering.Diagrams.Attributes-import Graphics.Rendering.Diagrams.Layouts import qualified Graphics.Rendering.Cairo as C-import Control.Arrow ((***)) import Control.Monad.Reader-import Data.List (foldl1') -- $preproc -- These functions take a user-generated 'Diagram' object and@@ -71,56 +70,130 @@ sizeAndPos (Compound (Layout l ds)) = (s, Union ds') where (s, ds') = layoutSizeAndPos l (fmap sizeAndPos ds) +sizeAndPos (Union _) = error "sizeAndPos (Union _): This should never happen!"+ -- $render -- The rendering code takes a 'Diagram' and turns it into -- actual graphics output, using the Cairo library to perform the low-level -- drawing operations. --- | Given a target width and height and a user-constructed 'Diagram',+-- | Given a target width or height and a user-constructed 'Diagram', -- render it using the Cairo rendering library. Note that 'compose' -- takes care of all the rendering details, including preprocessing -- of the 'Diagram', and scaling/translating the final output so--- that it fits within the given width and height.+-- that it fits within the given width or height. 'compose' also+-- produces the size of the final diagram; the width or height will+-- be equal to that specified in the input, and the other dimension+-- will be determined by the aspect ratio of the diagram. -- -- The background of the output diagram will be opaque white. -- -- In order to produce a physical output, the output of 'compose' -- must be given as input to an output adapter such as 'writePng'.-compose :: Double -- ^ output width- -> Double -- ^ output height- -> Diagram -- ^ 'Diagram' to render- -> C.Render ()-compose w h d = do+-- Normally, however, a user of the diagrams library should not need+-- to call 'compose' directly.+compose :: SizeSpec -- ^ output width or height+ -> Diagram -- ^ 'Diagram' to render+ -> (Point, C.Render ())+ -- ^ Output width and height, and Cairo action+ -- to render it+compose size d = compose' 1 size d +compose' :: Double -> SizeSpec -> Diagram -> (Point, C.Render ())+compose' opacity size d =+ -- Preprocess the diagram, and use the global bounding box size to -- scale and translate the output so that it fits within the target -- output width and height. let ((x,y), d') = sizeAndPos d- s = min (w/x) (w/y)- C.scale s s- C.translate (x/2) (y/2)+ s = case size of+ Width w -> w/x -- scale so width is as desired+ Height h -> h/y -- scale so height is as desired+ Auto -> 1 -- do not scale+ in (,) (s*x,s*y) $ do+ C.scale s s+ C.translate (x/2) (y/2) - -- Set the output background to opaque white.- C.save- C.setSourceRGBA 1 1 1 1- C.paint- C.restore+ -- Set the output background to opaque white.+ C.save+ C.setSourceRGBA 1 1 1 opacity+ C.paint+ C.restore - -- render the final diagram.- flip runDiaRenderM defaultDiaRenderEnv . render $ d'+ -- render the final diagram.+ flip runDiaRenderM defaultDiaRenderEnv . render $ d' --- | Given a rendered diagram, output it to a .png file with the given--- width and height.-writePng :: String -> Int -> Int -> C.Render () -> IO ()-writePng fileName w h render =- C.withImageSurface C.FormatARGB32 w h $ \surface -> do- C.renderWith surface render- C.surfaceWriteToPNG surface fileName+-- | Given a rendered diagram, output it to a file in PNG format with+-- the given width and height.+writePNG :: String -> Point -> C.Render () -> IO ()+writePNG dstfile wh r = usingBackground wh+ (\surface -> writeSurfaceToPNG surface dstfile r) +-- | Given a rendered diagram, output it to a file in PNG format with+-- the size and background of the PNG image @srcfile@.+overlayPNG :: String -> String -> C.Render () -> IO ()+overlayPNG srcfile dstfile r = usingPNG srcfile+ (\surface -> writeSurfaceToPNG surface dstfile r)++writeSurfaceToPNG :: C.Surface -> FilePath -> C.Render () -> IO ()+writeSurfaceToPNG surface dstfile r = do+ C.renderWith surface r+ C.surfaceWriteToPNG surface dstfile++usingPNG :: FilePath -> (C.Surface -> IO ()) -> IO ()+usingPNG srcfile = C.withImageSurfaceFromPNG srcfile+usingBackground :: Point -> (C.Surface -> IO ()) -> IO ()+usingBackground (w,h) = C.withImageSurface C.FormatARGB32 (ceiling w) (ceiling h)++writeSurface :: (String -> Double -> Double -> (C.Surface -> IO a) -> IO a)+ -> String+ -> Point+ -> C.Render a+ -> IO a+writeSurface withSurface fileName (w,h) r =+ withSurface fileName w h $ \surface ->+ C.renderWith surface r++-- | Given a rendered diagram, output it to a file in PostScript+-- format with the given width and height.+writePS :: String -> Point -> C.Render () -> IO ()+writePS = writeSurface C.withPSSurface++-- | Given a rendered diagram, output it to a file in PDF+-- format with the given width and height.+writePDF :: String -> Point -> C.Render () -> IO ()+writePDF = writeSurface C.withPDFSurface++-- | Given a rendered diagram, output it to a file in SVG+-- format with the given width and height.+writeSVG :: String -> Point -> C.Render () -> IO ()+writeSVG = writeSurface C.withSVGSurface++-- | Given a file name, an output size specification, and a 'Diagram',+-- use a \"backend\" to render the 'Diagram' to an actual physical+-- output.+renderWithBackend :: (String -> Point -> C.Render () -> IO ()) -- ^ backend+ -> String -- ^ file name+ -> SizeSpec -- ^ output size specification+ -> Diagram -- ^ the diagram to render+ -> IO ()+renderWithBackend backend name size dia = backend name wh r+ where (wh, r) = compose size dia++renderOverlayPNG :: FilePath -> FilePath -> Diagram -> IO ()+renderOverlayPNG srcfile dstfile dia = overlayPNG srcfile dstfile r+ where r = snd $ compose' 0 Auto dia++chooseBackend :: OutputType -> (String -> Point -> C.Render () -> IO ())+chooseBackend PNG = writePNG+chooseBackend PS = writePS+chooseBackend PDF = writePDF+chooseBackend SVG = writeSVG+ -- | Perform a rendering operation atomically, by saving the state and -- restoring it afterwards. atomic :: DiaRenderM () -> DiaRenderM ()-atomic render = (c C.save) >> render >> (c C.restore)+atomic r = (c C.save) >> r >> (c C.restore) -- | Render a diagram. render :: Diagram -> DiaRenderM ()@@ -129,3 +202,4 @@ render (Ann (Attr a) d) = atomic $ renderAttr a >>= flip local (render d) render (Union ds) = mapM_ render ds render (Sized _ d) = render d+render d@(Compound _) = render $ snd $ sizeAndPos d
Graphics/Rendering/Diagrams/Layouts.hs view
@@ -29,17 +29,33 @@ , hdistrib, vdistrib , hdistribA, vdistribA + , position, positionA+ , VAlignment , top, vcenter, bottom , HAlignment , left, hcenter, right + -- * Tree++ , tree++ -- * Miscellaneous++ , pad, padA+ , showBBox, showBBoxes+ , withSize+ ) where import Graphics.Rendering.Diagrams.Types import Graphics.Rendering.Diagrams.Attributes-import Control.Arrow ((***), first, (>>>))+import Graphics.Rendering.Diagrams.Shapes+import Graphics.Rendering.Diagrams.Engine (sizeAndPos)+import Control.Arrow (first) +import Data.Tree+ -- Union ----------------------------------------------- -- | The union layout, which lays out diagrams superimposed on one@@ -54,8 +70,8 @@ where (sizes, diagrams) = unzip pds (xs, ys) = unzip sizes (w,h) = (maximum xs, maximum ys)- xs' = align halign w xs- ys' = align valign h ys+ xs' = aligns halign w xs+ ys' = aligns valign h ys positionedDs = zipWith3 translate xs' ys' diagrams -- | Create a 'Diagram' as a union of subdiagrams which will not be@@ -64,7 +80,7 @@ union :: [Diagram] -> Diagram union = unionA hcenter vcenter --- | Superimpose one diagram atop another. @d1 ## d2@ results in a+-- | Superimpose one diagram atop another. @d1 \#\# d2@ results in a -- diagram in which @d2@ is on top of @d1@ (i.e., @d1@ is drawn -- first, then @d2@). (##) :: Diagram -> Diagram -> Diagram@@ -107,11 +123,31 @@ -- | Compute new coordinates for the centers of the subdiagrams of a -- list, based on the alignment.-align :: Alignment -> Double -> [Double] -> [Double]-align TopLeft h hs = map ((/2) . (subtract h)) hs-align Center h hs = repeat 0-align BottomRight h hs = map negate (align TopLeft h hs)+aligns :: Alignment -- ^ the alignment to use+ -> Double -- ^ the total height (resp. width) we're working with+ -> [Double] -- ^ the individual heights (resp. widths) of+ -- the diagrams to align+ -> [Double] -- ^ the amount to translate each diagram in+ -- order to be properly aligned+aligns a h hs = map (align a h) hs +-- | Given a requested alignment, the total width (resp. height) of+-- the enclosing bounding box, and the width (resp. height) of a+-- diagram, compute the offset needed to properly align the diagram.+align :: Alignment -- ^ the alignment to use+ -> Double -- ^ the total height (resp. width) we're working with+ -> Double -- ^ the height (resp. widths) of the diagram to+ -- align+ -> Double -- ^ the offset needed to align the diagram+align a h x = alignOffset a (h - x)++-- | Compute an offset corresponding to a given alignment and width.+alignOffset :: Alignment -> Double -> Double+alignOffset TopLeft x = -x/2+alignOffset Center _ = 0+alignOffset BottomRight x = x/2++ -- | A list of 'Diagram's can be distributed in one of several ways. data Distribution = Sep Double -- ^ Put a constant separation between -- each pair of diagrams@@ -179,7 +215,7 @@ offsWSeps = zipWith (+) offsets (zipWith (*) [0..] (repeat sep)) centers = zipWith (+) (init offsWSeps) (map (/2) ws) xs = map (subtract (w/2)) centers- ys = align a h hs+ ys = aligns a h hs listPosns a (Distrib da sep) (w,h) sizes = zip xs ys where (ws,hs) = unzip sizes@@ -189,14 +225,14 @@ centerOffs Center _ = sep/2 centerOffs BottomRight width = sep - width/2 xs = map (subtract (w/2)) centers- ys = align a h hs+ ys = aligns a h hs -- | Lay out a list of 'Diagram's horizontally from left to right, -- aligned along their top edges. hcat :: [Diagram] -> Diagram hcat = hsep 0 --- | @d1 <> d2@ is a 'Diagram' with @d1@ to the left of @d2@, aligned+-- | @d1 \<\> d2@ is a 'Diagram' with @d1@ to the left of @d2@, aligned -- along their top edges. (<>) :: Diagram -> Diagram -> Diagram d1 <> d2 = hcat [d1, d2]@@ -214,7 +250,7 @@ -- | Lay out a list of 'Diagram's horizontally, with the given -- amount of separation in between each pair, using the given--- vertical alignment ('top', 'center', or 'bottom').+-- vertical alignment ('top', 'vcenter', or 'bottom'). hsepA :: Double -- ^ amount of separation between each pair of diagrams -> VAlignment -- ^ alignment to use ('top', 'vcenter', or 'bottom') -> [Diagram] -> Diagram@@ -242,7 +278,7 @@ vcat :: [Diagram] -> Diagram vcat = vsep 0 --- | @d1 <> d2@ is a 'Diagram' with @d1@ above @d2@, aligned+-- | @d1 \/\/ d2@ is a 'Diagram' with @d1@ above @d2@, aligned -- along their left edges. (//) :: Diagram -> Diagram -> Diagram d1 // d2 = vcat [d1, d2]@@ -287,10 +323,129 @@ -- | The mother-combinator for all the @sep@ functions, used -- internally. sepA :: ListType -> Double -> Alignment -> [Diagram] -> Diagram-sepA lt sep align = Compound . Layout (List lt align (Sep sep))+sepA lt sep algn = Compound . Layout (List lt algn (Sep sep)) -- | The mother-combinator for all the @distrib@ functions, used -- internally. distribA :: ListType -> Double -> Alignment -> Alignment -> [Diagram] -> Diagram-distribA lt sep alignD align =- Compound . Layout (List lt align (Distrib alignD sep))+distribA lt sep alignD algn =+ Compound . Layout (List lt algn (Distrib alignD sep))+++-- Explicit subdiagram positioning ---------------------++data Positioned = Positioned [Point] HAlignment VAlignment+instance LayoutClass Positioned [] where+ layoutSizeAndPos _ [] = ((0,0), [])+ layoutSizeAndPos (Positioned ps ha va) dss = ((w,h), pds)+ where (sizes, diagrams) = unzip dss+ (ws, hs) = unzip sizes+ (pxs, pys) = unzip ps++ xs' = zipWith (\x w1 -> x - alignOffset ha w1) pxs ws+ ys' = zipWith (\y h1 -> y - alignOffset va h1) pys hs++ hws = map (/2) ws+ hhs = map (/2) hs+ xmax = maximum (zipWith (+) xs' hws)+ xmin = minimum (zipWith (-) xs' hws)+ w = xmax - xmin+ ymax = maximum (zipWith (+) ys' hhs)+ ymin = minimum (zipWith (-) ys' hhs)+ h = ymax - ymin++ xs'norm = map (subtract (xmin + w/2)) xs'+ ys'norm = map (subtract (ymin + h/2)) ys'++ pds = zipWith3 translate xs'norm ys'norm diagrams++-- | Create a diagram from a list of subdiagrams with explicit+-- positions in a local coordinate system. Each subdiagram will be+-- positioned with its center at the corresponding+-- position. @position@ is equivalent to @positionA hcenter+-- vcenter@.+position :: [(Point, Diagram)] -> Diagram+position = positionA hcenter vcenter++-- | Create a diagram from a list of subdiagrams with explicit+-- positions in a local coordinate system. The alignment options+-- specify what part of each subdiagram should be placed on the+-- corresponding position. For example, @positionA left top@ will+-- position the top left corner of each subdiagram at the+-- corresponding point.+positionA :: HAlignment -> VAlignment -> [(Point,Diagram)] -> Diagram+positionA ha va pds = Compound (Layout (Positioned ps ha va) ds)+ where (ps, ds) = unzip pds+++-- Tree ------------------------------------------++-- | Lay out a 'Tree' (from "Data.Tree") of 'Diagram's in a top-down+-- fashion. This layout is experimental; future releases of the+-- Diagrams library are planned which will be able to automatically+-- draw edges between nodes in the tree.+tree :: Double -- ^ separation between layers+ -> Double -- ^ separation between siblings+ -> Tree Diagram+ -> Diagram+tree _ _ (Node d []) = d+tree ls ss (Node d ts) = vsepA ls hcenter [ d, hsep ss (map (tree ls ss) ts) ]++-- Miscellaneous ---------------------------------++newtype Identity a = Identity a+instance Functor Identity where+ fmap f (Identity x) = Identity (f x)++data Padded = Padded Double Double HAlignment VAlignment+instance LayoutClass Padded Identity where+ layoutSizeAndPos (Padded dw dh ha va) (Identity ((w,h), d))+ = ((w', h'), [translate (align ha w' w) (align va h' h) d])+ where w' = w + dw+ h' = h + dh++-- | Add extra padding to a diagram. @pad w h d@ is a diagram which+-- is the same as @d@, but with @w@ units added to the width and @h@+-- units added to the height, with @d@ centered in the available+-- space. Thus @pad w h@ is equivalent to @padA w h hcenter vcenter@.+pad :: Double -> Double -> Diagram -> Diagram+pad pw ph d = padA pw ph hcenter vcenter d++-- | Add extra padding to a diagram, aligning the diagram as indicated+-- within the avilable space.+padA :: Double -> Double -> HAlignment -> VAlignment -> Diagram -> Diagram+padA pw ph aw ah d = Compound (Layout (Padded pw ph aw ah) (Identity d))++++data ShowBBox = ShowBBox+instance LayoutClass ShowBBox Identity where+ layoutSizeAndPos _ (Identity ((w,h), d))+ = ((w,h), [defaultAttributes $ rect w h, d])++-- | Show a rectangle denoting a diagram's bounding box, in addition+-- to the diagram itself.+showBBox :: Diagram -> Diagram+showBBox Empty = Empty+showBBox d = Compound . Layout ShowBBox . Identity $ d++-- | Show the bounding boxes of a diagram and all its subdiagrams.+showBBoxes :: Diagram -> Diagram+showBBoxes Empty = Empty+showBBoxes d@(Prim _) = showBBox d+showBBoxes (Ann a d) = showBBox (Ann a (showBBoxes d))+showBBoxes (Compound (Layout l ds)) = showBBox (Compound (Layout l (fmap showBBoxes ds)))+showBBoxes (Union ds) = showBBox (Union (map showBBoxes ds))+showBBoxes (Sized p d) = showBBox (Sized p (showBBoxes d))++data FromSize = FromSize (Double -> Double -> Diagram)+instance LayoutClass FromSize Identity where+ layoutSizeAndPos (FromSize f) (Identity ((w,h),_))+ = let d = f w h in (fst (sizeAndPos d), [d])++-- | Create one diagram using the current size of another.+-- The new diagram is returned, the old one is discarded.+withSize :: (Double -> Double -> Diagram) -- ^ Function for new diagram+ -> Diagram -- ^ Old diagram+ -> Diagram+withSize f dia = Compound (Layout (FromSize f) (Identity dia))
+ Graphics/Rendering/Diagrams/Paths.hs view
@@ -0,0 +1,177 @@+-----------------------------------------------------------------------------+-- |+-- Module : Graphics.Rendering.Diagrams.Paths+-- Copyright : (c) Brent Yorgey 2008+-- License : BSD-style (see LICENSE)+-- Maintainer : byorgey@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- Type definitions and convenience functions for+-- "Graphics.Rendering.Diagrams", an embedded domain-specific language+-- (EDSL) for creating simple diagrams.+--+-----------------------------------------------------------------------------++module Graphics.Rendering.Diagrams.Paths+ (+ emptyPath++ , pathFromVertices, pathFromVectors+ , pathConcat+ , closed, isClosed++ , rotPath++ , pathSizeAndOffset+ , renderPath++ ) where++import Graphics.Rendering.Diagrams.Types+import qualified Graphics.Rendering.Cairo as C++import Control.Monad (when)++-- | \"Integrate\" a path given by a starting point and a sequence of+-- displacements, resulting in a list of vertex coordinates.+pathInt :: Point -> Path -> [Point]+pathInt s (Path _ vs) = scanl (.+.) s vs++-- | \"Differentiate\" a list of vertex coordinates to produce an open+-- path. Calling 'pathDeriv' on an empty list will result in a+-- run-time error.+pathDeriv :: [Point] -> Path+pathDeriv ps = Path Open $ zipWith (.-.) (tail ps) ps++-- | Create an open path from a list of edge displacement vectors.+-- For example, @pathFromVectors [(1,1), (3,4)]@ describes the path+-- with two segments which first moves one unit in the positive x+-- and y directions, and then moves three units in the positive x+-- direction and four in the positive y direction.+pathFromVectors :: [Vec] -> Path+pathFromVectors = Path Open++-- | The empty path, i.e. a path with no edges.+emptyPath :: Path+emptyPath = pathFromVectors []++-- | Create an open path from a list of vertices. For example,+-- @pathFromVertices [(1,3), (4,4), (6,5)]@ describes the path with+-- two segments which starts at (1,3), has a corner at (4,4), and+-- ends at (6,5). Note, however, that the vertices themselves are+-- not significant, only the distances between them. That is,+-- @pathFromVertices [(0,1), (3,2), (5,3)]@ describes exactly the+-- same path.+pathFromVertices :: [Point] -> Path+pathFromVertices [] = emptyPath+pathFromVertices vs = pathDeriv vs++-- | Concatenate two open paths into a single open path consisting of+-- the first followed by the second.+pathConcat :: Path -> Path -> Path+pathConcat (Path _ es1) (Path _ es2) = Path Open (es1 ++ es2)++-- | Create a closed path (by connecting the first and last points in+-- the path).+closed :: Path -> Path+closed (Path _ vs) = Path Closed vs++-- | Determine whether a 'Path' is closed or open.+isClosed :: Path -> Bool+isClosed (Path Closed _) = True+isClosed _ = False++-- | Rotate a path by a fraction of a circle. @rotPath d@ rotates+-- paths by an angle of @d*2*pi@ radians. Note that creating a+-- 'Diagram' from a 'Path' (using 'straight' or 'curved' or some+-- other such function) and then applying 'rotate' to it is+-- different than first applying 'rotPath' to the 'Path' before+-- making it into a 'Diagram'. In the latter case, the bounding box+-- will be correct, whereas in the former case, the bounding box+-- will still correspond to the unrotated version of the path.+rotPath :: Double -> Path -> Path+rotPath d (Path clsd ps) = Path clsd (map rot ps)+ where ang = d*2*pi+ ca = cos ang+ sa = sin ang+ rot (x,y) = (x * ca - y * sa, x * sa + y * ca)++-- | Compute the size of a bounding box for the given 'Path', and the+-- | offset of the starting vertex from the center.+pathSizeAndOffset :: Path -> (Vec,Point)+pathSizeAndOffset p = case pathInt (0,0) p of+ [] -> ((0,0),(0,0))+ ps -> ((xmax - xmin, ymax - ymin), ((-xmax - xmin)/2, (-ymax - ymin)/2))+ where (xs,ys) = unzip ps+ xmax = maximum xs+ xmin = minimum xs+ ymax = maximum ys+ ymin = minimum ys++-- | Render a path using a particular style in the Cairo rendering monad.+renderPath :: PathStyle -> Path -> C.Render ()+renderPath Straight = renderPathStraight+renderPath (Bezier d) = renderPathBezier d++-- | Render a path using straight line segments.+renderPathStraight :: Path -> C.Render ()+renderPathStraight p@(Path clsd vs) = do+ let (_,offs) = pathSizeAndOffset p -- not nice to recalculate this,+ -- but oh well++ uncurry C.moveTo offs -- move to the start+ mapM_ (uncurry C.relLineTo) vs -- draw all the segments+ when (clsd==Closed) $ C.closePath -- maybe close the path++-- | Render a path using Bezier curves. The first parameter+-- determines what fraction of the path segments will be rounded off+-- with curves; the remainder of the segments will be drawn with+-- straight lines.+renderPathBezier :: Double -> Path -> C.Render ()+renderPathBezier _ (Path _ []) = return ()+renderPathBezier d p@(Path clsd segs) | d > 1 = renderPathBezier 1 p+ | d < 0 = renderPathBezier 0 p+ | otherwise = do+ let (_,offs) = pathSizeAndOffset p+ segcls = ((-1)*.) . last $ pathInt (0,0) p+ isClsd = (clsd == Closed)++ uncurry C.moveTo offs -- move to the first path vertex++ -- move to start of the first straight segment+ -- (draw a line if not closed)+ uncurry (if' isClsd C.relMoveTo C.relLineTo) ((d/2) *. head segs)++ -- draw (straight, curved) pairs along path+ mapM_ (drawCurveSegment d) (zip segs (tail segs))++ -- if closed path, we still need to draw+ -- two more (straight, curved) pairs:+ -- one for last segment + closing+ -- segment, one for closing segment ++ -- first segment+ if isClsd+ then do+ drawCurveSegment d (last segs, segcls)+ drawCurveSegment d (segcls, head segs)+ else -- otherwise, just finish off the last+ -- segment with a straight line+ uncurry C.relLineTo ((1 - d/2) *. last segs)++if' :: Bool -> a -> a -> a+if' True x _ = x+if' False _ x = x++-- | Given a fraction specifying which part of the segments should be+-- rounded off, and two segments, draw the straight portion of the+-- first segment and the curve between the first and second+-- segments, using the shared vertex as a control point.+drawCurveSegment :: Double -> (Vec,Vec) -> C.Render ()+drawCurveSegment d (v1, v2) = do+ let s = 1 - d+ uncurry C.relLineTo $ s *. v1++ let ctrl@(ctrlx, ctrly) = (d/2) *. v1+ let (endx, endy) = ctrl .+. ((d/2) *. v2)+ C.relCurveTo ctrlx ctrly ctrlx ctrly endx endy
Graphics/Rendering/Diagrams/Shapes.hs view
@@ -13,34 +13,49 @@ ----------------------------------------------------------------------------- module Graphics.Rendering.Diagrams.Shapes ( circle- , poly++ , regPolyPath+ , regPoly+ , rotRegPoly+ , rect+ , roundRect - , draw+ , straight+ , curved++ , textPath++ , rawCairo+ ) where import Graphics.Rendering.Diagrams.Types import Graphics.Rendering.Diagrams.Attributes (scale)+import Graphics.Rendering.Diagrams.Paths import qualified Graphics.Rendering.Cairo as C-import Control.Arrow ((&&&), (***))+import qualified Graphics.Rendering.Cairo.Internal as CI+import Control.Arrow ((&&&)) import Control.Monad.Reader+import System.IO.Unsafe (unsafePerformIO)+import Control.Exception (bracket) -- | Draw the shape defined by the current cairo path, using the -- current fill color, stroke color, and stroke width settings. draw :: DiaRenderM () draw = do c $ C.save- (RGBA r g b a) <- asks envFillColor- c $ C.setSourceRGBA r g b a+ (rf,gf,bf,af) <- asks (colorToRGBA . envFillColor)+ c $ C.setSourceRGBA rf gf bf af c $ C.fillPreserve - (RGBA r g b a) <- asks envStrokeColor- c $ C.setSourceRGBA r g b a+ (rs,gs,bs,as) <- asks (colorToRGBA . envStrokeColor)+ c $ C.setSourceRGBA rs gs bs as sw <- asks envStrokeWidth c $ fmap dist (C.deviceToUserDistance sw 0) >>= C.setLineWidth c $ C.stroke c $ C.restore- where dist = sqrt . uncurry (+) . ((^2) *** (^2))+ where dist (x,y) = sqrt (x*x + y*y) -- | A unit circle centered at the origin. data Circle = Circle deriving (Eq, Show, Read)@@ -54,28 +69,56 @@ circle :: Double -> Diagram circle r = scale r $ Prim (Shape Circle) +-- | A path-based shape.+data PathShape = PathShape PathStyle Path deriving (Eq, Show, Read)+instance ShapeClass PathShape where+ shapeSize (PathShape _ p) = fst $ pathSizeAndOffset p+ renderShape (PathShape style p) = c (renderPath style p) >> draw +-- | @straight@ creates a 'Diagram' from a path, by drawing straight+-- lines along the path edges.+straight :: Path -> Diagram+straight = Prim . Shape . PathShape Straight --- | @RPoly n@ is a regular n-gon centered at the origin, with a--- vertex at (1,0).-data RPoly = RPoly Int deriving (Eq, Show, Read)-instance ShapeClass RPoly where- shapeSize _ = (2,2)- renderShape (RPoly n) = do- c $ C.moveTo 1 0- c $ mapM_ (uncurry C.lineTo . (cos &&& sin)) $- tail [0,2*pi/nd .. (nd-1)*2*pi/nd]- c $ C.closePath- draw- where nd = fromIntegral n+-- | @curved d p@ is a curved path which follows generally the path+-- @p@. The parameter @d@ specifies the amount of corner rounding.+-- In particular, @d@ should be a value between 0 and 1, which+-- specifies what fraction of the path segments should be rounded+-- off with bezier curves, using the path vertices as control+-- points. Thus @d = 0@ produces the polygonal path itself, with no+-- curved segments; @d = 1@ produces a continuously curving path+-- tangent to the midpoints of the path segments; and intermediate+-- values of @d@ interpolate between the two. The curved path+-- produced will be everywhere differentiable as long as @d > 0@.+-- If the path is not closed, the curve will begin and end at the+-- first and last path vertices (no rounding will take place at+-- these vertices).+curved :: Double -> Path -> Diagram+curved d = Prim . Shape . PathShape (Bezier d) --- | @poly n r@ is a regular n-gon, with a circumcircle of radius @r@.--- One vertex is oriented along the positive x-axis. Note that the--- bounding box is the square circumscribed around the circumcircle.-poly :: Int -> Double -> Diagram-poly n r = scale r $ Prim (Shape (RPoly n))+-- | @regPolyPath n r@ is an open path corresponding to a regular+-- polygon, with the first vertex oriented along the positive+-- x-axis and proceeding clockwise.+regPolyPath :: Int -> Double -> Path+regPolyPath n r = pathFromVertices verts+ where verts = map (((*r) . cos) &&& ((*r) . sin))+ [0,2*pi/nd .. (nd-1)*2*pi/nd]+ nd = fromIntegral n +-- | @regPoly n r@ is a regular n-gon, with a circumcircle of radius+-- @r@. One vertex is oriented along the positive x-axis.+regPoly :: Int -> Double -> Diagram+regPoly n r = straight . closed $ regPolyPath n r +-- | @rotRegPoly n r a@ is the same as @'regPoly' n r@ but rotated+-- through an angle of @a*2*pi@ radians (i.e., @a@ represents a+-- fraction of an entire revolution). This is different than+-- @'rotate' a $ 'regPoly' n r@; @rotRegPoly@ will adjust the+-- bounding box correctly (using 'rotPath'), whereas the+-- construction using @rotate@ will still have a bounding box+-- corresponding to the unrotated polygon.+rotRegPoly :: Int -> Double -> Double -> Diagram+rotRegPoly n r a = straight . closed . rotPath a $ regPolyPath n r -- | @Rect w@ is a 2w (width) by 2 (height) rectangle, centered at the -- origin.@@ -90,3 +133,72 @@ rect :: Double -> Double -> Diagram rect w h = scale (h/2) $ Prim (Shape (Rect (w/h))) +-- | @RoundRect w h@ is a rectangle with rounded corners.+-- Both dimensions are given to avoid unnecessary+-- distortion in the curves when scaling.+data RoundRect = RoundRect Double Double deriving (Eq, Show, Read)+instance ShapeClass RoundRect where+ shapeSize (RoundRect w h) = (w,h)+ renderShape (RoundRect w h) = do+ let (x,y) = (w/2, h/2)+ r = min (w/3) (h/3)+ c $ do C.arc (r-x) (r-y) r pi (-pi/2)+ C.lineTo (x-r) (-y)+ C.arc (x-r) (r-y) r (-pi/2) 0+ C.lineTo (x) (y-r)+ C.arc (x-r) (y-r) r 0 (pi/2)+ C.lineTo (r-x) (y)+ C.arc (r-x) (y-r) r (pi/2) pi+ C.closePath+ draw++-- | @roundRect w h@ is a rectangle of width @w@ and height @h@ with+-- rounded corners having a radius one third the length of the+-- shortest edge.+roundRect :: Double -> Double -> Diagram+roundRect w h = Prim $ Shape $ RoundRect w h++-- | @Text s t@ is a text string @t@ at size @s@.+data Text = Text Double String deriving (Eq, Show, Read)+instance ShapeClass Text where+ shapeSize t = (x,y)+ where x = C.textExtentsWidth e + C.textExtentsXbearing e+ y = C.fontExtentsHeight f+ (f,e) = unsafeExtents t+ renderShape (Text s t) = do+ c $ do C.setFontSize s+ (x,y) <- C.getCurrentPoint+ te <- C.textExtents t+ fe <- C.fontExtents+ C.moveTo+ (x - (C.textExtentsWidth te/2) - C.textExtentsXbearing te)+ (y + (C.fontExtentsHeight fe/2) - C.fontExtentsDescent fe)+ C.textPath t+ draw++{-# NOINLINE unsafeExtents #-}+unsafeExtents :: Text -> (CI.FontExtents, CI.TextExtents)+unsafeExtents (Text s t) = unsafePerformIO $ do+ bracket+ (CI.create =<< C.createImageSurface C.FormatARGB32 1000 1000)+ (CI.destroy)+ (\cxt -> do CI.setFontSize cxt s+ te <- CI.textExtents cxt t+ fe <- CI.fontExtents cxt+ return (fe, te))++-- | @textPath s t@ is a string of text @t@ at size @s@,+-- represented as an outline with separate stroke and fill.+textPath :: Double -> String -> Diagram+textPath s t = Prim (Shape (Text s t))++data RawCairo = RawCairo Point (C.Render ())+instance ShapeClass RawCairo where+ shapeSize (RawCairo s _) = s+ renderShape (RawCairo _ r) = c r++-- | @rawCairo s r@ is a diagram with bounding box size @s@, rendered+-- by executing Cairo 'Render' action @r@. Import+-- "Graphics.Rendering.Cairo" to access Cairo operations.+rawCairo :: Point -> C.Render () -> Diagram+rawCairo s r = Prim (Shape (RawCairo s r))
Graphics/Rendering/Diagrams/Types.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ExistentialQuantification, GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}+{-# LANGUAGE ExistentialQuantification, GeneralizedNewtypeDeriving, MultiParamTypeClasses, FlexibleInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Graphics.Rendering.Diagrams.Types@@ -21,10 +21,14 @@ Diagram(..) - , Color(..), rgb, rgba- , Point- , (.+), (.*)+ , Color(..), SomeColor(..)+ , Point, Vec+ , (*.), (.+.), (.-.), (.*.) + , Path(..)+ , PathType(..)+ , PathStyle(..)+ -- * Shapes, attributes, and layouts , ShapeClass(..), Shape(..)@@ -40,11 +44,19 @@ , runDiaRenderM , c + , SizeSpec(..)+ , OutputType(..)+ ) where -import Graphics.Rendering.Cairo+import qualified Graphics.Rendering.Cairo as C import Control.Monad.Reader+import Data.Colour+import Data.Colour.Names (black)+import qualified Data.Colour.SRGB.Linear as RGB +-- Diagrams ----------------------------------------------------------+ -- | 'Diagram' is the core data type which describes a diagram. -- 'Diagram's may be constructed, transformed, combined, and -- ultimately rendered as an image.@@ -58,51 +70,94 @@ -- ^ An explicitly sized diagram whose bounding box -- takes up a particular amount of space. --- | An existential wrapper type for layouts. A layout consists of a--- (possibly parameterized) layout type, along with a container of--- 'Diagram's.-data Layout = forall l f. (LayoutClass l f) => Layout l (f Diagram)+-- Colors ------------------------------------------------------------ --- | All layouts must be instances of 'LayoutClass', along with an--- appropriate container type which must be an instance of Functor.-class (Functor f) => LayoutClass l f where- -- | Given a layout and a container of @(size, diagram)@ pairs (which- -- have already had all subdiagrams appropriately positioned),- -- compute the overall bounding box size for this layout, as well- -- as a list of positioned subdiagrams.- layoutSizeAndPos :: l -> f (Point,Diagram) -> (Point, [Diagram])+-- | The 'Color' type class encompasses color representations which+-- can be used by the Diagrams library; that is, every function in+-- the Diagrams library which expects a color can take any type+-- which is an instance of 'Color'. Instances are provided for both+-- the 'Data.Colour.Colour' and 'Data.Colour.AlphaColour' types from+-- the "Data.Colour" library.+class Color c where+ colorToRGBA :: c -> (Double,Double,Double,Double) --- | The 'Color' type represents colors in red-green-blue-alpha--- format, with each channel in the range 0-1. For a large list of--- predefined colors, see "Graphics.Rendering.Diagrams.Colors".-data Color = RGBA Double Double Double Double- deriving (Eq, Show, Read)+-- | Existential wrapper for instances of the 'Color' class.+data SomeColor = forall c. Color c => SomeColor c --- | Construct an opaque (alpha = 1) color from RGB values specified--- as Doubles in the range 0-1.-rgb :: Double -- ^ red channel- -> Double -- ^ green channel- -> Double -- ^ blue channel- -> Color-rgb r g b = rgba r g b 1+-- Note: we would like to just be able to say 'instance Color (Colour+-- Double)' and so on, but the problem is that the named color+-- constants in Data.Colour.Names are polymorphic with type (Floating+-- a, Ord a) => Colour a, so trying to pass one of these constants to+-- a function like 'lc' gives an error that there is no instance for+-- Color (Colour a). Adding a type annotation like 'lc (black ::+-- Colour Double)' works, but this is a pain for the user. The+-- (admittedly hackish) solution is to make general instances which+-- require Floating and Real (so that we can convert to Double with+-- fromRational . toRational), and let type defaulting figure out that+-- in the expression 'lc black', black should have type Colour Double.+-- This is still unsatisfactory, though---even though we know we will+-- (almost) always be getting (Colour Doubles), we still run the+-- values through fromRational . toRational! --- | Construct a color from RGBA values, specified as Doubles in the--- range 0-1.-rgba :: Double -- ^ red channel- -> Double -- ^ green channel- -> Double -- ^ blue channel- -> Double -- ^ alpha (transparency) channel- -> Color-rgba = RGBA+instance (Floating a, Real a) => Color (Colour a) where+ colorToRGBA col = (r,g,b,1)+ where c' = RGB.toRGB col+ r = toDouble $ RGB.channelRed c'+ g = toDouble $ RGB.channelGreen c'+ b = toDouble $ RGB.channelBlue c' +instance (Floating a, Real a) => Color (AlphaColour a) where+ colorToRGBA col = (r,g,b,a)+ where a = toDouble $ alphaChannel col+ c' = RGB.toRGB $ alphaToColour col+ r = toDouble $ RGB.channelRed c'+ g = toDouble $ RGB.channelGreen c'+ b = toDouble $ RGB.channelBlue c'++toDouble :: (Real a) => a -> Double+toDouble = fromRational . toRational++instance Color SomeColor where+ colorToRGBA (SomeColor col) = colorToRGBA col++alphaToColour :: (Floating a, Ord a, Fractional a) => AlphaColour a -> Colour a+alphaToColour ac = darken (recip (alphaChannel ac)) (ac `over` black)++-- Points ------------------------------------------------------------+ -- | Basic 2D points/vectors. type Point = (Double,Double)+type Vec = Point --- | Elementwise addition and multiplication for 'Point's.-(.+), (.*) :: Point -> Point -> Point-(x1,y1) .+ (x2,y2) = (x1 + x2, y1 + y2)-(x1,y1) .* (x2,y2) = (x1 * x2, y1 * y2)+-- | Scalar multiplication.+(*.) :: Double -> Point -> Point+s *. (x,y) = (s*x, s*y) +-- | Elementwise addition, subtraction and multiplication for 'Point's.+(.+.), (.-.), (.*.) :: Point -> Point -> Point+(x1,y1) .+. (x2,y2) = (x1 + x2, y1 + y2)+(x1,y1) .*. (x2,y2) = (x1 * x2, y1 * y2)+a .-. b = a .+. ((-1) *. b)++-- Paths -------------------------------------------------------------++-- | A path can be open (normal) or closed (first and last vertices+-- connected automatically).+data PathType = Open | Closed+ deriving (Eq, Show, Read)++-- | A path is a series of edges which can be stroked, filled, etc.+-- It can be either open (the default) or closed (i.e. the first and+-- last vertices are connected).+data Path = Path PathType+ [Vec]+ deriving (Eq, Show, Read)++-- | The styles in which a path can be rendered.+data PathStyle = Straight | Bezier Double deriving (Eq, Show, Read)++-- Attributes --------------------------------------------------------+ -- | Existential wrapper type for attributes. data Attr = forall a. AttrClass a => Attr a @@ -125,6 +180,8 @@ -- former state afterwards. renderAttr :: a -> DiaRenderM (DiaRenderEnv -> DiaRenderEnv) +-- Shapes ------------------------------------------------------------+ -- | Existential wrapper type for shapes. data Shape = forall s. ShapeClass s => Shape s @@ -156,44 +213,70 @@ -- | Calculate a cairo Render action to render a shape. renderShape :: s -> DiaRenderM () +-- Layouts -----------------------------------------------------------++-- | An existential wrapper type for layouts. A layout consists of a+-- (possibly parameterized) layout type, along with a container of+-- 'Diagram's.+data Layout = forall l f. (LayoutClass l f) => Layout l (f Diagram)++-- | All layouts must be instances of 'LayoutClass', along with an+-- appropriate container type which must be an instance of Functor.+class (Functor f) => LayoutClass l f where+ -- | Given a layout and a container of @(size, diagram)@ pairs (which+ -- have already had all subdiagrams appropriately positioned),+ -- compute the overall bounding box size for this layout, as well+ -- as a list of positioned subdiagrams.+ layoutSizeAndPos :: l -> f (Point,Diagram) -> (Point, [Diagram])++-- Rendering ---------------------------------------------------------+ -- | An environment containing additional parameters to be made -- available while rendering, which for one reason or another are -- not or cannot be provided by the cairo 'Render' monad itself. -- For example, cairo only tracks one current color, so we must -- track a fill color and stroke color separately.-data DiaRenderEnv = DREnv { envFillColor :: Color- , envStrokeColor :: Color+data DiaRenderEnv = DREnv { envFillColor :: SomeColor+ , envStrokeColor :: SomeColor , envStrokeWidth :: Double }- deriving (Show) -setEnvFillColor :: Color -> DiaRenderEnv -> DiaRenderEnv-setEnvFillColor c d = d { envFillColor = c }+setEnvFillColor :: Color c => c -> DiaRenderEnv -> DiaRenderEnv+setEnvFillColor col d = d { envFillColor = SomeColor col } -setEnvStrokeColor :: Color -> DiaRenderEnv -> DiaRenderEnv-setEnvStrokeColor c d = d { envStrokeColor = c }+setEnvStrokeColor :: Color c => c -> DiaRenderEnv -> DiaRenderEnv+setEnvStrokeColor col d = d { envStrokeColor = SomeColor col } setEnvStrokeWidth :: Double -> DiaRenderEnv -> DiaRenderEnv-setEnvStrokeWidth c d = d { envStrokeWidth = c }+setEnvStrokeWidth w d = d { envStrokeWidth = w } -- | The default rendering environment: transparent fill with 1-pixel -- black strokes. defaultDiaRenderEnv :: DiaRenderEnv-defaultDiaRenderEnv = DREnv { envFillColor = RGBA 1 1 1 0- , envStrokeColor = RGBA 0 0 0 1+defaultDiaRenderEnv = DREnv { envFillColor = SomeColor (transparent :: AlphaColour Double)+ , envStrokeColor = SomeColor (black :: Colour Double) , envStrokeWidth = 1 } -- | The custom rendering monad: ReaderT 'DiaRenderEnv' on top of -- cairo's Render monad.-newtype DiaRenderM a = DRM (ReaderT DiaRenderEnv Render a)+newtype DiaRenderM a = DRM (ReaderT DiaRenderEnv C.Render a) deriving (Functor, Monad, MonadReader DiaRenderEnv) -- | Run a 'DiaRenderM' action, given an initial rendering -- environment, to produce a cairo @Render@ action.-runDiaRenderM :: DiaRenderM a -> DiaRenderEnv -> Render a+runDiaRenderM :: DiaRenderM a -> DiaRenderEnv -> C.Render a runDiaRenderM (DRM m) e = runReaderT m e -- | Lift a cairo @Render@ action into a 'DiaRenderM' action.-c :: Render a -> DiaRenderM a+c :: C.Render a -> DiaRenderM a c = DRM . lift++-- | A specification of the size of a rendered 'Diagram'.+data SizeSpec = Width Double -- ^ an explicit width; the height is determined automatically+ | Height Double -- ^ an explicit height; the width is determined automatically+ | Auto -- ^ determine the size automatically+ -- (do not scale)++-- | The supported output file types for rendered diagrams.+data OutputType = PNG | PS | PDF | SVG
README view
@@ -1,12 +1,14 @@ Graphics.Rendering.Diagrams provides an embedded domain-specific-language (EDSL) for creating simple diagrams in a compositional style.+language (EDSL) for creating simple graphics in a compositional style. +For some examples of use, see http://code.haskell.org/diagrams/ .+ ------------------------------------------------------------------------ -Building:+To install the Diagrams library: -Get the dependencies+1. Get the dependencies The diagrams library uses Haskell bindings to the Cairo vector graphics library. In order to build the diagrams library, you@@ -24,26 +26,39 @@ website (http://www.haskell.org/gtk2hs/) and follow the instructions to download and build it. + * The colour library, which is available from Hackage. If you use+ the cabal-install build option described below, the colour+ library will be downloaded and installed for you automatically. -Build with Cabal:+2. Build - runhaskell Setup.lhs configure --prefix=$HOME --user- runhaskell Setup.lhs build- runhaskell Setup.lhs install+ * Option 1: use cabal-install - (Optionally, you can omit the --prefix and --user arguments to the- configure step, and run the install step with 'sudo' in order to- install the library systemwide.)+ If you have cabal-install, *after* installing gtk2hs, you can+ install diagrams and the remaining dependencies with+ cabal-install: + cabal install diagrams -Building Haddock documentation (recommended):+ Optionally, you can also pass options such as --user+ --prefix=$HOME to install locally. - runhaskell Setup.lhs haddock+ * Option 2: manual build - Once the documentation has been built, you can access it by - pointing your browser to dist/doc/html/index.html.+ Once all the dependencies are built and installed, you can build+ and install diagrams as follows:+ + runhaskell Setup.lhs configure --prefix=$HOME --user+ runhaskell Setup.lhs build+ runhaskell Setup.lhs install + (Optionally, you can omit the --prefix and --user arguments to the+ configure step, and run the install step with 'sudo' in order to+ install the library systemwide.) -For some examples of use, see +3. Building Haddock documentation (recommended) -http://byorgey.wordpress.com/2008/04/30/new-haskell-diagrams-library/+ runhaskell Setup.lhs haddock++ Once the documentation has been built, you can access it by + pointing your browser to dist/doc/html/diagrams/index.html.
diagrams.cabal view
@@ -1,22 +1,33 @@ Name: diagrams-Version: 0.1+Version: 0.2 Stability: experimental Description: An embedded domain-specific language (EDSL) for creating simple diagrams, built on top of the Cairo rendering engine. +Homepage: http://code.haskell.org/diagrams Synopsis: An EDSL for creating simple diagrams License: BSD3 License-file: LICENSE-Extra-source-files: README+Extra-source-files: README,CHANGELOG Author: Brent Yorgey Maintainer: byorgey@gmail.com Category: Graphics-Build-Depends: base,mtl,cairo Build-type: Simple-Exposed-Modules: Graphics.Rendering.Diagrams,+Cabal-version: >= 1.2++flag testing+ description: Testing mode+ default: False++library+ ghc-options: -Wall+ if flag(testing)+ ghc-options: -Werror+ Build-Depends: base,mtl,containers,cairo,colour+ Exposed-Modules: Graphics.Rendering.Diagrams, Graphics.Rendering.Diagrams.Types,+ Graphics.Rendering.Diagrams.Paths, Graphics.Rendering.Diagrams.Shapes, Graphics.Rendering.Diagrams.Attributes, Graphics.Rendering.Diagrams.Layouts,- Graphics.Rendering.Diagrams.Colors, Graphics.Rendering.Diagrams.Engine