Summary

Dichotomous branching

Demo-file: Demo5.pov

While the branching pattern in the previous chapter has been defined more or less by chance, we now want to create a strictly dichotomous pattern. (With some residual variability, of course.)

Dichotomous branching

Such a pattern is created in three steps: First, all the positions from this pattern are defined. The macro doing this, which is detailed below, takes advantage of the fact that the number of positions is doubled for each level.

#macro DichotomousBranching (StartPosition, Levels, StartDistance, Anglexy0, Anglez0, Variance)
//This macro defines the positions for a dichotomously branching structure along the x-axis and stores
//these positions in the array Positions.
//Parameters of the macro are the starting position, the number of different levels, the starting distance between
//two levels, the angles between the branches in the first levels and a factor of random variance.
//Anglexy refers to a rotation around the z-axis, Anglez to a rotation around the y-axis.

//Initialization of the arrays storing positions and angles.

#declare Positions = array [Levels + 1][pow(2, Levels + 1) + 1];
#local AAnglexy = array [Levels + 1][pow(2, Levels + 1) + 1];
#local AAnglez = array [Levels + 1][pow(2, Levels + 1) + 1];

//Definition of Positions

//Definition of the starting position.
#local ticker2 = 0;
#local ticker = 0;
#local P1 = StartPosition;
#declare Positions [ticker2][ticker] = P1;
#local AAnglexy [ticker2][ticker] = 0;
#local AAnglez [ticker2][ticker] = 0;

//Definition of the further levels.
//The following two nested loops first run through the various levels (ticker2)
//and then through the various elements on each level (ticker1).

#local ticker2 = 1;
#while (ticker2 <Levels)
#local Elements = pow (2, ticker2);//Element numbers are doubled each level.
#local Distance = 0.4 + StartDistance * sin (pi/2 + ticker2 * pi/18);//The distances are shortened each level.
#local Anglexy = Anglexy0 - 10 * sin (ticker2 * pi/18);//Anglexy is decreased each level.
#local Anglez = Anglez0 - 10 * sin (ticker2 * pi/18);//Anglez is decreased each level.
#local ticker = 0;
#while ( ticker <Elements)
#local var1 = rand(chance1);
#local var2 = rand(chance2);
#local var3 = rand(chance3);

//The values for the positions and angles from the previous level are extracted from the respective arrays.
#local P0 = Positions [ticker2-1][int(ticker/2)];
#local Angle0xy = AAnglexy [ticker2-1][int(ticker/2)];
#local Angle0z = AAnglez [ticker2-1][int(ticker/2)];

//Definition of positions and angles for the current level. The if-clauses result in a dichotomous, alternating branching.
#if (mod(ticker2, 2) >0)
#if (mod(ticker, 2) >0)
#local P1=<P0.x + ((cos(radians(Angle0xy + Anglexy)) * Distance) * (cos(radians(Angle0z)))) + Variance * (0.5 - rand(chance1))/10, P0.y + (sin(radians(Angle0xy + Anglexy)) * Distance) + Variance * (0.5 - rand(chance2)), P0.z + (sin(radians(Angle0z)) * Distance * (cos(radians(Angle0xy + Anglexy)))) + Variance * (0.5 - rand(chance3))>;
#local AAnglexy [ticker2][ticker] = (Angle0xy + Anglexy);
#local AAnglez [ticker2][ticker] = (Angle0z);
#else
#local P1=<P0.x + ((cos(radians(Angle0xy - Anglexy)) * Distance) * (cos(radians(Angle0z)))) + Variance * (0.5 - rand(chance1))/10, P0.y + (sin(radians(Angle0xy - Anglexy)) * Distance) + Variance * (0.5 - rand(chance2)), P0.z + (sin(radians(Angle0z)) * Distance * (cos(radians(Angle0xy + Anglexy)))) + Variance * (0.5 - rand(chance3))>;
#local AAnglexy [ticker2][ticker] = (Angle0xy - Anglexy);
#local AAnglez [ticker2][ticker] = (Angle0z);
#end
#else
#if (mod(ticker, 2) >0)
#local P1=<P0.x + ((cos(radians(Angle0z + Anglez)) * Distance) * (cos(radians(Angle0xy)))) + Variance * (0.5 - rand(chance1))/10, P0.y + (sin(radians(Angle0xy)) * Distance) + Variance * (0.5 - rand(chance2)), P0.z + (sin(radians(Angle0z + Anglez)) * Distance * (cos(radians(Angle0xy)))) + Variance * (0.5 - rand(chance3))>;
#local AAnglexy [ticker2][ticker] = (Angle0xy);
#local AAnglez [ticker2][ticker] = (Angle0z + Anglez);
#else
#local P1=<P0.x + ((cos(radians(Angle0z - Anglez)) * Distance) * (cos(radians(Angle0xy)))) + Variance * (0.5 - rand(chance1))/10, P0.y + (sin(radians(Angle0xy)) * Distance) + Variance * (0.5 - rand(chance2)), P0.z + (sin(radians(Angle0z - Anglez)) * Distance * (cos(radians(Angle0xy)))) + Variance * (0.5 - rand(chance3))>;
#local AAnglexy [ticker2][ticker] = (Angle0xy);
#local AAnglez [ticker2][ticker] = (Angle0z - Anglez);
#end
#end

