10 Recursion+interfaces

Slideshow Version

Libraries (Interfaces), Importing Files, and Recursion

This module covers three independent concepts.

The first is the power existing code libraries offer a designer. This will include a demonstration of how to import existing libraries into Processing sketches. We’ll demonstrate this by importing a interface library.

The second is the power of importing/ exporting geometry or data. This allows designers to use existing models and information as input for their code. Also it allows output in the form of geometric products, text, etc. for use with other software tools.

The last is the process called recursion. We will briefly discuss the power it offers designers, and how to implement it in our code.

Readings

Reading 1: In Processing, read “Shape 2: Parameters, Recursion”, pgs 197-204

Unassigned: We will use several libraries today — some of which have great documentation. Necessity may require a familiarization with the documentation for controlP5, OBJLoader, iGEO, etc.

Assignment

There is no assignment based on this week’s material.

Instead students continue work on their final projects.

EVERYONE MUST HAVE A ‘CODE CONSULTATIONNEXT WEEK.

Before (12:30-1:30), possibly during, or after (3:30-5:00) next week’s class

We have a juror coming to help supply everyone with technical assistance.

It would be GREAT to push your projects to “within viewing distance of the end” next week…

Libraries

So, what are Processing Libraries?

We looked at much of Processing’s core functionality in this class.

We started with the API. We’ve explored any of the embedded functions and data models.

Now lets talk about how to extend Processing’s functionality to non-core uses…

Libraries — They’re like work you use all the time…

For example, suppose you do a lot of 3D work in Processing, and you write a few rotate() methods to spin around your 3D model to inspect the sides and back. Perhaps you make these rotate() functions dependent on right-click and right-drag, so that the interface behaves like Rhino.

Naturally, this is very useful in iterative workflow. As a result, in each sucessive sketch’s draw() code bracket, you copy-and paste the same rotate() lines of code.

Eventually, this grows tiresome. Processing has a tool to import other people’s code to use their functionality.

That imported code must be encapsulated…

Time out! “Encapsulation”?

Encapsulation — the bundling of data with the methods that operate on that data.

(Often that definition is misconstrued to mean that the data is somehow hidden. In Java, you can have encapsulated data that is not hidden at all.)

Great discussions here, here, but this is overly JAVA-specific

Time in! Ok, how do I use a Processing Library?

The following libraries are included with the Processing software.

Video, Network, Serial, PDF Export, OpenGL, Minim, DXF Export, Arduino, Netscape.JavaScript

To add one to a project, select its name from the “Import Library…” option in the Sketch menu.

These libraries are open source; the code is distributed with Processing.

Wait, “OpenGL”? We used that last week! We’re already using Library?

Yes.

The only new code was that first line import processing.dxf.*; and “OPENGL” in the size() method. Do you remember?

Let’s use another Library: DXF Export

We can add that import... code line ourselves, or use the processing GUI.

Let’s use an example of the DXFExport library next.

Try this, and play with the part that says… // FIDDLE WITH DRAWING COMMANDS HERE!


            import processing.dxf.*;
          
            boolean record;
          
            void setup() {
              size(700, 700, P3D);
            }
          
            void keyPressed() {
              // use a key press so that it doesn't make a million files
              if (key == 'r') record = true;
            }
          
            void draw() {
              if (record) {
                beginRaw(DXF, "output.dxf");
              }
          
              //  FIDDLE WITH DRAWING COMMANDS HERE!
              drawSomething();
          
              if (record) {
                endRaw();
                println("done");
                record = false;
              }
            }
          
            void drawSomething() {
              pushMatrix();
              translate(width/2, height/2);
              for  (int i=0; i < 360; i++) {
                pushMatrix();
                rotate(radians(i));
                line(0,0, random(width/2), 0);
                popMatrix();
              }
              popMatrix();
              delay(1000);
            }
          

Great. I exported a DXF. Where?

The “output.dxf” file you made should be in your code’s folder. This is typical.

Currently the file is over-written every time the user hits “r”. How can we prevent this from happening?

How did someone write this library? Change exported file’s extension from .DXF to .TXT and discuss

Another useful library – Physics (formerly TraerPhysics)

This library helps Processing users use Particle Systems.

We have been making our own rudimentary Particle Systems over the last few weeks. Oh the comic misery that is “thisDot.”

A Particle System is a collection of independent objects, often represented by a simple shape or dot.

Another useful library – Physics (formerly TraerPhysics)

