All post of ElecFreaksProgram

Interesting Processing Programming Guidance for Designer–Custom Functions and Fractal Recursion

By November 28, 2017 No Comments
11.23主图博客

Custom Functions

 

An important concept in program is reuse. And custom function is the best embodiment for the idea of reuse. It is no exaggeration to say only if we have flexibly mastered it that we can be really considered to have stepped into the gate of programming. Because you will start to think how to abstract some serialization operations in order to improve the effeciency of programming.

Like the self-carried drawing functions in OF, actually ofDrawCicle and ofDrawRectangle are created after its designers’ abstraction. Its bottom layer consists of some more “original” code. When we use, we don’t have to know what’s inside as long as we know its name and relative functions. Once we have grasped the usage of custom functions, we can use the similar ways to pack code bricks and customize components by ourselves.

“Return Value Type” stands for the type of function return value, which I will talk further in the latter chapters.

While “Function Name” means the name you give to the function. Later we can invoke this function through its name directly. Similar to variables’ naming regulations, the function name can only use alphabets, numbers or underlines and its first character must be an alphabet or underline.

Within two braces, we need to write statements that are expected to be executed by the function. This part is also called “Function Body”.

 

Basic Grammar:

Return Value Type ofApp:: Function Name (){

Statements;

}

 

Within OF, this is a standard writing method. It means functions defined by us will be included into the main program of ofApp. If we observe it carefully, we will find functions like setup, update and draw are all without exceptions to write ofApp:: in the front. In current stage, we only have to abide by this regulation and that’s enough. (There are special writing method under certain circumstances.)

Let’s look at a most basic example.

 

Code Example (8-1):

 

Within --- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

void myFunction();

};

Within --- ofApp.cpp

void ofApp::setup(){

myFunction();

}

void ofApp::update(){

}

void ofApp::draw(){

}

void ofApp::myFunction(){

cout << "1" << endl;

cout << "2" << endl;

cout << "3" << endl;

cout << "4" << endl;

}

 

Output Result:


Similar to declare a variable, if we want to define a function in OF, we have to declare in ofApp.h beforehand. ” void ” stands for no value returned to the function, which means this function will only execute code in the function body instead of return data to the outside. The ” myFunction ” behind is for the name of the function.

As for what’s inside the custom functions, we have to define in the ofApp.cpp. Here the ” void ” we wrote shall be correspondent to the “void” in ofApp.h in order to keep consistency.

When we invoking functions, we only have to write function name and a bracket behind. In the example of setup function, we have invoked function myFunction for once. Therefore, it will execute function contents we defined and output number 1, 2, 3, 4 in the console in turns.

The above example is only for outputting character data in the console. In the following, we can place it under the graphic circumstances to understand custom functions.

Code Example (8-2):

Within --- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

void myShape();

};

Within --- ofApp.cpp

void ofApp::setup(){

ofSetWindowShape(400,400);

}

void ofApp::update(){

}

void ofApp::draw(){

ofBackground(255);

myShape();

}

void ofApp::myShape(){

ofSetColor(0,0,255,70);

ofDrawCircle(ofGetWidth()/2,ofGetHeight()/2,50);

ofSetColor(0,255,0,70);

ofDrawRectangle(ofGetWidth()/2, ofGetHeight()/2, 50,50);

ofDrawRectangle(ofGetWidth()/2 - 50, ofGetHeight()/2 - 50, 50,50);

}


 

Function myShape in the above example has drawn a composite graphic, which includes a circle and two rectangles. Every time when we invoke myShape for once, this group of elements will be drawn once.

We can try to write two myShape functions in function draw. Due to its original graphic color is transparent, so the color will deepen if we overlap the two graphics together.

 


Parameter Input

 

It is very convenient to define functions. But we can see there are some limits in the above methods that we can not modify parameters in the functions. Therefore the position of graphic elements are fixed. We can learn another writing method: to input something into functions.

Basic Grammar:

Return Value Type Function Name (Parameter Type Parameter Name){

Statements;

}

