Nell Blog
This is the blog for the book: Nell: An SVG Drawing Language. We will post new drawings here and other information about the book and related software.
Tesseract Projections
May 10, 2021
Here are four B4 Coxeter plane projections of a tesseract arranged in a square pattern.
The Nell program (tesseract.nll) shown below was used to create the figure.
; nell tesseract.nll START 3 | nellsvg 5 5 in 0.02 1 > tess.svg l=1; a = pi/2; b = pi/4; SQ :M(l) T(b); P1 : M(l/sqrt(2)) S(SQ,8) M(l+l*sqrt(2)) S(SQ,8); START : [S(P1,1)] P(0,l+l*sqrt(2)) [S(P1,1)];
The command line for generating the svg is shown as a comment on the first line of the program.
Danger Radiation Symbol
July 28, 2020
We recently needed a "Danger Radiation" sign, so we figured why not draw the symbol in the Nell language. With the resulting svg we could customize it in inkscape to make a nice sign.
The Nell program shown below is used to create the figure.
; Draws a danger radiation symbol ; nell dangerrad.nll START 2 | nellsvg 5.2 5.2 in 0.03 1 > dangerrad.svg ; stang = pi/3; start angle swang = pi/3; sweep angle WEDGE : <R(1,1,stang,-swang) L(1) M(-2) R(2,2,0,swang) L(-1)> M(-1) T(stang); START : P(2.6,2.6) C(0.5) S(WEDGE,3) C(2.5);
The command line for generating the svg is shown as a comment on the second line of the program.
The three wedges of the radiation symbol should each be a closed path so they can be colored and shaded in inkscape the way we'd like. Using arcs to create the wedges seems the most straightforward way. Arcs have, up to now, not been allowed to be a part of a path in the Nell language. We have now modified the language to enable this. Download the software and recompile it to use this new feature. Only nellsvg.c
has changed, so that's the only program that has to be recompiled.
Note that if you use a Nell path closing commmand, Z(), in a path that has an arc command, R(rx,ry,a,da), in it, then the path will only close to the beginning of the last arc which is not necessarily the beginning of the defined path. You can get around this weirdness by manually closing the path instead of using Z() as we have done in the above program.
Below is the finished sign that we completed in inkscape.
Total Internal Reflection
June 17, 2020
The image above shows a point source of light in water. When a ray meets the air/water interface it is refracted according to Snell's law. When the ray's incident angle is greater than the critical angle, it no longer crosses over into air but is reflected back down into the water. This is called total internal reflection.
The Nell program shown below is used to create the figure.
; This shows internal reflection of light from water to a water/air boundary. ; nell waterair.nll START 3 | nellsvg 6 3 in 0.02 1 > waterair.svg n0 = 4/3; water index of refraction n1 = 1; air index of refraction tc = asin(n1/n0); critical angle dt = 5*pi/180; change in angle k = 12; number of steps of size dt to take (not including start at t0 = 0) t0 = 0; ray start angle tir = pi-2*t0; internal reflection angle t1 = if(t0>tc,t0+tir,asin(n0*sin(t0)/n1)); internal reflection angle or angle from Snell's law s = 1.0; vertical distance from light source to water/air junction l0 = s/cos(t0); ray length from light source to water/air junction CALC1 : A(t0,t0+dt) A(tir,pi-2*t0) A(t1,if(t0>tc,t0+tir,asin(n0*sin(t0)/n1))) A(l0,s/cos(t0)); INIT : P(3,0.1) D(pi/2); initialize position & direction RAYL : S(INIT,1) <T(t0) L(l0) T(t1-t0) L(1)> S(CALC1,1); draw a left-half ray RAYR : S(INIT,1) <T(-t0) L(l0) T(t0-t1) L(1)> S(CALC1,1); draw a right-half ray BOUNDARY : [M(s) [T(pi/2) L(3)] T(-pi/2) L(3)]; draw the water/air boundary START : S(RAYL,k+1) A(t0,0) S(CALC1,1) S(RAYR,k) S(INIT,1) S(BOUNDARY,1);
The command line for generating the svg is shown as a comment on the second line of the program.
Sun Drawing
May 13, 2020
Since spring is underway here in the Northern Hemisphere, we figure it's a good time to make a sun drawing, to pay homage to the primary engine of life here on Earth. Below is our Nell program for doing it.
; Draws a sun with wavy arms using cubic Bezier curves. ; nell sun04.nll START 3 | nellsvg 8.5 8.5 in 0.03 1 > sun04.svg;display sun04.svg ; ;*****ARMS section***** n = 12; a = 2*pi/n; r1 = 2; r2 = 4; l = sqrt(r1^2+r2^2-2*r1*r2*cos(a/2)); phi = asin(r2*sin(a/2)/l); ARMS : [M(r1) [T(phi) B(l,l/2,phi,-l/2,phi)] [T(-phi) B(l,l/2,phi,-l/2,phi)]] T(a); ;*****EYES section***** EYES : P(3.5,5) E(0.5,0.25) P(5,5) E(0.5,0.25) P(4.0,5) L(0.5) P(5.5,5) T(pi/6) L(0.5) T(-pi/6) P(3.0,5) T(5*pi/6) L(0.5) T(-5*pi/6); ;*****SMILE section***** b = 0.4; l2 = 2.75; SMILE1 : [Q(l2,(l2/2)*sqrt(b^2*l2^2+1),atan(-b*l2))] A(b,b/2); SMILE : P(2.9,3.5) S(SMILE1,2); ;*****NOSE section***** l3 = 0.8; lc = 1.25; ac = 0.22*pi; NOSE : P(4.3,4.6) T(-pi/2) [Q(l3,lc,ac)] [Q(l3,lc,-ac)]; ;*****MAIN section***** START : P(4.25,4.25) C(r1) S(ARMS,n) S(EYES,1) S(SMILE,1) S(NOSE,1);
For ease of understanding, the program is separated into four
anatomical
sections: ARMS
, EYES
, SMILE
,
and NOSE
. The ARMS
section uses cubic Bezier
curves. The SMILE
and NOSE
sections use
quadratic Bezier curves. The SMILE
is composed of two
parabolas created just as
in bezier2.nll and found in
the book's chapter on
Bezier curves.
The command line for generating the svg is shown as a comment on the second line of the program.
Making graph paper - triangular grid
May 6, 2020
Triangular grid graph paper with equilateral triangles is useful for organic chemistry, since the six triangles in common with every vertex form a hexagon.
; Creates a triangular grid sheet of graph paper. ; nell gptri.nll START 3 | nellsvg 8.5 11 in 0.0025 1 > gptri.svg W=8.5; paper width H=11; paper height d=0.5; width of triangle base t=pi/3; triangle base angle tt=tan(t); ct=cos(t); st=sin(t); ht=d*tt/2; height of triangle xm=H/tt; n=int(xm/d)+1; ; L1 code strings draw the lines at angle t L1A : A(h,x*tt) P(0,h) L(if(H-h < W*tt, (H-h)/st, W/ct)) A(x,x+d); L1B : A(h,(W-x)*tt) P(x,0) L(if(h < H, (W-x)/ct, H/st)) A(x,x+d); L1 : A(x,0) S(L1A,n) A(x,d) S(L1B,int(W/d)); ; L2 code strings draw the lines at angle pi-2*t L2A : A(h,x*tt) P(x,0) L(if(h < H, x/ct, H/st)) A(x,x+d); L2B : A(h,(x-W)*tt) P(W,h) L(if(H-h < W*tt, (H-h)/st, W/ct)) A(x,x+d); L2 : A(x,d) S(L2A,int(W/d)) S(L2B,n-1); ; HL draws the horizontal lines HL : [T(-pi/2) L(W)] M(d*tt/2); START : T(t) S(L1,1) T(pi-2*t) S(L2,1) P(0,0) D(pi/2) S(HL,int(H/ht)+1);
The above program does the job, with the line that starts
with t=pi/3
being the key to making the triangles
equilateral. To make the triangles bigger, we edit the line that
starts with d=0.5
, increasing the value. Another possibly
useful angle is t=pi/4
which creates a triangular grid
with square symmetry.
The command line for generating the svg is shown as a comment on the second line of the program. You can get pdf versions of the above mentioned graph paper below:
- Equilateral triangle graph paper (letter paper size)
- Square symmetry triangle graph paper (letter paper size
Here we have changed the default solid lines to dotted lines by
opening up the svg output files in inkscape, selecting the grid, and
choosing from the menu: Object | Fill and Stroke | Stroke
Syle
.
To make a version of the program for A4 paper size (210x297 mm),
the command line would be:
nell gptri.nll START 3 | nellsvg 210 297 mm 0.254 1 > gptri.svgwhere we would need to change the first 3 lines of the program to:
W=210; paper width H=297; paper height d=12.7; width of triangle base
Software Update
April 26, 2020
The following new math functions and operators have been added to
the software. Download the software and
recompile it to use them. Specifically, what's changed
is calcfun.c
and calcfun.h
, so you'll
need to recompile nell.c
. It's not necessary to
recompile nellsvg.c
.
New Functions
abs(x)
Returns the absolute value of x.int(x)
Returns the integer part of x.frac(x)
Returns the fractional part of x.if(x1,x2,x3)
If x1 evaluates to a number greater than zero then the value x2 is returned otherwise x3 is returned.rand(x)
Returns a random number uniformly distributed in the range [0,x]. The value of x can range from 1 to 2147483647. The sequence of random numbers generated by repeated calls to this function is determined by the random number generator seed. The seed is set using the srand function. The same seed will always generate the same sequence of random numbers.srand(x)
Sets the random number generator seed to the integer part of x. The return value is the seed.
New Operators
%
Modulo operator. x % y will return the remainder of x divided by y. Example 7 % 5 = 2. The operation is performed on the integer parts of x and y.<, <=, >, >=
Less than, less than or equal, greater than, greater than or equal operators. x < y evaluates to 1 if x is less than y otherwise it evaluates to 0. x <= y evaluates to 1 if x is less than or equal to y otherwise it evaluates to 0. x > y evaluates to 1 if x is greater than y otherwise it evaluates to 0. x >= y evaluates to 1 if x is greater than or equal to y otherwise it evaluates to 0.==, !=
Equal and not equal operators.x == y
evaluates to 1 if x and y are equal otherwise it evaluates to 0.x != y
evaluates to 1 if x and y are not equal otherwise it evaluates to 0.&&, ||
Logical AND and OR operators.x && y
evaluates to 1 if both x and y are positive otherwise it evaluates to 0.x || y
evaluates to 1 if x or y or both are positive otherwise it evaluates to 0.
Making graph paper - log-linear grid
March 26, 2020
Log-linear grid graph paper is commonly used in math and engineering. Let's make some with the Nell language. Below is a Nell program that will do it.
; Creates a log-linear sheet of graph paper. ; nell gploglin1.nll START 3 | nellsvg 8.5 11 in 0.01 1 > gploglin1.svg w=8.5; width h=11; height mt=0.5; margin at top mb=0.5; margin at bottom dw=0.5; dh=2.0; nx=w/dw-1; ny=(h-mt-mb)/dh; y=1; dy=1; H0 : P(0,mb+dh*log(y)/log(10.0)) L(w) A(y,y+dy); HL : S(H0,9) A(dy,dy*10); VL : [T(pi/2) M(mb) L(h-mt-mb)] M(dw); START : [S(HL,ny) S(H0,1)] M(dw) S(VL,nx);
The above program creates a vertical log spacing versus a horizontal linear spacing grid on a letter size (8.5x11 inch) paper. There are 5 decades of log spacing, each decade taking 2 inches, and 17 steps of linear spacing, taking 1/2 inch each. Note that the thickness of the grid lines is set here as 0.01 inches. All of these parameters can be changed in the program or command line. The command line for generating the svg is shown as a comment on the second line of the program.
Below is a version of the program for an A4 paper size (210x297 mm).
; Creates a log-linear sheet of graph paper. ; nell gploglin2.nll START 3 | nellsvg 210 297 mm 0.254 1 > gploglin2.svg w=210; width h=297; height mt=24; margin at top mb=23; margin at bottom dw=12; dh=50; nx=w/dw-1; ny=(h-mt-mb)/dh; y=1; dy=1; H0 : P(0,mb+dh*log(y)/log(10.0)) L(w) A(y,y+dy); HL : S(H0,9) A(dy,dy*10); VL : [T(pi/2) M(mb) L(h-mt-mb)] M(dw); START : [S(HL,ny) S(H0,1)] M(dw) S(VL,nx);
You can get pdf versions of the above mentioned graph paper below:
Here we have changed the default solid lines to dotted lines by
opening up the svg output files in inkscape, selecting the grid, and
choosing from the menu: Object | Fill and Stroke | Stroke
Syle
.
Making graph paper - square grid
March 21, 2020
Square grid graph paper is commonly used in math and engineering. Let's make some with the Nell language. Below is a Nell program that will do it.
; Creates a linear-linear sheet of graph paper. ; nell gplinlin.nll START 3 | nellsvg 8.5 11 in 0.01 0 > gplinlin.svg w=8.5; w = width of graph h=11; h = height of graph d=0.25; d = distance between lines HL : [T(-pi/2) L(w)] M(d); VL : [T(pi/2) L(h)] M(d); START : [T(pi/2) M(d) S(HL,h/d-1)] M(d) S(VL,w/d);
The above program creates a 1/4 inch square grid on a letter size (8.5x11 inch) paper. The command line for generating the svg is shown as a comment on the second line of the program. Note that the thickness of the grid lines is set here as 0.01 inches, which you can change to anything you like.
If you want to change the grid size from 1/4 inch to the more common 5 mm size, just replace the "d=0.25", on the fifth line of the program, with "d=5/25.4". For an A4 paper size (210x297 mm) with 5 mm grid size, the program below will work.
; Creates a linear-linear sheet of graph paper. ; nell gplinlin2.nll START 3 | nellsvg 210 297 mm 0.254 0 > gplinlin.svg w=210; w = width of graph h=297; h = height of graph d=5; d = distance between lines HL : [T(-pi/2) L(w)] M(d); VL : [T(pi/2) L(h)] M(d); START : [T(pi/2) M(d) S(HL,h/d-1)] M(d) S(VL,w/d);
You can get pdf versions of the above mentioned graph paper below:
Here we have changed the default solid lines to dotted lines by
opening up the svg output files in inkscape, selecting the grid, and
choosing from the menu: Object | Fill and Stroke | Stroke
Syle
.
Drawing a convex lens
March 17, 2020
A staple of geometric optics is the convex lens. Let's draw a biconvex lens with the Nell language.
A biconvex lens can be drawn as two arcs. From the figure, the distance
from the origin, o
,
defined as the point from which the first arc is drawn, to the
center of the lens is:
rc=r*cos(a)
The distance from the origin to the point where the second arc is drawn is:
x=2*rc
Based on the above, we can write the Nell program shown below.
; Creates a biconvex lens. ; nell biconvex.nll START 1 | nellsvg 13.2 5.6 cm 0.04 1 > biconvex.svg r = 7; r = radius of arc of lens surface a = pi/8; a = angle at drawing origin from x axis to top of lens rc = r*cos(a); rc = distance from drawing origin to center of lens x = 2*rc; x = point on x axis from which 2nd arc is drawn NONLENS : P(0.1,2.8) C(0.05) [M(rc) C(0.05)] [L(2*rc) C(0.05)] [T(a) L(r)] [T(-a) L(r)]; LENS : R(r,r,-a,2*a) M(x) R(r,r,pi-a,2*a); START : S(NONLENS,1) S(LENS,1);
The output is
Note: the 2nd line of the program gives the command for generating the output.
The code labeled NONLENS
are points and lines that
are not part of the lens.
Encircling a circle with circles
March 14, 2020
The program circ3.nll
in the book shows how to draw a
circle that is completely encircled by circles. Here we want to show
where the formulas for the distance from the center of the inner
circle to the center of an outer circle, as well as the radius of the
outer circles, comes from.
The isosceles triangle shown in the figure can be split into 2
identical right triangles with angles a/2
and b
. From one of these triangles, we see
that cos(b)=r/x
where we define x=r0+r
,
giving r=x*cos(b)
, which is the radius of the outer
circles. The distance from the center of the inner circle to the
center of an outer circle is just x
, which we can express
as
x=r0+r
=r0+x*cos(b)
Solving this for x
gives
x=r0/(1-cos(b))
.
The angle b
can be written in terms of the number of
circles encircling the inner circle, n
, as follows:
a = 2π/n
a + 2b = π
=> b = (π-a)/2 = (π-2π/n)/2 = π(n-2)/(2n)
Circles inscribed and circumscribed on a regular polygon
March 12, 2020
The program circ4.nll
in the book shows how to
inscribe a circle in a regular n
sided polygon. Here we
want to show where the formulas for inscribing and circumscribing
circles come from. If you draw lines from the center of a
regular n
sided polygon to each of the vertices, you will
divide the polygon into n
equal isosceles triangles. One
of these triangles is shown in the figure below.
φ = 2π/n
h = radius of inscribed circle
d = radius of circumscribed circle
θ = (π-φ)/2
From these parameters and some simple trigonometry we get
h = x*tan(θ)/2 = x/(2*tan(φ/2))
d = x/(2*cos(θ)) = x/(2*sin(φ/2))
The following is a Nell program for drawing both an inscribed and
circumscribed circle in a regular n
sided polygon.
; Creates a circle inscribed/circumscribed in an n-sided polygon. ; nell inscribed.nll START 10 | nellsvg 2 2 in 0.02 1 > inscribed.svg n = 5; x = 1; a = 2*pi/n; b = (pi-a)/2; h = x/(2*tan(a/2)); d = x/(2*sin(a/2)); T1 : L(x) T(a); START : P(0.5,0.25) <S(T1,n-1) Z()> T(b) M(d) C(d) C(h);
The output is
Note: the 2nd line of the program gives the command for generating the output.
Send questions or comments to:
Richard Hollos (richard[AT]exstrom DOT com)
Stefan Hollos (stefan[AT]exstrom DOT com)
Copyright 2021 by Exstrom Laboratories LLC