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.