We only have to write parameter type and parameter name in the bracket behind the function name. Suppose if we want to input a floating point variable into myFunction, we can write like this:

void ofApp::myFunction(float x){

Statements;

}

At this time, we can invoke this parameter X in the function body. We can name the variable name of the parameter randomly as long as it abides by the variable naming regulations. When we want to input more parameters, we only have to add a comma behind while writing the parameter type and name.

Like:

void ofApp::myFunction(float x,float y){

Statements;

}

When you have grasped this method of writing, we can change the position of graphic elements by inputting parameters.

 

Code Example (8-3):

 

Within —- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

void myShape(float x,float y);

};

Whithin —- ofApp.cpp

void ofApp::setup(){

ofSetWindowShape(400,400);

}

void ofApp::update(){

}

void ofApp::draw(){

ofBackground(255);

myShape(ofGetWidth()/3, ofGetHeight()/2);

myShape(ofGetWidth()/3 * 2, ofGetHeight()/2);

myShape(mouseX,mouseY);

}

void ofApp::myShape(float x,float y){

ofSetColor(0,0,255,70);

ofDrawCircle(x,y,50);

ofSetColor(0,255,0,70);

ofDrawRectangle(x,y, 50,50);

ofSetColor(0,255,0,70);

ofDrawRectangle(x - 50, y - 50, 50,50);

}


0

Multiple Type Input

 

The parameters input can not only be float, but also data types like boolintstring.

 

Code Example (8-4):

 

Within —- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

void myShape(bool type,float x,float y);

};

Within —- ofApp.cpp

void ofApp::setup(){

ofSetWindowShape(400,400);

}

void ofApp::update(){

}

void ofApp::draw(){

ofBackground(255);

ofSetColor(255);

myShape(true,mouseX,mouseY);

myShape(false,ofGetWidth() - mouseX,ofGetHeight() - mouseY);

}

void ofApp::myShape(bool type,float x,float y){

ofSetColor(0);

ofDrawCircle(x,y,50);

if(type){

ofSetColor(0,0,255);

}else{

ofSetColor(255,0,0);

}

ofDrawRectangle(x,y, 50,50);

ofDrawRectangle(x - 50, y - 50, 50,50);

}


1This example takes advantage of the difference of bool value together with if statements to decide graphic color. In the next chapter, we will learn a new data type: ofColor. It can store color value. If we use this type as incoming parameter, it will be more flexible for us to control.

 

Parameter Output

 

Where there is input, there is output. Sometimes we hope functions will return back some results. At this time, we can consider using return key words in the function body. Suppose if we want to create some mathematical formulas such as to calculate the circle area. We can write like the following in our program:

 

Code Example (8-5):

 

Within —- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

float circleArea(float r);

};

Within —- ofApp.cpp

void ofApp::setup(){

cout << circleArea(2) << endl;

}

float ofApp::circleArea(float r){

float area = PI * r * r;

return area;

}

 

Output Result:


 

The area created in the function is equivalent to a local variable, which can be used to store the area after calculated. In the last, through writing it behind the key words of return, we can output the data stored in the area while invoking the function.

Because of the output data type is float, so at the beginning of custom functions, the type of return value must write float in order to replace void where there is no return value.

 

Function Overloading

 

Functions in OF can be allowed to overload. The meaning of overload is that you can define multiple functions with different parameters and use a same function name. When invoking, the program will judge the quantity of parameter and then decide the relative function.

Do you still remember the previously referred function ofSetColor ?The permitted quantity of its input parameters can be 1, 3, 4. According to the difference of parameters, the usage of functions will be differentiated.

In the example below, we will design a function named calculate. When the quantity of parameter is 2, then multiply the two parameters (just like to calculate the area). When the quantity of parameter is 3, then multiply the three parameters.

 

Code Example (8-6):

 

Within —- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

float calculate(float a,float b);

float calculate(float a,float b,float c);

};

Within —- ofApp.cpp

