Portability | GHC |
---|---|
Stability | unstable |
Maintainer | stephen.tetley@gmail.com |
Construction of pictures, paths and text labels.
Note - the text label functions are only appropriate for single printed lines of text. Wumpus-Core does not interpret special white-space characters (i.e. tab or newline) and passes them forward into the output file. Renderers will then deal with white-space as they please, which is usually to ignore it.
Also, SVG output does not currently use space="preserve"
.
It would be desirable to do so, as the PostScript generated by
Wumpus can use doubled up spaces to print wide spaces.
Unfortunately, SVG renderers seem to differ as to whether they
can inherit space="preserve"
from a top level attribute or
whether it must be annotated on every <text>
element.
Wumpus considers the latter to be a too-high burden as it will
expand the code size (this view may change).
- frame :: [Primitive] -> Picture
- multi :: [Picture] -> Picture
- fontDeltaContext :: FontAttr -> Primitive -> Primitive
- absPrimPath :: DPoint2 -> [AbsPathSegment] -> PrimPath
- absLineTo :: DPoint2 -> AbsPathSegment
- absCurveTo :: DPoint2 -> DPoint2 -> DPoint2 -> AbsPathSegment
- relPrimPath :: DPoint2 -> [PrimPathSegment] -> PrimPath
- relLineTo :: DVec2 -> PrimPathSegment
- relCurveTo :: DVec2 -> DVec2 -> DVec2 -> PrimPathSegment
- vertexPrimPath :: [DPoint2] -> PrimPath
- vectorPrimPath :: DPoint2 -> [DVec2] -> PrimPath
- emptyPrimPath :: DPoint2 -> PrimPath
- curvedPrimPath :: [DPoint2] -> PrimPath
- xlinkhref :: String -> XLink
- xlinkPrim :: XLink -> Primitive -> Primitive
- svgattr :: String -> String -> SvgAttr
- annotateGroup :: [SvgAttr] -> Primitive -> Primitive
- annotateXLink :: XLink -> [SvgAttr] -> Primitive -> Primitive
- primGroup :: [Primitive] -> Primitive
- primCat :: Primitive -> Primitive -> Primitive
- ostroke :: RGBi -> StrokeAttr -> PrimPath -> Primitive
- cstroke :: RGBi -> StrokeAttr -> PrimPath -> Primitive
- zostroke :: PrimPath -> Primitive
- zcstroke :: PrimPath -> Primitive
- fill :: RGBi -> PrimPath -> Primitive
- zfill :: PrimPath -> Primitive
- fillStroke :: RGBi -> StrokeAttr -> RGBi -> PrimPath -> Primitive
- clip :: PrimPath -> Primitive -> Primitive
- textlabel :: RGBi -> FontAttr -> String -> DPoint2 -> Primitive
- rtextlabel :: RGBi -> FontAttr -> String -> Radian -> DPoint2 -> Primitive
- ztextlabel :: String -> DPoint2 -> Primitive
- escapedlabel :: RGBi -> FontAttr -> EscapedText -> DPoint2 -> Primitive
- rescapedlabel :: RGBi -> FontAttr -> EscapedText -> Radian -> DPoint2 -> Primitive
- zescapedlabel :: EscapedText -> DPoint2 -> Primitive
- hkernlabel :: RGBi -> FontAttr -> [KerningChar] -> DPoint2 -> Primitive
- vkernlabel :: RGBi -> FontAttr -> [KerningChar] -> DPoint2 -> Primitive
- kernchar :: Double -> Char -> KerningChar
- kernEscInt :: Double -> Int -> KerningChar
- kernEscName :: Double -> String -> KerningChar
- strokeEllipse :: RGBi -> StrokeAttr -> Double -> Double -> DPoint2 -> Primitive
- rstrokeEllipse :: RGBi -> StrokeAttr -> Double -> Double -> Radian -> DPoint2 -> Primitive
- fillEllipse :: RGBi -> Double -> Double -> DPoint2 -> Primitive
- rfillEllipse :: RGBi -> Double -> Double -> Radian -> DPoint2 -> Primitive
- zellipse :: Double -> Double -> DPoint2 -> Primitive
- fillStrokeEllipse :: RGBi -> StrokeAttr -> RGBi -> Double -> Double -> DPoint2 -> Primitive
- rfillStrokeEllipse :: RGBi -> StrokeAttr -> RGBi -> Double -> Double -> Radian -> DPoint2 -> Primitive
- extendBoundary :: Double -> Double -> Picture -> Picture
- picOver :: Picture -> Picture -> Picture
- picMoveBy :: Picture -> DVec2 -> Picture
- picBeside :: Picture -> Picture -> Picture
- printPicture :: Picture -> IO ()
- illustrateBounds :: RGBi -> Picture -> Picture
- illustrateBoundsPrim :: RGBi -> Primitive -> Picture
- illustrateControlPoints :: RGBi -> Primitive -> Picture
Construction
frame :: [Primitive] -> PictureSource
Lift a list of primitives to a composite picture.
The order of the list maps to the order of printing - the front of the list is drawn first in the file. This also means that the front of the list is drawn underneath in the Z-Order.
** WARNING ** - this function throws a runtime error when supplied the empty list.
multi :: [Picture] -> PictureSource
Place multiple pictures within the standard affine frame.
** WARNING ** - this function throws a runtime error when supplied the empty list.
fontDeltaContext :: FontAttr -> Primitive -> PrimitiveSource
Update the font delta attributes for SVG output.
Note - fontDeltaContext
does not set the font properties of
elements in the supplied Picture, it is solely a mechanism to
help reduce the code size of the generated SVG by factoring
common attributes into a group (g) element. For instance,
settting the font properties with fontDeltaContext
can
eliminate the repeated use of font-family and font-size in
this code:
<text font-family="Helvetica" font-size="12"> ... </text> <text font-family="Helvetica" font-size="12"> ... </text> <text font-family="Helvetica" font-size="12"> ... </text>
With the appropriate font delta context, this code will be generated:
<g font-family="Helvetica" font-size="12"> <text > ... </text> <text > ... </text> <text > ... </text> </g>
Wumpus ignores fontDeltaContext
directives when generating
PostScript. Unlike SVG, PostScript is not naturally nested, so
introducing nesting with gsave
and grestore
is not likely
to improve the PostScript Wumpus generates.
absPrimPath :: DPoint2 -> [AbsPathSegment] -> PrimPathSource
absPrimPath
: start_point * [abs_path_segment] -> PrimPath
Create a PrimPath
from a start point and a list of absolute
path segments.
absLineTo :: DPoint2 -> AbsPathSegmentSource
absLineTo
: end_point -> path_segment
Create a straight-line AbsPathSegment
, the start point is
implicitly the previous point in a path.
absCurveTo :: DPoint2 -> DPoint2 -> DPoint2 -> AbsPathSegmentSource
absCurveTo
: control_point1 * control_point2 * end_point ->
path_segment
Create a curved AbsPathSegment
, the start point is implicitly
the previous point in a path.
relPrimPath :: DPoint2 -> [PrimPathSegment] -> PrimPathSource
relPrimPath
: start_point * [rel_path_segment] -> PrimPath
Create a PrimPath
from a start point and a list of relative
path segments.
Note - internally Wumpus works with relative paths so
constructing them directly with relPrimPath
is more efficient
than using absPrimPath
.
relLineTo :: DVec2 -> PrimPathSegmentSource
relLineTo
: vec_to_end -> path_segment
Create a straight-line PrimPathSegment
, the vector is the
relative displacement.
relCurveTo :: DVec2 -> DVec2 -> DVec2 -> PrimPathSegmentSource
relCurveTo
: vec_to_cp1 * vec_to_cp2 * vec_to_end ->
path_segment
Create a curved RelPathSegment
.
vertexPrimPath :: [DPoint2] -> PrimPathSource
vertexPrimPath
: [point] -> PrimPath
Convert the list of vertices to a path of straight line segments.
** WARNING ** - this function throws a runtime error when supplied the empty list.
vectorPrimPath :: DPoint2 -> [DVec2] -> PrimPathSource
vectorPrimPath
: start_point -> [next_vector] -> PrimPath
Build a "relative" path from the start point, appending successive straight line segments formed from the list of next_vectors.
This function can be supplied with an empty list - this simulates a null graphic.
emptyPrimPath :: DPoint2 -> PrimPathSource
emptyPrimPath
: start_point -> PrimPath
Build an empty path. The start point must be specified even though the path is not drawn - a start point is the minimum information needed to calculate a bounding box.
curvedPrimPath :: [DPoint2] -> PrimPathSource
curvedPrimPath
: points -> PrimPath
Convert a list of vertices to a path of curve segments. The first point in the list makes the start point, each curve segment thereafter takes 3 points. Spare points at the end are discarded.
** WARNING - this function throws an error when supplied the empty list.
xlinkhref :: String -> XLinkSource
Create a hyperlink for SVG output.
Note - hyperlinks are ignored in the PostScript output.
xlinkPrim :: XLink -> Primitive -> PrimitiveSource
Create a hyperlinked Primitive.
Note - hyperlinks are ignored in the PostScript output.
svgattr :: String -> String -> SvgAttrSource
Create an attribute for SVG output.
Attributes are expected to be non-graphical e.g. onclick
events or similar. Wumpus does not check the syntax and simply
emits the Strings as-is in the output.
Graphical properties should not be encoded, they may conflict with output that Wumpus produces.
** WARNING ** - currently this functionality is undercooked. Because SVG has more extra-graphical facilities than PostScript (hyperlinks, mouseovers, etc.) it seems important to have an escape hatch to them, yet so far the escape hatch has not been needed.
annotateGroup :: [SvgAttr] -> Primitive -> PrimitiveSource
Add SVG attribute annotations to a Primitive.
The primitive will be printed in a g
(group) element
labelled with the annotations.
annotateXLink :: XLink -> [SvgAttr] -> Primitive -> PrimitiveSource
Add SVG XLink and attribute annotations to a Primitive.
The primitive will be printed in a g
(group) element, itself
inside an a
link.
primGroup :: [Primitive] -> PrimitiveSource
Group a list of Primitives.
** WARNING ** - this function throws a runtime error when supplied the empty list.
primCat :: Primitive -> Primitive -> PrimitiveSource
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.
Constructing primitives
zostroke :: PrimPath -> PrimitiveSource
zostroke
: path -> Primitive
Create an open, stroked path using the default stroke attributes and coloured black.
zcstroke :: PrimPath -> PrimitiveSource
zcstroke
: path -> Primitive
Create a closed stroked path using the default stroke attributes and coloured black.
fillStroke :: RGBi -> StrokeAttr -> RGBi -> PrimPath -> PrimitiveSource
fillStroke
: fill_rgb * stroke_attr * stroke_rgb * path -> Primitive
Create a closed path that is both filled and stroked (the fill is below in the zorder).
clip :: PrimPath -> Primitive -> PrimitiveSource
clip
: path * primitive -> Primitive
Clip a primitive to be inside the supplied path.
textlabel :: RGBi -> FontAttr -> String -> DPoint2 -> PrimitiveSource
textlabel
: rgb * font_attr * string * baseline_left -> Primitive
Create a text label. The string should not contain newline
or tab characters. Also double-spaces should not be used - a
rendering agent for SVG will coalesce double-spaces into a
single space. For precise control of spacing and kerning use
hkernlabel
.
The supplied point is the left baseline.
rtextlabel :: RGBi -> FontAttr -> String -> Radian -> DPoint2 -> PrimitiveSource
rtextlabel
: rgb * font_attr * string * theta *
baseline_left -> Primitive
Create a text label rotated by the supplied angle about the baseline-left.
The supplied point is the left baseline.
ztextlabel :: String -> DPoint2 -> PrimitiveSource
ztextlabel
: string * baseline_left -> Primitive
Create a label where the font is Courier
, text size is 14pt
and colour is black.
escapedlabel :: RGBi -> FontAttr -> EscapedText -> DPoint2 -> PrimitiveSource
escapedlabel
: rgb * font_attr * escaped_text *
baseline_left -> Primitive
Version of textlabel
where the label text has already been
parsed for special characters.
The supplied point is the left baseline.
rescapedlabel :: RGBi -> FontAttr -> EscapedText -> Radian -> DPoint2 -> PrimitiveSource
rescapedlabel
: rgb * font_attr * escaped_text * theta *
baseline_left -> Primitive
Version of rtextlabel
where the label text has already been
parsed for special characters.
The supplied point is the left baseline.
zescapedlabel :: EscapedText -> DPoint2 -> PrimitiveSource
zescapedlabel
: escaped_text * baseline_left -> Primitive
Version of ztextlabel
where the label text has already been
encoded.
hkernlabel :: RGBi -> FontAttr -> [KerningChar] -> DPoint2 -> PrimitiveSource
hkernlabel
: rgb * font_attr * kerning_chars *
baseline_left -> Primitive
Create a text label with horizontal kerning for each character.
Note - kerning is relative to the left baseline of the previous character, it is *not relative* to the right-hand boundary of the previous char. While the later would be more obvious it would take a lot of effort to implement as it would need access to the metrics encoded in font files.
Characters are expected to be drawn left to right, so displacements should not be negative. If the displacement is zero the character will be drawn ontop of the previous char.
The charcters should not contain newline or tab characters.
The supplied point is the left baseline.
** CAUTION ** - for SVG, hkernlabel
generates a
coordinate list of X-positions rather than a single start
point. This is syntactically valid SVG, but it is not
universally supported by renderers. Chrome support is fine,
but Firefox and Safari currently seem lacking.
Also, note this feature does not have a directly compatible PostScript analogue. While the same picture is generated in both cases, the PostScript code is not particularly inefficient.
vkernlabel :: RGBi -> FontAttr -> [KerningChar] -> DPoint2 -> PrimitiveSource
vkernlabel
: rgb * font_attr * kerning_chars *
baseline_left -> Primitive
Create a text label with vertical kerning for each character - the text is expected to grow downwards.
Note - kerning here is the measure between baselines of sucessive characters, it is *not* the distance between the bottom of one chararter and the top of the next character.
While the later maybe be more obvious from a drawing perspective, it would take a lot of effort to implement as it would need access to the metrics encoded in font files.
Characters are expected to be drawn downwards - a positive number represents the downward displacement - so displacements should not be negative. If the displacement is zero the character will be drawn ontop of the previous char.
The charcters should not contain newline or tab characters.
The supplied point is the left baseline of the top character.
** CAUTION ** - for SVG, hkernlabel
generates a
coordinate list of Y-positions rather than a single start
point. This is syntactically valid SVG, but it is not
universally supported by renderers. Chrome support is fine,
but Firefox and Safari currently seem lacking.
Also, note this feature does not have a directly compatible PostScript analogue. While the same picture is generated in both cases, the PostScript code is not particularly inefficient.
kernchar :: Double -> Char -> KerningCharSource
kernchar
: displacement * char -> KerningChar
Construct a regular (i.e. non-special) Char along with its displacement from the left-baseline of the previous Char.
kernEscInt :: Double -> Int -> KerningCharSource
kernEscInt
: displacement * char_code -> KerningChar
Construct a Char by its character code along with its displacement from the left-baseline of the previous Char.
kernEscName :: Double -> String -> KerningCharSource
kernEscName
: displacement * char_name -> KerningChar
Construct a Char by its character name along with its displacement from the left-baseline of the previous Char.
strokeEllipse :: RGBi -> StrokeAttr -> Double -> Double -> DPoint2 -> PrimitiveSource
strokeEllipse
: rgb * stroke_attr * rx * ry * center -> Primtive
Create a stroked ellipse.
Note - within Wumpus, ellipses are considered an unfortunate
but useful optimization. Drawing good cicles with Beziers
needs four curves, but drawing them with PostScript's arc
command uses a single operation. For drawings with many dots
(e.g. scatter plots) it seems sensible to employ this
optimization.
A deficiency of using PostScript's arc
command to draw
ellipses is that (non-uniformly) scaling a stroked ellipse
also (non-uniformly) scales the pen it is drawn with. Where
the ellipse is wider, the pen stroke
will be wider too.
Avoid non-uniform scaling stroked ellipses!
rstrokeEllipse :: RGBi -> StrokeAttr -> Double -> Double -> Radian -> DPoint2 -> PrimitiveSource
rstrokeEllipse
: rgb * stroke_attr * rx * ry * theta *
center -> Primtive
Create a stroked primitive ellipse rotated about the center by theta.
fillEllipse :: RGBi -> Double -> Double -> DPoint2 -> PrimitiveSource
fillEllipse
: rgb * rx * ry * center -> Primtive
Create a filled primitive ellipse.
rfillEllipse :: RGBi -> Double -> Double -> Radian -> DPoint2 -> PrimitiveSource
rfillEllipse
: rgb * rx * ry * theta * center -> Primitive
Create a filled primitive ellipse rotated about the center by theta.
zellipse :: Double -> Double -> DPoint2 -> PrimitiveSource
zellipse
: rx * ry * center -> Primtive
Create a black, filled ellipse.
fillStrokeEllipse :: RGBi -> StrokeAttr -> RGBi -> Double -> Double -> DPoint2 -> PrimitiveSource
fillStrokeEllipse
: fill_rgb * stroke_attr * stroke_rgb * rx * ry *
center -> Primtive
Create a bordered (i.e. filled and stroked) primitive ellipse.
rfillStrokeEllipse :: RGBi -> StrokeAttr -> RGBi -> Double -> Double -> Radian -> DPoint2 -> PrimitiveSource
rfillStrokeEllipse
: fill_rgb * stroke_attr * stroke_rgb * rx * ry *
theta * center -> Primtive
Create a bordered (i.e. filled and stroked) ellipse rotated about the center by theta.
Operations
extendBoundary :: Double -> Double -> Picture -> PictureSource
extendBoundary
: x * y * picture -> Picture
Extend the bounding box of a picture.
The bounding box is both horizontal directions by x
and
both vertical directions by y
. x
and y
must be positive
This function cannot be used to shrink a boundary.
Picture composition
picOver :: Picture -> Picture -> PictureSource
picOver
: picture * picture -> Picture
Draw the first picture on top of the second picture - neither picture will be moved.
picMoveBy :: Picture -> DVec2 -> PictureSource
picMoveBy
: picture * vector -> Picture
Move a picture by the supplied vector.
picBeside :: Picture -> Picture -> PictureSource
picBeside
: picture * picture -> Picture
Move the second picture to sit at the right side of the first picture
Illustrating pictures and primitives
printPicture :: Picture -> IO ()Source
Print the syntax tree of a Picture to the console.
illustrateBounds :: RGBi -> Picture -> PictureSource
illustrateBounds
: bbox_rgb * picture -> Picture
Draw the picture on top of an image of its bounding box. The bounding box image will be drawn in the supplied colour.
illustrateBoundsPrim :: RGBi -> Primitive -> PictureSource
illustrateBoundsPrim
: bbox_rgb * primitive -> Picture
Draw the primitive on top of an image of its bounding box. The bounding box image will be drawn in the supplied colour.
The result will be lifted from Primitive to Picture.
illustrateControlPoints :: RGBi -> Primitive -> PictureSource
illustrateControlPoints
: control_point_rgb * primitive -> Picture
Generate the control points illustrating the Bezier curves within a picture.
This has no effect on TextLabels. Nor does it draw Beziers of a hyperlinked object.