packages feed

wumpus-core 0.18.0 → 0.19.0

raw patch · 14 files changed

+527/−311 lines, 14 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Wumpus.Core.AffineTrans: instance (Floating a, Real a) => Rotate (Point2 a)
- Wumpus.Core.AffineTrans: instance (Floating a, Real a) => Rotate (Vec2 a)
- Wumpus.Core.AffineTrans: instance (Floating a, Real a) => RotateAbout (Point2 a)
- Wumpus.Core.AffineTrans: instance (Floating a, Real a) => RotateAbout (Vec2 a)
- Wumpus.Core.BoundingBox: instance (Eq a) => Eq (BoundingBox a)
- Wumpus.Core.BoundingBox: instance (Ord a) => Semigroup (BoundingBox a)
- Wumpus.Core.BoundingBox: instance (Pretty a) => Pretty (BoundingBox a)
- Wumpus.Core.BoundingBox: instance (Show a) => Show (BoundingBox a)
- Wumpus.Core.BoundingBox: instance Pointwise (BoundingBox a)
- Wumpus.Core.BoundingBox: withinBB :: (Ord a) => Point2 a -> BoundingBox a -> Bool
- Wumpus.Core.Geometry: instance (Eq a) => Eq (Frame2 a)
- Wumpus.Core.Geometry: instance (Eq a) => Eq (Matrix3'3 a)
- Wumpus.Core.Geometry: instance (Eq a) => Eq (Point2 a)
- Wumpus.Core.Geometry: instance (Eq a) => Eq (Vec2 a)
- Wumpus.Core.Geometry: instance (Num a) => AdditiveGroup (Matrix3'3 a)
- Wumpus.Core.Geometry: instance (Num a) => AdditiveGroup (Vec2 a)
- Wumpus.Core.Geometry: instance (Num a) => AffineSpace (Point2 a)
- Wumpus.Core.Geometry: instance (Num a) => MatrixMult (Point2 a)
- Wumpus.Core.Geometry: instance (Num a) => MatrixMult (Vec2 a)
- Wumpus.Core.Geometry: instance (Num a) => Monoid (Vec2 a)
- Wumpus.Core.Geometry: instance (Num a) => Num (Matrix3'3 a)
- Wumpus.Core.Geometry: instance (Num a) => VectorSpace (Matrix3'3 a)
- Wumpus.Core.Geometry: instance (Num a) => VectorSpace (Vec2 a)
- Wumpus.Core.Geometry: instance (Num a, InnerSpace (Vec2 a)) => Monoid (Frame2 a)
- Wumpus.Core.Geometry: instance (Ord a) => CMinMax (Point2 a)
- Wumpus.Core.Geometry: instance (Ord a) => Ord (Point2 a)
- Wumpus.Core.Geometry: instance (PSUnit a) => Pretty (Matrix3'3 a)
- Wumpus.Core.Geometry: instance (Pretty a) => Pretty (Frame2 a)
- Wumpus.Core.Geometry: instance (Pretty a) => Pretty (Point2 a)
- Wumpus.Core.Geometry: instance (Pretty a) => Pretty (Vec2 a)
- Wumpus.Core.Geometry: instance (Scalar a ~ a, Num a, InnerSpace a) => InnerSpace (Vec2 a)
- Wumpus.Core.Geometry: instance (Show a) => Show (Frame2 a)
- Wumpus.Core.Geometry: instance (Show a) => Show (Matrix3'3 a)
- Wumpus.Core.Geometry: instance (Show a) => Show (Point2 a)
- Wumpus.Core.Geometry: instance (Show a) => Show (Vec2 a)
- Wumpus.Core.Geometry: instance Pointwise (Point2 a)
- Wumpus.Core.Geometry: instance Pointwise (Vec2 a)
+ Wumpus.Core.AffineTrans: class Transform t
+ Wumpus.Core.AffineTrans: instance (Floating u, Real u) => Rotate (Point2 u)
+ Wumpus.Core.AffineTrans: instance (Floating u, Real u) => Rotate (Vec2 u)
+ Wumpus.Core.AffineTrans: instance (Floating u, Real u) => RotateAbout (Point2 u)
+ Wumpus.Core.AffineTrans: instance (Floating u, Real u) => RotateAbout (Vec2 u)
+ Wumpus.Core.AffineTrans: instance (Num u) => Transform (Point2 u)
+ Wumpus.Core.AffineTrans: instance (Num u) => Transform (Vec2 u)
+ Wumpus.Core.AffineTrans: transform :: (Transform t, u ~ (DUnit t)) => Matrix3'3 u -> t -> t
+ Wumpus.Core.BoundingBox: instance (Eq u) => Eq (BoundingBox u)
+ Wumpus.Core.BoundingBox: instance (Ord u) => Semigroup (BoundingBox u)
+ Wumpus.Core.BoundingBox: instance (Pretty u) => Pretty (BoundingBox u)
+ Wumpus.Core.BoundingBox: instance (Show u) => Show (BoundingBox u)
+ Wumpus.Core.BoundingBox: instance Pointwise (BoundingBox u)
+ Wumpus.Core.BoundingBox: within :: (Ord u) => Point2 u -> BoundingBox u -> Bool
+ Wumpus.Core.Geometry: bezierCircle :: (Fractional u, Floating u) => Int -> u -> Point2 u -> [Point2 u]
+ Wumpus.Core.Geometry: instance (Eq u) => Eq (Frame2 u)
+ Wumpus.Core.Geometry: instance (Eq u) => Eq (Matrix3'3 u)
+ Wumpus.Core.Geometry: instance (Eq u) => Eq (Point2 u)
+ Wumpus.Core.Geometry: instance (Eq u) => Eq (Vec2 u)
+ Wumpus.Core.Geometry: instance (Num u) => AdditiveGroup (Matrix3'3 u)
+ Wumpus.Core.Geometry: instance (Num u) => AdditiveGroup (Vec2 u)
+ Wumpus.Core.Geometry: instance (Num u) => AffineSpace (Point2 u)
+ Wumpus.Core.Geometry: instance (Num u) => MatrixMult (Point2 u)
+ Wumpus.Core.Geometry: instance (Num u) => MatrixMult (Vec2 u)
+ Wumpus.Core.Geometry: instance (Num u) => Monoid (Vec2 u)
+ Wumpus.Core.Geometry: instance (Num u) => Num (Matrix3'3 u)
+ Wumpus.Core.Geometry: instance (Num u) => VectorSpace (Matrix3'3 u)
+ Wumpus.Core.Geometry: instance (Num u) => VectorSpace (Vec2 u)
+ Wumpus.Core.Geometry: instance (Num u, InnerSpace (Vec2 u)) => Monoid (Frame2 u)
+ Wumpus.Core.Geometry: instance (Ord u) => Ord (Point2 u)
+ Wumpus.Core.Geometry: instance (PSUnit u) => Pretty (Matrix3'3 u)
+ Wumpus.Core.Geometry: instance (Pretty u) => Pretty (Frame2 u)
+ Wumpus.Core.Geometry: instance (Pretty u) => Pretty (Point2 u)
+ Wumpus.Core.Geometry: instance (Pretty u) => Pretty (Vec2 u)
+ Wumpus.Core.Geometry: instance (Scalar u ~ u, Num u, InnerSpace u) => InnerSpace (Vec2 u)
+ Wumpus.Core.Geometry: instance (Show u) => Show (Frame2 u)
+ Wumpus.Core.Geometry: instance (Show u) => Show (Matrix3'3 u)
+ Wumpus.Core.Geometry: instance (Show u) => Show (Point2 u)
+ Wumpus.Core.Geometry: instance (Show u) => Show (Vec2 u)
+ Wumpus.Core.Geometry: instance Pointwise (Point2 u)
+ Wumpus.Core.Geometry: instance Pointwise (Vec2 u)
+ Wumpus.Core.Geometry: maxPt :: (Ord u) => Point2 u -> Point2 u -> Point2 u
+ Wumpus.Core.Geometry: minPt :: (Ord u) => Point2 u -> Point2 u -> Point2 u
+ Wumpus.Core.Picture: wumpus_default_font :: FontAttr
- Wumpus.Core.AffineTrans: rotateAbout :: (RotateAbout t) => Radian -> Point2 (DUnit t) -> t -> t
+ Wumpus.Core.AffineTrans: rotateAbout :: (RotateAbout t, u ~ (DUnit t)) => Radian -> Point2 u -> t -> t
- Wumpus.Core.AffineTrans: scale :: (Scale t) => DUnit t -> DUnit t -> t -> t
+ Wumpus.Core.AffineTrans: scale :: (Scale t, u ~ (DUnit t)) => u -> u -> t -> t
- Wumpus.Core.BoundingBox: BBox :: Point2 a -> Point2 a -> BoundingBox a
+ Wumpus.Core.BoundingBox: BBox :: Point2 u -> Point2 u -> BoundingBox u
- Wumpus.Core.BoundingBox: bbox :: (Ord a) => Point2 a -> Point2 a -> BoundingBox a
+ Wumpus.Core.BoundingBox: bbox :: (Ord u) => Point2 u -> Point2 u -> BoundingBox u
- Wumpus.Core.BoundingBox: boundary :: (Boundary a) => a -> BoundingBox (DUnit a)
+ Wumpus.Core.BoundingBox: boundary :: (Boundary a, (DUnit a) ~ u) => a -> BoundingBox u
- Wumpus.Core.BoundingBox: boundaryBottomLeft :: BoundingBox a -> Point2 a
+ Wumpus.Core.BoundingBox: boundaryBottomLeft :: BoundingBox u -> Point2 u
- Wumpus.Core.BoundingBox: boundaryBottomRight :: BoundingBox a -> Point2 a
+ Wumpus.Core.BoundingBox: boundaryBottomRight :: BoundingBox u -> Point2 u
- Wumpus.Core.BoundingBox: boundaryHeight :: (Num a) => BoundingBox a -> a
+ Wumpus.Core.BoundingBox: boundaryHeight :: (Num u) => BoundingBox u -> u
- Wumpus.Core.BoundingBox: boundaryTopLeft :: BoundingBox a -> Point2 a
+ Wumpus.Core.BoundingBox: boundaryTopLeft :: BoundingBox u -> Point2 u
- Wumpus.Core.BoundingBox: boundaryTopRight :: BoundingBox a -> Point2 a
+ Wumpus.Core.BoundingBox: boundaryTopRight :: BoundingBox u -> Point2 u
- Wumpus.Core.BoundingBox: boundaryWidth :: (Num a) => BoundingBox a -> a
+ Wumpus.Core.BoundingBox: boundaryWidth :: (Num u) => BoundingBox u -> u
- Wumpus.Core.BoundingBox: corners :: BoundingBox a -> (Point2 a, Point2 a, Point2 a, Point2 a)
+ Wumpus.Core.BoundingBox: corners :: BoundingBox u -> (Point2 u, Point2 u, Point2 u, Point2 u)
- Wumpus.Core.BoundingBox: data BoundingBox a
+ Wumpus.Core.BoundingBox: data BoundingBox u
- Wumpus.Core.BoundingBox: leftPlane :: BoundingBox a -> a
+ Wumpus.Core.BoundingBox: leftPlane :: BoundingBox u -> u
- Wumpus.Core.BoundingBox: ll_corner :: BoundingBox a -> Point2 a
+ Wumpus.Core.BoundingBox: ll_corner :: BoundingBox u -> Point2 u
- Wumpus.Core.BoundingBox: lowerPlane :: BoundingBox a -> a
+ Wumpus.Core.BoundingBox: lowerPlane :: BoundingBox u -> u
- Wumpus.Core.BoundingBox: obbox :: (Num a) => a -> a -> BoundingBox a
+ Wumpus.Core.BoundingBox: obbox :: (Num u) => u -> u -> BoundingBox u
- Wumpus.Core.BoundingBox: rightPlane :: BoundingBox a -> a
+ Wumpus.Core.BoundingBox: rightPlane :: BoundingBox u -> u
- Wumpus.Core.BoundingBox: trace :: (Num a, Ord a) => [Point2 a] -> BoundingBox a
+ Wumpus.Core.BoundingBox: trace :: (Num u, Ord u) => [Point2 u] -> BoundingBox u
- Wumpus.Core.BoundingBox: union :: (Ord a) => BoundingBox a -> BoundingBox a -> BoundingBox a
+ Wumpus.Core.BoundingBox: union :: (Ord u) => BoundingBox u -> BoundingBox u -> BoundingBox u
- Wumpus.Core.BoundingBox: upperPlane :: BoundingBox a -> a
+ Wumpus.Core.BoundingBox: upperPlane :: BoundingBox u -> u
- Wumpus.Core.BoundingBox: ur_corner :: BoundingBox a -> Point2 a
+ Wumpus.Core.BoundingBox: ur_corner :: BoundingBox u -> Point2 u
- Wumpus.Core.Geometry: (*#) :: (MatrixMult t, (DUnit t) ~ a) => Matrix3'3 a -> t -> t
+ Wumpus.Core.Geometry: (*#) :: (MatrixMult t, (DUnit t) ~ u) => Matrix3'3 u -> t -> t
- Wumpus.Core.Geometry: Frame2 :: (Vec2 a) -> (Vec2 a) -> (Point2 a) -> Frame2 a
+ Wumpus.Core.Geometry: Frame2 :: (Vec2 u) -> (Vec2 u) -> (Point2 u) -> Frame2 u
- Wumpus.Core.Geometry: M3'3 :: !a -> !a -> !a -> !a -> !a -> !a -> !a -> !a -> !a -> Matrix3'3 a
+ Wumpus.Core.Geometry: M3'3 :: !u -> !u -> !u -> !u -> !u -> !u -> !u -> !u -> !u -> Matrix3'3 u
- Wumpus.Core.Geometry: P2 :: !a -> !a -> Point2 a
+ Wumpus.Core.Geometry: P2 :: !u -> !u -> Point2 u
- Wumpus.Core.Geometry: V2 :: !a -> !a -> Vec2 a
+ Wumpus.Core.Geometry: V2 :: !u -> !u -> Vec2 u
- Wumpus.Core.Geometry: avec :: (Floating a) => Radian -> a -> Vec2 a
+ Wumpus.Core.Geometry: avec :: (Floating u) => Radian -> u -> Vec2 u
- Wumpus.Core.Geometry: data Frame2 a
+ Wumpus.Core.Geometry: data Frame2 u
- Wumpus.Core.Geometry: data Matrix3'3 a
+ Wumpus.Core.Geometry: data Matrix3'3 u
- Wumpus.Core.Geometry: data Point2 a
+ Wumpus.Core.Geometry: data Point2 u
- Wumpus.Core.Geometry: data Vec2 a
+ Wumpus.Core.Geometry: data Vec2 u
- Wumpus.Core.Geometry: determinant :: (Num a) => Matrix3'3 a -> a
+ Wumpus.Core.Geometry: determinant :: (Num u) => Matrix3'3 u -> u
- Wumpus.Core.Geometry: direction :: (Floating a, Real a) => Vec2 a -> Radian
+ Wumpus.Core.Geometry: direction :: (Floating u, Real u) => Vec2 u -> Radian
- Wumpus.Core.Geometry: displaceOrigin :: (Num a) => Vec2 a -> Frame2 a -> Frame2 a
+ Wumpus.Core.Geometry: displaceOrigin :: (Num u) => Vec2 u -> Frame2 u -> Frame2 u
- Wumpus.Core.Geometry: frame2Matrix :: (Num a) => Frame2 a -> Matrix3'3 a
+ Wumpus.Core.Geometry: frame2Matrix :: (Num u) => Frame2 u -> Matrix3'3 u
- Wumpus.Core.Geometry: frameProduct :: (Num a, InnerSpace (Vec2 a)) => Frame2 a -> Frame2 a -> Frame2 a
+ Wumpus.Core.Geometry: frameProduct :: (Num u, InnerSpace (Vec2 u)) => Frame2 u -> Frame2 u -> Frame2 u
- Wumpus.Core.Geometry: hvec :: (Num a) => a -> Vec2 a
+ Wumpus.Core.Geometry: hvec :: (Num u) => u -> Vec2 u
- Wumpus.Core.Geometry: identityMatrix :: (Num a) => Matrix3'3 a
+ Wumpus.Core.Geometry: identityMatrix :: (Num u) => Matrix3'3 u
- Wumpus.Core.Geometry: invert :: (Fractional a) => Matrix3'3 a -> Matrix3'3 a
+ Wumpus.Core.Geometry: invert :: (Fractional u) => Matrix3'3 u -> Matrix3'3 u
- Wumpus.Core.Geometry: langle :: (Floating a, Real a) => Point2 a -> Point2 a -> Radian
+ Wumpus.Core.Geometry: langle :: (Floating u, Real u) => Point2 u -> Point2 u -> Radian
- Wumpus.Core.Geometry: matrix2Frame :: Matrix3'3 a -> Frame2 a
+ Wumpus.Core.Geometry: matrix2Frame :: Matrix3'3 u -> Frame2 u
- Wumpus.Core.Geometry: originatedRotationMatrix :: (Floating a, Real a) => Radian -> (Point2 a) -> Matrix3'3 a
+ Wumpus.Core.Geometry: originatedRotationMatrix :: (Floating u, Real u) => Radian -> (Point2 u) -> Matrix3'3 u
- Wumpus.Core.Geometry: ortho :: (Num a) => Point2 a -> Frame2 a
+ Wumpus.Core.Geometry: ortho :: (Num u) => Point2 u -> Frame2 u
- Wumpus.Core.Geometry: pointInFrame :: (Num a) => Point2 a -> Frame2 a -> Point2 a
+ Wumpus.Core.Geometry: pointInFrame :: (Num u) => Point2 u -> Frame2 u -> Point2 u
- Wumpus.Core.Geometry: pvec :: (Num a) => Point2 a -> Point2 a -> Vec2 a
+ Wumpus.Core.Geometry: pvec :: (Num u) => Point2 u -> Point2 u -> Vec2 u
- Wumpus.Core.Geometry: rotationMatrix :: (Floating a, Real a) => Radian -> Matrix3'3 a
+ Wumpus.Core.Geometry: rotationMatrix :: (Floating u, Real u) => Radian -> Matrix3'3 u
- Wumpus.Core.Geometry: scalingMatrix :: (Num a) => a -> a -> Matrix3'3 a
+ Wumpus.Core.Geometry: scalingMatrix :: (Num u) => u -> u -> Matrix3'3 u
- Wumpus.Core.Geometry: standardFrame :: (Num a) => Frame2 a -> Bool
+ Wumpus.Core.Geometry: standardFrame :: (Num u) => Frame2 u -> Bool
- Wumpus.Core.Geometry: translationMatrix :: (Num a) => a -> a -> Matrix3'3 a
+ Wumpus.Core.Geometry: translationMatrix :: (Num u) => u -> u -> Matrix3'3 u
- Wumpus.Core.Geometry: transpose :: Matrix3'3 a -> Matrix3'3 a
+ Wumpus.Core.Geometry: transpose :: Matrix3'3 u -> Matrix3'3 u
- Wumpus.Core.Geometry: vangle :: (Floating a, Real a, InnerSpace (Vec2 a)) => Vec2 a -> Vec2 a -> Radian
+ Wumpus.Core.Geometry: vangle :: (Floating u, Real u, InnerSpace (Vec2 u)) => Vec2 u -> Vec2 u -> Radian
- Wumpus.Core.Geometry: vvec :: (Num a) => a -> Vec2 a
+ Wumpus.Core.Geometry: vvec :: (Num u) => u -> Vec2 u
- Wumpus.Core.Geometry: zeroPt :: (Num a) => Point2 a
+ Wumpus.Core.Geometry: zeroPt :: (Num u) => Point2 u

Files

CHANGES view
@@ -1,3 +1,35 @@++0.18,0 to 0.19.0:+  +  * Added @Transform@ type class to apply a matrix transformation+    directly.+  +  * Changed the ordering of picture drawing in PostScript and SVG+    output so the list gets drawn from tail to head with right +    folds. This makes the list order of pictures match their +    zorder.+  +  * Renamed the function @withinBB@ (Core.BoundingBox) to +    @within@.+  +  * On many type signatures with e.g. Points, I\'ve changed the +    parameter name on the type constructor from @a@ to @u@.+    This is to indicate that @u@ is some unit - almost always a+    Double. e.g @Point2 a@ becomes @Point2 u@ and all the class+    obligations change lexically as well @Floating a =>@ to +    @Floating u =>@. Superficially this means a lot of type +    signatures have diffs but haven\'t really changed. +  +  * Added function @bezierCircle@ to generate the Bezier curve +    points for arcs describing a circle.+  +  * Added new demo - MultiPic. The PostScript it generates+    is efficient - no extraneous use of @concat@. +  +  * Added wumpus_default_font constant.+  ++ 0.17.0 to 0.18.0:      * Added instances of the affine operation classes (Scale, 
+ demo/MultiPic.hs view
@@ -0,0 +1,33 @@+{-# OPTIONS -Wall #-}++module MultiPic where++import Wumpus.Core+import Wumpus.Core.Colour++import Data.AffineSpace++main :: IO ()+main = do +  writeEPS_latin1 "./out/multi_pic.eps"  pic1+  writeSVG_latin1 "./out/multi_pic.svg"  pic1++++pic1 :: DPicture+pic1 = uniformScale 2 $ frameMulti $ +    [ ellipse blue 10 10 zeroPt+    , ellipse red 10 10 (P2 40 40)+    , ztextlabel "Wumpus!" (P2 40 20)+    , square red 5 (P2 50 10)  +    ]+++square :: (Num u, Ord u) => DRGB -> u -> Point2 u -> Primitive u+square rgb sidelen bl = fill rgb $ vertexPath $+    [bl, bl .+^ hvec sidelen, bl .+^ V2 sidelen sidelen, bl .+^ vvec sidelen]++-- The PostScript generated from this is pretty good.+-- +-- No extraneous use of @concat@.+--
src/Wumpus/Core/AffineTrans.hs view
@@ -38,7 +38,8 @@ module Wumpus.Core.AffineTrans   (    -- * Type classes-    Rotate(..)+    Transform(..)+  , Rotate(..)   , RotateAbout(..)   , Scale(..)   , Translate(..)@@ -76,29 +77,41 @@ -------------------------------------------------------------------------------- -- Affine transformations  +-- | Apply a matrix trasnformation directly.+class Transform t where+  transform :: u ~ DUnit t => Matrix3'3 u -> t -> t ++ -- | Type class for rotation.+--  class Rotate t where   rotate :: Radian -> t -> t +instance Num u => Transform (Point2 u) where+  transform ctm = (ctm *#) -instance (Floating a, Real a) => Rotate (Point2 a) where+instance Num u => Transform (Vec2 u) where+  transform ctm = (ctm *#)+++instance (Floating u, Real u) => Rotate (Point2 u) where   rotate a = ((rotationMatrix a) *#) -instance (Floating a, Real a) => Rotate (Vec2 a) where+instance (Floating u, Real u) => Rotate (Vec2 u) where   rotate a = ((rotationMatrix a) *#)   -- | Type class for rotation about a point. class RotateAbout t where-  rotateAbout :: Radian -> Point2 (DUnit t) -> t -> t +  rotateAbout :: u ~ DUnit t =>  Radian -> Point2 u -> t -> t   -instance (Floating a, Real a) => RotateAbout (Point2 a) where+instance (Floating u, Real u) => RotateAbout (Point2 u) where   rotateAbout a pt = ((originatedRotationMatrix a pt) *#)   -instance (Floating a, Real a) => RotateAbout (Vec2 a) where+instance (Floating u, Real u) => RotateAbout (Vec2 u) where   rotateAbout a pt = ((originatedRotationMatrix a pt) *#)     --------------------------------------------------------------------------------@@ -106,7 +119,7 @@  -- | Type class for scaling. class Scale t where-  scale :: DUnit t -> DUnit t -> t -> t+  scale :: u ~ DUnit t => u -> u -> t -> t  instance Num u => Scale (Point2 u) where   scale x y = ((scalingMatrix x y) *#) 
src/Wumpus/Core/BoundingBox.hs view
@@ -40,7 +40,7 @@   , retrace    , corners-  , withinBB+  , within   , boundaryWidth   , boundaryHeight   , boundaryBottomLeft@@ -57,7 +57,6 @@  import Wumpus.Core.AffineTrans import Wumpus.Core.Geometry-import Wumpus.Core.Utils ( CMinMax(..), within )  import Data.Semigroup @@ -72,9 +71,9 @@ -- spared the obligation to be /empty/. BoundingBox is an instance -- of the Semigroup class where @append@ is the union operation. -- -data BoundingBox a = BBox -      { ll_corner :: Point2 a-      , ur_corner :: Point2 a +data BoundingBox u = BBox +      { ll_corner :: Point2 u+      , ur_corner :: Point2 u        }   deriving (Eq,Show) @@ -87,11 +86,11 @@  -- BBox is NOT monoidal - it\'s much simpler that way. -instance Ord a => Semigroup (BoundingBox a) where+instance Ord u => Semigroup (BoundingBox u) where   append = union  -instance Pretty a => Pretty (BoundingBox a) where+instance Pretty u => Pretty (BoundingBox u) where   pretty (BBox p0 p1) = text "|_" <+> pretty p0 <+> pretty p1 <+> text "_|"   @@ -113,14 +112,14 @@ -- Picture, Path etc. -- class Boundary a where-  boundary :: a -> BoundingBox (DUnit a)+  boundary :: DUnit a ~ u => a -> BoundingBox u    --------------------------------------------------------------------------------  -instance Pointwise (BoundingBox a) where-  type Pt (BoundingBox a) = Point2 a+instance Pointwise (BoundingBox u) where+  type Pt (BoundingBox u) = Point2 u   pointwise f (BBox bl tr) = BBox (f bl) (f tr)  @@ -132,7 +131,7 @@ -- @bbox@ throws an error if the width or height of the  -- constructed bounding box is negative. ---bbox :: Ord a => Point2 a -> Point2 a -> BoundingBox a+bbox :: Ord u => Point2 u -> Point2 u -> BoundingBox u bbox ll@(P2 x0 y0) ur@(P2 x1 y1)     | x0 <= x1 && y0 <= y1 = BBox ll ur     | otherwise            = error "Wumpus.Core.BoundingBox.bbox - malformed."@@ -141,15 +140,15 @@ -- | Create a BoundingBox with bottom left corner at the origin, -- and dimensions @w@ and @h@. ---obbox :: Num a => a -> a -> BoundingBox a+obbox :: Num u => u -> u -> BoundingBox u obbox w h = BBox zeroPt (P2 w h)   -- | The union of two bounding boxes. This is also the @append@  -- of BoundingBox\'s @Semigroup@ instance. ---union :: Ord a => BoundingBox a -> BoundingBox a -> BoundingBox a-BBox ll ur `union` BBox ll' ur' = BBox (cmin ll ll') (cmax ur ur')+union :: Ord u => BoundingBox u -> BoundingBox u -> BoundingBox u+BBox ll ur `union` BBox ll' ur' = BBox (minPt ll ll') (maxPt ur ur')  -- | Trace a list of points, retuning the BoundingBox that  -- includes them.@@ -157,8 +156,8 @@ -- 'trace' throws a run-time error when supplied with the empty  -- list. ---trace :: (Num a, Ord a) => [Point2 a] -> BoundingBox a-trace (p:ps) = uncurry BBox $ foldr (\z (a,b) -> (cmin z a, cmax z b) ) (p,p) ps+trace :: (Num u, Ord u) => [Point2 u] -> BoundingBox u+trace (p:ps) = uncurry BBox $ foldr (\z (a,b) -> (minPt z a, maxPt z b) ) (p,p) ps trace []     = error $ "BoundingBox.trace called in empty list"  -- | Perform the supplied transformation on the four corners of @@ -177,24 +176,24 @@  -- | Generate all the corners of a bounding box, counter-clock  -- wise from the bottom left, i.e. @(bl, br, tr, tl)@.-corners :: BoundingBox a -> (Point2 a, Point2 a, Point2 a, Point2 a)+corners :: BoundingBox u -> (Point2 u, Point2 u, Point2 u, Point2 u) corners (BBox bl@(P2 x0 y0) tr@(P2 x1 y1)) = (bl, br, tr, tl) where     br = P2 x1 y0     tl = P2 x0 y1  -- | Within test - is the supplied point within the bounding box? ---withinBB :: Ord a => Point2 a -> BoundingBox a -> Bool-withinBB p (BBox ll ur) = within p ll ur+within :: Ord u => Point2 u -> BoundingBox u -> Bool+within p (BBox ll ur) = (minPt p ll) == ll && (maxPt p ur) == ur  -- | Extract the width of a bounding box. ---boundaryWidth :: Num a => BoundingBox a -> a+boundaryWidth :: Num u => BoundingBox u -> u boundaryWidth (BBox (P2 xmin _) (P2 xmax _)) = xmax - xmin  -- | Extract the height of a bounding box. ---boundaryHeight :: Num a => BoundingBox a -> a+boundaryHeight :: Num u => BoundingBox u -> u boundaryHeight (BBox (P2 _ ymin) (P2 _ ymax)) = ymax - ymin  @@ -203,19 +202,19 @@ -- Points on the boundary  -- | Extract the bottom-left corner of the bounding box.-boundaryBottomLeft  :: BoundingBox a -> Point2 a+boundaryBottomLeft  :: BoundingBox u -> Point2 u boundaryBottomLeft (BBox p0 _ ) = p0  -- | Extract the top-right corner of the bounding box.-boundaryTopRight :: BoundingBox a -> Point2 a+boundaryTopRight :: BoundingBox u -> Point2 u boundaryTopRight (BBox _ p1) = p1  -- | Extract the top-left corner of the bounding box.-boundaryTopLeft :: BoundingBox a -> Point2 a+boundaryTopLeft :: BoundingBox u -> Point2 u boundaryTopLeft (BBox (P2 x _) (P2 _ y)) = P2 x y  -- | Extract the bottom-right corner of the bounding box.-boundaryBottomRight :: BoundingBox a -> Point2 a+boundaryBottomRight :: BoundingBox u -> Point2 u boundaryBottomRight (BBox (P2 _ y) (P2 x _)) = P2 x y  @@ -228,19 +227,19 @@ -- Are these really worthwhile ? ...  -- | Extract the unit of the left vertical plane.-leftPlane :: BoundingBox a -> a+leftPlane :: BoundingBox u -> u leftPlane (BBox (P2 l _) _) = l  -- | Extract the unit of the right vertical plane.-rightPlane :: BoundingBox a -> a+rightPlane :: BoundingBox u -> u rightPlane (BBox _ (P2 r _)) = r  -- | Extract the unit of the lower horizontal plane.-lowerPlane :: BoundingBox a -> a+lowerPlane :: BoundingBox u -> u lowerPlane (BBox (P2 _ l) _) = l  -- | Extract the unit of the upper horizontal plane.-upperPlane :: BoundingBox a -> a+upperPlane :: BoundingBox u -> u upperPlane (BBox _ (P2 _ u)) = u  
src/Wumpus/Core/Geometry.hs view
@@ -58,6 +58,8 @@    -- * Point operations   , zeroPt+  , minPt+  , maxPt   , langle    -- * Frame operations@@ -91,10 +93,11 @@    -- * Bezier curves   , bezierArc+  , bezierCircle    ) where -import Wumpus.Core.Utils ( CMinMax(..), PSUnit(..), oo )+import Wumpus.Core.Utils ( PSUnit(..), oo )   import Data.AffineSpace@@ -117,16 +120,18 @@ -- Datatypes   -- | 2D Vector - both components are strict.-data Vec2 a = V2 !a !a+--+data Vec2 u = V2 !u !u   deriving (Eq,Show)  type DVec2 = Vec2 Double  -- | 2D Point - both components are strict. -- --- Point2 derives Ord so it can be used as a key in Data.Map etc.+-- Note - Point2 derives Ord so it can be used as a key in +-- Data.Map etc. ---data Point2 a = P2 !a !a+data Point2 u = P2 !u !u   deriving (Eq,Ord,Show)  type DPoint2 = Point2 Double@@ -143,7 +148,7 @@ -- > Frame2 (V2 e0x e0y) (V2 e1x e1y) (P2 ox oy) --  -data Frame2 a = Frame2 (Vec2 a) (Vec2 a) (Point2 a)+data Frame2 u = Frame2 (Vec2 u) (Vec2 u) (Point2 u)   deriving (Eq,Show)  type DFrame2 = Frame2 Double@@ -184,7 +189,7 @@ --   -data Matrix3'3 a = M3'3 !a !a !a  !a !a !a  !a !a !a+data Matrix3'3 u = M3'3 !u !u !u  !u !u !u  !u !u !u   deriving (Eq)  type DMatrix3'3 = Matrix3'3 Double@@ -201,19 +206,19 @@ -------------------------------------------------------------------------------- -- Family instances -type instance DUnit (Point2 a)    = a-type instance DUnit (Vec2 a)      = a-type instance DUnit (Frame2 a)    = a-type instance DUnit (Matrix3'3 a) = a+type instance DUnit (Point2 u)    = u+type instance DUnit (Vec2 u)      = u+type instance DUnit (Frame2 u)    = u+type instance DUnit (Matrix3'3 u) = u  -------------------------------------------------------------------------------- -- lifters / convertors -lift2Vec2 :: (a -> a -> a) -> Vec2 a -> Vec2 a -> Vec2 a+lift2Vec2 :: (u -> u -> u) -> Vec2 u -> Vec2 u -> Vec2 u lift2Vec2 op (V2 x y) (V2 x' y') = V2 (x `op` x') (y `op` y')  -lift2Matrix3'3 :: (a -> a -> a) -> Matrix3'3 a -> Matrix3'3 a -> Matrix3'3 a+lift2Matrix3'3 :: (u -> u -> u) -> Matrix3'3 u -> Matrix3'3 u -> Matrix3'3 u lift2Matrix3'3 op (M3'3 a b c d e f g h i) (M3'3 m n o p q r s t u) =        M3'3 (a `op` m) (b `op` n) (c `op` o)              (d `op` p) (e `op` q) (f `op` r)  @@ -242,27 +247,27 @@  -- Vectors have a sensible Monoid instance as addition, points don't -instance Num a => Monoid (Vec2 a) where+instance Num u => Monoid (Vec2 u) where   mempty  = V2 0 0   mappend = lift2Vec2 (+)    -- Affine frames also have a sensible Monoid instance -instance (Num a, InnerSpace (Vec2 a)) => Monoid (Frame2 a) where+instance (Num u, InnerSpace (Vec2 u)) => Monoid (Frame2 u) where   mempty = ortho zeroPt   mappend = frameProduct   -- Show -instance Show a => Show (Matrix3'3 a) where+instance Show u => Show (Matrix3'3 u) where   show (M3'3 a b c d e f g h i) = "(M3'3 " ++ body ++ ")" where     body = show [[a,b,c],[d,e,f],[g,h,i]]  -- Num -instance Num a => Num (Matrix3'3 a) where+instance Num u => Num (Matrix3'3 u) where   (+) = lift2Matrix3'3 (+)    (-) = lift2Matrix3'3 (-) @@ -290,19 +295,19 @@ -------------------------------------------------------------------------------- -- Pretty printing -instance Pretty a => Pretty (Vec2 a) where+instance Pretty u => Pretty (Vec2 u) where   pretty (V2 a b) = angles (char '|' <+> pretty a <+> pretty b <+> char '|') -instance Pretty a => Pretty (Point2 a) where+instance Pretty u => Pretty (Point2 u) where   pretty (P2 a b) = brackets (char '|' <+> pretty a <+> pretty b <+> char '|') -instance Pretty a => Pretty (Frame2 a) where+instance Pretty u => Pretty (Frame2 u) where   pretty (Frame2 e0 e1 o) = braces $         text "e0:" <> pretty e0     <+> text "e1:" <> pretty e1     <+> text "o:" <> pretty o -instance PSUnit a => Pretty (Matrix3'3 a) where+instance PSUnit u => Pretty (Matrix3'3 u) where   pretty (M3'3 a b c  d e f  g h i) =        matline a b c <$> matline d e f <$> matline g h i     where@@ -317,38 +322,38 @@ -------------------------------------------------------------------------------- -- Vector space instances -instance Num a => AdditiveGroup (Vec2 a) where+instance Num u => AdditiveGroup (Vec2 u) where   zeroV = V2 0 0    (^+^) = lift2Vec2 (+)     negateV = fmap negate   -instance Num a => VectorSpace (Vec2 a) where-  type Scalar (Vec2 a) = a+instance Num u => VectorSpace (Vec2 u) where+  type Scalar (Vec2 u) = u   s *^ v = fmap (s*) v   -- scalar (dot / inner) product via the class InnerSpace -instance (Num a, InnerSpace a, Scalar a ~ a) -    => InnerSpace (Vec2 a) where+instance (Num u, InnerSpace u, Scalar u ~ u) +    => InnerSpace (Vec2 u) where   (V2 a b) <.> (V2 a' b') = (a <.> a') ^+^ (b <.> b')  -instance Num a => AffineSpace (Point2 a) where-  type Diff (Point2 a) = Vec2 a+instance Num u => AffineSpace (Point2 u) where+  type Diff (Point2 u) = Vec2 u   (P2 a b) .-. (P2 x y)   = V2 (a-x)  (b-y)   (P2 a b) .+^ (V2 vx vy) = P2 (a+vx) (b+vy)  -instance Num a => AdditiveGroup (Matrix3'3 a) where+instance Num u => AdditiveGroup (Matrix3'3 u) where   zeroV = fromInteger 0   (^+^) = (+)   negateV = negate  -instance Num a => VectorSpace (Matrix3'3 a) where-  type Scalar (Matrix3'3 a) = a+instance Num u => VectorSpace (Matrix3'3 u) where+  type Scalar (Matrix3'3 u) = u   s *^ m = fmap (s*) m   --------------------------------------------------------------------------------@@ -371,20 +376,15 @@   type Pt [a] = Pt a   pointwise f pts = map (pointwise f) pts  -instance Pointwise (Vec2 a) where-  type Pt (Vec2 a) = Vec2 a+instance Pointwise (Vec2 u) where+  type Pt (Vec2 u) = Vec2 u   pointwise f v = f v -instance Pointwise (Point2 a) where-  type Pt (Point2 a) = Point2 a+instance Pointwise (Point2 u) where+  type Pt (Point2 u) = Point2 u   pointwise f pt = f pt --------------------------------------------------------------------------------- -instance Ord a => CMinMax (Point2 a) where-  cmin (P2 x y) (P2 x' y') = P2 (min x x') (min y y')-  cmax (P2 x y) (P2 x' y') = P2 (max x x') (max y y')- -------------------------------------------------------------------------------- -- Matrix multiply @@ -394,14 +394,14 @@ -- represented as homogeneous coordinates.  -- class MatrixMult t where -  (*#) :: DUnit t ~ a => Matrix3'3 a -> t -> t+  (*#) :: DUnit t ~ u => Matrix3'3 u -> t -> t  -instance Num a => MatrixMult (Vec2 a) where       +instance Num u => MatrixMult (Vec2 u) where          (M3'3 a b c d e f _ _ _) *# (V2 m n) = V2 (a*m+b*n+c*0) (d*m+e*n+f*0)  -instance Num a => MatrixMult (Point2 a) where+instance Num u => MatrixMult (Point2 u) where   (M3'3 a b c d e f _ _ _) *# (P2 m n) = P2 (a*m+b*n+c*1) (d*m+e*n+f*1)  --------------------------------------------------------------------------------@@ -411,19 +411,22 @@ -- | Direction of a vector - i.e. the counter-clockwise angle  -- from the x-axis. ---direction :: (Floating a, Real a) => Vec2 a -> Radian+direction :: (Floating u, Real u) => Vec2 u -> Radian direction (V2 x y) = langle (P2 0 0) (P2 x y)  -- | Construct a vector with horizontal displacement.-hvec :: Num a => a -> Vec2 a+--+hvec :: Num u => u -> Vec2 u hvec d = V2 d 0  -- | Construct a vector with vertical displacement.-vvec :: Num a => a -> Vec2 a+--+vvec :: Num u => u -> Vec2 u vvec d = V2 0 d  -- | Construct a vector from an angle and magnitude.-avec :: Floating a => Radian -> a -> Vec2 a+--+avec :: Floating u => Radian -> u -> Vec2 u avec theta d = V2 x y where   ang = fromRadian theta   x   = d * cos ang@@ -434,25 +437,50 @@ -- -- > pvec = flip (.-.) ---pvec :: Num a => Point2 a -> Point2 a -> Vec2 a+pvec :: Num u => Point2 u -> Point2 u -> Vec2 u pvec = flip (.-.)  -- | Extract the angle between two vectors. ---vangle :: (Floating a, Real a, InnerSpace (Vec2 a)) -       => Vec2 a -> Vec2 a -> Radian+vangle :: (Floating u, Real u, InnerSpace (Vec2 u)) +       => Vec2 u -> Vec2 u -> Radian vangle u v = realToFrac $ acos $ (u <.> v) / (on (*) magnitude u v)  -------------------------------------------------------------------------------- -- Points  -- | Construct a point at 0 0.-zeroPt :: Num a => Point2 a+--+zeroPt :: Num u => Point2 u zeroPt = P2 0 0 ++-- | /Component-wise/ min on points.  +-- Standard 'min' and 'max' via Ord are defined lexographically+-- on pairs, e.g.:+-- +-- > min (1,2) (2,1) = (1,2)+-- +-- For Points we want the component-wise min and max, e.g:+--+-- > minPt (P2 1 2) (Pt 2 1) = Pt 1 1 +-- > maxPt (P2 1 2) (Pt 2 1) = Pt 2 2+-- +minPt :: Ord u => Point2 u -> Point2 u -> Point2 u+minPt (P2 x y) (P2 x' y') = P2 (min x x') (min y y')++-- | /Component-wise/ max on points.  +--+-- > maxPt (P2 1 2) (Pt 2 1) = Pt 2 2+-- +maxPt :: Ord u => Point2 u -> Point2 u -> Point2 u+maxPt (P2 x y) (P2 x' y') = P2 (max x x') (max y y')++ -- | Calculate the counter-clockwise angle between two points  -- and the x-axis.-langle :: (Floating a, Real a) => Point2 a -> Point2 a -> Radian+--+langle :: (Floating u, Real u) => Point2 u -> Point2 u -> Radian langle (P2 x1 y1) (P2 x2 y2) = step (x2 - x1) (y2 - y1)   where     -- north-east quadrant @@ -476,16 +504,19 @@  -- | Create a frame with standard (orthonormal bases) at the  -- supplied point.-ortho :: Num a => Point2 a -> Frame2 a+--+ortho :: Num u => Point2 u -> Frame2 u ortho o = Frame2 (V2 1 0) (V2 0 1) o  -- | Displace the origin of the frame by the supplied vector.-displaceOrigin :: Num a => Vec2 a -> Frame2 a -> Frame2 a+--+displaceOrigin :: Num u => Vec2 u -> Frame2 u -> Frame2 u displaceOrigin v (Frame2 e0 e1 o) = Frame2 e0 e1 (o.+^v)  -- | \'World coordinate\' calculation of a point in the supplied -- frame.-pointInFrame :: Num a => Point2 a -> Frame2 a -> Point2 a+--+pointInFrame :: Num u => Point2 u -> Frame2 u -> Point2 u pointInFrame (P2 x y) (Frame2 vx vy o) = (o .+^ (vx ^* x)) .+^ (vy ^* y)    -- | Concatenate the elements of the frame as columns forming a@@ -502,7 +533,7 @@ -- >        0   0   1  ) -- -frame2Matrix :: Num a =>  Frame2 a -> Matrix3'3 a+frame2Matrix :: Num u =>  Frame2 u -> Matrix3'3 u frame2Matrix (Frame2 (V2 e0x e0y) (V2 e1x e1y) (P2 ox oy)) =      M3'3 e0x e1x ox            e0y e1y oy @@ -519,21 +550,24 @@ -- -- > Frame (V2 e0x e0y) (V2 e1x e1y) (P2 ox oy) -- -matrix2Frame :: Matrix3'3 a -> Frame2 a+matrix2Frame :: Matrix3'3 u -> Frame2 u matrix2Frame (M3'3 e0x e1x ox                     e0y e1y oy                    _   _   _ ) = Frame2 (V2 e0x e0y) (V2 e1x e1y) (P2 ox oy)   -- | /Multiplication/ of frames to form their product.-frameProduct :: (Num a, InnerSpace (Vec2 a)) => Frame2 a -> Frame2 a -> Frame2 a+--+frameProduct :: (Num u, InnerSpace (Vec2 u)) +             => Frame2 u -> Frame2 u -> Frame2 u frameProduct = matrix2Frame `oo` on (*) frame2Matrix    -- | Is the origin at (0,0) and are the basis vectors orthogonal  -- with unit length?-standardFrame :: Num a => Frame2 a -> Bool+--+standardFrame :: Num u => Frame2 u -> Bool standardFrame (Frame2 (V2 1 0) (V2 0 1) (P2 0 0)) = True standardFrame _                                   = False @@ -547,7 +581,7 @@ -- >       0 1 0 -- >       0 0 1 ) ---identityMatrix :: Num a => Matrix3'3 a+identityMatrix :: Num u => Matrix3'3 u identityMatrix = M3'3 1 0 0                         0 1 0                         0 0 1@@ -560,7 +594,7 @@ -- >       0  sy 0 -- >       0  0  1 ) ---scalingMatrix :: Num a => a -> a -> Matrix3'3 a+scalingMatrix :: Num u => u -> u -> Matrix3'3 u scalingMatrix sx sy = M3'3  sx 0  0                                0  sy 0                                0  0  1@@ -571,7 +605,7 @@ -- >       0  1  y -- >       0  0  1 ) ---translationMatrix :: Num a => a -> a -> Matrix3'3 a+translationMatrix :: Num u => u -> u -> Matrix3'3 u translationMatrix x y = M3'3 1 0 x                                0 1 y                                0 0 1@@ -582,7 +616,7 @@ -- >       sin(a)   cos(a)  y -- >       0        0       1 ) ---rotationMatrix :: (Floating a, Real a) => Radian -> Matrix3'3 a+rotationMatrix :: (Floating u, Real u) => Radian -> Matrix3'3 u rotationMatrix a = M3'3 (cos ang) (negate $ sin ang) 0                          (sin ang) (cos ang)          0                           0         0                  1@@ -600,8 +634,8 @@ -- (T being the translation matrix, R the rotation matrix and -- T^-1 the inverse of the translation matrix). ---originatedRotationMatrix :: (Floating a, Real a) -                         => Radian -> (Point2 a) -> Matrix3'3 a+originatedRotationMatrix :: (Floating u, Real u) +                         => Radian -> (Point2 u) -> Matrix3'3 u originatedRotationMatrix ang (P2 x y) = mT * (rotationMatrix ang) * mTinv   where     mT    = M3'3 1 0 x     @@ -615,15 +649,18 @@   -- | Invert a matrix.-invert :: Fractional a => Matrix3'3 a -> Matrix3'3 a +--+invert :: Fractional u => Matrix3'3 u -> Matrix3'3 u invert m = (1 / determinant m) *^ adjoint m  -- | Determinant of a matrix.-determinant :: Num a => Matrix3'3 a -> a+--+determinant :: Num u => Matrix3'3 u -> u determinant (M3'3 a b c d e f g h i) = a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g  -- | Transpose a matrix.-transpose :: Matrix3'3 a -> Matrix3'3 a+--+transpose :: Matrix3'3 u -> Matrix3'3 u transpose (M3'3 a b c                  d e f                  g h i) = M3'3 a d g  @@ -632,23 +669,23 @@  -- Helpers -adjoint :: Num a => Matrix3'3 a -> Matrix3'3 a +adjoint :: Num u => Matrix3'3 u -> Matrix3'3 u adjoint = transpose . cofactor . mofm  -cofactor :: Num a => Matrix3'3 a -> Matrix3'3 a+cofactor :: Num u => Matrix3'3 u -> Matrix3'3 u cofactor (M3'3 a b c                  d e f                  g h i) = M3'3   a  (-b)   c                              (-d)   e  (-f)                                g  (-h)   i -mofm :: Num a => Matrix3'3 a -> Matrix3'3 a+mofm :: Num u => Matrix3'3 u -> Matrix3'3 u mofm (M3'3 a b c                  d e f                  g h i)  = M3'3 m11 m12 m13                                 m21 m22 m23 -                          m31 m32 m33+                              m31 m32 m33   where       m11 = (e*i) - (f*h)     m12 = (d*i) - (f*g)@@ -726,5 +763,27 @@     p1    = p0 .+^ avec (ang1 + pi/2) e     p2    = p3 .+^ avec (ang2 - pi/2) e     p3    = pt .+^ avec ang2 r+++-- | Make a circle from Bezier curves - @n@ is the number of +-- subdivsions per quadrant.+--+bezierCircle :: (Fractional u, Floating u) +             => Int -> u -> Point2 u -> [Point2 u]+bezierCircle n radius pt = start $ subdivisions (n*4) (2*pi)+  where+    start (a:b:xs) = s : cp1 : cp2 : e : rest (b:xs)+      where (s,cp1,cp2,e) = bezierArc radius a b pt+                     +    start _        = [] ++    rest (a:b:xs)  = cp1 : cp2 : e : rest (b:xs)+      where (_,cp1,cp2,e) = bezierArc radius a b pt ++    rest _         = [] ++    subdivisions i a = 0 : take i (iterate (+one) one) +      where  one  = a / fromIntegral i+  
+ src/Wumpus/Core/OneList.hs view
@@ -0,0 +1,139 @@+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module      :  Wumpus.Core.OneList+-- Copyright   :  (c) Stephen Tetley 2010+-- License     :  BSD3+--+-- Maintainer  :  Stephen Tetley <stephen.tetley@gmail.com>+-- Stability   :  highly unstable+-- Portability :  GHC+--+-- Data type for non-empty lists.+-- +-- Structurally the same as OneMany - but used for a different+-- purpose.+--+--------------------------------------------------------------------------------++module Wumpus.Core.OneList+  (+   -- OneMany+    OneList+  , ViewOL(..)++  , one+  , cons+  , head+  , viewl++  , fromList++  , toListF+  , accumMapL+  , isOne+  , isMany+   +  ) where+++import Data.Semigroup           -- package: algebra++import Control.Applicative+import Data.Foldable+import Data.Monoid+import Data.Traversable++import Prelude hiding ( head )++-- type OneMany a = OneList a++data OneList a = One a | Many a (OneList a)+  deriving (Eq)++data ViewOL a = OneL a | a :<< (OneList a)+  deriving (Eq)++--------------------------------------------------------------------------------+-- Instances++instance Show a => Show (OneList a) where+  show = ('{':) . ($ []) . step where+     step (One a)     = shows a . showChar '}'+     step (Many a as) = shows a . showChar ',' . step as+++instance Functor OneList where+  fmap f (One a)        = One $ f a+  fmap f (Many a as)    = Many (f a) (fmap f as)++instance Foldable OneList where+  foldMap f (One a)     = f a+  foldMap f (Many a as) = f a `mappend` foldMap f as++  foldr f b0 = step b0 where+    step b (One a)      = f a b+    step b (Many a as)  = f a (step b as)++  foldl f b0 = step b0 where+    step b (One a)      = f b a+    step b (Many a as)  = step (f b a) as+++instance Traversable OneList where+  traverse f (One a)      = One  <$> f a+  traverse f (Many a as)  = Many <$> f a <*> traverse f as+++instance Semigroup (OneList e) where+  (One a)     `append` bs  = Many a bs+  (Many a as) `append` bs  = Many a (as `append` bs)++--------------------------------------------------------------------------------+-- | Construct One.+one :: a -> OneList a+one = One+++-- | Prepend an element. Obviously this transforms a One to a Many.+cons :: a -> OneList a -> OneList a+cons a as   = Many a as++-- | 'head' is total of course.+head :: OneList a -> a+head (One a)    = a+head (Many a _) = a++viewl :: OneList a -> ViewOL a+viewl (One a)     = OneL a+viewl (Many a as) = a :<< as++-- | Construct Many. Not this function throws a error if the list has+-- zero or one elements+fromList :: [a] -> OneList a+fromList []     = error "OneList.fromList: cannot build Many from empty list"+fromList [a]    = One a+fromList (a:as) = Many a (fromList as)+++toListF :: (a -> b) -> OneList a -> [b]+toListF f = step where+  step (One x)     = [f x]+  step (Many x xs) = f x : step xs+++accumMapL :: (x -> st -> (y,st)) -> OneList x -> st -> (OneList y,st)+accumMapL f (One x)     st = let (y,st') = f x st in (One y,st')+accumMapL f (Many x xs) st = (Many y ys,st'')+                             where (y, st')  = f x st+                                   (ys,st'') = accumMapL f xs st'++isMany :: OneList a -> Bool+isMany (Many _ _) = True+isMany _          = False++isOne :: OneList a -> Bool+isOne (One _)     = True+isOne _           = False+
src/Wumpus/Core/OutputPostScript.hs view
@@ -41,6 +41,7 @@  import MonadLib hiding ( Label ) +import qualified Data.Foldable as F   @@ -167,8 +168,8 @@ outputPicture (PicBlank  _)             = return () outputPicture (Single (fr,_) prim)      =      updateFrame fr $ outputPrimitive prim-outputPicture (Picture (fr,_) ones)      = do-    updateFrame fr $ onesmapM_ outputPicture  ones+outputPicture (Picture (fr,_) ones)     =+    updateFrame fr $ F.foldrM (\p _ -> outputPicture p) () ones outputPicture (Clip (fr,_) cp p)        =      updateFrame fr $ do { clipPath cp ; outputPicture p } 
src/Wumpus/Core/OutputSVG.hs view
@@ -55,6 +55,7 @@  import Text.XML.Light +import qualified Data.Foldable as F  type Clipped    = Bool @@ -107,9 +108,12 @@     return $ gElement (maybe [] return $ frameChange fr) [elt]  picture c (Picture (fr,_) ones)    = do-    es <- toListWithM (picture c) ones+    -- Note - list in zorder, so we want to draw the tail first +    es <- liftM toListH $ F.foldrM fn emptyH ones     return $ gElement (maybe [] return $ frameChange fr) es-+  where+    fn e hl = picture c e >>= \a -> return $ hl `snocH` a+   picture _ (Clip (fr,_) p a) = do     cp <- clipPath p    e1 <- picture True a
src/Wumpus/Core/Picture.hs view
@@ -33,6 +33,8 @@   , vertexPath     , curvedPath +  , wumpus_default_font+   -- * Constructing primitives   , Stroke(..)   , zostroke@@ -67,9 +69,9 @@ import Wumpus.Core.Colour import Wumpus.Core.Geometry import Wumpus.Core.GraphicsState+import Wumpus.Core.OneList import Wumpus.Core.PictureInternal import Wumpus.Core.TextEncodingInternal-import Wumpus.Core.Utils  import Data.Semigroup @@ -128,6 +130,9 @@ -- | Lift a list of primitives to a composite picture, all  -- primitives will be located within the standard frame. --+-- The order of the list maps to the zorder - the front of the+-- list is drawn at the top.+-- -- This function throws an error when supplied the empty list. -- frameMulti :: (Fractional u, Floating u, Ord u) @@ -141,12 +146,14 @@ -- This function throws an error when supplied the empty list. -- multi :: (Fractional u, Ord u) => [Picture u] -> Picture u-multi ps = Picture (stdFrame, sconcat $ map boundary ps) ones+multi ps = Picture (stdFrame, sconcat $ map boundary ps) $ step ps   where      sconcat []      = error err_msg     sconcat (x:xs)  = foldr append x xs -    ones            = fromListErr ps err_msg+    step [x]        = one x+    step (x:xs)     = x `cons` step xs+    step _          = error err_msg      err_msg         = "Wumpus.Core.Picture.multi - empty list" @@ -192,7 +199,19 @@     +-- | Constant for the default font, which is @Courier@ (aliased +-- to @Courier New@ for SVG).+-- +-- The font size is 24 point. Note that only a handful of font +-- sizes are available directly to PostScript / GhostScript.+--+-- To get non-standard sizes, consider drawing the text and +-- applying a 'uniformScale'.+--+wumpus_default_font :: FontAttr+wumpus_default_font = FontAttr "Courier" "Courier New" SVG_REGULAR 24 + -------------------------------------------------------------------------------- -- Take Paths to Primitives @@ -322,11 +341,7 @@   where     lbl = Label pt (lexLabel txt) identityMatrix --- SVG seems to have an issue with /Courier/ and needs /Courier New/. -default_font :: FontAttr-default_font = FontAttr "Courier" "Courier New" SVG_REGULAR 24- -- | Create a text label. The string should not contain newline -- or tab characters. Use 'multilabel' to create text with  -- multiple lines.@@ -343,16 +358,17 @@   textlabel :: Num u => t -> String -> Point2 u -> Primitive u  -instance TextLabel () where textlabel () = mkTextLabel psBlack default_font+instance TextLabel () where +    textlabel () = mkTextLabel psBlack wumpus_default_font  instance TextLabel (RGB3 Double) where-  textlabel c = mkTextLabel (psColour c) default_font+  textlabel c = mkTextLabel (psColour c) wumpus_default_font  instance TextLabel (HSB3 Double) where-  textlabel c = mkTextLabel (psColour c) default_font+  textlabel c = mkTextLabel (psColour c) wumpus_default_font  instance TextLabel (Gray Double) where-  textlabel c = mkTextLabel (psColour c) default_font+  textlabel c = mkTextLabel (psColour c) wumpus_default_font  instance TextLabel FontAttr where   textlabel a = mkTextLabel psBlack a@@ -369,7 +385,7 @@ -- | Create a label where the font is @Courier@, text size is 24pt -- and colour is black. ztextlabel :: Num u => String -> Point2 u -> Primitive u-ztextlabel = mkTextLabel psBlack default_font+ztextlabel = mkTextLabel psBlack wumpus_default_font   @@ -385,7 +401,7 @@   -- | Create an ellipse, the ellipse will be filled unless the --- supplied attributes /imply/ a stoked ellipse, e.g.:+-- supplied attributes /imply/ a stroked ellipse, e.g.: -- -- > ellipse (LineWidth 4) zeroPt 40 40  --@@ -491,7 +507,7 @@ -- neither picture will be moved. -- picOver :: (Num u, Ord u) => Picture u -> Picture u -> Picture u-a `picOver` b = Picture (ortho zeroPt, bb) (mkList2 b a) +a `picOver` b = Picture (ortho zeroPt, bb) (cons b $ one a)    where     bb = union (boundary a) (boundary b) 
src/Wumpus/Core/PictureInternal.hs view
@@ -59,6 +59,7 @@ import Wumpus.Core.FontSize import Wumpus.Core.Geometry import Wumpus.Core.GraphicsState+import Wumpus.Core.OneList import Wumpus.Core.TextEncodingInternal import Wumpus.Core.Utils @@ -234,12 +235,12 @@ instance (Num u, Pretty u) => Pretty (Picture u) where   pretty (PicBlank m)       = text "*BLANK*" <+> ppLocale m   pretty (Single m prim)    = ppLocale m <$> indent 2 (pretty prim)-  pretty (Picture m ones)  = -      ppLocale m <$> indent 2 (list $ toListWith pretty ones)+  pretty (Picture m ones)   = +      ppLocale m <$> indent 2 (list $ toListF pretty ones)    pretty (Clip m cpath p)   =        text "Clip:" <+> ppLocale m <$> indent 2 (pretty cpath)-                                   <$> indent 2 (pretty p)+                                  <$> indent 2 (pretty p)  ppLocale :: (Num u, Pretty u) => Locale u -> Doc ppLocale (fr,bb) = align (ppfr <$> pretty bb) where@@ -303,7 +304,10 @@ type instance DUnit (Path u)        = u type instance DUnit (PrimEllipse u) = u +instance (Num u, Ord u) => Transform (Picture u) where+  transform ctm pic = transformPicture (transform ctm) (transform ctm) pic + instance (Floating u, Real u) => Rotate (Picture u) where   rotate = rotatePicture  @@ -316,6 +320,18 @@ instance (Num u, Ord u) => Translate (Picture u) where   translate = translatePicture ++-- Primitives++instance Num u => Transform (Primitive u) where+  transform ctm (PPath   attr path) = +      PPath attr $ transformPath (transform ctm) path++  transform ctm (PLabel   attr lbl) = PLabel attr $ transformLabel ctm lbl++  transform ctm (PEllipse attr ell) = PEllipse attr $ transformEllipse ctm ell++ instance (Real u, Floating u) => Rotate (Primitive u) where   rotate ang (PPath    attr path) = PPath    attr $ rotatePath ang path   rotate ang (PLabel   attr lbl)  = PLabel   attr $ rotateLabel ang lbl@@ -361,7 +377,11 @@ translatePicture :: (Num u, Ord u) => u -> u -> Picture u -> Picture u translatePicture x y = transformPicture (translate x y) (translate x y) -+-- TODO - the nameing for these functions is confusing now that+-- I've added a Transform typeclass.+--+-- Look to unifying the naming scheme in someway.+-- transformPicture :: (Num u, Ord u)                   => (Point2 u -> Point2 u)                   -> (Vec2 u -> Vec2 u) @@ -417,6 +437,9 @@  -- Labels +transformLabel :: Num u => Matrix3'3 u -> Label u -> Label u+transformLabel m33 (Label pt txt ctm) = Label pt txt (ctm * m33)+ -- rotate CTM and pt or just CTM ?? rotateLabel :: (Real u, Floating u) => Radian -> Label u -> Label u rotateLabel ang (Label pt txt ctm) = Label pt txt (ctm * rotationMatrix ang)@@ -437,6 +460,10 @@  --  +transformEllipse :: Num u => Matrix3'3 u -> PrimEllipse u -> PrimEllipse u+transformEllipse m33 (PrimEllipse pt hw hh ctm) = +    PrimEllipse pt hw hh (ctm * m33)+ rotateEllipse :: (Real u, Floating u)                => Radian -> PrimEllipse u -> PrimEllipse u rotateEllipse ang (PrimEllipse pt hw hh ctm) = @@ -569,19 +596,14 @@ -- ellipseControlPoints :: (Floating u, Ord u)                      => PrimEllipse u -> [Point2 u]-ellipseControlPoints (PrimEllipse ctr hw hh ctm) = -    map (new_mtrx *#) $ start circ+ellipseControlPoints (PrimEllipse ctr hw hh ctm) = map (new_mtrx *#) circ   where     (radius,(dx,dy)) = circleScalingProps hw hh     new_mtrx         = ctm * scalingMatrix dx dy-    circ             = bezierCircle radius ctr-    -    start ((a,b,c,d):xs)  = a:b:c:d : rest xs-    start _               = []      -- should be unreachable-    -    rest  ((_,b,c,d):xs)  = b:c:d : rest xs-    rest  _               = []+    circ             = bezierCircle 1 radius ctr +    -- subdivide the bezierCircle with 1 to get two+    -- control points per quadrant.       --@@ -598,16 +620,5 @@     (dx,dy)    = if radius == hw then (1, rescale (0,hw) (0,1) hh)                                  else (rescale (0,hh) (0,1) hw, 1) ----- | Make a circle from Bezier curves - @n@ is the number of --- subdivsions per quadrant.----bezierCircle :: Floating u -             => u -> Point2 u -> [(Point2 u, Point2 u, Point2 u, Point2 u)]-bezierCircle radius pt = map mkQuad angs-  where-    angs         = [(0, pi*0.5), (pi*0.5,pi), (pi, pi*1.5), (pi*1.5, pi*2)]-    mkQuad (a,b) = bezierArc radius a b pt  
src/Wumpus/Core/Utils.hs view
@@ -19,12 +19,9 @@ module Wumpus.Core.Utils   (  -  -- * Component-wise min and max-    CMinMax(..)-  , within    -- * Three values  -  , max3+    max3   , min3   , med3 @@ -55,16 +52,9 @@    -- * Hughes list   , H+  , emptyH   , toListH-  --  -- * OneList type - non-empty list type-  , OneList(..)-  , mkList2-  , onesmapM_-  , toListWith-  , toListWithM-  , fromListErr+  , snocH       -- * specs etc. from Data.Aviary@@ -80,7 +70,6 @@   import Control.Applicative-import Control.Monad ( ap ) import Data.List ( intersperse ) import Data.Ratio import Data.Time@@ -89,35 +78,7 @@  -------------------------------------------------------------------------------- --- | /Component-wise/ min and max. --- Standard 'min' and 'max' via Ord are defined lexographically--- on pairs, e.g.:--- --- > min (1,2) (2,1) = (1,2)--- --- For certain geometrical objects (Points!) we want the --- (constructed-) componentwise min and max, e.g:------ > cmin (1,2) (2,1) = (1,1) --- > cmax (1,2) (2,1) = (2,2)---  -class CMinMax a where-  cmin :: a -> a -> a-  cmax :: a -> a -> a----instance (Ord a, Ord b) => CMinMax (a,b) where-  cmin (x,y) (x',y') = (min x x', min y y')-  cmax (x,y) (x',y') = (max x x', max y y')----- | Test whether a is within opper and lower.-within :: Eq a => CMinMax a => a -> a -> a -> Bool-within a lower upper = (cmin a lower) == lower && (cmax a upper) == upper-- -- | max of 3 max3 :: Ord a => a -> a -> a -> a max3 a b c = max (max a b) c@@ -265,52 +226,16 @@  type H a = [a] -> [a] +emptyH :: H a+emptyH = id+ toListH :: H a -> [a] toListH = ($ []) -----------------------------------------------------------------------------------infixr 5 `Many`--data OneList a = One a | Many a  (OneList a)-  deriving (Eq)--instance Show a => Show (OneList a) where-  show = ('{':) . ($ []) . step where-     step (One a)     = shows a . showChar '}'-     step (Many a xs) = shows a . showChar ',' . step xs---mkList2 :: a -> a -> OneList a-mkList2 a b = a `Many` One b---onesmapM_ :: Monad m => (a -> m b) -> OneList a -> m ()-onesmapM_ f (One x)     = f x >> return ()-onesmapM_ f (Many x xs) = f x >> onesmapM_ f xs--toListWith :: (a -> b) -> OneList a -> [b]-toListWith f (One x)     = [f x]-toListWith f (Many x xs) = f x : toListWith f xs--toListWithM :: Monad m => (a -> m b) -> OneList a -> m [b]-toListWithM mf (One x)     = mf x >>= \a -> return [a]-toListWithM mf (Many x xs) = return (:) `ap` mf x `ap` toListWithM mf xs----- Error msg is a parameter, so client code can supply a --- meaningful warning.--- -fromListErr :: [a] -> String -> OneList a-fromListErr xs0 msg = step xs0 where-   step []     = error msg-   step [a]    = One a-   step (a:xs) = Many a $ step xs--+snocH :: H a -> a -> H a+snocH hl a = hl . (a:)  ---------------------------------------------------------------------------------  -- | A variant of the @D2@ or dovekie combinator - the argument -- order has been changed to be more satisfying for Haskellers:
src/Wumpus/Core/VersionNumber.hs view
@@ -22,4 +22,4 @@   wumpus_core_version :: (Int,Int,Int)-wumpus_core_version = (0,18,0)+wumpus_core_version = (0,19,0)
src/Wumpus/Extra/SVGColours.hs view
@@ -172,7 +172,7 @@ import Wumpus.Core.Colour ( RGB3(..), DRGB )  -import Prelude hiding ( tan )+import Prelude ( )     
wumpus-core.cabal view
@@ -1,5 +1,5 @@ name:             wumpus-core-version:          0.18.0+version:          0.19.0 license:          BSD3 license-file:     LICENSE copyright:        Stephen Tetley <stephen.tetley@gmail.com>@@ -16,7 +16,7 @@   It can generate PostScript (EPS) files and SVG files. The    generated PostScript code is plain [1] and reasonably    efficient as the use of stack operations, i.e @gsave@ and -  @grestore@ is minimized.+  @grestore@, is minimized.   .   Pictures in Wumpus are made from /paths/ and text /labels/.    Paths themselves are made from points. The usual affine @@ -25,35 +25,34 @@   is no notion of a current point, Wumpus builds pictures in a   coordinate-free style.    .-  With recent revisions, I\'ve added some extra helper modules-  that are not really part of the \"core\", but they provide -  lists of named colours and /safe/ fonts, plus some code  -  (Extra.PictureLanguage) that has been moved out of the-  wumpus-core namespace because it is somewhat \"higher-level\". +  Wumpus-core includes some extra helper modules that are not +  really part of the \"core\", but are otherwise currently +  homeless. They provide lists of named colours and /safe/ +  fonts, plus some prototype code (Extra.PictureLanguage) for +  arranging pictures.   .   WARNING...   .-  With revision 0.18.0, I\'ve changed the internals a bit so that -  Primitives (paths, text labels) support affine transformations. -  In the end, this didn\'t changed the API significantly, though -  with the next revision, I want to look at changing the -  PostScript output - swapping some uses of @concat@ to @moveto@; -  so again there is the possibility of significant changes -  between this revision and the next one.+  The modules @Core.BoundingBox@ and @Extra.PictureLanguage@ are+  likely to be reworked significantly in the future.    .-  Also the module, Core.BoundingBox, is still a candidate for -  reworking, as it has too many functions that do not offer +  @Core.BoundingBox@ has too many functions that do not offer    distinct functionality. Some functions were removed in    revision 0.17.0 and some more are likely to follow.    .+  @Extra.PictureLanguage@ needs some more thought. The current +  set of classes is rather cumbersome, and some of the operations +  would benefit new names.+  .   NOTE...   .-  One consequence of adding affine transformations for primitives-  is that the bounding box of a primitive under transformation -  may be tighter than than the bounding box of transformed -  picture containing the same primitive, i.e.:+  Revision 0.17.0 added affine transformations for primitives +  (paths, text labels, ellipses), one consequence of this is +  the bounding box may be tighter for a primitive under affine +  transformation then lifted to a picture, than a primitive +  lifted to picture then transformed, i.e.:   . -  @liftToPicture (transform PRIM) /= transform (liftToPicture PRIM)@+  @boundary (liftToPicture (transform PRIM)) /= boundary (transform (liftToPicture PRIM))@   .   Where liftToPicture is usually @frame@ from    @Wumpus.Core.Picture@.@@ -72,22 +71,52 @@   found at <http://code.google.com/p/copperbox/> though.   .   Some of the design decisions made for wumpus-core are not -  sophisticated (e.g. how attributes like colour are -  handled, and how the bounding boxes of text labels are -  calculated), so Wumpus might be limited compared to other -  systems. However, the design permits a simple implementation - -  which is a priority. Text encoding an exception - I\'m not -  sure how reasonable the design is. The current implementation +  sophisticated (e.g. how attributes like colour are handled, +  and how the bounding boxes of text labels are calculated), so +  Wumpus might be limited compared to other systems. However, +  the design permits a fairly simple implementation - which is +  a priority. Text encoding an exception - I\'m not sure how +  reasonable the design is. The current implementation    appears okay for Latin 1 but may be inadequate for other    character sets, so I may have to revise it significantly.   .   .   \[1\] Because the output is simple, straight-line PostScript -  code, it is possible to use GraphicsMagick or a similar tool to -  convert Wumpus'\s EPS files to many other formats (bitmaps). +  code, it is possible to use GraphicsMagick or a similar tool +  to convert Wumpus'\s EPS files to many other formats +  (bitmaps).    .   Changelog:   .+  0.18,0 to 0.19.0:+  .+  * Added @Transform@ type class to apply a matrix transformation+    directly.+  .+  * Changed the ordering of picture drawing in PostScript and SVG+    output so the list gets drawn from tail to head with right +    folds. This makes the list order of pictures match their +    zorder.+  .+  * Renamed the function @withinBB@ (Core.BoundingBox) to +    @within@.+  .+  * On many type signatures with e.g. Points, I\'ve changed the +    parameter name on the type constructor from @a@ to @u@.+    This is to indicate that @u@ is some unit - almost always a+    Double. e.g @Point2 a@ becomes @Point2 u@ and all the class+    obligations change lexically as well @Floating a =>@ to +    @Floating u =>@. Superficially this means a lot of type +    signatures have diffs but haven\'t really changed. +  .+  * Added function @bezierCircle@ to generate the Bezier curve +    points for arcs describing a circle.+  .+  * Added new demo - MultiPic. The PostScript it generates+    is efficient - no extraneous use of @concat@. +  .+  * Added wumpus_default_font constant.+  .   0.17.0 to 0.18.0:   .   * Added instances of the affine operation classes (Scale, @@ -105,7 +134,7 @@     transformation, Pictures may generate a larger bounding box      than composite primitives.   .-  * Minor change - ztextlabal changed to use 24pt type rather +  * Minor change - ztextlabel changed to use 24pt type rather      than 12pt.    .   * Corrected the cabal file to include the correct files for @@ -113,54 +142,7 @@     missing with the generated file @WorldFrame.eps@ incorrectly      included instead.   .-  0.16.0 to 0.17.0:   .-  * Added Core.WumpusTypes to export opaque versions of-    datatypes from Core.PictureInternal. This should make-    the Haddock documentation more cohesive.-  . -  * Moved the Core.PictureLanguage module into the Extra-    namespace (Extra.PictureLanguage). This module may change-    in detail, if not in spirit in the future as I'm not -    very happy with it. Also this module is somewhat -    \"higher-level\" than the modules in wumpus-core, so -    a different home seems fitting. -  . -  * Removed CardinalPoint and boundaryPoint from BoundingBox.-  .-  * Argument order of 'textlabel' and 'ztextlabel' changed so-    that Point2 is the last argument.-  .-  * PathSegment constructor names changed - this is an internal-    change as the constructors are not exported.-  .-  * Primitive type changed - moved Ellipse properties into -    PrimEllipse type - internal change.-  .-  * Removed dependency on \'old-time\'.-  .-  0.15.0 to 0.16.0:-  .-  * Additions to Core.Geometry (direction, pvec, vangle, -    circularModulo).-  .-  * Fixed error with langle due to not accounting for circle -    quadrants in Core.Geometry.-  .-  * Point2 now derives Ord - so it can be used as a key for-    Data.Map.-  .-  * Added escape-character handling to text output in PostScript.-    This was causing a nasty bug where a drawing would completely-    fail when special chars shown (GhostView gives little hint of -    what is wrong when such errors are present).-  . -  * Changed BoundingBox operation 'corners' to return a 4-tuple-    rather than a list.-  .  -  * Added centeredAt to PictureLanguage-  .-  . build-type:         Simple stability:          unstable cabal-version:      >= 1.2@@ -175,6 +157,7 @@   demo/AffineTestBase.hs,   demo/FontPic.hs,   demo/LabelPic.hs,+  demo/MultiPic.hs   demo/Picture.hs,   doc/Guide.pdf,   doc-src/Guide.lhs,@@ -214,6 +197,7 @@     Wumpus.Core.PictureInternal,     Wumpus.Core.PostScript,     Wumpus.Core.SVG,+    Wumpus.Core.OneList,     Wumpus.Core.TextEncodingInternal,     Wumpus.Core.Utils