Crop
A Language for Crop Circles

The Main Idea

Crop circles are a fascinating subject. Whether you believe they're created by artists in the middle of the night, visiting extraterrestrials, both, or neither, there's no doubting that crop formations are frequently beautiful and remarkably diverse.

If you look at a lot of crop circle formations, you'll see many of the same underlying geometric ideas appearing over and over. Because of this regularity, Zef Damen has ben able to produce detailed, step-by-step geometric reconstructions of many formations. Part of the beauty of the subject is that crop formations combine these classical geometric ideas in new ways, just as composers combine existing notes to create new melodies.

While working on the subject of crop formations for one of my columns for IEEE Computer Graphics & Applications, I started to think of creating a symbolic shorthand notation that could capture the geometric essence of crop formations. This led to the language described here, which I call Crop.

Crop has three useful qualities. First, it is compact and easy to read. Second, it is a convenient way to create new patterns and analyze existing ones. Third, the language can be parsed to create diagrams, as well as specific, step-by-step instructions for forming the figure in the field.

The design of Crop is simple and its goals are modest: to represent crop circle formations efficiently in a form that can be parsed into construction steps. It is most certainly not a general-purpose programming language!

The description below is a shortened version of the language description to be published in the November 2004 issue of IEEE CG&A, and also discussed in detail in my book, Morphs, Mallards, and Montages: Computer-Aided Imagination (published by AK Peters, to appear Summer 2004).

If you want to see what Crop is able to represent, you can jump directly to the examples.

Details

Crop uses a postfix syntax, like Hewlett-Packard calculators and Adobe's PostScript language. If you're unfamiliar with postfix (also called reverse Polish notation), you can read about the basic technique here.

You can define variables within Crop, just as in any other language. The collection of all the variables that exist at any given time, along with their values, is called the dictionary. Initially the dictionary starts off empty, but there are a few special variables that get computed for you on the fly when you need them, as I'll discuss below.

There are three distinct types of objects in Crop: scalars (floating-point or integer numbers), points (represented by pairs of numbers), and objects (circles, ellipses, and polygons). In the following discussion, I'll label variables starting with the letters s, p, or o to identify their type (I'll also use i to refer to scalars that must be integers). I'll often include a letter or number after the type letter to suggest its meaning (e.g., I'll usually write sr for a scalar that defines a radius).

Crop is written in plain text, with tokens separated by white space. Any string of characters bounded by white space that doesn't have a predefined meaning is simply pushed on the stack as that string of characters. Anywhere a single space would do, you can insert as many spaces, tabs, carriage returns, or other white space that you want to improve legibility. The language is case-insensitive for all commands (so, for example, makepoint, makePoint, and MAKEPOINT all do the same thing), but it's case sensitive for variable names (so bob, BoB, and Bob are all distinct variables).

Let's start with the basic mathematical operations for calculating with scalars:

s1 s2 +
Push the sum s1+s2 onto the stack.

s1 s2 -
Push the difference s1-s2 onto the stack.

s1 s2 *
Push the product s1*s2 onto the stack.

s1 s2 /
Push the ratio s1/s2 onto the stack.

Points are obviously important for describing formations. We create a point by naming two scalars and then bundling them together with makePoint:

s1 s2 makePoint p
This puts the point (s1,s2) on top of the stack.

There's also a shortcut for the special point (0,0), also called the origin. You can use the symbol # any time to represent the origin (this is meant to remind us of the center of a coordinate system; I'd have used the plus sign, but that was taken!).

We can add and subtract points, and multiply and divide them by scalars:

p1 p2 p+
Add the components together and push the new point onto the stack.

p1 p2 p-
Subtract the components and push the difference onto the stack.

p1 s1 p*
Scale the components and push the scaled point onto the stack.

p1 s1 p/
Divide the components and push the scaled point onto the stack.

Note that the operators here are all prefixed with the letter p, giving us for example p+ instead of simply +. In computer science terms, the + operator is not overloaded (that is, built so that it works differently for different types of operands). If you try to add two points with +, rather than p+, you'll get an error. I think that for this little language, there's value to explicitly distinguishing these operators.

