diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,26 @@
 
+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
+
+
 0.14.0 to 0.15.0:
 
   * Added Named colours and "safe fonts" from wumpus-extra.
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -19,7 +19,7 @@
     msg = [ "-------------------------------------------------------"
           , "-------------------------------------------------------"
           , ""
-          , "WARNING - is Wumpus.Core.Version.Number correct?"
+          , "WARNING - is Wumpus.Core.VersionNumber correct?"
           , ""
           , "-------------------------------------------------------"
           , "-------------------------------------------------------"
diff --git a/src/Wumpus/Core/BoundingBox.hs b/src/Wumpus/Core/BoundingBox.hs
--- a/src/Wumpus/Core/BoundingBox.hs
+++ b/src/Wumpus/Core/BoundingBox.hs
@@ -100,7 +100,8 @@
 type instance DUnit (BoundingBox u) = u
 
 instance (Num u, Ord u) => Scale (BoundingBox u) where
-  scale x y bb     = trace $ map (scale x y) $ corners bb
+  scale x y bb     = trace $ map (scale x y) $ [bl,br,tr,tl]
+    where (bl,br,tr,tl) = corners bb
 
 
 
@@ -153,9 +154,9 @@
 trace []     = error $ "BoundingBox.trace called in empty list"
 
 -- | 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]
-corners (BBox bl@(P2 x0 y0) tr@(P2 x1 y1)) = [bl, br, tr, tl] where
+-- wise from the bottom left, i.e. @(bl, br, tr, tl)@.
+corners :: BoundingBox a -> (Point2 a, Point2 a, Point2 a, Point2 a)
+corners (BBox bl@(P2 x0 y0) tr@(P2 x1 y1)) = (bl, br, tr, tl) where
     br = P2 x1 y0
     tl = P2 x0 y1
 
diff --git a/src/Wumpus/Core/Geometry.hs b/src/Wumpus/Core/Geometry.hs
--- a/src/Wumpus/Core/Geometry.hs
+++ b/src/Wumpus/Core/Geometry.hs
@@ -49,9 +49,12 @@
   , MatrixMult(..)
 
   -- * Vector operations
+  , direction
   , hvec
   , vvec
   , avec
+  , pvec
+  , vangle
 
   -- * Point operations
   , zeroPt
@@ -84,6 +87,7 @@
   , fromRadian
   , d2r
   , r2d
+  , circularModulo
 
   ) where
 
@@ -116,8 +120,11 @@
 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.
+--
 data Point2 a = P2 !a !a
-  deriving (Eq,Show)
+  deriving (Eq,Ord,Show)
 
 type DPoint2 = Point2 Double
 
@@ -397,6 +404,13 @@
 --------------------------------------------------------------------------------
 -- Vectors
 
+
+-- | Direction of a vector - i.e. the counter-clockwise angle 
+-- from the x-axis.
+--
+direction :: (Floating a, Real a) => Vec2 a -> 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 d = V2 d 0
@@ -413,6 +427,19 @@
   y   = d * sin ang
 
 
+-- | The vector between two points
+--
+-- > pvec = flip (.-.)
+--
+pvec :: Num a => Point2 a -> Point2 a -> Vec2 a
+pvec = flip (.-.)
+
+-- | Extract the angle between two vectors.
+--
+vangle :: (Floating a, Real a, InnerSpace (Vec2 a)) 
+       => Vec2 a -> Vec2 a -> Radian
+vangle u v = realToFrac $ acos $ (u <.> v) / (on (*) magnitude u v)
+
 --------------------------------------------------------------------------------
 -- Points
 
@@ -422,10 +449,25 @@
 
 -- | Calculate the counter-clockwise angle between two points 
 -- and the x-axis.
-langle :: (Floating u, Real u) => Point2 u -> Point2 u -> Radian
-langle (P2 x y) (P2 x' y') = toRadian $ atan $ (y'-y) / (x'-x) 
+langle :: (Floating a, Real a) => Point2 a -> Point2 a -> Radian
+langle (P2 x1 y1) (P2 x2 y2) = step (x2 - x1) (y2 - y1)
+  where
+    -- north-east quadrant 
+    step x y | pve x && pve y = toRadian $ atan (y/x)          
+    
+    -- north-west quadrant
+    step x y | pve y          = pi     - (toRadian $ atan (y / abs x))
 