A Particle System can be used to model many irregular types of natural phenomena, such as explosions, fire, smoke, sparks, waterfalls, clouds, fog, petals, grass, bubbles, and so on.

In a system, each particle will have its own set of properties related to its behavior (for example, velocity, acceleration, etc.) as well as its look (for example, color, shape, image, etc.).

Particle System libraries can implement environmental behaviors too Springs (axial force), Gravity (universal attraction), Friction (motion damping), and all sorts of cool resulting behaviors.

(Physics is) Particle Systems… more

Sand in gravity…

Particle Systems… and still more

Springs as a mesh/net…

Physics – 02 – Download required

First, go to the Processing Libraries page and notice how Physics is not above-the-fold.

This means that Physics did not ship, or install, with the original Processing installation that the DM staff provided. The Processing installation is designed to be granular, and project specific, saving everyone bandwidth and time.

As a result, we must manually download this library, and install it somewhere the Processing system knows to find it.

DOWNLOAD THE PHYSICS LIBRARY + SOURCE NOW

Physics – 03 – Put the Library Where Processing can Find It

Where does the web browser download that file? We have to manually install it inside the local Processing installation. Here’s more description of what we are doing…

UnZip it, and put it in:

[OS X] User → Documents → Processing → Libraries

…or…

[Windows] User → My Documents → Processing → Libraries (I think…)

As before, simply select this library from Processing’s “Sketch → Import Library…” submenu.

Physics – Example 1 – Pendulum

FIRST: Do you see that this is mostly Class Implementation (Week 11)?
ALSO: Scroll down here to inspect the super-short API with me.


            import traer.physics.*;
          
            ParticleSystem physics;
          
            Particle p;
            Particle anchor;
            Spring s;
          
            void setup()
            {
              size( 400, 600 );
              smooth();
              fill( 0 );
              ellipseMode( CENTER );
          
              physics = new ParticleSystem( 1, 0.01 ); // AIR RESIST HERE
          
              p = physics.makeParticle( 1.0, width/2, height/2, 0 );
              anchor = physics.makeParticle( 1.0, width/2, height/4, 0 );
              anchor.makeFixed(); 
              s = physics.makeSpring( p, anchor, 0.5, 0.1, 275 ); //275 REST LENGTH HERE
            }
          
            void mousePressed()
            {
               p.makeFixed(); 
               p.position().set( mouseX, mouseY, 0 );
            }
          
            void mouseDragged()
            {
              p.position().set( mouseX, mouseY, 0 );
            }
          
            void mouseReleased()
            {
               p.makeFree(); 
            }
          
            void draw()
            {
              physics.tick();
          
              background( 255 );
          
              line( p.position().x(), p.position().y(), anchor.position().x(), anchor.position().y() );
              ellipse( anchor.position().x(), anchor.position().y(), 5, 5 );
              ellipse( p.position().x(), p.position().y(), 20, 20 );
            }
          

Physics – Example 2 – Meshes

This cloth example is helpful when aiming for complex, local behaviors. Many have used it and simply not drawn the springs to help viewers focus on other effects…


            import traer.physics.*;
          
            ParticleSystem physics;
            Particle[][] particles;
            int gridSize = 10;
          
            float SPRING_STRENGTH = 0.2;
            float SPRING_DAMPING = 0.05;
          
            void setup()
            {
              size(700, 600);
              smooth();
              fill(0);
          
              physics = new ParticleSystem(0.1, 0.01);
          
              particles = new Particle[gridSize][gridSize];
          
              float gridStepX = (float) ((width / 2) / gridSize);
              float gridStepY = (float) ((height / 2) / gridSize);
          
              for (int i = 0; i < gridSize; i++)
              {
                for (int j = 0; j < gridSize; j++)
                {
                  particles[i][j] = physics.makeParticle(0.2, j * gridStepX + (width / 4), i * gridStepY + 20, 0.0);
                  if (j > 0)
                  {
                    physics.makeSpring(particles[i][j - 1], particles[i][j], SPRING_STRENGTH, SPRING_DAMPING, gridStepX);
                  }
                }
              }
          
              for (int j = 0; j < gridSize; j++)
              {
                for (int i = 1; i < gridSize; i++)
                {
                  physics.makeSpring(particles[i - 1][j], particles[i][j], SPRING_STRENGTH, SPRING_DAMPING, gridStepY);
                }
              }
          
              particles[0][0].makeFixed();
              particles[0][gridSize - 1].makeFixed();
          
            }
          
            void draw()
            {
              physics.tick();
          
              if (mousePressed)
              {
                particles[0][gridSize - 1].position().set(mouseX, mouseY, 0);
                particles[0][gridSize - 1].velocity().clear();
              }
          
              noFill();
              background(255);
              
              /*
              fill(0);
              for (int i = 0; i < gridSize; i++){
                for (int j = 0; j < gridSize; j++)
                {
                  ellipse(particles[i][j].position().x(), particles[i][j].position().y(), 25, 25);
                }
              }
              noFill();
              */
          
              for (int i = 0; i < gridSize; i++)
              {
                beginShape();
                curveVertex(particles[i][0].position().x(), particles[i][0].position().y());
                for (int j = 0; j < gridSize; j++)
                {
                  curveVertex(particles[i][j].position().x(), particles[i][j].position().y());
                }
                curveVertex(particles[i][gridSize - 1].position().x(), particles[i][gridSize - 1].position().y());
                endShape();
              }
              for (int j = 0; j < gridSize; j++)
              {
                beginShape();
                curveVertex(particles[0][j].position().x(), particles[0][j].position().y());
                for (int i = 0; i < gridSize; i++)
                {
                  curveVertex(particles[i][j].position().x(), particles[i][j].position().y());
                }
                curveVertex(particles[gridSize - 1][j].position().x(), particles[gridSize - 1][j].position().y());
                endShape();
              }
            }
          
            void mouseReleased()
            {
              particles[0][gridSize - 1].velocity().set( (mouseX - pmouseX), (mouseY - pmouseY), 0 );
            }
          

