In order to introduce computation to non-programmers, the ANAR+ library implements a version of the LOGO language with its well-known turtles.
With the initial aim to let kids discover geometry and logic in a playful way, the LOGO language was developed among others by Seymour Papert, a mathematician and developmental psychologist, former student of Piaget. It consisted on a 2D graphic world were turtles can be controlled through simple instructions. They can themselves trace a line along their path enabling kids to draw through instructions. The use of such virtual turtles allowed for immediate visual feedback and debugging
One of the important feature of the language is the notion of intrinsic geometry: instructions to the turtle are meant in a local frame of reference. Another is its procedural nature, which is however not implemented in the ANAR+ library.
The implementation is meant to be faithful to the original LOGO. However, since the library has a 3D world, some additional commands are needed to control the turtle in the extra dimension.
The simplest way to use a Turtle from the ANAR+ library is shown in the code below:
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); } void draw(){ background(200); t.draw(); }
now that you have a turtle, issue some instructions to it, stepping into the 3rd dimension
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); t.FORWARD(10); t.LEFT(80); t.UP(25); t.FORWARD(30); t.LEFT(80); t.FORWARD(50); t.DOWN(50); t.LEFT(80); t.FORWARD(70); // equivalent in a single line //t.LOGO("fd 10 lt 80 up 25 fd 30 lt 80 fd 50 dn 50 lt 80 fd 70"); } void draw(){ background(200); t.draw(); }
repeat the same set of instructions as much as you like
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); t.REPEAT( 10, "fd 10 lt 80 up 25 fd 30 lt 80 fd 50 dn 50 lt 80 fd 70"); // equivalent //t.LOGO("repeat 10 [fd 10 lt 80 up 25 fd 30 lt 80 fd 50 dn 50 lt 80 fd 70]"); } void draw(){ background(200); t.draw(); } void keyPressed(){save("ggg.jpg"); print("saved");}
Below are presented the most useful LOGO commands implemented. Refer to the JavaDoc Turtle page for additional functionality
| command | abbreviated | description |
|---|---|---|
| FORWARD n | FD n | go forward n units |
| BACK n | BK n | go backwards n units |
| RIGHT n | RT n | turn right by n degree |
| LEFT n | LT n | turn left by n degree |
| UP n | UP n | turn up by n degree |
| DOWN n | DW n | turn down by n degree |
| PENUP | PU | stop drawing |
| PENDOWN | PD | start drawing |
| CLEARSCREEN | CS | clear screen |
| SETPENCOLOR r g b | SETPC r g b | change pen color |
| REPEAT n [ … ] | not abbreviated | repeat n times instructions in brackets |
| HOME | HM | reset the turtle at the origin |
It is possible to mix LOGO and JAVA in the same sketch. For instance for () is the equivalent of REPEAT in JAVA.
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); for(int i=0; i<250; i++) { t.RT(1); t.UP(1); t.FORWARD(1); } // LOGO equivalent using repeat //t.LOGO("repeat 250 [rt 1 up 1 fd 1]"); } void draw(){ background(200); t.draw(); } // this saves a frame when pressing any key void keyPressed(){ save("frame.jpg"); print("saved"); }
The advantage of using JAVA is the possibility to use the number of iteration into a LOGO instruction (note the 'i' in t.FORWARD(i))
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); for(int i=0; i<250; i++) { t.RT(1); t.UP(1); t.FORWARD(i); // equivalent //t.LOGO("rt 1 up 1 fd "+i); } } void draw(){ background(200); t.draw(); }
It is also possible to test for an iteration value using if ().
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); for(int i=0; i<250; i++) { t.RT(1); if (i==100) t.UP(90); t.FORWARD(1); } } void draw(){ background(200); t.draw(); }
For the use of randomness it is possible to make use of processing built-in functions.
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); for(int i=0; i<250; i++) { t.RT(random(45)); t.UP(1); t.FORWARD(i); // equivalent //t.LOGO("rt "+random(45)+" up 1 fd "+i); } } void draw(){ background(200); t.draw(); }
If more complex arithmetics is needed, it is possible to use JAVA variables
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(); for(int i=0; i<1000; i++) { float a = 10*sin(i/10.0); t.RT(a); t.UP(1); t.FORWARD(1); // equivalent //t.LOGO("rt "+a+" up 1 fd 1"); } // the variable a is no longer available in this part of the code // it only exists within the block of the for loop // this is related to the notion of variable *scope* Anar.camTarget(t.trace); } void draw(){ background(255,155,155); t.draw(); }
The code can be simplified into blocks encapsulated in JAVA functions.
import processing.opengl.*; import anar.*; Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(); for(int i=0; i<10; i++) { DOTTED(10); t.RT(36); } Anar.camTarget(t.trace); } // a dotted line using penUp and penDown serval times // example logo instruction REPEAT 10 [ FD 1 PU FD 1 PD ] void DOTTED(int L){ t.LOGO("REPEAT "+L+" [ FD 1 PU FD 1 PD ]"); } void draw(){ background(255,155,155); t.draw(); }
Alternatively it is possible to write LOGO instructions in a separate file and read it from processing
import processing.opengl.*; import anar.*; /* * Example for Anar library by Guillaume LaBelle + Julien Nembrini * http://anar.ch */ Turtle t = new Turtle(); void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); String[] stuff = loadStrings("my.logo"); println(stuff); for(int i=0; i<stuff.length; i++) t.LOGO(stuff[i]+" "); } void draw(){ background(200); t.draw(); }
with the the following file my.logo located in <sketch folder>/data
forward 100 lt 45 forward 100 repeat 100 [ forward 5 rt 5 up 6 forward 3 lt 5 forward 2 ]
Nothing prevents from having several turtles at the same time. Below an example using the parametric capabilities of ANAR+:
JAVA uses the concept of object. One example is the Turtle object. This object can be made to have more capabilities by extending it. The code below show how to add a DOTTED line capability to the turtles.
import processing.opengl.*; import anar.*; /* * Example for Anar library by Guillaume LaBelle + Julien Nembrini * http://anar.ch */ SuperTurtle t = new SuperTurtle(); class SuperTurtle extends Turtle { // this is needed for Java SuperTurtle() { super(); } // this is a function that will draw a dotted line of length l // with dots of length dl void DOTTEDLINE (float l, float dl) { // transform from float to int int ll = int(l); int dd = int(dl); // compute the number of dots/undots int nDots = ll/dd; // start pen down boolean drawing = true; for (int i=0; i<nDots; i++) { if (drawing) LOGO("pd fd "+dl); else LOGO("pu fd "+dl); // alternate drawing and not drawing drawing = !drawing; } // draw the remaining length // works also if the dot is longer than the length if (ll%dd > 0) LOGO("pd fw "+ll%dd); // make sure at the end that the pen is up // for next move LOGO("pu"); } } void setup(){ size(800,400,OPENGL); Anar.init(this); Anar.drawAxis(true); for(int i=0; i<200; i++) { float a = 100; t.RT(random(10)); t.DOTTEDLINE(a,9); for (int j=0; j<200; j++) { float b = 5; t.LOGO("up "+random(3)+" lt "+random(4)); b++; } } Anar.camTarget(t.trace); } void draw(){ background(255,25,25); t.draw(); }