Context Free Art


From Context Free Art

Jump to: navigation, search


Basic Concept

The SQUARE, CIRCLE, and TRIANGLE primitive shapes are implemented as lists of path operations, which are drawn on a canvas. The new path feature allows new primitive shapes paths to be defined. A path contains a list of path operations and path commands. Paths are defined to support the path drawing features found of SVG files and the OpenVG specification.

The simplest path is a path sequence followed by a path command. The path sequence specifies where to draw and the path command specifies whether to fill the path sequence or stroke it. A path sequence begins with a MOVETO to set where the drawing part of the path starts, some number of path operations (LINETO, CURVETO, ARCTO) that specify the path for drawing, and an optional CLOSEPOLY that causes the path sequence to return to the its beginning (i.e., the MOVETO). Here is a simple path:

path box {
MOVETO{x 0.5 y 0.5}
LINETO{x -0.5 y 0.5}
LINETO{x -0.5 y -0.5}
LINETO{x 0.5 y -0.5}
CLOSEPOLY{} // go back to (0.5, 0.5) and close the path
STROKE{} // draw a line on the path using the default line width (10%)

There are a couple of ways that a path can be more complex:


Example of multiple path commands and path operation loops. Example of geometric adjustments in loops and color adjustments in path commands:

startshape stars
background {sat 0.35}
path stars {
MOVETO{x cos(90-144) y sin(90-144)}
4* {r 144} LINETO {y 1}
5* {r 72} {
FILL{y 1.88 b 0.5 p evenodd}
STROKE{y 1.88}


Example of optional MOVETOs and multiple sets of path sequences and commands:

path dot {
MOVETO{y 1} // required
ARCTO{y -1 r 1}
ARCTO{y 1 r 1}
FILL{hue 216 sat 1 b 0.7333}
MOVETO{y 1} // can be left out
ARCTO{y -1 r 1}
STROKE{b -1 width 0.25}
MOVETO{y -1} // can be left out
ARCTO{y 1 r 1}
STROKE{b 1 width 0.25}

The second and third MOVETO operations are redundant. If they were left out then Context Free would automatically have generated them because all they do is move to the same position as the ARCTO operations that are at the end of the preceding path sequences.


Example of implicit fill command:

path heptagon {
MOVETO{x cos(90-360/7) y sin(90-360/7)}
6* {r (360/7)} LINETO{y 1}


Path Operations

The supported path operations are:

It is not necessary to list all of the path operation parameters. If a path operation parameter is omitted then a default value will be used. The default position is (0,0) for end points and control points. If the x or y part of a position or control point is omitted then 0 will be used. However, for cubic bezier curves either x2 or y2 must be specified for Context Free to know that it is cubic and not quadratic. For non-smooth cubic and quadratic bezier curves either x1 or y1 must be specified for Context Free to know that the non-smooth variant is desired. For arcs, the default ellipse radius is (1,1) and the default angle is 0.

The smooth forms of the quadratic and cubic curve operations infer the unspecified control point by looking at the preceding curve operation. If the preceding operation is not a curve operation (CURVETO, CURVEREL, ARCTO, or ARCREL) then a smooth curve operation is not permitted.

Relative Path Operations

Each of the absolute path operations above has a relative form in which the position of the previous path operation is added to the current position (and to any control points):

Path Ending Operations

Path sequences can be explicitly ended and closed:

A path sequence is implicitly ended without closure by starting a new path sequence with MOVETO/MOVEREL, by following it with one or more path commands, or by ending the path.
path SomeOpenPathsAndAClosedPath {
MOVETO{x 1} // ended previous path
STROKE{} // ended previous path sequence, strokes both open path sequences
} // ended last path sequence and fills it, which looks like a closed path

Aligned Path Closures

A design might have a series of drawing operations that should result in the last point being the same as the first point. But when the path is closed a small line segment might be seen at the join between the beginning and end points. This is due to floating point math errors causing the end point to be slightly off from the beginning point. There is an alternate form of CLOSEPOLY that modifies the last drawing point so that the end point exactly matches the beginning point:

Context Free will scan backward until it finds a MOVETO or MOVEREL and sets the ending drawing operation to the same point as the MOVETO/MOVEREL.

Path Commands

After a path sequence there can be one or more path commands. Path commands instruct Context Free to draw (stroke or fill) all of the path sequences between the path command and the previous group of path commands.

Non-Zero filling fillrule-nonzero.png

Even-Odd filling fillrule-evenodd.png

Note that the shape adjustments in path commands can either be basic or ordered (see basic vs. ordered).

If a path is completed (by a closing curly brace, '}') with no path command following the last set of path sequences then an implicit fill command is appended to the path.


Many path operations and commands have parameters that modify their action. These parameters have the form of the keyword 'p' or 'param' followed by a string. The string can be without quotes if it has no white-space characters. If there are white-space characters then the string must be enclosed in quotes.

Join types linejoin.png

Cap types linecap.png

File:iso2.pngTop is default, bottom is isowidth

Arc Parameters

The basic arc drawing operation specifies a start point, an end point, and an ellipse. The ellipse is positioned such that the start point and end points touch the ellipse and the arc is drawn from the start to the finish. However, in general there are two possible ellipse positions for any pair of starting and ending points, and two different arcs on each ellipse that can be drawn. The cw and large parameters indicate which of the four possible arcs are drawn.


Two of the four arcs are large, i.e., more than 180°. Specifying the large parameter indicates that one of these arcs should be drawn. Otherwise one of the arcs that are less than 180° will be drawn. Two of the four arcs draw from start to end clockwise around the ellipse and two draw counter-clockwise. Specifying the cw parameter indicates that a clockwise arc should be drawn. Otherwise a counter-clockwise arc will be drawn.

Setting the radius of the arc to be negative has the effect of inverting the arc drawing direction. A counter-clockwise arc will be drawn clockwise if the radius is negative. A clockwise arc will be drawn counter-clockwise if the radius is negative.

Bezier Control Points

The control points for bezier curve segments control the slope of the curve at the ends. For cubic bezier curves each end has its own control point and the slope at each end is indicated by the slope of the line from the end to the control point. For quadratic bezier curves both ends share a single control point and the slope at each end is indicated by the slope of the line from each end to the shared control point.


For smooth cubic bezier curves the starting control point is the mirror of the ending control point on the previous bezier curve or arc curve. For smooth quadratic bezier curves the single control point is the mirror of the ending control point on the previous bezier curve or arc curve. The preceding curve does not need to be of the same order (quadratic or cubic) as the smooth curve. The preceding curve can even be an ARCTO. Context Free will figure out what control point will match the slope and curvature between the smooth curve and the curve the precedes it.

Loops in Paths

Paths support the same extended loop constructs as rules, with a slight difference. Simple loops look pretty much the same as rule simple loops:

path trill {
MOVETO {x cos(234) y sin(234)}
5* {r -144}
CURVETO {y 1 x1 (cos(234) + cos(324)) y1 (sin(234) + sin(324)) x2 1 y2 1}
CLOSEPOLY {p align}
5* {r 72}
STROKE {y 2 p buttjoin a -0.5}

But for complex loops there is the restriction that loops must either be all path operations or all path commands, no mixing is allowed.

path suns {
20* {r (360/20)} {
LINETO{x (2*cos(360/40)) y (2*sin(360/40))}
LINETO{x cos(360/20) y sin(360/20)}
CLOSEPOLY{p align}
5* {r 72} {
FILL{y 4}
STROKE{y 4 b -0.1}

Z changes are not allowed in the loop transform for path operation or command loops and color changes are not allowed in the loop transform for path operation loops.

Personal tools
Powered by MediaWiki
Attribution-Share Alike 2.5
book coverSee our book:
Community of Variation