We can also find the distance between two points:

p1 p2 distance
This pushes the scalar distance |p1-p2| onto the stack.

To name an object so we can use it later, we use the name command. This takes whatever object is on top of the stack (a scalar, point, or object) and assigns it to the given name. You can redefine a name any time by just assigning a new value to it.

pso varname name
For example, you might say 3.14 pi name to create a value for pi, or p1 p2 + 2 / midpoint name to set the variable midpoint to the point between p1 and p2. This makes it easy to refer to the same thing multiple times in your formation without creating it anew each time. You don't need to declare the types of your variables - the type is inferred from the assignment. Each time you assign a new value to a variable, the variable adopts the type of the object it's been assigned to.

Okay, that finishes up the foundation. Let's make some geometry! Our three stars of the geometry world are line, ellipse, and circle:

< p0 p1 p2 ... pn > line
Draws a line from p0 to p1, then to p2, and so on, to pn. Requires a minimum of two points.

p < s1 s2 ... sn > circle
Draws concentric circles centered at p, with radii s1, s2, and so on. Requires at least one radius.

pp pq ss ellipse
Draws an ellipse using the points pp and pq as foci, and a string of length ss.

The line and circle commands use lists. A list is just a sequence of values between angle brackets. The angle brackets are necessary, even if the list has just one or two elements. Lists cannot be empty (or else you'd be drawing nothing).

Lines naturally create polygons. Crop supports regular polygons, or n-gons. Here are the commands that create circles, ellipses, and polygon objects (Each of these commands pushes the new-constructed object onto the top of the stack.):

pc sr makeCircle
pp ps ss makeEllipse
pc in sr sa makeNgon

A circle is defined by a center pc and a radius sr. An ellipse is defined by two points pp and ps and a length ss. A polygon is defined by a center pc, the number of sides in, a radius sr, and an angle sa.The radius is the distance from the center to the first vertex. The angle is the number of degrees to rotate the polygon clockwise. If the angle is zero, the first vertex lies on the +X axis. As a convenience, the special character % can be used for the angle rather than a number - this means to rotate the polygon 180/in degrees: this puts the midpoint of the last edge on the +X axis. The percent sign (two circles and a line) is meant to remind us of the edge between two vertices.

The next command we'll look at is trope, which takes four arguments: two points and two scalars. The name is a contraction of "triangle-rope," which is a way to think of locating points in the field. Suppose you have two points A and B, and you know you want to find a new point that is a distance a and b from each point, respectively. You can do this with a rope that has those lengths marked off on it, and friends standing at the two points. I call this loop a "triangle-rope", so the command that emulates it is trope:

pa pb sa sb trope

trope finds the two points that are simultaneously a distance sa from pa, and a distance sb from pb. It selects the point that's on the left side of the line from pa to pb, and pushes that point onto the top of the stack. The geometry for computing this point requires finding the intersections of two circles; the details are in my column and book.

Another way to find a point with respect to other points is with the pwalk command:

o1 p1 sd pwalk

This command takes an object o1, a starting point p1, and a distance sd to walk clockwise around the perimeter of that object, and pushes the newly-computed point back onto the stack. Note that the distance is not the straight line between the starting point and the ending point, but instead is the distance as measured along the object itself. If the object is a circle or ellipse, then the point is found by walking along the curve. If the object is a polygon, then we walk along the polygon's edges until we've covered the necessary distance.

As a convenience, before pwalk begins it looks at the starting point, and if it's not already on the perimeter of the object, it moves the starting point temporarily to its nearest point on the perimeter.

Related to pwalk is pspin:

o1 p1 sd pspin

This command takes an object o1, a starting point p1, and an angle sd about which to rotate that point clockwise around the center of the object. Like pwalk, this command will move the resulting point to the nearest point on the perimeter of o1 if it's not already on there.

Many crop formations are built on a structure defined by one or more regular polygons. We've seen above how to define a polygon. Now we'll see how to use a polygon to drive the formation of a structure. In many ways, the next command is the heart of Crop:

[ commands ] pc in sr sa ngonloop

Like makengon, the values pc in sr sa define a polygon with a center at pc, made of in points, with a radius sr, rotated clockwise by an angle sa. As before, sr is the distance from the center to each vertex, and sa is an angle in degrees to rotate the polygon clockwise (and again, the special character % used here means to rotate the polygon 180/in degrees).

The stuff between the square brackets gets executed in times, once for each vertex in the polygon. What makes this loop special is that while a loop is executing, variables beginning with the letter V take on a special meaning: they refer to the vertices of the polygon. The system takes the rest of the name of the variable and interprets it as a number (if you use variables in the loop that begin with V but aren't immediately followed by an integer, you'll get an error).

The variable V0 has the value of the current vertex (that is, it's a point). The variable V1 is the next point clockwise around the polygon, V2 is the one after that, and so on. Variable V-1 is the point preceding the current point (that is, counter-clockwise from V0), V-2 is the one counter-clockwise from that one, and so on. Note that V-2 is a variable name, not an arithmetic expression (both because Crop is not an infix language, and because V-2 has no spaces).

Another special variable is LC, which stands for LoopCount. This is an integer that tells us how many times the loop has been completed. The first time through the loop, LC is zero. The next time it's one, and so on.

Before the loop begins, the system saves the current stack. When the loop is finished, the stack is reset to its saved condition. Each iteration of the loop begins by clearing the stack (the dictionary is left intact). On the first iteration, the current vertex (that is, V0) is the vertex on the positive X axis (assuming that the angle is zero; if it's not, we use the first vertex in its rotated position). Then the commands are executed as usual, with the only exception that the V variables refer to vertices as described above. When the last command has been executed, the stack is cleared, the current vertex is moved to the next one in a clockwise direction, and the commands are executed again.

You can nest loops if you want, for example by putting one ngonloop inside another. The variables V0, V1, V-1, and so on, as well as LC, refer to the innermost loop in which they appear. If you want to refer to the vertices of the polygon in an outer loop, append a prime to the variable name. Thus V1' refers to the vertex after the current one in the polygon one loop up, and V-2'' refers to the vertex two steps before the current one in the polygon two loops up. Similarly, LC' refers to the loop count in the loop one up, LC'' goes two loops up, and so on. Each polygon loop can of course have a different center, radius, and number of vertices. In fact, a common idiom is to place the center of an inner polygon on the vertices of an outer one.

For example, suppose we want to place a small pentagon on each vertex of a big triangle, and draw a line from each vertex of each pentagon to the vertex of the triangle it's centered upon. To make things more interesting, let's rotate each pentagon so that it's first vertex lies on the line from the center of the triangle to the center of the pentagon. We could write:

[ [ < V0 V0' > line ]
V0 5 1 LC 120 * ngonloop
] # 3 6 0 ngonloop

In the innermost loop, V0 refers to the current vertex of the pentagon, and V0' refers to the current vertex of the triangle. The expression LC 120 * rotates the pentagon based on how many times we've gone through the triangle loop.

That's it for the body of the language. There are a few miscellaneous housekeeping commands that are common to most postfix languages:

pop
This command takes no arguments; it just pops the top element off the stack and discards it.

printDictionary
This command takes no arguments; it prints the complete current dictionary to the output.

printStack
This command takes no arguments; it prints the current stack to the output.

// comment
Anything after a pair of double slashes is considered a comment until the end of the line.

This wraps up the Crop language as it stands today. Crop is a completely phenomenological language, designed to match the formations that I've looked at and tried to replicate compactly. I've tried hard to keep it as simple and small as possible, while also remaining legible and easy to understand. I encourage readers to extend the language if they think of other commands that are as simple and useful as the ones above.

Examples

Consider the very pretty "Folly Barn 2001" crop formation. The formation itself is shown below on the left, and on the right is its geometric skeleton.


As you can see, the formation consists of fifteen circles and a triangle. Excluding the triangle (which isn't necessary to make the formation), we can represent this formation in Crop with just three lines of code:

[ V0 < 3.46 3.64 > circle ] # 3 2 0 ngonloop
[ V0 < 2.46 2.64 > circle ] # 3 1 0 ngonloop
# < 1 5.64 0.09 > circle

The first two lines create the twelve circles that make up the crescents. The last line creates the three circles corresponding to the innermost dot, the circle around it, and the large circle surrounding the whole figure.


The example above is the "Tegdown Hill 2003" formation. The Crop code for this geometry has four lines of setting variable values, and only two lines of actual geometry-making instructions:

1.0 Ar name
1.08565 Br name
0.732051 Cr name
0.646402 Dr name
[ V0 < Ar Br Cr Dr > circle ] # 6 Ar 0 ngonloop
# < Ar Br > circle


The example above is the "Windmill Hill 2003" formation. The Crop version is only four lines long:

# < 10.3 > circle
[ V0 < 1.6 > circle ] # 5 1 0 ngonloop
[ V0 < 2.4 > circle ] # 5 1.3 0 ngonloop
[ V0 < 6.1 6.4 > circle ] # 5 3.2 0 ngonloop


Above is the "West Stowell 2003" formation. The Crop code for this example shows the use of the line command, and the use of % in the ngonloop command (note that the circles are are positioned between the points of the stars):

1 Ar name
Ar 5 * 64 / Br name
Ar 30 * 64 / Cr name
Ar 64 / Dr name
# < Ar > circle
[ < V0 V5 > line ] # 13 Ar 0 ngonloop
[ V0 < Br > circle ] # 13 Ar % ngonloop
[ V0 < Dr > circle ] # 13 Cr % ngonloop


The formation and skeleton above are an original design that I created for my first live field test of Crop. Here's the source code for the central iris and the swirls that make up the "pendant" hanging on the "necklace" of circles:

// make central iris
[ V0 < 25.290 30.708 > circle ]
# 5 18 0 ngonloop
// make outer swirls
25.108 d1 name
44.251 d2 name
17.576 d3 name
# 5 118 0 makengon N1 name
[
N1 V0 d1 pwalk < d1 > circle
N1 V0 d2 pwalk < d2 > circle
V0 V1 distance edgelen name
N1 V0 edgelen d1 - pwalk < d1 > circle
N1 V0 edgelen d2 - pwalk < d2 > circle
N1 V0 edgelen d3 - pwalk < d3 > circle
]
# 5 118 0 ngonloop

I used this Crop code to guide the construction of this formation, created with a pressure washer on top of a parking structure with the help of two friends.

More Info

This discussion of Crop was adapted from the material in my November 2004 column in IEEE CG&A, and also in my book, Morphs, Mallards, and Montages: Computer-Aided Imagination (published by AK Peters, to appear Summer 2004), where there is more discussion of crop circles and related phenomena (including a clear presentation of all five Hawkins' Theorems, proofs of each one, and a summary of the fascinating social history of the theorems and their tantalizing near-publication over many years).

There are dozens of websites devoted to crop circles. Many of them contain extensive libraries of beautiful color photographs of formations found in the field, as well as discussions of different theories of construction and interpretation. Most sites provide a wealth of links to other sites, so once you get started, it's easy to spend a long time browsing. Some good sites to get a running start into the subject include (in alphabetical order) BLT Research, Circlemakers, Crop Circle Connector, Crop Circle Info, The Crop Circular, FGK, Invisible Circle, Kores, Swirled News, and Temporary Temples.

I wrote my Crop interpreter in Microsoft's C#. It's a standalone program that reads a text file of Crop commands and produces either a PostScript file of the formation, step-by-step instructions for creating the pattern, or both. My prototype developed as the language did, so it's not very clean code, and it has no error handling (if there's a syntax or other error, the program simply crashes!). I hope to clean up the interpreter and post the code here before too long. But the description above is complete, and if you're handy with programming you should be able to roll your own pretty easily.