draw recursive tree with lines and circles
Repeat: RECURSIVE TREE
Within the domain of image making, recursion involves drawing a group of related, self-similar shapes. Treelike forms are a clear example — each branch spawns many smaller branches, which in turn spawn more branches. As a simple example, draw the letter Y on a sheet of paper. Now draw two smaller Ys sprouting from the top of each branch. After repeating this process a few times, the number of Ys drawn at each step has increased from 1 to 2, to 4, 8, 16, 32, 64, and so on.
While this type of tree makes a predictable shape, adding a small amount of randomness to the line lengths and number of branches can yield more organic forms. These treelike forms were created by drawing one circle at a time. Starting at the base, each circle was slightly rotated and scaled relative to the one before it. At random intervals during the growth, two smaller branches sprout to form new growths. This continues until the circles reach the minimum size set by the user.
/** * Repeat: Recursive Tree * from Form+Code in Design, Art, and Architecture * by Casey Reas, Chandler McWilliams, and LUST * Princeton Architectural Press, 2010 * ISBN 9781568989372 * * This program is based on Context Free program * "Foggy Tree by Chris Coyne: * http://www.contextfreeart.org/gallery/view.php?id=4 * * This code was written for Processing 1.2+ * Get Processing at http://www.processing.org/download */ float dotSize = 9; float angleOffsetA; float angleOffsetB; void setup () {size(900, 600);noStroke();fill(0);smooth();frameRate(1); // Redraw the tree once a second angleOffsetA =radians(1.5); // Convert 1.5 degrees to radians angleOffsetB =radians(50); // Convert 50 degrees to radians } void draw () {background(255); // White backgroundtranslate(width/2, height); // Move to the center, bottom of the screen seed1(dotSize,radians(270), 0, 0); // Start the tree } void seed1(float dotSize, float angle, float x, float y) {if (dotSize > 1.0) {// Create a random numbers between 0 and 1float r = random(0, 1.0);// 98% chance this will happenif (r > 0.02) {ellipse(x, y, dotSize, dotSize);float newx = x + cos(angle) * dotSize;float newy = y + sin(angle) * dotSize; seed1(dotSize * 0.99, angle - angleOffsetA, newx, newy); }// 02% chance this will happenelse {ellipse(x, y, dotSize, dotSize);float newx = x + cos(angle);float newy = y + sin(angle); seed2(dotSize * 0.99, angle + angleOffsetA, newx, newy); seed1(dotSize * 0.60, angle + angleOffsetB, newx, newy); seed2(dotSize * 0.50, angle - angleOffsetB, newx, newy); } } } void seed2(float dotSize, float angle, float x, float y) {if (dotSize > 1.0) {// Create a random numbers between 0 and 1float r = random(0, 1.0);// 95% chance this will happenif (r > 0.05) {ellipse(x, y, dotSize, dotSize);float newx = x + cos(angle) * dotSize;float newy = y + sin(angle) * dotSize; seed2(dotSize * 0.99, angle + angleOffsetA, newx, newy); }// 05% chance this will happenelse {ellipse(x, y, dotSize, dotSize);float newx = x + cos(angle);float newy = y + sin(angle); seed1(dotSize * 0.99, angle + angleOffsetA, newx, newy); seed2(dotSize * 0.60, angle + angleOffsetB, newx, newy); seed1(dotSize * 0.50, angle - angleOffsetB, newx, newy); } } }
Contributed Examples
-
Go
package main import "github.com/ajstarks/svgo" "fmt" "rand" "math" "time" "os" ) var width = 900 height = 600 canvas = svg.os.Stdout) ) var angleOffsetA = 1.5) angleOffsetB = 50) ) -
ActionScript
package { import flash.display.Sprite ; import flash.events.Event ; import flash.events.MouseEvent ; import flash.text.TextField ; import flash.text.TextFieldAutoSize ; [ SWF (width = '900', height = '600', backgroundColor = '#ffffff', framerate= 1)] public class Repeat_RecursiveTree extends Sprite { private var dotSize: Number = 9 ; private var angleOffsetA: Number ; private var angleOffsetB: Number ; private var instructions: TextField ; public function Repeat_RecursiveTree (): void { if (stage) init(); else addEventListener(Event .ADDED_TO_STAGE, init); } private function init (e: Event = null): void { removeEventListener(Event .ADDED_TO_STAGE, init); instructions = new TextField(); instructions. text = "Click to generate a Tree, Double-Click to clear the stage." ; instructions. autoSize = TextFieldAutoSize .LEFT ; addChild(instructions); angleOffsetA = degToRad(1 .5); angleOffsetB = degToRad(50); stage . doubleClickEnabled = true ; stage . addEventListener(MouseEvent .CLICK, generateThree); stage . addEventListener(MouseEvent .DOUBLE_CLICK, clearStage); } private function clearStage (e: MouseEvent): void { this . graphics . clear(); } private function generateThree (e: MouseEvent): void { this . graphics . beginFill(0x000000); seed1(dotSize, degToRad(270), mouseX, mouseY); } private function seed1 (dotSize: Number, angle: Number, xpos: Number, ypos: Number): void { var newX: Number ; var newY: Number ; if (dotSize> 1) { var r: Number = Math . random(); if (r> 0 .02) { this . graphics . drawEllipse(xpos, ypos, dotSize, dotSize); newX = xpos + Math . cos(angle) * dotSize; newY = ypos + Math . sin(angle) * dotSize; seed1(dotSize * 0 .99, angle- angleOffsetA, newX, newY); } else { this . graphics . drawEllipse(xpos, ypos, dotSize, dotSize); newX = xpos + Math . cos(angle); newY = ypos + Math . sin(angle); seed2(dotSize * 0 .99, angle + angleOffsetA, newX, newY); seed1(dotSize * 0 .60, angle + angleOffsetB, newX, newY); seed2(dotSize * 0 .50, angle-angleOffsetB, newX, newY); } } } private function seed2 (dotSize: Number, angle: Number, xpos: Number, ypos: Number): void { var newX: Number ; var newY: Number ; if (dotSize> 1) { var r: Number = Math . random(); if (r> 0 .05) { this . graphics . drawEllipse(xpos, ypos, dotSize, dotSize); newX = xpos + Math . cos(angle) * dotSize; newY = ypos + Math . sin(angle) * dotSize; seed2(dotSize * 0 .99, angle+ angleOffsetA, newX, newY); } else { this . graphics . drawEllipse(xpos, ypos, dotSize, dotSize); newX = xpos + Math . cos(angle); newY = ypos + Math . sin(angle); seed1(dotSize * 0 .99, angle + angleOffsetA, newX, newY); seed2(dotSize * 0 .60, angle + angleOffsetB, newX, newY); seed1(dotSize * 0 .50, angle-angleOffsetB, newX, newY); } } } private function degToRad (deg: Number): Number { return deg * (Math .PI / 180); } } }
-
OpenFrameworks
#include "ofMain.h" class testApp : public ofBaseApp{ public: void setup(); void draw(); void seed1(float dotSize, float angle, float x, float y); void seed2(float dotSize, float angle, float x, float y); float dotSize, angleOffsetA, angleOffsetB; }; #include "Repeat_RecursiveTree.h" void testApp::setup(){ ofSetFrameRate(1); ofBackground(255, 255, 255); ofEnableSmoothing(); dotSize = 9.0f; angleOffsetA = ofDegToRad(1.5); angleOffsetB = ofDegToRad(50); } void testApp::draw(){ ofBackground(255, 255, 255); ofSetColor(0, 0, 0); ofTranslate(ofGetWidth()/2, ofGetHeight(), 0); seed1(dotSize, ofDegToRad(270), 0, 0); } void testApp::seed1(float dotSize, float angle, float x, float y){ if(dotSize > 1.0f){ float r = ofRandomuf(); if(r > 0.02f){ ofCircle(x, y, dotSize); float newx = x + cos(angle) * dotSize; float newy = y + sin(angle) * dotSize; seed1(dotSize * 0.99f, angle - angleOffsetA, newx, newy); } else { ofCircle(x, y, dotSize); float newx = x + cos(angle); float newy = y + sin(angle); seed2(dotSize * 0.99f, angle + angleOffsetA, newx, newy); seed1(dotSize * 0.6f, angle + angleOffsetB, newx, newy); seed2(dotSize * 0.5f, angle - angleOffsetB, newx, newy); } } } void testApp::seed2(float dotSize, float angle, float x, float y){ if(dotSize > 1.0f){ float r = ofRandomuf(); if(r > 0.05f){ ofCircle(x, y, dotSize); float newx = x + cos(angle) * dotSize; float newy = y + sin(angle) * dotSize; seed2(dotSize * 0.99f, angle + angleOffsetA, newx, newy); } else { ofCircle(x, y, dotSize); float newx = x + cos(angle); float newy = y + sin(angle); seed1(dotSize * 0.99f, angle + angleOffsetA, newx, newy); seed2(dotSize * 0.6f, angle + angleOffsetB, newx, newy); seed1(dotSize * 0.5f, angle - angleOffsetB, newx, newy); } } }
-
Cinder
#include "cinder/app/AppBasic.h" #include "cinder/CinderMath.h" #include "cinder/Rand.h" class Repeat_RecursiveTree : public ci::app::AppBasic { public: void prepareSettings(Settings* settings); void setup(); void draw(); void seed1(float dotSize, float angle, float x, float y); void seed2(float dotSize, float angle, float x, float y); private: float dotSize; float angleOffsetA; float angleOffsetB; ci::Rand rand; }; void Repeat_RecursiveTree::prepareSettings(Settings* settings) { dotSize = 9; settings->setWindowSize(900, 600); settings->setFrameRate(1.0f); } void Repeat_RecursiveTree::setup() { ci::gl::color(ci::Color::black()); glEnable(GL_SMOOTH); angleOffsetA = ci::toRadians(1.5f); angleOffsetB = ci::toRadians(50.0f); rand.randomize(); } void Repeat_RecursiveTree::draw() { ci::gl::setMatricesWindow(getWindowSize()); ci::gl::clear(ci::Color::white()); ci::gl::translate(ci::Vec2f(getWindowWidth()/2, getWindowHeight())); seed1(dotSize, ci::toRadians(270.0f), 0, 0); } void Repeat_RecursiveTree::seed1(float dotSize, float angle, float x, float y) { if (dotSize > 1.0) { float r = rand.randFloat(0, 1.0f); if (r > 0.02) { ci::gl::drawSolidCircle(ci::Vec2f(x, y), dotSize/2); float newx = x + ci::math<float>::cos(angle) * dotSize; float newy = y + ci::math<float>::sin(angle) * dotSize; seed1(dotSize * 0.99, angle - angleOffsetA, newx, newy); } else { ci::gl::drawSolidCircle(ci::Vec2f(x, y), dotSize/2); float newx = x + ci::math<float>::cos(angle); float newy = y + ci::math<float>::sin(angle); seed2(dotSize * 0.99, angle + angleOffsetA, newx, newy); seed1(dotSize * 0.60, angle + angleOffsetB, newx, newy); seed2(dotSize * 0.50, angle - angleOffsetB, newx, newy); } } } void Repeat_RecursiveTree::seed2(float dotSize, float angle, float x, float y) { if (dotSize > 1.0) { float r = rand.randFloat(0, 1.0); if (r > 0.05) { ci::gl::drawSolidCircle(ci::Vec2f(x, y), dotSize/2); float newx = x + ci::math<float>::cos(angle) * dotSize; float newy = y + ci::math<float>::sin(angle) * dotSize; seed2(dotSize * 0.99, angle + angleOffsetA, newx, newy); } else { ci::gl::drawSolidCircle(ci::Vec2f(x, y), dotSize/2); float newx = x + ci::math<float>::cos(angle); float newy = y + ci::math<float>::sin(angle); seed1(dotSize * 0.99, angle + angleOffsetA, newx, newy); seed2(dotSize * 0.60, angle + angleOffsetB, newx, newy); seed1(dotSize * 0.50, angle - angleOffsetB, newx, newy); } } } CINDER_APP_BASIC(Repeat_RecursiveTree, 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
Source: http://formandcode.com/code-examples/repeat-recursive-tree
0 Response to "draw recursive tree with lines and circles"
Postar um comentário