5
5
#include " source/utilities/NodeUtilities.hpp"
6
6
#include " source/utilities/GeometryUtilities.hpp"
7
7
8
+
9
+ using namespace Mtree ;
10
+
11
+ namespace
12
+ {
13
+ void update_positions_rec (Node& node, const Vector3& position)
14
+ {
15
+ auto & info = static_cast <BranchFunction::BranchGrowthInfo&>(*node.growthInfo );
16
+ info.position = position;
17
+
18
+ for (auto & child : node.children )
19
+ {
20
+ Vector3 child_position = position + node.direction * node.length * child->position_in_parent ;
21
+ update_positions_rec (child->node , child_position);
22
+ }
23
+ }
24
+
25
+ bool avoid_floor (const Vector3& node_position, Vector3& node_direction, float parent_length) // return true if branch should be terminated
26
+ {
27
+ if (node_direction.z () < 0 )
28
+ {
29
+ node_direction[2 ] -= node_direction[2 ] * 2 / (2 + node_position.z ());
30
+ }
31
+ return (node_position + node_direction).z () * parent_length * 4 < 0 ; // is node heading to floor too fast
32
+ }
33
+
34
+ Vector3 get_main_child_direction (Node& parent, const Vector3& parent_position, const float up_attraction, const float flatness, const float randomness, const float resolution, bool & should_terminate)
35
+ {
36
+ Vector3 random_dir = Geometry::random_vec (flatness).normalized () + Vector3{ 0 ,0 ,1 } * up_attraction;
37
+ Vector3 child_direction = parent.direction + random_dir * randomness / resolution;
38
+ should_terminate = avoid_floor (parent_position, child_direction, parent.length );
39
+ child_direction.normalize ();
40
+ return child_direction;
41
+ }
42
+
43
+ Vector3 get_split_direction (const Node& parent, const Vector3& parent_position, const float up_attraction, const float flatness, const float resolution, const float angle)
44
+ {
45
+ Vector3 child_direction = Geometry::random_vec ();
46
+ child_direction = child_direction.cross (parent.direction ) + Vector3{ 0 ,0 ,1 } *up_attraction * flatness;
47
+ Vector3 flat_normal = Vector3{ 0 ,0 ,1 }.cross (parent.direction ).cross (parent.direction ).normalized ();
48
+ child_direction -= child_direction.dot (flat_normal) * flatness * flat_normal;
49
+ avoid_floor (parent_position, child_direction, parent.length );
50
+ child_direction = Geometry::lerp (parent.direction , child_direction, angle / 90 ); // TODO use slerp for correct angle
51
+ child_direction.normalize ();
52
+ return child_direction;
53
+ }
54
+
55
+ void mark_inactive (Node& node)
56
+ {
57
+ auto & info = static_cast <BranchFunction::BranchGrowthInfo&>(*node.growthInfo );
58
+ info.inactive = true ;
59
+ }
60
+
61
+ bool propagate_inactive_rec (Node& node)
62
+ {
63
+ auto * info = dynamic_cast <BranchFunction::BranchGrowthInfo*>(node.growthInfo .get ());
64
+
65
+ if (node.children .size () == 0 || info->inactive )
66
+ return info->inactive ;
67
+
68
+ bool inactive = false ;
69
+ for (size_t i = 0 ; i < node.children .size (); i++)
70
+ {
71
+ if (propagate_inactive_rec (node.children [i]->node ))
72
+ inactive = true ;
73
+ }
74
+ info->inactive = inactive;
75
+ return inactive;
76
+ }
77
+ }
78
+
8
79
namespace Mtree
9
80
{
10
- void BranchFunction::apply_gravity (Node& node )
81
+ void BranchFunction::apply_gravity_to_branch (Node& branch_origin )
11
82
{
12
- update_weight_rec (node);
13
- apply_gravity_rec (node, Eigen::AngleAxisf::Identity ());
83
+ propagate_inactive_rec (branch_origin);
84
+ update_weight_rec (branch_origin);
85
+ apply_gravity_rec (branch_origin, Eigen::AngleAxisf::Identity ());
86
+ BranchGrowthInfo& info = static_cast <BranchGrowthInfo&>(*branch_origin.growthInfo );
87
+ update_positions_rec (branch_origin, info.position );
14
88
}
15
89
16
- void BranchFunction::apply_gravity_rec (Node& node, Eigen::AngleAxisf previous_rotations )
90
+ void BranchFunction::apply_gravity_rec (Node& node, Eigen::AngleAxisf curent_rotation )
17
91
{
18
- float horizontality = 1 -abs (node.direction .z ());
19
92
BranchGrowthInfo& info = static_cast <BranchGrowthInfo&>(*node.growthInfo );
20
- info.age += 1 /resolution;
21
- float displacement = horizontality * std::pow (info.cumulated_weight , .5f ) * gravity_strength / resolution / resolution / 1000 / (1 +info.age );
22
- displacement *= std::exp (- std::abs (info.deviation_from_rest_pose / resolution * stiffness));
23
- info.deviation_from_rest_pose += displacement;
93
+ if (!info.inactive || true )
94
+ {
95
+ float horizontality = 1 - abs (node.direction .z ());
96
+ info.age += 1 / resolution;
97
+ float displacement = horizontality * std::pow (info.cumulated_weight , .5f ) * gravity_strength / resolution / resolution / 1000 / (1 + info.age );
98
+ displacement *= std::exp (-std::abs (info.deviation_from_rest_pose / resolution * stiffness));
99
+ info.deviation_from_rest_pose += displacement;
24
100
25
- Vector3 tangent = node.direction .cross (Vector3{0 ,0 ,-1 }).normalized ();
26
- Eigen::AngleAxisf rot{displacement, tangent};
27
- rot = rot * previous_rotations ;
101
+ Vector3 tangent = node.direction .cross (Vector3{ 0 ,0 ,-1 }).normalized ();
102
+ Eigen::AngleAxisf rot{ displacement, tangent };
103
+ curent_rotation = rot * curent_rotation ;
28
104
29
- node.direction = rot * node.direction ;
105
+ node.direction = curent_rotation * node.direction ;
106
+ }
30
107
31
108
for (auto & child : node.children )
32
109
{
33
- apply_gravity_rec (child->node , rot );
110
+ apply_gravity_rec (child->node , curent_rotation );
34
111
}
35
112
}
36
-
113
+
37
114
void BranchFunction::update_weight_rec (Node& node)
38
115
{
39
116
float node_weight = node.length ;
@@ -48,54 +125,55 @@ namespace Mtree
48
125
info->cumulated_weight = node_weight;
49
126
}
50
127
51
-
52
128
// grow extremity by one level (add one or more children)
53
129
void BranchFunction::grow_node_once (Node& node, const int id, std::queue<std::reference_wrapper<Node>>& results)
54
130
{
55
131
bool break_branch = rand_gen.get_0_1 () * resolution < break_chance;
56
132
if (break_branch)
133
+ {
134
+ mark_inactive (node);
57
135
return ;
58
-
59
- bool split = rand_gen.get_0_1 () * resolution < split_proba; // should the node split into two children
136
+ }
60
137
61
138
BranchGrowthInfo& info = static_cast <BranchGrowthInfo&>(*node.growthInfo );
62
139
float factor_in_branch = info.current_length / info.desired_length ;
63
140
64
- Vector3 random_dir = Geometry::random_vec (flatness).normalized () + Vector3{0 ,0 ,1 } * up_attraction;
65
- Vector3 child_direction = node.direction + random_dir * randomness.execute (factor_in_branch) / resolution;
66
- // child_direction += Vector3{0,0,1} * up_attraction / resolution / 50 * (1 - node.direction.z());
67
- child_direction.normalize ();
68
141
float child_radius = Geometry::lerp (info.origin_radius , info.origin_radius * end_radius, factor_in_branch);
69
142
float child_length = std::min (1 /resolution, info.desired_length - info.current_length );
70
-
143
+ bool should_terminate;
144
+ Vector3 child_direction = get_main_child_direction (node, info.position , up_attraction, flatness, randomness.execute (factor_in_branch), resolution, should_terminate);
145
+
146
+ if (should_terminate)
147
+ {
148
+ mark_inactive (node);
149
+ return ;
150
+ }
151
+
71
152
NodeChild child{ Node{child_direction, node.tangent , child_length, child_radius, id}, 1 };
72
153
node.children .push_back (std::make_shared<NodeChild>(std::move (child)));
73
154
auto & child_node = node.children .back ()->node ;
74
155
75
156
float current_length = info.current_length + child_length;
76
- BranchGrowthInfo child_info{info.desired_length , info.origin_radius , current_length};
157
+ Vector3 child_position = info.position + child_direction * child_length;
158
+ BranchGrowthInfo child_info{info.desired_length , info.origin_radius , child_position, current_length};
77
159
child_node.growthInfo = std::make_unique<BranchGrowthInfo>(child_info);
78
160
if (current_length < info.desired_length )
79
161
{
80
162
results.push (std::ref<Node>(child_node));
81
163
}
82
164
165
+ bool split = rand_gen.get_0_1 () * resolution < split_proba; // should the node split into two children
83
166
if (split)
84
167
{
85
- child_direction = Geometry::random_vec ();
86
- child_direction = child_direction.cross (node.direction ) + Vector3{0 ,0 ,1 } * up_attraction * flatness;
87
- Vector3 flat_normal = Vector3{ 0 ,0 ,1 }.cross (node.direction ).cross (node.direction ).normalized ();
88
- child_direction -= child_direction.dot (flat_normal) * flatness * flat_normal;
89
- child_direction.normalize ();
90
- child_direction = Geometry::lerp (node.direction , child_direction, split_angle/90 );
91
- child_direction.normalize ();
92
- child_radius = node.radius * split_radius;
168
+ Vector3 split_child_direction = get_split_direction (node, info.position , up_attraction, flatness, resolution, split_angle);
169
+ float split_child_radius = node.radius * split_radius;
93
170
94
- NodeChild child{ Node{child_direction , node.tangent , child_length, child_radius , id}, rand_gen.get_0_1 () };
171
+ NodeChild child{ Node{split_child_direction , node.tangent , child_length, split_child_radius , id}, rand_gen.get_0_1 () };
95
172
node.children .push_back (std::make_shared<NodeChild>(std::move (child)));
96
173
auto & child_node = node.children .back ()->node ;
97
174
98
- BranchGrowthInfo child_info{ info.desired_length , info.origin_radius * split_radius, current_length };
175
+ Vector3 split_child_position = info.position + split_child_direction * child_length;
176
+ BranchGrowthInfo child_info{ info.desired_length , info.origin_radius * split_radius, split_child_position, current_length};
99
177
child_node.growthInfo = std::make_unique<BranchGrowthInfo>(child_info);
100
178
if (current_length < info.desired_length )
101
179
{
@@ -104,7 +182,7 @@ namespace Mtree
104
182
}
105
183
}
106
184
107
- void BranchFunction::grow_origins (NodeUtilities::NodeSelection & origins, const int id)
185
+ void BranchFunction::grow_origins (std::vector<std::reference_wrapper<Node>> & origins, const int id)
108
186
{
109
187
std::queue<std::reference_wrapper<Node>> extremities;
110
188
for (auto & node_ref : origins)
@@ -114,49 +192,50 @@ namespace Mtree
114
192
int batch_size = extremities.size ();
115
193
while (!extremities.empty ())
116
194
{
117
- batch_size --;
118
- auto & node = extremities.front ().get ();
119
- extremities.pop ();
120
- grow_node_once (node, id, extremities);
121
-
122
195
if (batch_size == 0 )
123
196
{
124
197
batch_size = extremities.size ();
125
198
for (auto & node_ref : origins)
126
199
{
127
- apply_gravity (node_ref.get ());
200
+ apply_gravity_to_branch (node_ref.get ());
128
201
}
129
202
}
203
+ auto & node = extremities.front ().get ();
204
+ extremities.pop ();
205
+ grow_node_once (node, id, extremities);
206
+ batch_size --;
130
207
}
131
208
}
132
209
210
+
133
211
// get the origins of the branches that will be created.
134
212
// origins are created from the nodes made by the parent TreeFunction
135
- NodeUtilities::NodeSelection BranchFunction::get_origins (std::vector<Stem>& stems, const int id, const int parent_id)
213
+ std::vector<std::reference_wrapper<Node>> BranchFunction::get_origins (std::vector<Stem>& stems, const int id, const int parent_id)
136
214
{
137
215
// get all nodes created by the parent TreeFunction, organised by branch
138
216
NodeUtilities::BranchSelection selection = NodeUtilities::select_from_tree (stems, parent_id);
139
- NodeUtilities::NodeSelection origins;
217
+ std::vector<std::reference_wrapper<Node>> origins;
140
218
141
219
float origins_dist = 1 / (branches_density + .001 ); // distance between two consecutive origins
142
220
143
- for (auto & branch : selection) // iterating over parent branches
221
+ for (auto & branch : selection) // parent branches
144
222
{
145
223
if (branch.size () == 0 )
146
224
{
147
225
continue ;
148
226
}
149
227
150
- float branch_length = NodeUtilities::get_branch_length (branch[0 ].get () );
228
+ float branch_length = NodeUtilities::get_branch_length (* branch[0 ].node );
151
229
float absolute_start = start * branch_length; // the length at which we can start adding new branch origins
152
230
float absolute_end = end * branch_length; // the length at which we stop adding new branch origins
153
231
float current_length = 0 ;
154
232
float dist_to_next_origin = absolute_start;
155
- Vector3 tangent = Geometry::get_orthogonal_vector (branch[0 ].get (). direction );
233
+ Vector3 tangent = Geometry::get_orthogonal_vector (branch[0 ].node -> direction );
156
234
157
235
for (size_t node_index = 0 ; node_index<branch.size (); node_index++)
158
236
{
159
- auto & node = branch[node_index].get ();
237
+ auto & node = *branch[node_index].node ;
238
+ Vector3 node_position = branch[node_index].node_position ;
160
239
if (node.children .size () == 0 ) // cant add children since it would "continue" the branch and not ad a split
161
240
{
162
241
continue ;
@@ -192,7 +271,8 @@ namespace Mtree
192
271
NodeChild child{Node{child_direction, node.tangent , 1 /(resolution+0 .001f ), child_radius, id}, position_in_parent};
193
272
node.children .push_back (std::make_shared<NodeChild>(std::move (child)));
194
273
auto & child_node = node.children .back ()->node ;
195
- child_node.growthInfo = std::make_unique<BranchGrowthInfo>(length.execute (factor), child_radius, child_node.length );
274
+ Vector3 child_position = node_position + node.direction * node.length * position_in_parent;
275
+ child_node.growthInfo = std::make_unique<BranchGrowthInfo>(length.execute (factor), child_radius, child_position, child_node.length , 0 );
196
276
origins.push_back (std::ref (child_node));
197
277
position_in_parent += position_in_parent_step;
198
278
if (i > 0 )
0 commit comments