• Aucun résultat trouvé

Stochastic Search

Dans le document Using the Processing Language (Page 188-195)

Advanced Graphics Algorithms

7.2 Stochastic Search

A stochastic search is defined here as a random search in space until a given condi-tion is met. For instance, the placement of toys in a playpen so that each toy does not overlap any other and they all fit within the limits of the playpen can be addressed with a stochastic search. This algorithm can be represented as follows:

while(no more toys are left to place){

choose randomly a position (rx, ry) within the playpen compare it with all previous toy locations

is there an overlap?

if no then place the toy at (rx, ry) }

This algorithm can be used to place objects within a site so that that there is no overlap (or some other criterion is satisfied). In the following code, a series of 10 × 10 rectangles are placed within an area of the screen (300 × 300 here):

1 float [] xp = new float[0]; //used to store the allocated elements 2 float [] yp = new float[0];

3 int numObjects = 0; //used to count the number of allocated elements 4 void setup(){

5 size(300,300);

6 }

7 void draw(){

8 background(255);

9 for(int i=0; i<xp.length; i++) //draw anything that has been allocated 10 rect(xp[i],yp[i],10,10);

11 }

12 void keyPressed(){

13 int k = 0;

14 while(true){ //until you find a successful location (i.e. without an overlap)

15 boolean overlap = false; //use it to mark overlaps 16 float xrand = random(10,width-10); //produce a random possible location 17 float yrand = random(10,height-10);

18 for(int j=0; j<xp.length; j++){ //go through all the remaining elements 19 float distance = dist(xrand,yrand,xp[j],yp[j]); //find distance 20 if(distance < 10) overlap = true; //if too short then it will overlap 21 }

22 if(overlap==false){ //if no overlap then this is a successful location 23 xp = append(xp,xrand); //add it to memory newly placed objects. We also need a variable called numObjects, which will hold to the number of objects. In the setup() section, we define the size of the window (300 × 300) and in the draw() section we draw rectangles (representing the objects to be allocated) at the locations defined by the coordinates xp[] and yp[]. These coordinates are calculated in the keyPressed() section so that each time a key is pressed an object is allocated. This section is composed basically of two loops: one for suggesting a random position and one for checking for the validity of the potential position (i.e., whether it overlaps the other objects already placed in the scene). We start with a “while” loop (line 14) that repeat-edly creates random locations that are input into the variables xrand and yrand. We also define a boolean variable called overlap that we set to false. Next, we loop through all the already existing objects in the scene, and that is done by looping from 0 to the length of the existing objects (x.length or y.length).

Then we calculate the distance between the suggested locations xrand and yrand from each already defined object. If it is less than a tolerance value (in this case 10), we consider this to be an overlap and set the variable overlap to true. If not, we create a new random location and try again. If we have no overlaps, we assign the xrand value as a valid new location and exit the loop (line 25).

However, it is possible that there is no more space, so there will always be an overlap (in which case we will run into an infinite loop). So, we use lines 28 to

31 as a way of forcing an exit from the loop if 10,000 attempts have been made and there is always an overlap. At each successful allocation of a new object we add one to the number of objects (line 33). The result of this algorithm is shown in Figure 7-5.

Figure 7-5: Stochastic search allocating 1 to 15 and then 541 squares

An alternative approach to the problem of stochastic allocation is to search for space availability that is adjacent to the last successful allocation. In other words, after allocating an object, then look around it for available space to allocate the next one. This can be interpreted as an attempt to fill the local region before searching further out. The effect of such a search mechanism is the creation of snake-like blobs of objects that move along the empty space populating it with new objects. The code is shown here:

1 float [] xp = new float[0];

2 float [] yp = new float[0];

3 int numObjects = 0;

4 void setup(){

5 size(300,300);

6 xp = append(xp,random(10,width-10));

7 yp = append(yp,random(10,height-10));

8 }

9 void draw(){

10 background(255);

11 for(int i=0; i<xp.length; i++) 12 rect(xp[i],yp[i],10,10);

18 float xrand = random(xp[xp.length-1]-20,xp[xp.length-1]+20);

19 float yrand = random(yp[yp.length-1]-20,yp[yp.length-1]+20);

20 for(int j=0; j<xp.length; j++){

21 float distance = dist(xrand,yrand,xp[j],yp[j]);

22 if(distance < 10 || xrand>width-20 || xrand<20 ||

This code is similar to that shown previously, except for three parts (shown in bold font): First, we start with a random initial location (lines 6 and 7). Second, we calculate a random new location, and we give it a range within which it can generate possible coordinates. This range is within 40 points of the previous (last) position. Finally, we change the condition for overlap by assuming that if the distance is greater than the minimum tolerance (i.e., 10), or the new location is out of the greater region (i.e., the screen), then the overlap is true. The result of this algorithm is shown in Figure 7-6.

Figure 7-6: Stochastic search allocating 1 to 15 and then 227 squares

7.3 Fractals

A fractal is a geometric object generated by a repeating pattern, in a typically recursive or iterative process. Some of the best examples can be divided into parts, each of which is similar to the original object. Fractals are said to possess infinite detail, and some of them have a self-similar structure that occurs at different levels of magnification. The term fractal was coined in 1975 by Benoît Mandelbrot, from the Latin fractus or “fractured.”

In a fractal, there are at least two shapes: a base and a generator. In each iteration, the generator replaces each segment of the base shape. Theoretically, this process can continue infinitely. The algorithm to create fractals consists of a basic procedure that fits a shape between two points. The process of fitting involves scaling, rotation, and translation of the generator to fit between two points of a segment of the base. The following code shows the procedure:

1 float [] px = new float[0]; //temp array 2 float [] py = new float[0];

3 float [] gx = {-10,10,20,30,40}; //generator data 4 float [] gy = {0, 0,-10, 0, 0};

5 float [] bx = {0,100,200,300,400}; //base data

6 float [] by = {200, 200,100,200, 200};

14 for(int i=1; i<bx.length; i++)

15 if(bx[i]!=999 && bx[i-1]!=999) //skip

22 for(int j=0; j<bx.length-1; j++){ //for all base lines 23 if(bx[j]!=999 && bx[j+1]!=999) //skip if marked

44 for(int i=0; i<px.length; i++){

45 bx = append(bx,px[i]);

46 by = append(by,py[i]);

47 } 48 }

In the first six lines of code we define the coordinates of the generator shape (gx[] and gy[]), the base shape (bx[] and by[]) as well as a temporary array to hold the points of the resulting fractal shape (px[] and py[]). In the draw() section, we just draw the lines that describe the base as it is being replaced

polyline and the beginning of a new polyline. It is assumed that there will not be no more than 999 replacement polylines to construct.

In the mousePressed() section, we perform the replacement operation. First, we set the resulting fractal shape array to 0. We do this every time we pro-duce a new fractal shape. The Processing command used is contract(), which essentially shrinks the array to 0, that is, it empties it. Then we go for all the base array points (stored in the bx[] and by[] arrays), skipping the end points (marked with the 999 number), and then loop for all the generator points and adjust them through the following three transformations:

1. Calculate the distance between two sequential base points and the distance between the first and last point of the generator array, then divide the distances to get the scaling factor (which we multiply by each generator point).

2. Find the angle between the base and the generator, using the acos() func-tion that returns the angle between two vectors (i.e., two lines whose first points are at the origin 0,0), then rotate the base by that angle (line 30).

3. Translate the base back to its location within their original location.

Finally, we add the newly transformed base points to the temporary array px[] and py[], adding a mark (999) at the end of each polyline to separate them later on when we draw them. When we are done with all the parts of the base, we empty bx[] and by[] and populate them with the px[] and py[] arrays.

The result of this process is shown in Figure 7-7.

Figure 7-7: Fractal process of 1 to 6 replacements of Polyline

Dans le document Using the Processing Language (Page 188-195)