Portability  GHC only 

Stability  experimental 
Maintainer  stephen.tetley@gmail.com 
Internal representation of Pictures
 data Picture u
 type DPicture = Picture Double
 data Primitive u
 type DPrimitive = Primitive Double
 data Path u = Path (Point2 u) [PathSegment u]
 type DPath = Path Double
 data PathSegment u
 type DPathSegment = PathSegment Double
 data Label u = Label {}
 type DLabel = Label Double
 type PathProps = (PSRgb, DrawPath)
 type LabelProps = (PSRgb, FontAttr)
 type EllipseProps = (PSRgb, DrawEllipse)
 data DrawPath
 = CFill
  CStroke [StrokeAttr]
  OStroke [StrokeAttr]
 data DrawEllipse
 = EFill
  EStroke [StrokeAttr]
 type Locale u = (Frame2 u, BoundingBox u)
 class Num a => PSUnit a where
 mapLocale :: (Locale u > Locale u) > Picture u > Picture u
 extractFrame :: Num u => Picture u > Frame2 u
 repositionProperties :: (Num u, Ord u) => Picture u > (BoundingBox u, Maybe (Vec2 u))
Data types
Picture is a leaf attributed tree  where atttibutes are colour, linewidth etc. It is parametric on the unit type of points (typically Double).
Wumpus's Picture, being a leaf attributed tree, is not ideally matched to PostScript's picture representation, which might be considered a node attributed tree if you recast graphics state updates as syntactic commands encountered during topdown evaluation.
Currently this mismatch means that the PostScript code
generated by Wumpus has significant overuse of PostScript's
gsave
and grestore
.
At some point a treerewriting step might be added to coalesce some of the repeated graphics state updates.
Apropos the constructors, Picture is a simple nonempty leaflabelled rose tree via
Single (aka leaf)  Picture (OneList tree)
Where OneList is a variant of the standard list type that disallows empty lists.
The additional constructors are convenience:
PickBlank
has a bounding box but no content and is useful for
some picture language operations (e.g. hsep
).
Clip
nests a picture (tree) inside a clipping path.
PicBlank (Locale u)  
Single (Locale u) (Primitive u)  
Picture (Locale u) (OneList (Picture u))  
Clip (Locale u) (Path u) (Picture u) 
Eq u => Eq (Picture u)  
Show u => Show (Picture u)  
(Num u, Pretty u) => Pretty (Picture u)  
Num u => Blank (Picture u)  
(Num u, Ord u, Horizontal (Picture u), Vertical (Picture u)) => Move (Picture u)  
(Num u, Ord u) => Composite (Picture u)  
(Num u, Ord u) => Vertical (Picture u)  
(Num u, Ord u) => Horizontal (Picture u)  
(Num u, Ord u) => Translate (Picture u)  
(Num u, Ord u) => Scale (Picture u)  
(Floating u, Real u) => RotateAbout (Picture u)  
(Floating u, Real u) => Rotate (Picture u)  
Boundary (Picture u) 
Wumpus's drawings are built from two fundamental primitives: paths (line segments and Bezier curves) and labels (single lines of text).
Ellipses are a included as a primitive only for optimization
 drawing a reasonable circle with Bezier curves needs at
least eight curves. This is inconvenient for drawing dots
which can otherwise be drawn with a single arc
command.
Wumpus does not follow PostScript and employ arcs as general path primitives  they are used only to draw ellipses. This is because arcs do not enjoy the nice properties of Bezier curves, whereby the affine transformation of a Bezier curve can simply be achieved by the affine transformation of it's control points.
Ellipses are represented by their center, halfwidth and halfheight. Halfwidth and halfheight are used so the bounding box can be calculated using only multiplication, and thus initially only obliging a Num constraint on the unit. Though typically for affine transformations a Fractional constraint is also obliged.
PPath PathProps (Path u)  
PLabel LabelProps (Label u)  
PEllipse  

type DPrimitive = Primitive DoubleSource
Path (Point2 u) [PathSegment u] 
data PathSegment u Source
Eq u => Eq (PathSegment u)  
Show u => Show (PathSegment u)  
Pretty u => Pretty (PathSegment u)  
Pointwise (PathSegment u) 
type DPathSegment = PathSegment DoubleSource
type LabelProps = (PSRgb, FontAttr)Source
type EllipseProps = (PSRgb, DrawEllipse)Source
Note when drawn filled and drawn stroked the same polygon will have (slightly) different size:
 A filled shape fills within the boundary of the shape
 A stroked shape draws a pen line around the boundary of the shape. The actual size depends on the thickness of the line (stroke width).
data DrawEllipse Source
Ellipses and circles are always closed.
type Locale u = (Frame2 u, BoundingBox u)Source
Locale = (current frame x bounding box)
Pictures (and subpictures) are located within an affine frame. So pictures can be arranged (vertical and horizontal composition) their bounding box is cached.
In Wumpus, affine transformations (scalings, rotations...)
transform the frame rather than the constituent points of
the primitives. Changes of frame are transmitted to PostScript
as concat
commands (and matrix transforms in SVG)  the
pointinworldcoordinate
of a point on a path is never
calculated.
So that picture composition is remains stable under affine transformation, the corners of bounding boxes are transformed pointwise when the picture is scaled, rotated etc.
Type class
Extras
extractFrame :: Num u => Picture u > Frame2 uSource
Should this really be public?
repositionProperties :: (Num u, Ord u) => Picture u > (BoundingBox u, Maybe (Vec2 u))Source