Physics – Example 3 – Attraction

This particle attractor is how we’ve seen previous drawings get made… all the particles act like planets orbiting a attractor “sun”.


            import traer.physics.*;
          
            int numParts = 30;
          
            Particle mouse;
            Particle[] parts;
            ParticleSystem physics;
          
            void setup()
            {
              size( 600, 800 );
              frameRate( 24 );
              smooth();
              ellipseMode( CENTER );
              noStroke();
              noCursor();
          
              physics = new ParticleSystem();
              mouse = physics.makeParticle();
              mouse.makeFixed();
              parts = new Particle[ numParts ];
              for (int i=0; i < numParts; i++){
                parts[i] = physics.makeParticle( 1.0, random( 0, width ), random( 0, height ), 0 );
              }
              for (int i=0; i < numParts; i++){
                physics.makeAttraction( mouse, parts[i], 7000, 100 );
              }
            }
          
            void draw()
            {
              mouse.position().set( mouseX, mouseY, 0 );
              for (int i=1; i < numParts; i++){
                handleBoundaryCollisions( parts[i] );
              }
              physics.tick();
          
              background( 255 );
          
              stroke( 0 );
              noFill();
              ellipse( mouse.position().x(), mouse.position().y(), 35, 35 );
              for (int i=1; i < numParts; i++){
                fill( i*10 );
                ellipse( parts[i].position().x(), parts[i].position().y(), 15, 15 );
              }
            }
          
            // really basic collision strategy:
            // sides of the window are walls
            // if it hits a wall pull it outside the wall and flip the direction of the velocity
            // the collisions aren't perfect so we take them down a notch too
            void handleBoundaryCollisions( Particle p )
            {
              if ( p.position().x() < 0 || p.position().x() > width )
                p.velocity().set( -0.9*p.velocity().x(), p.velocity().y(), 0 );
              if ( p.position().y() < 0 || p.position().y() > height )
                p.velocity().set( p.velocity().x(), -0.9*p.velocity().y(), 0 );
              p.position().set( constrain( p.position().x(), 0, width ), constrain( p.position().y(), 0, height ), 0 ); 
            }
          

Physics and Final Projects

Urbanism and RANDOM ARBORETUM

Unique Drawings and TENDRILS

Particles, Gravity and BOX

Drawings, Particles, Attractors and METROPOP DENIM

Solving today’s Original Problem – Camera Orbiting with peasycam

This library provides a simple mouse-driven camera operations for Processing.

The download is hosted here.

… and there is little to implement… just add the following to most sketches:


          PeasyCam camera;
          
          void setup() {
            camera = new PeasyCam(this, 0, 0, 0, 50);
          }
          

Camera Control example with peasycam