void ofApp::setup(){

cout << calculate(2,3) << endl;

cout << calculate(2,3,4) << endl;

}

float ofApp::calculate(float a,float b){

float result = a * b;

return result;

}

float ofApp::calculate(float a,float b,float c){

float result = a * b * c;

return result;

}

 

Recursion & Fractal

 

Recursion

 

When you have mastered the method of defining functions, you can start to write recursion functions. With recursion functions, you can easily and conveniently draw fractal graphics.

Recursion, it might heard deep and profound. Actually, it means the function invoke itself. We definitely heard a typical story like this before. Let me use it to show you an example first.

Long long ago, there was a mountain. In the mountain, there is a temple. Within the temple, there is an old monk. The monk was telling a story to a little monk. And the story was “Long long ago, there was a mountain. In the mountain, there is a temple. Within the temple, there is an old monk. The monk was telling a story to a little monk. And the story was Long long ago, there was a mountain. In the mountain, there is a temple……”

If we go on talk this, the story will never come to an end. It is just like a recursive structure. However, in the program, we can not let this process executed endlessly. We have to set a condition to decide continue or out, or it will trapped into a dead loop.

In the following, there is a basic recursion example:

 

Code Example (8-7):

 

Within —- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

void recursion(float l);

};

Within —- ofApp.cpp

void ofApp::setup(){

ofSetWindowShape(400,400);

}

void ofApp::update(){

}

void ofApp::draw(){

ofBackground(255);

ofTranslate(ofGetWidth()/2,ofGetHeight()/2);

recursion(350);

}

void ofApp::recursion(float l){

if(l > 30){

l = l * 0.92;

ofNoFill();

ofSetColor(0);

ofSetRectMode(OF_RECTMODE_CENTER);

ofDrawRectangle(0,0,l, l);

recursion(l);

}

}

 

 


 

We can see it is no big difference to the common custom functions in grammar. The only difference is recursion was invoked once again in resurcion function, while being wrapped by an if statement at the same time.

Within it, l, as an input parameter, is the rectangular side length. At the same time, it is the condition to decide whether to implement recursion function. Only when the rectangular side length I is beyond 30, the recursion will go on proceed. In other words, when I is under or equal to 30, it is the terminal condition for recursion. So you will see in the graphic that the center is blank.

It is still not enough to have judgement conditions. We have to think about whether there are situations when it cannot be met. The first line of code in if condition statement is l = l * 0.92. Every time when operate the function for once, the value of I will be decreased and passed to the next recursion function as an input parameter. If this repeated to continue, sooner or later, I will arrive to the terminal condition.

Suppose if we rectify 0.92 to a value beyond 1, the program will collapse. Because the value of I always keeps increasing, it cannot meet the requirement of under 30. But it do not mean that it will be completely out of question when this value is under 1. When you write 0.999999, the program will collapse as well. Because the smaller the change, the more execution it will have and more rectangles needed to be drawn in a frame. When this quantity surpassed the processing ability of the computer, it will collapse.

Recursive structure is a little bit like “a dream within a dream” in the movie Inception. Dreams are nested between each other. We need to have a condition to “wake up”, otherwise people will always fall into it.

 

Fractal

 

Now you can use recursion function to explore another charmful world– Fractal.

 


 

Fractal, also called deformity, is usually defined to “A rough or piecemeal geometry that can be divided into sections and each section is (at least approximately) an overall reduced shape”, i.e. to have similar nature.

In the nature, we can see lots of fractals.

 





2

3

 

Source of Pictures:

http://themindunleashed.org/2014/10/30-beautiful-photographs-fractals-nature.html

 

Now, I believe you might have some intuitive impression for fractal. It is quite simple to design fractal graphics in program. Through recursion, you can create abundant details with the most simplified regulation. Let’s take a look at the example below.

 

Code Example (8-8):

 

Within —- ofApp.h

#include "ofMain.h"

class ofApp : public ofBaseApp{

public:

void setup();

void update();

void draw();

...

void recursion(float r,int num);

};

