Sunday, 10 April 2016

As mentioned in the previous post, the JavaScript Flags hobby project encodes the drawing instructions for each flag as a string. For examples, the Japanese flag is encoded as

"FwCrO+0+0+72"

This is split up into a sequence of instructions or commands using a regular expression match:

[ ["F", "w"], ["C", "r"], ["O", "+0", "+0", "+72"] ]

The first element of each instruction is always a single upper-case letter. The remaining elements are either lower-case letters usually indicating colours (see the previous post) or signed integers (expressed as strings). Often, the integers represent coordinates. No matter what the aspect ratio of the flag, the top-left corner is always (-120,-120) and the bottom-right is (+120,+120). Two hundred and forty was chosen because it fits into a byte (although that's not important for this JavaScript implementation of the flag renderer) and is highly divisible.

The command letters are as follows:

"A n" — Executes the next command in the sequence "n" times, rotating about the origin by (360 ÷ "n")degrees each time.

"B xypath ..." — Draws a path made up of a mixture of straight-line and cubic Bezier segments and fills it with the current colour. See below.

"C c" — Sets the current colour to "c",

"D fw" — Draws diagonal lines of width "w". If "f" is 1, a diagonal line from top-left to bottom-right is drawn. If "f" is 2, a diagonal line from top-right to bottom-left is drawn. And if "f" is 3, both diagonals are drawn.

"E sxsy" — Executes the next command with scaling about the origin. If either "sx" or "sy" are negative, executes the next command twice: once with scaling (abs(sx),abs(sy)) and once with scaling (sx,sy). Otherwise, just executes the next command with scaling (sx,sy).

"R x0y0x1y1" — Draws and fills an axis-aligned rectangle with the current colour between (x0,y0) and (x1,y1).

"S xyr" or "S nr1r2xya" — With three arguments, draws a five-pointed star filled with the current colour at (x,y) and radius "r". With six arguments, draws an "n"-pointed star filled with the current colour at (x,y), inner radius "r1" and outer radius "r2" all rotated by "a" degrees.

"X cwx" — Draws an axis-aligned cross of width "w" in colour "c". The vertical bar passed through the x-axis at "x", The horizontal bar is along the x-axis.

"Y ndxdy" — Executes the next command in the sequence "n" times, translating by (dx,dy) after each iteration.

"Z x0y0x1y1" — Zooms in to a rectangle (x0,y0) and (x1,y1) where x0 < x1 and y0 < y1. All subsequent commands assume the 240-by-240 canvas is now (x0,y0) to (x1,y1).

The paths for the "B" and "M" commands start and finish at (x,y). The intervening points are prefixed by a lower-case letter:

"l xy" — Lower-case "L" — A straight-line segment from the previous point to (x,y).

"sx1y1xy" — Lower-case "S" — A smooth cubic Bezier segment from the previous point to (x,y) with control point (x1,y1).

"cx1y1x2y2xy" — Lower-case "C" — A general cubic Bezier segment from the previous point to (x,y) with control points (x1,y1) and (x2,y2).

For the "M" command, the path is mirrored about a vertical axis centred on the final point of the explicitly-specified path. This allows emblems such as the double-headed Albanian eagle to be encoded very efficiently.

In summary, less than twenty commands encode the instructions for drawing most of the world's flags very effectively. The use of regular expression string splitting and function lookup maps in JavaScript makes the encoded strings short whilst keeping the decoding code equally concise,