Remember to try orbiting, panning, and zooming…


            import peasy.*;
          
            PeasyCam cam;
          
            void setup() {
              size(600, 600, P3D);
              cam = new PeasyCam(this, 100);
              cam.setMinimumDistance(50);
              cam.setMaximumDistance(500);
            }
            void draw() {
              rotateX(-.5);
              rotateY(-.5);
              background(255);
              fill(150);
              box(20);
          
          
              for (int i=25; i < 70; i+=10) {
                pushMatrix();
                translate(0, 0, i);
                fill(75);
                box(5);
                popMatrix();
              }
            }
          

Orbit example with peasycam

… you know… about five more lines of code could make that sketch viewable with 3D glasses

Another useful library – controlP5

This is a Graphic User Interface library for Processing.

Don’t you hate launching an app, and then realizing you would like to adjust one variable? This usually means stopping the app, re-setting the variable value, and relaunching.

Or you could set up a slider bar…

Installing controlP5

Download the library from here, saving the zipped folder locally.

Unzip and put the extracted controlP5 folder into the libraries folder of your processing sketches. Reference and examples are included in the controlP5 folder.

Detailed instructions are here.

Sliders in controlP5


            /**
              * ControlP5 Slider.
              *
              * by andreas schlegel, 2009
              */
          
            import controlP5.*;
          
          
            ControlP5 controlP5;
          
            int myColorBackground = color(0,0,0);
          
            int sliderValue = 100;
          
            void setup() {
              size(400,400);
              controlP5 = new ControlP5(this);
              controlP5.addSlider("slider",100,200,128,100,160,100,10);
              controlP5.addSlider("sliderValue",100,200,100,100,200,100,10);
            }
          
            void draw() {
              background(myColorBackground);
              fill(sliderValue);
              rect(0,0,width,100);
            }
          
            void slider(int theColor) {
              myColorBackground = color(theColor);
              println("a slider event. setting background to "+theColor);
              controlP5.controller("sliderValue").setValue(theColor);
            }
          
            void keyPressed() {
              controlP5.controller("sliderValue").setValue(150);
            }
          

Cool things in controlP5


            // ControlP5quick
            // this example demonstrates how to quickly add Controllers such as
            // Button, Slider,Toggle and Numberbox to a sketch without having to set
            // positions, this is done automatically by controlP5.
            // controllers will be aligned horizontally - .linebreak() will
            // force the next controller to the next line.
            // the example shows as well how to link variables and functions to
            // a controller. this is done by assigning the name of the variable
            // or function to a controller.
            //
            // by andreas schlegel 2010
            //
          
            import controlP5.*;
          
            ControlP5 controlP5;
          
            float s1 = 5;
            float s2 = 2;
            boolean t1 = true;
            boolean t2 = true;
            boolean t3 = true;
            boolean t4 = true;
            float n1 = 100;
            int n2 = 50;
          
            void setup() {
              size(600,400);
              controlP5 = new ControlP5(this);
              controlP5.addButton("b1",1);
              controlP5.addButton("b2",2);
              controlP5.addButton("b3",3);
              controlP5.addButton("b4",4).linebreak();
              controlP5.addSlider("s1",0,10);
              controlP5.addSlider("s2",0,10).linebreak();
              controlP5.addButton("b5");
              controlP5.addToggle("t1");
              controlP5.addToggle("t2");
              controlP5.addToggle("t3");
              controlP5.addToggle("t4").linebreak();
              controlP5.addNumberbox("n1");
              controlP5.addNumberbox("n2");
            }
          
            void draw() {
              background(0);
              if(t1) {
                fill(s1*25);
                rect(0,200,150,height);
              }
              if(t2) {
                fill(s2*25);
                rect(150,200,150,height);
              }
              if(t3) {
                fill(n1);
                rect(300,200,150,height);
              }
              if(t4) {
                fill(n2);
                rect(450,200,150,height);
              }
            }
          
            void b1(int theN) {
              println(theN);
            }
          
            void b2(int theN) {
              println(theN);
            }
          

NURBS Surface handling – iGeo

During his visit to the “Is Drawing Dead?” Symposium, Casey Reas told me about an new library — one that handles NURBS Surfaces.

“A 3D modeling software library for computational design in architecture, product design, interaction design and more. It includes libraries of vector math operations, NURBS curve and surface geometries, polygon meshes and 3D model file I/O.”

I have yet to test iGEO.

Importing Files

Importing

Processing can read data (and thus act on data) from elsewhere on the computer, on the internet, or other accessible sources.

The next few slides will demonstrate how to load such external data as files, and use the information.

Importing Text Data – 01

First, let’s Processing to open a .TXT file, read the data, and draw with it.

