Polygons

One of the simplest things you can draw is a polygon. There are many ways to draw them in Nell. To draw an equilateral triangle with sides of length 1 you could use the program (poly00.nll).

Program: (poly00.nll)

START : L(1) T(2*pi/3) L(1) T(2*pi/3) L(1) T(2*pi/3);

Command line

nell poly00.nll START 6 | nellsvg 1 1 in 0.02 1 > poly00.svg

The exterior angles of an equilateral triangle are all equal to 120 degrees = 2*pi/3 radians, hence the T(2*pi/3) commands. The last T(2*pi/3) command is strictly not necessary. It just returns the direction to where it was at the beginning.

The program (poly00.nll) will produce an svg where each line is a separate path. To group all the lines into a single path, we simply put angle brackets around the command string as shown in program (poly00a.nll)

Program: (poly00a.nll)

START : <L(1) T(2*pi/3) L(1) T(2*pi/3) L(1) T(2*pi/3)>;

Command line

nell poly00a.nll START 6 | nellsvg 1 1 in 0.02 1 > poly00a.svg

This produces an svg where the triangle is a single path, but the path is still open, i.e. the first point is not connected to the last point. A triangle that is a single closed path is produced by program (poly01.nll)

Program: (poly01.nll)

START : <L(1) T(2*pi/3) L(1) T(2*pi/3) Z()>;

Command line

nell poly01.nll START 6 | nellsvg 1 1 in 0.02 1 > poly01.svg

Note that the last L(1) command has been left out since it is implicit in the Z() command which closes the path and sets the current position and direction to what it was at the start of the path.

You can use this same technique for drawing regular polygons with any number of sides, but instead of writing out the L commands for each side explicitly, you can use a substitution command. The program (poly02.nll) shows how to do this to draw a pentagon.

Program: (poly02.nll)

SIDE : L(1) T(2*pi/5);
START : M(0.5) <S(SIDE,4) Z()>;

Command line

nell poly02.nll START 6 | nellsvg 2 2 in 0.02 1 > poly02.svg

The command string labeled SIDE draws one side of the pentagon, and we use it four times inside the path to draw four sides of the polygon with the final Z command completing the last side. The initial M(0.5) command starts the drawing at the point (0.5,0) so that the entire pentagon is in the positive first quadrant.

With a substitution command and a variable definition we can easily generalize this to a program that will draw a polygon with n sides. Program (poly03.nll) shows how it's done.

Program: (poly03.nll)

n = 6;
SIDE : L(1) T(2*pi/n);
START : M(0.5) <S(SIDE,n-1) Z()>

Command line

nell poly03.nll START 6 | nellsvg 2 2 in 0.02 1 > poly03.svg

In (poly03.nll) we've defined the variable n which is set equal to 6 at the beginning of the program. If you run the program like this it will produce a hexagon. Set n = 8; and it will produce an octagon and so on.

So much for drawing single regular polygons. Now let's see how easy it is to create drawings with multiple polygons. You can easily make a series of nested regular polygons using a double set of substitutions. Program (poly04.nll) shows how it's done.

Program: (poly04.nll)

n=3;
SIDE : L(1) T(2*pi/n);
POLY : <S(SIDE,n-1) Z()> A(n,n+1);
START : M(1) S(POLY,6);

Command line

nell poly04.nll START 6 | nellsvg 3 3 in 0.02 1 > poly04.svg

In (poly04.nll) we've used the A command that assigns a new value to a variable, which in this case is the number of sides in the next polygon to draw. The POLY command string is substituted 6 times with the value of n incremented each time, starting with the value 3. The result is that a triangle, square, pentagon, hexagon, heptagon, and octagon are drawn, all starting at the same point and sharing a common side. The M(1) command sets the starting point for all polygons to (1,0) so they are horizontally centered on a 3 by 3 canvas.

Program (poly05.nll) shows how to arrange five pentagons so that they form a pentagon.

Program: (poly05.nll)

SIDE : L(1) T(-2*pi/5);
POLY : <S(SIDE,4) Z()> M(1) T(2*pi/5);
START : P(2,2) S(POLY,5);

Command line

nell poly05.nll START 6 | nellsvg 5 5 in 0.02 1 > poly05.svg

Here we've used the P command to position the starting point at (2,2). This centers the drawing on a 5 by 5 canvas. The POLY command string draws a pentagon, moves one unit in the current direction and changes direction by 2*pi/5 so that the next pentagon can be drawn.

The program (poly06.nll) draws a pentagram inside a pentagon.

