This will be a fractial(ish) tree with same code as in Fractal Tree 1, but with some added randomness. Instead of having the length ratio and branch angle as constant values throughout the fractal tree, length & angle tolerance parameters have been added in order to have some more unique results.
The lengths are derived as in Fractal Tree 1, for the first part at least. If we take the two branches following the ‘trunk’ (Length = 14). These two branches have lengths of 8.54 and 9.15. To calculate the lengths we have the previous segment length * length ratio (14 * 0.6 = 8.4). Now in order to achieve some randomness, length tolerance is introduced in order to have range of numbers to choose from. The range of numbers is calculated:
Range max value = length * length tolerance: 8.4*1.2 = 10.08
Range min value = length – (max value – length): 8.4-(10.08-8.4) = 6.72
This gives as a range from 6.72 to 10.08. This is the range from where iteration 1 will choose a random number from. In the picture above the the numbers chosen from the random function was 8.54 and 9.15.
For the next iteration the range for the left side is 4.0992 to 6.1488
and for the right side it is 4.392 to 6.588
Then angle parameter works with same logic as the branch length, having a range from where the final angle will be picked from. Branch Angle is the base parameter and Branch Angle Tolerance sets the range of possible angles to choose from. The higher the number, the more variability for the angles.
With some randomness for the branch lengths and angles, the fractal tree is starting to look a bit more ‘tree-like’, and variations are plentiful. Below is two variations of the code, first is without the random seed as a user parameter, which gives more conveniently unique variations. The second is with the random seed as a user parameter, giving more control to the user.
private void RunScript(double startLength, double lengthRatio, double lengthTolerance, double branchAngle, double angleTolerance, int iterations, ref object A)
{
Point3d startPoint = new Point3d(0, 0, 0);
Vector3d startVector = new Vector3d(0, 1, 0);
Vector3d z = new Vector3d(0, 0, 1);
Line first = new Line(startPoint, startVector, startLength);
int path = 0;
GH_Path firstPath = new GH_Path(path);
DataTree<Line> treeBranches = new DataTree<Line>();
treeBranches.Add(first, firstPath);
var random = new Random();
for(int i = 0;i < iterations;i++)
{
List<Line> branchList = treeBranches.Branch(treeBranches.BranchCount - 1);
path++;
GH_Path pth = new GH_Path(path);
foreach(Line branch in branchList)
{
Line newBranchLeft = treeBranch(branch, branchAngle, angleTolerance, lengthRatio, lengthTolerance, z, true, random);
Line newBranchRight = treeBranch(branch, branchAngle, angleTolerance, lengthRatio, lengthTolerance, z, false, random);
treeBranches.Add(newBranchLeft, pth);
treeBranches.Add(newBranchRight, pth);
}
}
A = treeBranches;
}
// <Custom additional code>
Line treeBranch (Line Branch, double degreeRotation, double rotationTolerance, double LengthRatio, double LengthTolerance, Vector3d RotationAxis, bool RotationDirection, Random random)
{
double rotation = RandomDoubleInRange(degreeRotation, rotationTolerance, random);
double radianRotation = RhinoMath.ToRadians(rotation);
Point3d endPoint = Branch.To;
Vector3d direction = Branch.To - Branch.From;
if(RotationDirection)
{
direction.Rotate(radianRotation, RotationAxis);
}
else
{
direction.Rotate(-radianRotation, RotationAxis);
}
double length = Branch.Length * LengthRatio;
double branchLength = RandomDoubleInRange(length, LengthTolerance, random);
Line newBranch = new Line(endPoint, direction, branchLength);
return newBranch;
}
double RandomDoubleInRange (double OriginalValue, double Tolerance, Random random)
{
double tolerance = (OriginalValue * Tolerance) - OriginalValue;
double min = OriginalValue - tolerance;
double max = OriginalValue + tolerance;
var rDouble = random.NextDouble();
var rRangeDouble = rDouble * (max - min) + min;
return rRangeDouble;
}
And second option with random seed as user parameter:
private void RunScript(double startLength, double lengthRatio, double lengthTolerance, double degreeRotation, double rotationTolerance, int iterations, int randomSeed, ref object A)
{
Point3d startPoint = new Point3d(0, 0, 0);
Vector3d startVector = new Vector3d(0, 1, 0);
Vector3d z = new Vector3d(0, 0, 1);
Line first = new Line(startPoint, startVector, startLength);
int path = 0;
GH_Path firstPath = new GH_Path(path);
DataTree<Line> treeBranches = new DataTree<Line>();
treeBranches.Add(first, firstPath);
var random = new Random(randomSeed);
for(int i = 0;i < iterations;i++)
{
List<Line> branchList = treeBranches.Branch(treeBranches.BranchCount - 1);
path++;
GH_Path pth = new GH_Path(path);
foreach(Line branch in branchList)
{
Line newBranchLeft = treeBranch(branch, degreeRotation, rotationTolerance, lengthRatio, lengthTolerance, z, true, random);
Line newBranchRight = treeBranch(branch, degreeRotation, rotationTolerance, lengthRatio, lengthTolerance, z, false, random);
treeBranches.Add(newBranchLeft, pth);
treeBranches.Add(newBranchRight, pth);
}
}
A = treeBranches;
}
// <Custom additional code>
Line treeBranch (Line Branch, double degreeRotation, double rotationTolerance, double LengthRatio, double LengthTolerance, Vector3d RotationAxis, bool RotationDirection, Random random)
{
double rotation = RandomDoubleInRange(degreeRotation, rotationTolerance, random);
double radianRotation = RhinoMath.ToRadians(rotation);
Point3d endPoint = Branch.To;
Vector3d direction = Branch.To - Branch.From;
if(RotationDirection)
{
direction.Rotate(radianRotation, RotationAxis);
}
else
{
direction.Rotate(-radianRotation, RotationAxis);
}
double length = Branch.Length * LengthRatio;
double branchLength = RandomDoubleInRange(length, LengthTolerance, random);
Line newBranch = new Line(endPoint, direction, branchLength);
return newBranch;
}
double RandomDoubleInRange (double OriginalValue, double Tolerance, Random random)
{
double tolerance = (OriginalValue * Tolerance) - OriginalValue;
double min = OriginalValue - tolerance;
double max = OriginalValue + tolerance;
var rDouble = random.NextDouble();
var rRangeDouble = rDouble * (max - min) + min;
return rRangeDouble;
}