We will need the following line pasted into a .TXT file called “positions.txt” and saved in our sketch…


          15,323,234,345,542,123,091,55,345,165,76,222
          

Importing Text Data – 02

Now, let’s look at how this sketch uses that file’s data…


            String[] pts;
            String[] f;
            int index = 0;
          
            void setup() {
              size(600, 800);
              background(0);
              stroke(255);
              frameRate(12);
              f = loadStrings("positions.txt");
            }
          
            void draw() {
              pts = split(f[0], ',');
              for (int i=0; i < pts.length; i++){
                int x = int (pts[i]) ;
                int y = int (pts[i]) ;
                ellipse(x, y, 15, 15);
              }
            }
          

Exporting?

Similar command help write files… but more on that later…

Importing 3D – 01 – OBJ-loading libraries

We’ll use a Processing Library called “OBJLoader”. It can be found here.

… as usual, download, unzip, and put the library’s folder in the Processing/libraries folder.

Importing 3D – 02 – Find an OBJ file….

Now it is time to prepare a sketch.

First, lets put an .OBJ model in our sketch’s folder.

I’ll use this model of an airplane.

Later, we’ll have to know about texture and meshing parameters of this file. For now, let’s continue…

Download, unzip, and place in your sketch’s folder. (For the folder to exist, this requires saving for a first time.)

Importing 3D – 03 – Find an OBJ file….

Next, let’s write a sketch to merely load the file…


            import peasy.*;
            import saito.objloader.*;
          
            OBJModel model ;
            PeasyCam cam;
          
            void setup() {
              size(800, 600, P3D);
              cam = new PeasyCam(this, 100);
              cam.setMinimumDistance(50);
              cam.setMaximumDistance(500);
              
              model = new OBJModel(this, "toyplane.obj", "absolute", TRIANGLES);
              model.enableDebug();
          
              model.scale(3);
              model.translateToCenter();
              
              stroke(255);
              noStroke();
            }
            
            void draw() {
              background(129);
              lights();
              pushMatrix();
              model.draw();
              popMatrix();
            }
          

Importing 3D – 04 Troubleshooting

Class constructor is as follows:

OBJModel(PApplet _parent, java.lang.String _fileName, int _shapeMode)

All the standard processing modes are supported TRIANGLES, POINTS, POLYGON, LINES, TRIANGLE_STRIP, QUAD_STRIP, QUADS

Importing 3D – 05 Troubleshooting

Familiar Skills:


          import peasy.*;
          import saito.objloader.*;
          
          OBJModel model;
          OBJModel orbiter;
          PeasyCam cam;
          
          void setup() {
            size(800, 600, P3D);
            cam = new PeasyCam(this, 300);
            cam.setMinimumDistance(50);
            cam.setMaximumDistance(500);
            
            model = new OBJModel(this, "toyplane.obj", "absolute", POLYGON);
            model.enableDebug();
            model.scale(3);
            model.translateToCenter();
            model.disableTexture();
            
            orbiter = new OBJModel(this, "toyplane.obj", "absolute", POLYGON);
            orbiter.enableDebug();
            orbiter.scale(.5);
            orbiter.translateToCenter();
            orbiter.disableTexture();
            
            stroke(255);
            noStroke();
          }
          
          void draw() {
            background(129);
            lights();
            pushMatrix();
            model.draw();
            rotateX( frameCount*.1 );
            translate(0,0,100);
            orbiter.draw();
            popMatrix();
          }
          

Recursion

Recursion – a definition

Informally, one can refer to recursion as method calls itself (either directly or indirectly).


          int factorial(int n)
              {
                int value;
          
                if   (n == 0) value = 1;
                else          value = n*factorial(n-1);
          
                return value;
              }
          

Recursion in a 2D Tree


          void setup() {
            size(600, 400);
            smooth();
            noLoop();
          }
          
          void draw() {
            background(255);
            strokeWeight(10);
            translate(width/2, height*.85);
            branch(0);
          }
          
          void branch(int depth) {
          
            if (depth < 10) {
              line(0, 0, 0, -height/3);
              pushMatrix();
              {
                translate(0, -height/5);
                rotate( random(-PI/4, PI/4) );
                scale(0.7);
                branch(depth+1);
              }
              popMatrix();
              pushMatrix();
              {
                translate(0, -height/3);
                rotate( random(-PI/4, PI/4) );
                scale(0.7);
                branch(depth+1);
              }
              popMatrix();  
          
              println("Depth is " + depth);
            }
          }
          
          void mouseClicked() {
            redraw();
          }