+    -- south-east quadrant
+    step x y | pve x          = (2*pi) - (toRadian $ atan (abs y / x)) 
 
+    -- otherwise... south-west quadrant
+    step x y                  = pi     + (toRadian $ atan (y/x))
+
+    pve a = signum a >= 0
+
+
+
 --------------------------------------------------------------------------------
 -- Frame operations
 
@@ -649,4 +691,16 @@
 -- | Radians to degrees.
 r2d :: (Floating a, Real a) => Radian -> a
 r2d = (*) (180/pi) . fromRadian
+
+
+-- | Modulate a (positive) angle to be in the range 0..2*pi
+--
+circularModulo :: Radian -> Radian
+circularModulo r = d2r $ dec + (fromIntegral $ i `mod` 360)
+  where
+    i       :: Integer
+    dec     :: Double
+    (i,dec) = properFraction $ r2d r
+
+
 
diff --git a/src/Wumpus/Core/OutputPostScript.hs b/src/Wumpus/Core/OutputPostScript.hs
--- a/src/Wumpus/Core/OutputPostScript.hs
+++ b/src/Wumpus/Core/OutputPostScript.hs
@@ -330,7 +330,7 @@
 outputEncodedText = mapM_ outputTextChunk . getEncodedText
 
 outputTextChunk :: TextChunk -> WumpusM () 
-outputTextChunk (SText s)  = ps_show s
+outputTextChunk (SText s)  = ps_show $ escapeStringPS s
 
 outputTextChunk (EscInt i) = 
     ask >>= \env -> maybe (failk env) ps_glyphshow $ lookupByCharCode i env
diff --git a/src/Wumpus/Core/Picture.hs b/src/Wumpus/Core/Picture.hs
--- a/src/Wumpus/Core/Picture.hs
+++ b/src/Wumpus/Core/Picture.hs
@@ -96,6 +96,7 @@
 
 
 -- | Lift a 'Primitive' to a 'Picture', located in the standard frame.
+--
 frame :: (Fractional u, Ord u) => Primitive u -> Picture u
 frame p = Single (stdFrame, boundary p) p 
 
@@ -152,16 +153,19 @@
 path = Path 
 
 -- | Create a straight-line PathSegment.
+--
 lineTo :: Point2 u -> PathSegment u
 lineTo = PLine
 
 -- | Create a curved PathSegment.
+--
 curveTo :: Point2 u -> Point2 u -> Point2 u -> PathSegment u
 curveTo = PCurve
 
 
 -- | Convert the list of vertices to a path of straight line 
 -- segments.
+--
 vertexPath :: [Point2 u] -> Path u
 vertexPath []     = error "Picture.vertexPath - empty point list"
 vertexPath (x:xs) = Path x (map PLine xs)
@@ -172,6 +176,7 @@
 -- The first point in the list makes the start point, each curve 
 -- segment thereafter takes 3 points. /Spare/ points at the end 
 -- are discarded. 
+--
 curvedPath :: [Point2 u] -> Path u
 curvedPath []     = error "Picture.curvedPath - empty point list"
 curvedPath (x:xs) = Path x (fn xs) where
@@ -258,10 +263,12 @@
 
 
 -- | Create an open stoke coloured black.
+--
 zostroke :: (Num u, Ord u) => Path u -> Primitive u
 zostroke = ostrokePath psBlack []
  
 -- | Create a closed stroke coloured black.
+--
 zcstroke :: (Num u, Ord u) => Path u -> Primitive u
 zcstroke = cstrokePath psBlack []
 
@@ -297,6 +304,7 @@
 -- Clipping 
 
 -- | Clip a picture with respect to the supplied path.
+--
 clip :: (Num u, Ord u) => Path u -> Picture u -> Picture u
 clip cp p = Clip (ortho zeroPt, boundary cp) cp p
 