Within —- ofApp.cpp

void ofApp::setup(){

ofSetWindowShape(400,400);

}

void ofApp::update(){

}

void ofApp::draw(){

ofBackground(255);

ofTranslate(ofGetWidth()/2,ofGetHeight()/2);

recursion(200,0);

}

void ofApp::recursion(float r,int num){

if(r > 10){

if(r > 30){

ofNoFill();

ofSetColor(0);

}else{

ofFill();

ofSetColor(0);

}

float ratio = mouseX/(float)ofGetWidth();

if(ratio > 0.6){

ratio = 0.6;

}

r = r * ratio;

num ++;

// draw center rectangle

ofSetRectMode(OF_RECTMODE_CENTER);

ofDrawRectangle(0,0, r * 2, r * 2);

// draw surrounding rectangles

ofPushMatrix();

ofRotate(ofGetElapsedTimef() * num * 10);

ofTranslate(-r,-r);

recursion(r,num);

ofPopMatrix();

ofPushMatrix();

ofRotate(ofGetElapsedTimef() * num * 10);

ofTranslate(-r,r);

recursion(r,num);

ofPopMatrix();

ofPushMatrix();

ofRotate(ofGetElapsedTimef() * num * 10);

ofTranslate(r,-r);

recursion(r,num);

ofPopMatrix();

ofPushMatrix();

ofRotate(ofGetElapsedTimef() * num * 10);

ofTranslate(r,r);

recursion(r,num);

ofPopMatrix();

}

}


4

 

In a recursion function, the function can be invoked for multiple times. The example above has been invoked for 4 times. Therefore, it has created multiple branches.

Why the complexity degree of the graphic is dynamic ? It is because the horizontal coordinate of mouse has controlled the proportion of ratio.

 

” ratio = mouseX/(float)width “.

Bigger value of ratio, the decreasing speed of the value r will be more slowly. So the recursive time will increase as well as the quantity of graphic.

 

A condition added after ratio ” if(ratio > 0.6){ratio = 0.6;}” is to make sure the value of ratio will not beyond 0.6 so that the program will not collapse due to too much graphics drawn.

ofRotate can be hided with comment so that we can see the whole branch and body structure more clearly. The function of variable num is to record the time of current recursion. Finally we can affect the rotate speed of our graphic through num. We can see that more recursive times will bring faster rotate speed to the rectangle.


5

 

In the fractal graphic, there is a famous graphic named Sierpinski carpet. This is quite similar to the above code. Only if we do a little small changes, you can draw it with program too.

 



Sierpinski carpet

 

Relative Artworks Of Fractal

 


6

7


8


9


10


11


12


13


14

 

Fractal is the black magic for graphic design. With fewer code and the most simplified structure, you can create abundant details. The above artworks are based on fractal. We can see the similar characteristics obviously. Now you can move your hands and try to design some charmful fractal graphics.

 

END

 

In the end of this chapter, I would like to recommend two record films about fractal for you. I am sure you will be addicted to it!

 


Hunting the Hidden Dimension (PBS)

The Secret Life of Chaos (BBC)

This article comes from designer Wenzy.

 

Relative Readings:

 

Interesting Programming Guidance for Designer——Processing Initial Touch

Interesting Programming Guidance for Designer–Create Your First Processing Program

Interesting Programming Guidance for Designer–Get Your Picture Running(Part One)

Interesting Programming Guidance for Designer–Get Your Picture Running(Part Two)

Interesting Programing Guidance for Designer–Program Process Control- Loop Statement

Interesting Programming Guidance for Designer–Program Process Control–Condition Statement (Part One)

Interesting Programming Guidance for Designer–Program Process Control–Condition Statement (Part Two)

Interesting Programming Guidance for Designer–Custom Functions and Fractal Recursion

VN:F [1.9.13_1145]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.13_1145]
Rating: 0 (from 0 votes)
song

Author song

More posts by song

Leave a Reply