Program (poly06.nll)

d = (1+sqrt(5))/2;
PENTAGON : <L(1) T(2*pi/5) L(1) T(2*pi/5) L(1) T(2*pi/5) L(1) T(2*pi/5) Z()>;
PENTAGRAM : T(pi/5) <L(d) T(4*pi/5) L(d) T(4*pi/5) L(d) T(4*pi/5) L(d) T(4*pi/5) Z()>;
START : M(0.5) S(PENTAGON,1) S(PENTAGRAM,1);

Command line

nell poly06.nll START 6 | nellsvg 2 2 in 0.02 1 > poly06.svg

The program (poly07.nll) draws concentric triangles starting with the outer triangle and going in.

Program: (poly07.nll)

n = 6;
l = 2;
dl = l/n;
dr = dl/sqrt(3);
a = 2*pi/3;
TRI : <L(l) T(a) L(l) T(a) Z()> T(pi/6) M(dr) T(-pi/6) A(l,l-dl);
START : S(TRI,n);

Command line

nell poly07.nll START 6 | nellsvg 2 2 in 0.02 1 > poly07.svg

The variable n defines the number of triangles to draw. The variable l is the length of a side of the outer triangle. The variable dl is the amount by which the length of the triangle side changes as you go in. The variable dr is the length by which you move in to draw the next triangle. As an exercise see if you can modify the program so the inner triangle is drawn first and the outer last.

You can generalize (poly07.nll) to draw concentric polygons with any number of sides. The program (conpoly.nll) shows how to do it.

Program: (conpoly.nll)

ns=6;  number of sides
n=12;  number of polygons
l=2;  length of a side
dl=l/n;
dr=dl/(2*sin(pi/ns));
a=2*pi/ns;
b=pi*(ns-2)/(2*ns);
SIDE : L(l) T(a);
POLY : <S(SIDE,ns-1) Z()> T(b) M(dr) T(-b) A(l,l-dl);
START : M(1) S(POLY,n);

Command line

nell conpoly.nll START 10 | nellsvg 4 4 in 0.02 1 > conpoly.svg

The program defines the variable ns that specifies the number of sides for the polygons and the variable b which is the angle to turn to move to the beginning of the next inner polygon.

A variation on the concentric polygons is to rotate each of the inner polygons by half the exterior angle. The program (rconpoly.nll) shows how to do it.

Program: (rconpoly.nll)

ns=8;  number of sides
n=28;  number of polygons
l=2;  length of a side
a=2*pi/ns;
rl = cos(a/2);
SIDE : L(l) T(a);
POLY : <S(SIDE,ns-1) Z()> M(l/2) T(a/2) A(l,l*rl);
START : M(sqrt(2)) S(POLY,n);

Command line

nell rconpoly.nll START 10 | nellsvg 4.83 4.83 in 0.02 1 > rconpoly.svg

We can also easily tile polygons. The program (tritile.nll) will create a tiling using triangles.

Program: (tritile.nll)

n = 8;
l = 0.5;
r = 1.0;
d = r*l;
a = 2*pi/3;
T1 : <L(l) T(a) L(l) T(a) Z()> M(d);
T2 : [S(T1,n)] T(a/2) M(d) T(-a/2) [S(T1,n-1)];
T3 : [S(T2,1)] T(pi/2) M(d*sqrt(3)) T(-pi/2);
START : S(T3,n/2);

Command line

nell tritile.nll START 10 | nellsvg 4 4 in 0.02 1 > tritile.svg

The variable n is the number of triangles per row, l is the length of a triangle side and r determines the tile spacing where r=1 gives an exact fit, r<1 gives an overlap, and r>1 adds space between the triangles. For r=1.25 we get this:

The program (hextile.nll) will create a tiling using hexagons.

Program: (hextile.nll)

a = pi/3;
s = 0.5;
r = 1.0;
d = r*s*sqrt(3);
n = 4;
T1 : L(s) T(a);
T2 : <S(T1,5) Z()>;
T3 : S(T2,1) T(a/2) M(d) T(-a/2) S(T2,1) T(-a/2) M(d) T(a/2);
T4 : [S(T3,n)] T(pi/2) M(d) T(-pi/2);
START : M(0.25) S(T4,n);

Command line

nell hextile.nll START 10 | nellsvg 6.25 4.0 in 0.02 1 > hextile.svg

Again the variable r determines the spacing. For r=1 there is no space between the hexagons. For r=0.5 the hexagons overlap as in the following figure.