wumpus-core 0.36.0 → 0.37.0
raw patch · 17 files changed
+528/−311 lines, 17 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Wumpus.Core.BoundingBox: bbox :: Ord u => Point2 u -> Point2 u -> BoundingBox u
- Wumpus.Core.BoundingBox: obbox :: Num u => u -> u -> BoundingBox u
- Wumpus.Core.Picture: xlinkGroup :: XLink -> [Primitive u] -> Primitive u
+ Wumpus.Core.BoundingBox: boundingBox :: Ord u => Point2 u -> Point2 u -> BoundingBox u
+ Wumpus.Core.BoundingBox: oboundingBox :: (Num u, Ord u) => u -> u -> BoundingBox u
+ Wumpus.Core.OutputSVG: instance Eq FontMatch
+ Wumpus.Core.OutputSVG: instance Ord FontMatch
+ Wumpus.Core.OutputSVG: instance Show FontMatch
+ Wumpus.Core.Picture: primCat :: Primitive u -> Primitive u -> Primitive u
+ Wumpus.Core.Picture: xlink :: XLink -> Primitive u -> Primitive u
+ Wumpus.Core.PtSize: instance Real PtSize
+ Wumpus.Core.PtSize: instance RealFloat PtSize
+ Wumpus.Core.PtSize: instance RealFrac PtSize
- Wumpus.Core.AffineTrans: translate :: Translate t => DUnit t -> DUnit t -> t -> t
+ Wumpus.Core.AffineTrans: translate :: (Translate t, u ~ (DUnit t)) => u -> u -> t -> t
- Wumpus.Core.Picture: fontDeltaContext :: FontAttr -> Picture u -> Picture u
+ Wumpus.Core.Picture: fontDeltaContext :: FontAttr -> Primitive u -> Primitive u
- Wumpus.Core.Picture: rtextlabel :: Num u => RGBi -> FontAttr -> String -> Radian -> Point2 u -> Primitive u
+ Wumpus.Core.Picture: rtextlabel :: Num u => RGBi -> FontAttr -> String -> Point2 u -> Radian -> Primitive u
Files
- CHANGES +76/−0
- demo/DeltaPic.hs +5/−2
- doc-src/Guide.lhs +12/−8
- doc/Guide.pdf binary
- src/Wumpus/Core/AffineTrans.hs +1/−1
- src/Wumpus/Core/BoundingBox.hs +18/−11
- src/Wumpus/Core/FontSize.hs +1/−1
- src/Wumpus/Core/OutputPostScript.hs +7/−5
- src/Wumpus/Core/OutputSVG.hs +36/−26
- src/Wumpus/Core/PageTranslation.hs +3/−2
- src/Wumpus/Core/Picture.hs +44/−22
- src/Wumpus/Core/PictureInternal.hs +50/−32
- src/Wumpus/Core/PtSize.hs +1/−1
- src/Wumpus/Core/Utils/JoinList.hs +240/−0
- src/Wumpus/Core/Utils/OneList.hs +0/−133
- src/Wumpus/Core/VersionNumber.hs +2/−2
- wumpus-core.cabal +32/−65
CHANGES view
@@ -1,4 +1,80 @@ ++0.36.0 to 0.37.0:++ * The bounding box constructors have been renamed - @bbox@ is + now @boundingBox@ and @obbox@ becomes @oboundingBox@. The + rationale for this change is that the names very cryptic in + the first place and the constructors are used infrequently + when @bbox@ in particular makes a descriptive variable name.++ * Changes to the Picture and Primitive types to enable better+ concatenation which is used heavily by Wumpus-Basic. The + Picture API exposes a new function @primCat@.++ * SVG /font delta context/ change - font deltas are now + annotated on Primitives not Pictures. The type of the + function @fontDeltaContext@ in @Core.Picture@ has changed + accordingly.++ * SVG hyperlink change - hyperlinks no longer group primitives+ (although a group of primitives can be hyperlinked). The + function @xlinkGroup@ has been removed from @Core.Picture@, + it is replaced by @xlink@.++ * @Core.Picture@ - the argument order for the function + @rtextlabel@ has been changed, the positions of the angle and + bottom-left corner have been swapped.++0.35.0 to 0.36.0:++ * API / behaviour change - rotation on primitives changed. New + functions have been added to create rotated text labels and + ellipses (@rtextlabel@, @rstrokeEllipse@, etc.), and + Primitives have been made instances of the Affine classes+ except for the general matrix Transform class. The old+ functions for transforming Primitives (@rotatePrim@, + @scalePrim@, etc.) have been removed. The demos (Rotated.hs,+ Scaled.hs, Translated.hs) have been removed as they pertain + to the old behaviour, there are new demos highlighting the+ new behaviour (TransformEllipse.hs, etc.).++ * Major change - removed the PrimElement type. The (opaque) + Primitive type has been changed to incorporate a grouping + constructor equivalent to PrimElement\'s @XLinkGroup@ + contructor. The change has made the implementation of SVG + hyperlinks more efficient, but has forced various type + signatures to change in @Core.Picture@. Client code will + also have to change type signatures - @PrimElement@ becomes+ @Primitive@.++ * @Core.PtSize@ - the class @FromPtSize@ has been given a @Num@+ superclass constraint. This can shorten type signatures of + functions that use @fromPtSize@.++ * Corrected a bug where textlabels would generate an invalid+ bounding box and cause a runtime error when supplied with an+ empty string. Now there is no runtime error - and /no-ops/ + are generated in the output.++ * Internal changes - moved @PrimCTM@ from @Core.PictureInternal@+ into separate module. Moved /utility/ modules into their own + directory @Utils@. Move /text/ modules into their own + directory @Text@. ++ * Removed dependency on @algebra@ for @Semigroup@. The + equivalent @append@ operation on @BoundingBox@ is + @boundaryUnion@.++ * Renamed the @Core.GraphicsState@ to @Core.GraphicProps@. + Moved the property datatypes from @Core.PictureInternal@ into + @Core.GraphicProps@ (StrokeProps, LabelProps, etc.).++ * Moved @wumpus_default_font@ from @Core.Picture@ into + @Core.Graphic.Props@.++ * Haddock docs improved.+ 0.34.0 to 0.35.0: * Bug fix - PostScript output - when more than one stroke
demo/DeltaPic.hs view
@@ -1,6 +1,9 @@ {-# LANGUAGE TypeFamilies #-} {-# OPTIONS -Wall #-} +-- SVG ouptut has some ability to minimization font change code.+-- This example demonstrates it.+ module DeltaPic where import Wumpus.Core@@ -25,14 +28,14 @@ pic1 :: DPicture-pic1 = fontDeltaContext delta_ctx $ frame +pic1 = frame1 $ fontDeltaContext delta_ctx $ primGroup [ helveticaLabel 18 "Optimized - size and face" (P2 0 60) , helveticaLabel 14 "Optimized - face only" (P2 0 40) , courierLabel "No optimization" (P2 0 20) ] where delta_ctx = FontAttr 18 common_ff- + frame1 a = frame [a] common_ff :: FontFace common_ff = FontFace "Helvetica" "Helvetica" SVG_REGULAR latin1_font_encoder
doc-src/Guide.lhs view
@@ -23,7 +23,7 @@ \section{About \wumpuscore} %----------------------------------------------------------------- -This guide was last updated for \wumpuscore version 0.36.0. +This guide was last updated for \wumpuscore version 0.37.0. \wumpuscore is a Haskell library for generating 2D vector pictures. It was written with portability as a priority, so it has @@ -124,14 +124,15 @@ type to represent them. \item[\texttt{Wumpus.Core.TextEncoder.}] -Types for handling extended character codes e.g. for accented -characters or the Symbol font. Special characters generally have -to be escaped in the PostScript and SVG output, this module -provides data types for lookup tables between the escaped -character code and its PostScript or SVG representation. +Types for handling extended character codes within fonts e.g. +for accented characters or the Symbol font. Special characters +generally have to be escaped in the PostScript and SVG output, +this module provides data types for lookup tables between the +escaped character code and its PostScript or SVG representation. Text encoders are associated with fonts - glyphs within a font are located by their character name / code. Currently -\wumpuscore has encoders for Latin1 and the Symbol font. +\wumpuscore has encoders for the Standard Latin Encoding table +and the Symbol font character set. \item[\texttt{Wumpus.Core.TextLatin1.}] A instance of the TextEncoder type for mapping Latin 1 characters @@ -315,6 +316,9 @@ \texttt{Wumpus.Basic.SafeFonts} encoding the fonts in this list and matching them to their appropriate \texttt{TextEncoder}. +Note that the Symbol font, whilst incredibly useful, is a taboo +with the W3C and they do not condone its use in SVG or HTML. +Likewise, certain browsers reject it out of course. \begin{tabular}{ l l } PostScript name & SVG name \\ @@ -331,7 +335,7 @@ Courier-Oblique & Courier New - style="italic" \\ Courier-Bold & Courier New - font-weight="bold" \\ Courier-Bold-Oblique & Courier New - style="italic", font-weight="bold" \\ -Symbol & Symbol \\ +Symbol & (Symbol - see text) \\ \hline \end{tabular}
doc/Guide.pdf view
binary file changed (59778 → 60184 bytes)
src/Wumpus/Core/AffineTrans.hs view
@@ -150,7 +150,7 @@ -- | Type class for translation. -- class Translate t where- translate :: DUnit t -> DUnit t -> t -> t+ translate :: u ~ DUnit t => u -> u -> t -> t instance Num u => Translate (Point2 u) where translate dx dy (P2 x y) = P2 (x+dx) (y+dy)
src/Wumpus/Core/BoundingBox.hs view
@@ -31,9 +31,11 @@ -- * Type class , Boundary(..) + -- * Constructors+ , boundingBox+ , oboundingBox+ -- * Operations- , bbox- , obbox , destBoundingBox , boundaryUnion , traceBoundary@@ -124,27 +126,32 @@ -------------------------------------------------------------------------------- --- | 'bbox' : @lower_left_corner * upper_right_corner -> BoundingBox@+-- | 'boundingBox' : @lower_left_corner * upper_right_corner -> BoundingBox@ -- -- Contruct a bounding box, vis the BBox constructor with range -- checking on the corner points. ----- @bbox@ throws an error if the width or height of the +-- 'boundingBox' throws an error if the width or height of the -- constructed bounding box is negative. ---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."+boundingBox :: Ord u => Point2 u -> Point2 u -> BoundingBox u+boundingBox ll@(P2 x0 y0) ur@(P2 x1 y1) + | x0 <= x1 && y0 <= y1 = BBox ll ur + | otherwise = error "Wumpus.Core.boundingBox - malformed." --- | 'obbox' : @width * height -> BoundingBox@+-- | 'oboundingBbox' : @width * height -> BoundingBox@ -- -- Create a BoundingBox with bottom left corner at the origin, -- and dimensions @w@ and @h@. ---obbox :: Num u => u -> u -> BoundingBox u-obbox w h = BBox zeroPt (P2 w h)+-- 'oboundingBox' throws an error if either the suppplied width +-- or height is negative.+-- +oboundingBox :: (Num u, Ord u) => u -> u -> BoundingBox u+oboundingBox w h + | h >= 0 && w >= 0 = BBox zeroPt (P2 w h)+ | otherwise = error "Wumpus.Core.oboundingBox - malformed." -- | 'destBoundingBox' : @ bbox -> (lower_left_x, lower_lefy_y, -- upper_right_x, upper_right_y)@
src/Wumpus/Core/FontSize.hs view
@@ -247,7 +247,7 @@ textBoundsBody :: (Num u, Ord u, FromPtSize u) => FontSize -> Point2 u -> Int -> BoundingBox u-textBoundsBody sz baseline_left len = bbox bl tr +textBoundsBody sz baseline_left len = boundingBox bl tr where h = fromPtSize $ textHeight sz w = fromPtSize $ textWidth sz len
src/Wumpus/Core/OutputPostScript.hs view
@@ -38,7 +38,7 @@ import Wumpus.Core.Text.TextInternal import Wumpus.Core.TrafoInternal import Wumpus.Core.Utils.Common-import Wumpus.Core.Utils.OneList+import Wumpus.Core.Utils.JoinList import Wumpus.Core.Utils.FormatCombinators @@ -279,14 +279,13 @@ picture :: (Real u, Floating u, PSUnit u) => Picture u -> PsMonad Doc picture (Leaf (_,xs) ones) = bracketTrafos xs $ oneConcat primitive ones picture (Picture (_,xs) ones) = bracketTrafos xs $ oneConcat picture ones-picture (Group (_,xs) _ pic) = bracketTrafos xs (picture pic) picture (Clip (_,xs) cp pic) = bracketTrafos xs $ (\d1 d2 -> vcat [ps_gsave,d1,d2,ps_grestore]) <$> clipPath cp <*> picture pic <* resetGS -oneConcat :: (a -> PsMonad Doc) -> OneList a -> PsMonad Doc+oneConcat :: (a -> PsMonad Doc) -> JoinList a -> PsMonad Doc oneConcat fn ones = outstep (viewl ones) where outstep (e :< rest) = fn e >>= \a -> instep a (viewl rest)@@ -296,14 +295,17 @@ instep ac (e :< rest) = fn e >>= \a -> instep (ac `vconcat` a) (viewl rest) --- No action is taken for hyperlinks in PostScript.+-- No action is taken for hyperlinks or font context changes in +-- PostScript. -- primitive :: (Real u, Floating u, PSUnit u) => Primitive u -> PsMonad Doc primitive (PPath props pp) = primPath props pp primitive (PLabel props lbl) = primLabel props lbl primitive (PEllipse props ell) = primEllipse props ell-primitive (PGroup _ ones) = oneConcat primitive ones+primitive (PContext _ chi) = primitive chi+primitive (PLink _ chi) = primitive chi+primitive (PGroup ones) = oneConcat primitive ones primPath :: PSUnit u
src/Wumpus/Core/OutputSVG.hs view
@@ -49,7 +49,7 @@ import Wumpus.Core.TrafoInternal import Wumpus.Core.Utils.Common import Wumpus.Core.Utils.FormatCombinators-import Wumpus.Core.Utils.OneList+import Wumpus.Core.Utils.JoinList import Control.Applicative hiding ( empty, some ) import Data.Maybe@@ -106,7 +106,7 @@ askGraphicsState = SvgMonad $ \_ r2 s -> (r2,s) asksGraphicsState :: (GraphicsState -> a) -> SvgMonad a-asksGraphicsState fn = SvgMonad $ \_ r2 s -> (fn r2,s)+asksGraphicsState fn = fmap fn askGraphicsState askFontAttr :: SvgMonad FontAttr askFontAttr = asksGraphicsState $ \r -> @@ -189,12 +189,11 @@ ; d2 <- picture pic ; return (vconcat d1 (elem_g (attr_clip_path lbl) d2)) } -picture (Group (_,xs) fn pic) = bracketTrafos xs $ bracketGS fn (picture pic) -oneConcat :: (a -> SvgMonad Doc) -> OneList a -> SvgMonad Doc+oneConcat :: (a -> SvgMonad Doc) -> JoinList a -> SvgMonad Doc oneConcat fn ones = outstep (viewl ones) where outstep (e :< rest) = fn e >>= \a -> instep a (viewl rest)@@ -205,13 +204,12 @@ primitive :: (Real u, Floating u, PSUnit u) => Primitive u -> SvgMonad Doc-primitive (PPath props pp) = primPath props pp-primitive (PLabel props lbl) = primLabel props lbl-primitive (PEllipse props ell) = primEllipse props ell-primitive (PGroup mb ones) = - case mb of- Nothing -> oneConcat primitive ones- Just xl -> drawXLink xl <$> oneConcat primitive ones+primitive (PPath props pp) = primPath props pp+primitive (PLabel props lbl) = primLabel props lbl+primitive (PEllipse props ell) = primEllipse props ell+primitive (PContext fa chi) = bracketGS fa (primitive chi)+primitive (PLink hypl chi) = drawXLink hypl <$> primitive chi+primitive (PGroup ones) = oneConcat primitive ones drawXLink :: XLink -> Doc -> Doc@@ -405,11 +403,27 @@ attr_stroke_dashoffset n <+> attr_stroke_dasharray xs +data FontMatch = FullMatch | DeltaPtSize | DeltaFont+ deriving (Eq,Show,Ord) + deltaFontAttrs :: FontAttr -> SvgMonad Doc-deltaFontAttrs fa = - (\inh -> if fa == inh then empty else makeFontAttrs fa) <$> askFontAttr+deltaFontAttrs fa = (\inh -> step $ fontMatch inh fa) <$> askFontAttr+ where+ step FullMatch = empty+ step DeltaPtSize = attr_font_size $ font_size fa+ step DeltaFont = makeFontAttrs fa ++fontMatch :: FontAttr -> FontAttr -> FontMatch+fontMatch (FontAttr s1 f1) (FontAttr s2 f2) + | s1 == s2 && f1 == f2 = FullMatch+ | f1 == f2 = DeltaPtSize+ | otherwise = DeltaFont++-- Note this is always adding FontSize - there are cases where +-- this is redundant. +-- makeFontAttrs :: FontAttr -> Doc makeFontAttrs (FontAttr sz face) = attr_font_family (svg_font_family face) <+> attr_font_size sz @@ -430,27 +444,23 @@ space <> attr_font_weight "bold" <+> attr_font_style "oblique" --- NOTE - as is only practical to delta the FontFace attributes --- it might be good to specialize / simplify the graphics state--- GSUpdate to a simpler type rather than a functional one... +-- Always update both the size and font-family even if only one+-- changes.+--+-- This seems more in the spirit of a font delta operation.+-- bracketGS :: FontCtx -> SvgMonad Doc -> SvgMonad Doc bracketGS (FontCtx new_font) mf = - (\old body -> mkElem old body) - <$> askGraphicsState <*> runLocalGS updateF mf+ (\old body -> mkElem (old == new_font) body) + <$> askFontAttr <*> runLocalGS updateF mf where- mkElem old body - | fontMatch old new_font = elem_g_no_attrs body- | otherwise = let a = makeFontAttrs new_font- in elem_g a body+ mkElem True body = elem_g_no_attrs body+ mkElem _ body = let a = makeFontAttrs new_font in elem_g a body updateF s = s { gs_font_size = font_size new_font , gs_font_face = font_face new_font } --fontMatch :: GraphicsState -> FontAttr -> Bool-fontMatch gs fa = - gs_font_size gs == font_size fa && gs_font_face gs == font_face fa --------------------------------------------------------------------------------
src/Wumpus/Core/PageTranslation.hs view
@@ -47,13 +47,14 @@ trivPic (Leaf lc ones) = Leaf lc $ fmap trivPrim ones trivPic (Picture lc ones) = Picture lc $ fmap trivPic ones trivPic (Clip lc pp pic) = Clip lc pp $ trivPic pic-trivPic (Group lc upd pic) = Group lc upd $ trivPic pic trivPrim :: Num u => Primitive u -> Primitive u trivPrim (PPath a pp) = PPath a pp trivPrim (PLabel a lbl) = PLabel a (trivLabel lbl) trivPrim (PEllipse a ell) = PEllipse a (trivEllipse ell)-trivPrim (PGroup xl ones) = PGroup xl $ fmap trivPrim ones+trivPrim (PContext a chi) = PContext a (trivPrim chi)+trivPrim (PLink a chi) = PLink a (trivPrim chi)+trivPrim (PGroup ones) = PGroup $ fmap trivPrim ones trivLabel :: Num u => PrimLabel u -> PrimLabel u
src/Wumpus/Core/Picture.hs view
@@ -30,9 +30,11 @@ , vertexPath , curvedPath , xlinkhref- , xlinkGroup+ , xlink , primGroup+ , primCat + -- * Constructing primitives , ostroke , cstroke@@ -90,7 +92,7 @@ import Wumpus.Core.TrafoInternal import Wumpus.Core.Utils.Common import Wumpus.Core.Utils.FormatCombinators hiding ( fill )-import Wumpus.Core.Utils.OneList+import Wumpus.Core.Utils.JoinList import Data.AffineSpace -- package: vector-space @@ -160,8 +162,8 @@ -- introducing nesting with @gsave@ and @grestore@ is not likely -- to improve the PostScript Wumpus generates. ---fontDeltaContext :: FontAttr -> Picture u -> Picture u-fontDeltaContext fa p = Group (boundary p, []) (FontCtx fa) p+fontDeltaContext :: FontAttr -> Primitive u -> Primitive u+fontDeltaContext fa p = PContext (FontCtx fa) p -- | Create a Path from a start point and a list of PathSegments.@@ -216,17 +218,10 @@ xlinkhref = XLink --- | Create a hyperlinked group of Primitives.+-- | Create a hyperlinked Primitive. ----- This function throws a runtime error when supplied with an--- empty list.--- -xlinkGroup :: XLink -> [Primitive u] -> Primitive u-xlinkGroup _ [] = error "Picture.xlinkGroup - empty prims list"-xlinkGroup xlink (x:xs) = PGroup (Just xlink) (step x xs)- where- step a [] = one a- step a (y:ys) = cons a (step y ys) +xlink :: XLink -> Primitive u -> Primitive u+xlink hypl p = PLink hypl p -- | Group a list of Primitives.@@ -236,11 +231,34 @@ -- primGroup :: [Primitive u] -> Primitive u primGroup [] = error "Picture.primGroup - empty prims list"-primGroup (x:xs) = PGroup Nothing (step x xs)+primGroup (x:xs) = PGroup (step x xs) where step a [] = one a step a (y:ys) = cons a (step y ys) ++-- | Concatenate two Primitives.+--+-- If both primitves are groups, then the groups are merged.+--+-- If one or other primitive is a group, the singleton is added+-- into the group at the respective end.+--+-- Otherwise a group is formed adding both elements as /children/.+--+-- The Primitive type in Wumpus is a tree. In theory 'primCat' +-- can make flatter and wider trees than 'primGroup', though in +-- practice this may have no noticeable benefit as Wumpus has very +-- simple access patterns into the Primitive tree. +--+primCat :: Primitive u -> Primitive u -> Primitive u+primCat (PGroup a) (PGroup b) = PGroup $ join a b+primCat (PGroup a) prim = PGroup $ join a (one prim) +primCat prim (PGroup b) = PGroup $ join (one prim) b+primCat p1 p2 = PGroup $ join (one p1) (one p2) +++ -------------------------------------------------------------------------------- -- Take Paths to Primitives @@ -339,10 +357,10 @@ -- textlabel :: Num u => RGBi -> FontAttr -> String -> Point2 u -> Primitive u-textlabel rgb attr txt pt = rtextlabel rgb attr txt 0 pt+textlabel rgb attr txt pt = rtextlabel rgb attr txt pt 0 --- | 'rtextlabel' : @ rgb * font_attr * string * rotation * --- baseline_left -> Primitive @+-- | 'rtextlabel' : @ rgb * font_attr * string * baseline_left * +-- rotation -> Primitive @ -- -- Create a text label rotated by the supplied angle about the -- baseline-left. @@ -350,8 +368,8 @@ -- The supplied point is the left baseline. -- rtextlabel :: Num u - => RGBi -> FontAttr -> String -> Radian -> Point2 u -> Primitive u-rtextlabel rgb attr txt theta pt = PLabel (LabelProps rgb attr) lbl + => RGBi -> FontAttr -> String -> Point2 u -> Radian -> Primitive u+rtextlabel rgb attr txt pt theta = PLabel (LabelProps rgb attr) lbl where lbl = PrimLabel pt (StdLayout $ lexLabel txt) (thetaCTM theta) @@ -394,6 +412,8 @@ -- renderers. Chrome support is fine, but Firefox and Safari -- currently seem lacking. --+-- Also, currently the generated PostScript is inefficient.+-- hkernlabel :: Num u => RGBi -> FontAttr -> [KerningChar u] -> Point2 u -> Primitive u@@ -432,6 +452,8 @@ -- renderers. Chrome support is fine, but Firefox and Safari -- currently seem lacking. --+-- Also, currently the generated PostScript is inefficient.+-- vkernlabel :: Num u => RGBi -> FontAttr -> [KerningChar u] -> Point2 u -> Primitive u@@ -595,11 +617,11 @@ -- neither picture will be moved. -- picOver :: (Num u, Ord u) => Picture u -> Picture u -> Picture u-a `picOver` b = Picture (bb,[]) (cons b $ one a) +a `picOver` b = Picture (bb,[]) (join (one b) (one a)) where bb = boundary a `boundaryUnion` boundary b --- picOver note - draw b, put b first in the list, so it draws +-- NOTE - picOver - draw b, put b first in the list, so it draws -- first in the output (this is also @behind@ in the Z-Order).
src/Wumpus/Core/PictureInternal.hs view
@@ -66,7 +66,7 @@ import Wumpus.Core.TrafoInternal import Wumpus.Core.Utils.Common import Wumpus.Core.Utils.FormatCombinators-import Wumpus.Core.Utils.OneList+import Wumpus.Core.Utils.JoinList import Data.AffineSpace -- package: vector-space@@ -110,25 +110,15 @@ -- updates for the SVG renderer - in some instances this can -- improve the code size of the generated SVG. ---data Picture u = Leaf (Locale u) (OneList (Primitive u))- | Picture (Locale u) (OneList (Picture u))+data Picture u = Leaf (Locale u) (JoinList (Primitive u))+ | Picture (Locale u) (JoinList (Picture u)) | Clip (Locale u) (PrimPath u) (Picture u)- | Group (Locale u) FontCtx (Picture u) deriving (Show) type DPicture = Picture Double --- | Set the font /delta/ for SVG rendering. --- --- Note - this does not change the default colour or font style. --- It is solely a backdoor into the SVG renderer to potential --- allow some code size reductions.----newtype FontCtx = FontCtx { getFontCtx :: FontAttr }- deriving (Eq,Show) - -- | Locale = (bounding box * current translation matrix) -- -- Pictures (and sub-pictures) are located frame consisting of a @@ -173,18 +163,36 @@ -- Though typically for affine transformations a Fractional -- constraint is also obliged. ----- To represent XLink hyperlinks, Primitives can be grouped --- together at the same type (so Primitives aren\'t strictly)--- /primitive/ as the actual implementation is a tree.+-- To represent XLink hyperlinks, Primitives can be annotated +-- with some a hyperlink (similarly a a font change for better+-- SVG code generation) and grouped - a hyperlinked arrow would+-- want the tip and the arrow body both to be incorporated in the+-- link even though they are two drawings. +--+-- This means that Primitives aren\'t strictly /primitive/ as +-- the actual implementation is a tree. -- data Primitive u = PPath PathProps (PrimPath u) | PLabel LabelProps (PrimLabel u) | PEllipse EllipseProps (PrimEllipse u)- | PGroup (Maybe XLink) (OneList (Primitive u))+ | PContext FontCtx (Primitive u)+ | PLink XLink (Primitive u)+ | PGroup (JoinList (Primitive u)) deriving (Eq,Show) + type DPrimitive = Primitive Double ++-- | Set the font /delta/ for SVG rendering. +-- +-- Note - this does not change the default colour or font style. +-- It is solely a backdoor into the SVG renderer to potential +-- allow some code size reductions.+--+newtype FontCtx = FontCtx { getFontCtx :: FontAttr }+ deriving (Eq,Show)+ -- | Primitives can be grouped with hyperlinks in SVG output. -- newtype XLink = XLink { getXLink :: String }@@ -305,12 +313,8 @@ , format path , format pic ] - format (Group m _ pic) = indent 2 $ vcat [ text "** Group **"- , fmtLocale m- , format pic ] --fmtPics :: PSUnit u => OneList (Picture u) -> Doc+fmtPics :: PSUnit u => JoinList (Picture u) -> Doc fmtPics ones = snd $ F.foldl' fn (0,empty) ones where fn (n,acc) e = (n+1, vcat [ acc, text "-- " <+> int n, format e, line])@@ -330,11 +334,17 @@ format (PEllipse props e) = indent 2 $ vcat [ text "ellipse:" <+> format props, format e ] - format (PGroup xl ones) = - vcat [ text "-- group " <+> (maybe empty format xl), fmtPrimlist ones ]+ format (PContext _ a) = + vcat [ text "-- svg ctx change " , format a ] + format (PLink _ a) = + vcat [ text "-- svg link " , format a ] -fmtPrimlist :: PSUnit u => OneList (Primitive u) -> Doc+ format (PGroup ones) = + vcat [ text "-- group ", fmtPrimlist ones ]+++fmtPrimlist :: PSUnit u => JoinList (Primitive u) -> Doc fmtPrimlist ones = snd $ F.foldl' fn (0,empty) ones where fn (n,acc) e = (n+1, vcat [ acc, text "-- leaf" <+> int n, format e, line])@@ -381,14 +391,15 @@ boundary (Leaf (bb,_) _) = bb boundary (Picture (bb,_) _) = bb boundary (Clip (bb,_) _ _) = bb- boundary (Group (bb,_) _ _) = bb instance (Real u, Floating u, FromPtSize u) => Boundary (Primitive u) where boundary (PPath _ p) = pathBoundary p boundary (PLabel a l) = labelBoundary (label_font a) l boundary (PEllipse _ e) = ellipseBoundary e- boundary (PGroup _ ones) = outer $ viewl ones + boundary (PContext _ a) = boundary a+ boundary (PLink _ a) = boundary a+ boundary (PGroup ones) = outer $ viewl ones where outer (OneL a) = boundary a outer (a :< as) = inner (boundary a) (viewl as)@@ -526,7 +537,6 @@ mapLocale f (Leaf lc ones) = Leaf (f lc) ones mapLocale f (Picture lc ones) = Picture (f lc) ones mapLocale f (Clip lc pp pic) = Clip (f lc) pp pic-mapLocale f (Group lc upd pic) = Group (f lc) upd pic --------------------------------------------------------------------------------@@ -542,28 +552,36 @@ rotate r (PPath a path) = PPath a $ rotatePath r path rotate r (PLabel a lbl) = PLabel a $ rotateLabel r lbl rotate r (PEllipse a ell) = PEllipse a $ rotateEllipse r ell- rotate r (PGroup xln xs) = PGroup xln $ fmap (rotate r) xs+ rotate r (PContext a chi) = PContext a $ rotate r chi + rotate r (PLink a chi) = PLink a $ rotate r chi + rotate r (PGroup xs) = PGroup $ fmap (rotate r) xs instance (Real u, Floating u) => RotateAbout (Primitive u) where rotateAbout r pt (PPath a path) = PPath a $ rotateAboutPath r pt path rotateAbout r pt (PLabel a lbl) = PLabel a $ rotateAboutLabel r pt lbl rotateAbout r pt (PEllipse a ell) = PEllipse a $ rotateAboutEllipse r pt ell- rotateAbout r pt (PGroup xln xs) = PGroup xln $ fmap (rotateAbout r pt) xs+ rotateAbout r pt (PContext a chi) = PContext a $ rotateAbout r pt chi+ rotateAbout r pt (PLink a chi) = PLink a $ rotateAbout r pt chi+ rotateAbout r pt (PGroup xs) = PGroup $ fmap (rotateAbout r pt) xs instance Num u => Scale (Primitive u) where scale sx sy (PPath a path) = PPath a $ scalePath sx sy path scale sx sy (PLabel a lbl) = PLabel a $ scaleLabel sx sy lbl scale sx sy (PEllipse a ell) = PEllipse a $ scaleEllipse sx sy ell- scale sx sy (PGroup xln xs) = PGroup xln $ fmap (scale sx sy) xs+ scale sx sy (PContext a chi) = PContext a $ scale sx sy chi+ scale sx sy (PLink a chi) = PLink a $ scale sx sy chi+ scale sx sy (PGroup xs) = PGroup $ fmap (scale sx sy) xs instance Num u => Translate (Primitive u) where translate dx dy (PPath a path) = PPath a $ translatePath dx dy path translate dx dy (PLabel a lbl) = PLabel a $ translateLabel dx dy lbl translate dx dy (PEllipse a ell) = PEllipse a $ translateEllipse dx dy ell- translate dx dy (PGroup xln xs) = PGroup xln $ fmap (translate dx dy) xs+ translate dx dy (PContext a chi) = PContext a $ translate dx dy chi+ translate dx dy (PLink a chi) = PLink a $ translate dx dy chi+ translate dx dy (PGroup xs) = PGroup $ fmap (translate dx dy) xs --------------------------------------------------------------------------------
src/Wumpus/Core/PtSize.hs view
@@ -38,7 +38,7 @@ -- etc. -- newtype PtSize = PtSize { ptSize :: Double } - deriving (Eq,Ord,Num,Floating,Fractional)+ deriving (Eq,Ord,Num,Floating,Fractional,Real,RealFrac,RealFloat) instance Show PtSize where showsPrec p d = showsPrec p (ptSize d)
+ src/Wumpus/Core/Utils/JoinList.hs view
@@ -0,0 +1,240 @@+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module : Wumpus.Core.Utils.JoinList+-- Copyright : (c) Stephen Tetley 2010+-- License : BSD3+--+-- A \"join list\" datatype and operations. +--+-- A join list is implemented a binary tree, so joining two +-- lists (catenation, aka (++)) is a cheap operation. +--+-- This constrasts with the regular list datatype which is a +-- cons list: while consing on a regular list is by nature cheap, +-- joining (++) is expensive. +--+-- This version has no Empty constructor, so empty join lists +-- cannot be built.+--+--------------------------------------------------------------------------------+++module Wumpus.Core.Utils.JoinList + ( + -- * Join list datatype, opaque.+ JoinList++ -- * Left view as per Data.Sequence + , ViewL(..)++ -- * Conversion between join lists and regular lists+ , fromList+ , toList+ , toListF++ -- * Construction+ , one+ , cons+ , snoc+ , join++ -- * Basic functions + , head++ , accumMapL+ , isOne+ , isMany++ -- * Left view+ , viewl+++ + ) where+++import Control.Applicative hiding ( empty )++import Data.Foldable ( Foldable )+import qualified Data.Foldable as F+import Data.Monoid ( mappend )+import Data.Traversable ( Traversable(..) )++import Prelude hiding ( head )++data JoinList a = One a + | Join (JoinList a) (JoinList a)+ deriving (Eq)++data ViewL a = OneL a | a :< (JoinList a)+ deriving (Eq,Show)+++--------------------------------------------------------------------------------++instance Show a => Show (JoinList a) where+ showsPrec _ xs = showString "fromList " . shows (toList xs) +++instance Functor JoinList where+ fmap f (One a) = One (f a)+ fmap f (Join t u) = Join (fmap f t) (fmap f u)++++instance Foldable JoinList where+ foldMap f (One a) = f a+ foldMap f (Join t u) = F.foldMap f t `mappend` F.foldMap f u++ foldr = joinfoldr+ foldl = joinfoldl++instance Traversable JoinList where+ traverse f (One a) = One <$> f a+ traverse f (Join t u) = Join <$> traverse f t <*> traverse f u++-- Views++instance Functor ViewL where+ fmap f (OneL a) = OneL $ f a+ fmap f (a :< as) = f a :< fmap f as+++--------------------------------------------------------------------------------+-- Conversion++-- | Convert a join list to a regular list.+--+toList :: JoinList a -> [a]+toList = joinfoldl (flip (:)) []++-- | Build a join list from a regular list.+--+-- This builds a tall skinny list.+--+-- WARNING - throws an error on empty list.+--++fromList :: [a] -> JoinList a+fromList [] = error "Wumpus.Core - internal error empty JoinList"+fromList [x] = One x+fromList (x:xs) = Join (One x) (fromList xs)+++-- Note -- this works from Right to left...+--+toListF :: (a -> b) -> JoinList a -> [b]+toListF f = step []+ where+ step acc (One x) = f x : acc+ step acc (Join t u) = let acc' = step acc u in step acc' t++++--------------------------------------------------------------------------------++isOne :: JoinList a -> Bool+isOne (One _) = True+isOne _ = False++isMany :: JoinList a -> Bool+isMany (Join _ _) = True+isMany _ = False+++++-- | Create a singleton join list.+--+one :: a -> JoinList a+one = One+++-- | Cons an element to the front of the join list.+--+cons :: a -> JoinList a -> JoinList a+cons a xs = Join (One a) xs ++-- | Snoc an element to the tail of the join list.+--+snoc :: JoinList a -> a -> JoinList a+snoc xs a = Join xs (One a)+++++infixr 5 `join`++-- | Because there is no empty join list, join is Join.+--+join :: JoinList a -> JoinList a -> JoinList a+join = Join++--------------------------------------------------------------------------------+-- Basic functions++-- | Extract the first element of a join list - i.e. the leftmost+-- element of the left spine. An error is thrown if the list is +-- empty. +-- +-- This function performs a traversal down the left spine, so +-- unlike @head@ on regular lists this function is not performed +-- in constant time.+--+head :: JoinList a -> a+head (One a) = a+head (Join t _) = head t+++++accumMapL :: (x -> st -> (y,st)) -> JoinList x -> st -> (JoinList y,st)+accumMapL f xs st0 = go xs st0 + where+ go (One x) st = let (y,st') = f x st in (One y,st')+ go (Join t u) st = (Join v w, st'')+ where (v,st') = go t st+ (w,st'') = go u st'+++++-- | Right-associative fold of a JoinList.+--+joinfoldr :: (a -> b -> b) -> b -> JoinList a -> b+joinfoldr f = go+ where+ go e (One a) = f a e+ go e (Join t u) = go (go e t) u+++-- | Left-associative fold of a JoinList.+--+joinfoldl :: (b -> a -> b) -> b -> JoinList a -> b+joinfoldl f = go + where+ go e (One a) = f e a+ go e (Join t u) = go (go e u) t++--------------------------------------------------------------------------------+-- Views++-- | Access the left end of a sequence.+--+-- Unlike the corresponing operation on Data.Sequence this is +-- not a cheap operation, the joinlist must be traversed down +-- the left spine to find the leftmost node.+--+-- Also the traversal may involve changing the shape of the +-- underlying binary tree.+--+viewl :: JoinList a -> ViewL a+viewl (One a) = OneL a+viewl (Join t u) = step t u+ where+ step (One a) r = a :< r+ step (Join t' u') r = step t' (Join u' r)++
− src/Wumpus/Core/Utils/OneList.hs
@@ -1,133 +0,0 @@-{-# OPTIONS -Wall #-}------------------------------------------------------------------------------------- |--- Module : Wumpus.Core.Utils.OneList--- Copyright : (c) Stephen Tetley 2009-2010--- License : BSD3------ Maintainer : Stephen Tetley <stephen.tetley@gmail.com>--- Stability : highly unstable--- Portability : GHC------ Data type for non-empty lists.--- -----------------------------------------------------------------------------------module Wumpus.Core.Utils.OneList- (- -- OneMany- OneList- , ViewL(..)-- , one- , cons- , head- , viewl-- , fromList-- , toListF- , accumMapL- , isOne- , isMany- - ) where----import Control.Applicative-import Data.Foldable-import Data.Monoid-import Data.Traversable--import Prelude hiding ( head )---data OneList a = One a | Many a (OneList a)- deriving (Eq)--data ViewL 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--------------------------------------------------------------------------------------- | 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 -> ViewL 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/VersionNumber.hs view
@@ -22,7 +22,7 @@ -- | Version number. ----- > (0,36,0)+-- > (0,37,0) -- wumpus_core_version :: (Int,Int,Int)-wumpus_core_version = (0,36,0)+wumpus_core_version = (0,37,0)
wumpus-core.cabal view
@@ -1,5 +1,5 @@ name: wumpus-core-version: 0.36.0+version: 0.37.0 license: BSD3 license-file: LICENSE copyright: Stephen Tetley <stephen.tetley@gmail.com>@@ -38,82 +38,49 @@ the design permits a fairly simple implementation, which is a priority. . + NOTE version 0.37.0 - there will be no release of Wumpus-Basic+ to match this release of Wumpus-Core. Wumpus-Basic is + undergoing substantial change to accommodate glyph metrics and+ thus enable proper text bounding boxes and right and center+ aligned text. The improvements to Wumpus-Core merit a release+ so that there is not a large hiatus between the APIs of the + Hackage published latest version and the SVN repository. .+ . \[1\] Because the output is simple, straight-line PostScript code, it is possible to use GraphicsMagick or a similar tool to convert EPS files generated by Wumpus to many other formats (bitmaps). .- VERSION 0.36.0 UPGRADE NOTES .- There are two major changes between 0.35.0 and 0.36.0. - .- @PrimElement@ has been removed and the grouping constructor it - provided has been moved into the @Primitive@ type. As both - types are opaque, definitions in client code will work without - change, /but all/ type signatures referencing @PrimElement@ will - need to replace @PrimElement@ with @Primitive@.- .- Rotations and scalings on Primitives have changed again.- Primitives are now instances of the affine classes so support - - @rotate@, @rotateAbout@, @scale@, @translate@. Primitives are - now considered to be in the implicit affine frame with origin at - (0,0). Previously rotatation on Primitives (via the function - @rotatePrim@) was really a special case to allow slanted text, - the rotation was about the text\'s baseline origin and not the - affine frame. As rotation now works differently there is a - special constructor for slanted text @rtextlabel@.- . Changelog:- .- 0.35.0 to 0.36.0:- .- * API / behaviour change - rotation on primitives changed. New - functions have been added to create rotated text labels and - ellipses (@rtextlabel@, @rstrokeEllipse@, etc.), and - Primitives have been made instances of the Affine classes- except for the general matrix Transform class. The old- functions for transforming Primitives (@rotatePrim@, - @scalePrim@, etc.) have been removed. The demos (Rotated.hs,- Scaled.hs, Translated.hs) have been removed as they pertain - to the old behaviour, there are new demos highlighting the- new behaviour (TransformEllipse.hs, etc.).- .- * Major change - removed the PrimElement type. The (opaque) - Primitive type has been changed to incorporate a grouping - constructor equivalent to PrimElement\'s @XLinkGroup@ - contructor. The change has made the implementation of SVG - hyperlinks more efficient, but has forced various type - signatures to change in @Core.Picture@. Client code will - also have to change type signatures - @PrimElement@ becomes- @Primitive@.- .- * @Core.PtSize@ - the class @FromPtSize@ has been given a @Num@- superclass constraint. This can shorten type signatures of - functions that use @fromPtSize@.- .- * Corrected a bug where textlabels would generate an invalid- bounding box and cause a runtime error when supplied with an- empty string. Now there is no runtime error - and /no-ops/ - are generated in the output.+ . + 0.36.0 to 0.37.0: .- * Internal changes - moved @PrimCTM@ from @Core.PictureInternal@- into separate module. Moved /utility/ modules into their own - directory @Utils@. Move /text/ modules into their own - directory @Text@. + * The bounding box constructors have been renamed - @bbox@ is + now @boundingBox@ and @obbox@ becomes @oboundingBox@. The + rationale for this change is that the names very cryptic in + the first place and the constructors are used infrequently + when @bbox@ in particular makes a descriptive variable name. .- * Removed dependency on @algebra@ for @Semigroup@. The - equivalent @append@ operation on @BoundingBox@ is - @boundaryUnion@.+ * Changes to the Picture and Primitive types to enable better+ concatenation which is used heavily by Wumpus-Basic. The + Picture API exposes a new function @primCat@. .- * Renamed the @Core.GraphicsState@ to @Core.GraphicProps@. - Moved the property datatypes from @Core.PictureInternal@ into - @Core.GraphicProps@ (StrokeProps, LabelProps, etc.).+ * SVG /font delta context/ change - font deltas are now + annotated on Primitives not Pictures. The type of the + function @fontDeltaContext@ in @Core.Picture@ has changed + accordingly. .- * Moved @wumpus_default_font@ from @Core.Picture@ into - @Core.Graphic.Props@.+ * SVG hyperlink change - hyperlinks no longer group primitives+ (although a group of primitives can be hyperlinked). The + function @xlinkGroup@ has been removed from @Core.Picture@, + it is replaced by @xlink@. Primitives are now grouped with the+ function @primGroup@. .- * Haddock docs improved.+ * @Core.Picture@ - the argument order for the function + @rtextlabel@ has been changed, the positions of the angle and + bottom-left corner have been swapped. . . build-type: Simple@@ -178,7 +145,7 @@ Wumpus.Core.Text.TextInternal, Wumpus.Core.TrafoInternal, Wumpus.Core.Utils.Common,- Wumpus.Core.Utils.OneList,+ Wumpus.Core.Utils.JoinList, Wumpus.Core.Utils.FormatCombinators extensions: