Repeat: EMBEDDED ITERATION
All programming languages can repeat an action, such as drawing the same shape over and over. When one repetition sequence is embedded within another, the effect multiplies. For example, if the action of drawing five lines is repeated ten times, fifty lines are drawn. This simple technique can be used to explore many kinds of patterns.
Each of these images was generated from the same grid of points. Sixteen elements along the x-axis and eleven along the y-axis combine to form 176 coordinates. Changing just one line of code produces the differences between theses images.
/**
* Repeat: Embedded Iteration
* from Form+Code in Design, Art, and Architecture
* by Casey Reas, Chandler McWilliams, and LUST
* Princeton Architectural Press, 2010
* ISBN 9781568989372
*
* This code was written for Processing 1.2+
* Get Processing at http://www.processing.org/download
*/
int option = 1;
void setup() {
size(400, 300);
smooth();
noFill();
}
void draw() {
background(255);
if (option == 1) {
// Option 1: Stitches
for (int x = 50; x <= width-50; x += 20) {
for (int y = 50; y <= height-50; y+=20) {
line(x-5, y-5, x+5, y+5);
line(x+5, y-5, x-5, y+5);
}
}
}
else if (option == 2) {
// Option 2: Perspective
for (int x = 50; x <= width-50; x += 20) {
for (int y = 50; y <= height-50; y+=20) {
line(x, y, width/2, height/2);
}
}
}
else if (option == 3) {
// Option 3: Overlapping circles
for (int x = 50; x <= width-50; x += 20) {
for (int y = 50; y <= height-50; y+=20) {
ellipse(x, y, 40, 40);
}
}
}
else if (option == 4) {
// Option 4: Rotating arcs
int count = 120;
for (int x = 50; x <= width-50; x += 20) {
for (int y = 50; y <= height-50; y+=20) {
float s = map(count, 120, 0, 0, TWO_PI*2);
arc(x, y, 14, 14, s, s + PI);
count--;
}
}
}
else if (option == 5) {
// Option 5: Groups of five
for (int x = 50; x < width-50; x += 20) {
for (int y = 50; y < height-50; y+=20) {
//rect(x-10, y-10, 22, 22);
for (int i = 0; i < 16; i+=4) {
line(x + i, y, x + i, y + 12);
}
line(x, y, x + 12, y + 12);
}
}
}
}
void mousePressed() {
option++;
if (option > 5) option = 1;
}
Contributed Examples
-
Go
/** * Repeat: Embedded Iteration from Form+Code in Design, Art, and Architecture * implemented in Go by Anthony Starks * * Requires the go programming language available at http://golang.org * and the SVGo libraray available at http://github.com/ajstarks/svgo * * Create SVG file from command line with: make * * For more information about Form+Code visit http://formandcode.com */ package main import "github.com/ajstarks/svgo" "fmt" "os" ) var width = 400 height = 300 canvas = svg. os.Stdout) )
-
ActionScript
/** * Repeat: Embedded Iteration from Form+Code in Design, Art, and Architecture * implemented in ActionScript 3 by João Goncalves <http://joaogoncalves.net> * * Run from the command line with: mxmlc Repeat_Embedded.as * Mxmlc is available free as part of the Flex SDK: http://opensource.adobe.com/wiki/display/flexsdk/Flex+SDK * * For more information about Form+Code visit http://formandcode.com */ package { import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.text.TextField; [SWF(width='400', height='300', backgroundColor='#000000')] public class Repeat_Embedded extends Sprite { private var option:int = 1; private var text:TextField; public function Repeat_Embedded():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); text = new TextField(); text.textColor = 0xffffff; text.text = "Click to change..."; addChild(text); stage.addEventListener(MouseEvent.CLICK, changeExample); drawSomething(); } private function drawSomething():void { graphics.clear(); switch (option) { case 1 : repeat1(); break;//call option 1 case 2 : repeat2(); break;//call option 2 case 3 : repeat3(); break;//call option 3 case 4 : repeat4(); break;//call option 4 case 5 : repeat5(); break;//call option 5 } } private function changeExample(e:MouseEvent):void { option < 5 ? option++ : option = 1; drawSomething(); } // option 1 private function repeat1():void { for (var xpos:int = 50; xpos < stage.stageWidth - 50; xpos += 20) { for (var ypos:int = 50; ypos < stage.stageHeight - 50; ypos += 20) { with (graphics) { lineStyle(1, 0xff0000); moveTo(xpos - 5, ypos - 5); lineTo(xpos + 5, ypos +5); moveTo(xpos + 5, ypos - 5); lineTo(xpos - 5, ypos +5); } } } } // option 2 private function repeat2():void { for (var xpos:int = 50; xpos < stage.stageWidth - 50; xpos += 20) { for (var ypos:int = 50; ypos < stage.stageHeight - 50; ypos += 20) { with (graphics) { lineStyle(1, 0xff0000); moveTo(xpos, ypos ); lineTo(stage.stageWidth/2, stage.stageHeight/2); } } } } // option 3 private function repeat3():void { for (var xpos:int = 50; xpos < stage.stageWidth - 50; xpos += 20) { for (var ypos:int = 50; ypos < stage.stageHeight - 50; ypos += 20) { with (graphics) { lineStyle(1, 0xff0000); graphics.drawCircle(xpos, ypos, 40 ); } } } } // option 4 private function repeat4():void { var i:int = 10; this.graphics.lineStyle(1, 0xff0000); for (var xpos:int = 50; xpos < stage.stageWidth - 50; xpos += 20) { for (var ypos:int = 50; ypos < stage.stageHeight - 50; ypos += 20) { DrawingShapes.drawArc( this.graphics, xpos, ypos, 7, 200,i); } i += 30; } } // option 5 private function repeat5():void { for (var xpos:int = 50; xpos < stage.stageWidth - 50; xpos += 20) { for (var ypos:int = 50; ypos < stage.stageHeight - 50; ypos += 20) { for (var i:int = 0; i < 16; i+=4) { with (graphics) { lineStyle(1, 0xff0000); moveTo(xpos+i, ypos ); lineTo(xpos+i, ypos+12); } } graphics.moveTo(xpos, ypos ); graphics.lineTo(xpos + 12, ypos + 12); } } } private function map(value:Number, inMin:Number, inMax:Number, outMin:Number, outMax:Number):Number { return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; } } }
-
OpenFrameworks
/** * Repeat: Embedded Iteration from Form+Code in Design, Art, and Architecture * implemented in OpenFrameworks by Anthony Stellato <http://rabbitattack.com/> * * Requires OpenFrameworks available at http://openframeworks.cc/ * * For more information about Form+Code visit http://formandcode.com */ // =========================================================== // - Repeat_Embedded.h // =========================================================== #include "ofMain.h" class testApp : public ofBaseApp{ public: void setup(); void draw(); void arc(float x, float y, float width, float height, float start, float stop); void mousePressed(int x, int y, int button); int option, width, height; }; // =========================================================== // - Repeat_Embedded.cpp // =========================================================== #include "Repeat_Embedded.h" //-------------------------------------------------------------- void testApp::setup(){ option = 1; width = ofGetWidth(); height = ofGetHeight(); ofNoFill(); } //-------------------------------------------------------------- void testApp::draw(){ ofBackground(0, 0, 0); ofSetColor(255, 255, 255); if(option == 1){ // Option 1: Stitches for(int x = 50; x <= width-50; x += 20){ for(int y = 50; y <= height-50; y += 20){ ofLine(x-5, y-5, x+5, y+5); ofLine(x+5, y-5, x-5, y+5); } } } else if(option == 2){ // Option 2: Perspective for(int x = 50; x <= width-50; x += 20){ for(int y = 50; y <= height-50; y += 20){ ofLine(x, y, width/2, height/2); } } } else if(option == 3){ // Option 3: Overlapping circles for(int x = 50; x <= width-50; x += 20){ for(int y = 50; y <= height-50; y += 20){ ofEllipse(x, y, 40, 40); } } } else if(option == 4){ // Option 3: Rotating arcs int count = 120; for(int x = 50; x <= width-50; x += 20){ for(int y = 50; y <= height-50; y += 20){ float s = ofMap(count, 0, 120, 0, TWO_PI*2, false); arc(x, y, 14, 14, s, s + PI); count--; } } } else if(option == 5){ // Option 3: Groups of five for(int x = 50; x <= width-50; x += 20){ for(int y = 50; y <= height-50; y += 20){ for(int i = 0; i < 16; i += 4){ ofLine(x + i, y, x + i, y+12); } ofLine(x, y, x + 12, y + 12); } } } } //-------------------------------------------------------------- void testApp::arc(float x, float y, float width, float height, float start, float stop){ float hr = width / 2.0f; float vr = height / 2.0f; float centerX = x + hr; float centerY = y + vr; float startLUT = start; float stopLUT = stop; glBegin(GL_LINE_STRIP); float increment = 0.2f; for (float i = startLUT; i < stopLUT; i += increment) { glVertex2f(centerX + cos(i) * hr, centerY + sin(i)* vr); } glVertex2f(centerX + cos(stopLUT) * hr, centerY + sin(stopLUT) * vr); glEnd(); } //-------------------------------------------------------------- void testApp::mousePressed(int x, int y, int button){ option++; if(option > 5) option = 1; }
-
Cinder
/** * Repeat: Embedded Iteration from Form+Code in Art, Design, and Architecture * implemented in C++ by Patrick Tierney <http://ptierney.com> * * Requires Cinder 0.8.2 available at http://libcinder.org * * Project files are located at https://github.com/hlp/form-and-code * * For more information about Form+Code visit http://formandcode.com */ #include "cinder/app/AppBasic.h" #include "cinder/CinderMath.h" class Repeat_Embedded : public ci::app::AppBasic { public: void prepareSettings(Settings* settings); void setup(); void draw(); void mouseDown(ci::app::MouseEvent); private: void arc(const ci::Vec2f& center, float radius, float start, float stop); int option; }; void Repeat_Embedded::prepareSettings(Settings* settings) { settings->setWindowSize(400, 300); } void Repeat_Embedded::setup() { option = 1; glEnable(GL_SMOOTH); ci::gl::enableAlphaBlending(); glLineWidth(1.2f); ci::gl::color(ci::Color::black()); } void Repeat_Embedded::draw() { ci::gl::setMatricesWindow(getWindowSize()); ci::gl::clear(ci::Color::white()); if (option == 1) { // Option 1: Stitches for (int x = 50; x <= getWindowWidth()-50; x += 20) { for (int y = 50; y <= getWindowHeight()-50; y+=20) { ci::gl::drawLine(ci::Vec2f(x-5, y-5), ci::Vec2f(x+5, y+5)); ci::gl::drawLine(ci::Vec2f(x+5, y-5), ci::Vec2f(x-5, y+5)); } } } else if (option == 2) { // Option 2: Perspective for (int x = 50; x <= getWindowWidth()-50; x += 20) { for (int y = 50; y <= getWindowHeight()-50; y+=20) { ci::gl::drawLine(ci::Vec2f(x, y), ci::Vec2f(getWindowWidth()/2, getWindowHeight()/2)); } } } else if (option == 3) { // Option 3: Overlapping circles for (int x = 50; x <= getWindowWidth()-50; x += 20) { for (int y = 50; y <= getWindowHeight()-50; y+=20) { ci::gl::drawStrokedCircle(ci::Vec2f(x, y), 40/2); } } } else if (option == 4) { // Option 4: Rotating arcs int count = 120; for (int x = 50; x <= getWindowWidth()-50; x += 20) { for (int y = 50; y <= getWindowHeight()-50; y +=20) { float s = ci::lmap<float>(count, 120, 0, 0, M_PI*2*2); arc(ci::Vec2f(x, y), 14/2, s, s + M_PI); count--; } } } else if (option == 5) { // Option 5: Groups of five for (int x = 50; x < getWindowWidth()-50; x += 20) { for (int y = 50; y < getWindowHeight()-50; y+=20) { //rect(x-10, y-10, 22, 22); for (int i = 0; i < 16; i+=4) { ci::gl::drawLine(ci::Vec2f(x + i, y), ci::Vec2f(x + i, y + 12)); } ci::gl::drawLine(ci::Vec2f(x, y), ci::Vec2f(x + 12, y + 12)); } } } } void Repeat_Embedded::mouseDown(ci::app::MouseEvent /*event*/) { option++; if (option > 5) option = 1; } void Repeat_Embedded::arc(const ci::Vec2f& center, float radius, float start, float stop) { // automatically determine the number of segments from the circumference int numSegments = (int) ci::math<double>::floor(radius * M_PI * 2); int startSegments = (int) ci::math<double>::floor(radius * start); int endSegments = (int) ci::math<double>::floor(radius * stop); if (numSegments < 2) numSegments = 2; int numVerts = (endSegments-startSegments)*2; if (numVerts < 2) numVerts = 2; GLfloat* verts = new float[numVerts]; int i = 0; for(int s = startSegments; s < endSegments; s++) { float t = s / (float)numSegments * 2.0f * 3.14159f; verts[i*2+0] = center.x + ci::math<float>::cos(t) * radius; verts[i*2+1] = center.y + ci::math<float>::sin(t) * radius; i++; } glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, verts); glDrawArrays(GL_LINE_STRIP, 0, numVerts / 2); glDisableClientState(GL_VERTEX_ARRAY); delete [] verts; } CINDER_APP_BASIC(Repeat_Embedded, ci::app::RendererGl)
We are looking for implementations of the code examples in other programming languages to post on the site. If you would like to submit a sample, or if you find a bug, please write to