@@ -23,35 +23,27 @@ from dataclasses import dataclass
2323# Override these externs via Lsystem(..., variables) to point at a specific
2424# architecture without editing this shared file.
2525extern(
26+ color_manager = None,
2627 prototype_dict_path = "examples.Envy.Envy_prototypes.basicwood_prototypes",
2728 trunk_class_path = "examples.Envy.Envy_prototypes.Trunk",
2829 simulation_config_class_path = "examples.Envy.Envy_simulation.EnvySimulationConfig",
29- point_generator_path = "examples.Envy.Envy_simulation.generate_points_v_trellis",
30- energy_function_path = "examples.Envy.Envy_simulation.get_energy_mat",
31- decide_function_path = "examples.Envy.Envy_simulation.decide_guide",
32- tie_function_path = "examples.Envy.Envy_simulation.tie",
33- prune_function_path = "examples.Envy.Envy_simulation.prune",
30+ simulation_class_path = "examples.Envy.Envy_simulation.EnvySimulation",
3431 axiom_pitch = 0.0,
3532 axiom_yaw = 0.0,
36- )
37-
38- # Resolve extern-provided dotted paths so the rest of the script can operate on
33+ )# Resolve extern-provided dotted paths so the rest of the script can operate on
3934# concrete classes/functions exactly like the Envy/UFO drivers do.
4035basicwood_prototypes = resolve_attr(prototype_dict_path)
4136Trunk = resolve_attr(trunk_class_path)
4237SimulationConfigClass = resolve_attr(simulation_config_class_path)
43- point_generator_fn = resolve_attr(point_generator_path)
44- get_energy_mat = resolve_attr(energy_function_path)
45- decide_guide = resolve_attr(decide_function_path)
46- tie = resolve_attr(tie_function_path)
47- prune = resolve_attr(prune_function_path)
38+ SimulationClass = resolve_attr(simulation_class_path)
4839
4940simulation_config = SimulationConfigClass()
41+ simulation = SimulationClass(simulation_config)
5042main_trunk = Trunk(copy_from = basicwood_prototypes['trunk'])
5143
5244# Build trellis geometry and cadence numbers up front so callbacks stay simple.
5345trellis_support = Support(
54- point_generator_fn(simulation_config ),
46+ simulation.generate_points( ),
5547 simulation_config.support_num_wires,
5648 simulation_config.support_spacing_wires,
5749 simulation_config.support_trunk_wire_point,
@@ -62,7 +54,30 @@ main_trunk.tying.guide_target = trellis_support.trunk_wire
6254
6355# Track parent/child relationships for tying/pruning decisions.
6456branch_hierarchy = {main_trunk.name: []}
65- enable_color_labeling = simulation_config.label
57+ enable_semantic_labeling = simulation_config.semantic_label
58+ enable_instance_labeling = simulation_config.instance_label
59+ enable_per_cylinder_labeling = simulation_config.per_cylinder_label
60+
61+ if (enable_instance_labeling or enable_per_cylinder_labeling) and color_manager is None:
62+ raise ValueError(
63+ "Instance labeling is enabled but no color_manager extern was provided."
64+ )
65+
66+
67+ def _get_energy_mat(branches, arch, _config):
68+ return simulation.get_energy_mat(branches, arch)
69+
70+
71+ def _decide_guide(energy_matrix, branches, arch, _config):
72+ return simulation.decide_guide(energy_matrix, branches, arch)
73+
74+
75+ def _tie(lstring, _config):
76+ return simulation.tie(lstring)
77+
78+
79+ def _prune(lstring, _config):
80+ return simulation.prune(lstring)
6681
6782# L-Py callbacks delegate to the Python helpers so architectures share logic.
6883def StartEach(lstring):
@@ -81,12 +96,12 @@ def EndEach(lstring):
8196 simulation_config,
8297 main_trunk,
8398 getIterationNb,
84- get_energy_mat ,
85- decide_guide ,
86- tie ,
87- prune ,
99+ _get_energy_mat ,
100+ _decide_guide ,
101+ _tie ,
102+ _prune ,
88103 )
89-
104+ generalized_cylinder = getattr(simulation_config, "use_generalized_cylinder", False)
90105# =============================================================================
91106# L-SYSTEM GRAMMAR DEFINITION
92107# =============================================================================
@@ -149,18 +164,28 @@ grow_object(plant_segment) :
149164 #Update internal state of the plant segment
150165 plant_segment.grow_one()
151166 #Update physical representation
152- if enable_color_labeling :
167+ if enable_semantic_labeling :
153168 # Add color visualization if labeling is enabled -- Can this be moved to the start of building the segment?
154169 r, g, b = plant_segment.info.color
170+ plant_part = plant_segment.name.split("_")[0] # Get the part type (e.g., "trunk", "branch")
171+ color_manager.set_unique_color((r,g,b), plant_part) # Ensure part type has a color assig
172+ nproduce SetColor(r,g,b)
173+ if enable_instance_labeling:
174+ # Instance-level labeling (unique color per branch instance)
175+ r, g, b = color_manager.get_unique_color(plant_segment.name)
155176 nproduce SetColor(r,g,b)
177+
156178 #Produce internode segments (n cylinders per growth step)
157179 n_cylinders = int(plant_segment.growth.growth_length / plant_segment.growth.cylinder_length)
158180 for i in range(n_cylinders):
181+ if enable_per_cylinder_labeling:
182+ r, g, b = color_manager.get_unique_color(plant_segment.name, if_exists=False)
183+ nproduce SetColor(r,g,b)
159184 nproduce I(plant_segment.growth.cylinder_length, plant_segment.growth.thickness, plant_segment)
160185 #Produce bud (after all cylinders in this growth step)
161186 if plant_segment.pre_bud_rule(plant_segment, simulation_config):
162187 for generated in plant_segment.post_bud_rule(plant_segment, simulation_config):
163- nproduce new(generated[0], *generated[1])
188+ nproduce new(generated[0], *generated[1])
164189
165190 if should_bud(plant_segment, simulation_config):
166191 # Age-based bud production for lateral branching
@@ -190,15 +215,18 @@ bud(bud_parameters) :
190215 bud_parameters.num_buds+=1
191216 bud_parameters.type.info.num_branches+=1
192217
218+ nproduce [
219+ if generalized_cylinder:
220+ nproduce @Gc
193221 if hasattr(new_branch, 'curve_x_range'):
194222 # Curved branches: set up custom growth guide curve
195- curve = create_bezier_curve(x_range=new_branch.curve_x_range, y_range=new_branch.curve_y_range, z_range=new_branch.curve_z_range, seed_value=time.time())
196- nproduce[@GcSetGuide(curve, new_branch.growth.max_length)
197- else:
198- # Straight branches: use default orientation
199- nproduce [@Gc
223+ curve = create_bezier_curve(x_range=new_branch.curve_x_range, y_range=new_branch.curve_y_range, z_range=new_branch.curve_z_range, seed_value=rd.randint(0,1000))
224+ nproduceSetGuide(curve, new_branch.growth.max_length)
200225 # Produce new branch with random orientation and growth object
201- nproduce @RGetPos(new_branch.location.start)WoodStart(ParameterSet(type = new_branch))/(rd.random()*360)&(rd.random()*360)grow_object(new_branch)GetPos(new_branch.location.end)@Ge]bud(bud_parameters)
226+ nproduce @RGetPos(new_branch.location.start)WoodStart(ParameterSet(type = new_branch))/(rd.random()*360)&(rd.random()*360)grow_object(new_branch)GetPos(new_branch.location.end)
227+ if generalized_cylinder:
228+ nproduce @Ge
229+ produce ]bud(bud_parameters)
202230
203231# -----------------------------------------------------------------------------
204232# GEOMETRIC INTERPRETATION (HOMOMORPHISM)
0 commit comments