diff --git a/src/Wumpus/Core/PictureInternal.hs b/src/Wumpus/Core/PictureInternal.hs
--- a/src/Wumpus/Core/PictureInternal.hs
+++ b/src/Wumpus/Core/PictureInternal.hs
@@ -335,7 +335,9 @@
 -- For instance after a reflection in the y-axis br becomes bl.
 transformBBox :: (Num u, Ord u)
               => (Point2 u -> Point2 u) -> BoundingBox u -> BoundingBox u
-transformBBox fp = trace . map fp . corners
+transformBBox fp bb = trace $ map fp $ [bl,br,tl,tr]
+  where
+    (bl,br,tr,tl) = corners bb
 
 
 --------------------------------------------------------------------------------
diff --git a/src/Wumpus/Core/PictureLanguage.hs b/src/Wumpus/Core/PictureLanguage.hs
--- a/src/Wumpus/Core/PictureLanguage.hs
+++ b/src/Wumpus/Core/PictureLanguage.hs
@@ -53,6 +53,7 @@
   , above
   , below
   , at
+  , centeredAt
   , stackOnto
   , hcat 
   , vcat
@@ -266,8 +267,16 @@
 
 
 -- | Place the picture at the supplied point.
+-- 
 at :: (Move a, u ~ PUnit a) => a -> Point2 u  -> a
 p `at` (P2 x y) = move x y p
+
+-- | Center the picture at the supplied point.
+--
+centeredAt :: (Horizontal a, Vertical a, Move a, Composite a, Blank a, 
+               Fractional u, u ~ PUnit a) 
+           => a -> Point2 u -> a
+centeredAt p pt = p -@- (blank 0 0 `at` pt) 
 
 
 
diff --git a/src/Wumpus/Core/PostScript.hs b/src/Wumpus/Core/PostScript.hs
--- a/src/Wumpus/Core/PostScript.hs
+++ b/src/Wumpus/Core/PostScript.hs
@@ -31,6 +31,9 @@
 
   , runWumpus
 
+  -- * Escape sepcial characters
+  , escapeStringPS
+
   -- * Deltas 
   , deltaFontAttr
   , deltaRgbColour
@@ -205,6 +208,22 @@
 -- | Drop state and result, take the Writer trace.
 runWumpus :: TextEncoder -> WumpusM a -> String
 runWumpus = (toListH . snd) `oo` pstId
+
+--------------------------------------------------------------------------------
+-- Escape special chars
+
+-- | Escape these characters:
+--
+-- > \\ - (, ), <, >, [, ], {, }, /, and %
+--
+escapeStringPS :: String -> String
+escapeStringPS = foldr f "" where
+  f c ss | c `elem` ps_special = '\\' : c : ss
+         | otherwise           = c : ss
+
+ps_special :: [Char]
+ps_special = "\\()<>[]{}/%"
+
 
 --------------------------------------------------------------------------------
 -- "Deltas" of the graphics state
diff --git a/src/Wumpus/Core/VersionNumber.hs b/src/Wumpus/Core/VersionNumber.hs
--- a/src/Wumpus/Core/VersionNumber.hs
+++ b/src/Wumpus/Core/VersionNumber.hs
@@ -22,4 +22,4 @@
 
 
 wumpus_core_version :: (Int,Int,Int)
-wumpus_core_version = (0,15,0)
+wumpus_core_version = (0,16,0)
diff --git a/wumpus-core.cabal b/wumpus-core.cabal
--- a/wumpus-core.cabal
+++ b/wumpus-core.cabal
@@ -1,5 +1,5 @@
 name:             wumpus-core
-version:          0.15.0
+version:          0.16.0
 license:          BSD3
 license-file:     LICENSE
 copyright:        Stephen Tetley <stephen.tetley@gmail.com>
@@ -8,6 +8,7 @@
 category:         Graphics
 synopsis:         Pure Haskell PostScript and SVG generation. 
 description:
+  .
   Wumpus - (W)riter (M)onad (P)ost (S)cript. 
   .
   Wumpus is a library for generating 2D vector pictures, its 
@@ -62,6 +63,26 @@
   convert Wumpus'\s EPS files to many other formats (bitmaps). 
   .
   Changelog:
+  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
   .
   0.14.0 to 0.15.0:
   .