//Storing of positions in the respective array.
#declare Positions [ticker2][ticker] = P1;
#local ticker = ticker + 1;
#end
#local ticker2 = ticker2 + 1;
#end
#end

In the second step, positions for the drawing of individual sphere_sweeps are selected from the positions defined above and stored in a new array. The macro for this selection is specified below. The selection of such positions is started at the outermost level. A loop will be used to define a suitable sphere_sweep for each of these positions.

#macro SearchDichotomousBranch (Levels, InputArray, Branch)
//This macro selects individual branches from the dichotomously branched positions defined in the previous macro.
//Parameters for the macro are the number of levels included in the prospective sphere_sweeps, the name of the
//input array and the number for a specific endpoint at the last level.
//The output array of this macro has the name SweepPositions.

//First the point from the last level is extracted from the input array.

#local PEnd = Positions [Levels-1][Branch];

//Initialization of the output array.
#declare SweepPositions = array [Levels + 1];

//Definition of the outer positions of the sphere_sweep.

#declare SweepPositions[Levels] = PEnd;
#declare SweepPositions[1] = Positions [0][0];
#declare SweepPositions[0] = SweepPositions[1] - ((PEnd - SweepPositions[1])/Levels);

//Definition of the inner positions of the sphere_sweep.
#local Number = Branch;
#local ticker4 = 1;
#while (ticker4 <Levels-1)
#local Level = Levels-ticker4;
#local PNext = Positions [Level-1][int(Number/2)];
#local Number = int(Number/2);
#declare SweepPositions[Level] = PNext;
#local ticker4 = ticker4 + 1;
#end
#end

Here comes the code, which invokes the macros detailed above and finally uses the arrays defined in these macros to draw sphere_sweeps and spheres.

//Initialization of pseudo-random streams.
#local chance1 = seed (13);
#local chance2 = seed (15);
#local chance3 = seed (23);

//Definition of the number of levels of the branching.
#declare Levels = 10;

//macro to define the positions of the dichotomously branched structure.
DichotomousBranching (<0, 0, 0>, Levels, 1.5, 20, 20, 0.2, )

//This loop draws a sphere_sweep for every positions from the outermost level.
#declare ticker3 = 0;
#while (ticker3 <pow (2, (Levels-1)))
//macro to search a path to a given point from the outermost level.
//the path is stored in the array SweepPositions.
SearchDichotomousBranch (Levels, Positions, ticker3)

//macro to draw the sphere_sweeps.
DrawSphereSweep (SweepPositions, 0.12, Levels)

//macro to draw spheres.
DrawSpheres (SweepPositions, 0.135, Levels-1)

#declare ticker3 = ticker3 + 1;
#end

Summary