Skip to content

Commit 8b062f7

Browse files
committed
allow side branch to change angles for 2d tree.
1 parent 7041933 commit 8b062f7

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

BeingAliveLanguage/BALCore/coreTree2D.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ public static void ClearAll() {
4646

4747
class Tree2D {
4848
public Tree2D() {}
49-
public Tree2D(Plane pln, double height, bool unitary = false) {
49+
public Tree2D(Plane pln, double height, bool unitary = false, double sideBranchAngle = 95.0) {
5050
mPln = pln;
5151
mHeight = height;
5252
mUnitary = unitary;
53+
mBaseAngle = sideBranchAngle; // Use the provided angle instead of default
5354

5455
// Configure growth parameters
5556
mTrunkSegLen = height / mStage1;
@@ -622,6 +623,7 @@ private void ApplyTopBranchRemoval(int stage4Phase) {
622623
mSubBranch_r = newSubBranchR;
623624
mSubBranch = mSubBranch_l.Concat(mSubBranch_r).ToList();
624625
} // Helper method to determine if a branch is on the left side of the plane
626+
625627
private bool IsBranchOnLeftSide(Curve branch) {
626628
// Get the branch's endpoint (or midpoint for better accuracy)
627629
Point3d branchEnd = branch.PointAtEnd;
@@ -1066,7 +1068,7 @@ private void ClearTreeData() {
10661068
private double mTrunkSegLen; // Length of trunk segment per phase
10671069
private double mMaxBranchLen; // Maximum branch length
10681070
private double mMinBranchLen; // Minimum branch length
1069-
private readonly double mBaseAngle = 95; // Base angle for side branches
1071+
private double mBaseAngle = 95; // Base angle for side branches (can be overridden)
10701072
private readonly double mTopBranchAngle = 35; // Angle for top branches
10711073

10721074
// curve collection

BeingAliveLanguage/BALtree.cs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ protected override void RegisterInputParams(GH_Component.GH_InputParamManager pM
3131
Plane.WorldXY);
3232
pManager.AddNumberParameter("Height", "H", "Height of the tree.", GH_ParamAccess.list);
3333
pManager.AddIntegerParameter("Phase", "phase", "Phase of the tree.", GH_ParamAccess.list);
34+
pManager.AddNumberParameter("SideBranchAngle",
35+
"sbAng",
36+
"Opening angle of side branches in degrees (30-120).",
37+
GH_ParamAccess.list,
38+
95.0);
39+
pManager[3].Optional = true;
3440
}
3541

3642
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) {
@@ -62,6 +68,9 @@ protected override void SolveInstance(IGH_DataAccess DA) {
6268
return;
6369
}
6470

71+
var angLst = new List<double>();
72+
DA.GetDataList("SideBranchAngle", angLst);
73+
6574
var trunk = new List<Curve>();
6675
var canopyC = new List<Curve>();
6776
var sideB = new List<Curve>();
@@ -91,6 +100,26 @@ protected override void SolveInstance(IGH_DataAccess DA) {
91100
return;
92101
}
93102

103+
// Handle angle list - replicate single value or validate count
104+
if (angLst.Count == 0)
105+
angLst = Enumerable.Repeat(95.0, plnLst.Count).ToList();
106+
else if (angLst.Count == 1)
107+
angLst = Enumerable.Repeat(angLst[0], plnLst.Count).ToList();
108+
else if (angLst.Count != plnLst.Count) {
109+
AddRuntimeMessage(GH_RuntimeMessageLevel.Error,
110+
"SideBranchAngle # does not match Plane #, please check.");
111+
return;
112+
}
113+
114+
// Validate angle range
115+
foreach (var ang in angLst) {
116+
if (ang < 30 || ang > 120) {
117+
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning,
118+
"SideBranchAngle should be within [30, 120]. Values will be clamped.");
119+
break;
120+
}
121+
}
122+
94123
// Create a copy of plane list for sorting (while keeping original order intact)
95124
var sortedPlaneIndices = Enumerable.Range(0, plnLst.Count).ToList();
96125
sortedPlaneIndices.Sort((i1, i2) => {
@@ -115,7 +144,9 @@ protected override void SolveInstance(IGH_DataAccess DA) {
115144
//! 2. Draw trees in original order, collect tree widths
116145
var widCol = new List<double>();
117146
for (int i = 0; i < plnLst.Count; i++) {
118-
var t = new Tree2D(plnLst[i], hLst[i], false);
147+
// Clamp angle to valid range
148+
double clampedAngle = Math.Max(30, Math.Min(120, angLst[i]));
149+
var t = new Tree2D(plnLst[i], hLst[i], false, clampedAngle);
119150
var res = t.GrowToPhase(phLst[i]);
120151

121152
if (!res.Item1) {
@@ -158,8 +189,12 @@ protected override void SolveInstance(IGH_DataAccess DA) {
158189
}
159190
} else if (plnLst.Count == 1) // special case: only one tree
160191
{
192+
// Handle angle for single tree
193+
double singleAngle = angLst.Count > 0 ? angLst[0] : 95.0;
194+
singleAngle = Math.Max(30, Math.Min(120, singleAngle));
195+
161196
tscal.Add(Tuple.Create(1.0, 1.0));
162-
treeCol.Add(new Tree2D(plnLst[0], hLst[0], false));
197+
treeCol.Add(new Tree2D(plnLst[0], hLst[0], false, singleAngle));
163198
var res = treeCol.Last().GrowToPhase(phLst[0]);
164199

165200
if (!res.Item1) {

0 commit comments

Comments
 (0)