from pathlib import Path from openalea.mtg import traversal from openalea.plantgl.all import Scene, Viewer import json import hydroshoot from hydroshoot import architecture, display, model print(hydroshoot.__file__) def main(): # 📂 Percorso del progetto (dove sono params.json, digit.input, meteo.input, ecc.) path_project = Path(r".\hydroshoot\example\vsp_ws_grapevine") # ============================================================================= # 🌱 Costruzione della vite a partire da digit.input # ============================================================================= g = architecture.vine_mtg(path_project / 'digit.input') for v in traversal.iter_mtg2(g, g.root): architecture.vine_phyto_modular(g, v) architecture.vine_axeII( g, v, pruning_type='avg_field_model', N_max=6, insert_angle=90, N_max_order=6 ) architecture.vine_petiole( g, v, pet_ins=90., pet_ins_cv=0., phyllo_angle=180. ) architecture.vine_leaf( g, v, leaf_inc=-45., leaf_inc_cv=100., lim_max=12.5, lim_min=5., order_lim_max=6, max_order=55, rand_rot_angle=90., cordon_vector=None ) architecture.vine_mtg_properties(g, v) architecture.vine_mtg_geometry(g, v) architecture.vine_transform(g, v) # 👀 Visualizzazione (opzionale, richiede PlantGL viewer) scene = display.visu( g, def_elmnt_color_dict=True, scene=Scene(), view_result=False ) Viewer.display(scene) Viewer.saveSnapshot("output_initial.png") print("✅ Immagine salvata come output.png") # ============================================================================= # 🚀 Esegui la simulazione # ============================================================================= model.run( g=g, wd=path_project, path_weather=path_project / 'meteo.input', scene=scene ) # Stato finale scene_final = display.visu( g, def_elmnt_color_dict=True, scene=Scene(), view_result=False ) Viewer.display(scene_final) Viewer.saveSnapshot("output_final.png") print("✅ Immagine finale salvata come output_final.png") # ============================================================================= # 📊 Estrazione parametri fisici dalla pianta # ============================================================================= positions = g.property("position") if not positions: print("⚠️ Nessuna proprietà 'position' trovata, provo con 'geometry'...") positions = g.property("geometry") if positions: height = max(pos[2] for pos in positions.values()) print(f"Altezza pianta: {height:.2f} cm") else: print("❌ Non ci sono coordinate nella pianta, impossibile calcolare l’altezza") positions = g.property("position") classes = g.property("label") # Numero foglie n_leaves = sum(1 for vid, lbl in classes.items() if "Leaf" in lbl) print(f"Numero foglie: {n_leaves}") # Numero internodi / rami n_internodes = sum(1 for vid, lbl in classes.items() if "Internode" in lbl) print(f"Numero internodi (rami): {n_internodes}") # Numero frutti presenti n_fruits = sum(1 for vid, lbl in classes.items() if "Fruit" in lbl) print(f"Numero frutti: {n_fruits}") print("✅ Simulazione completata! Output in:") print(f" - {path_project}/time_series.output") print(f" - {path_project}/*.pckl (stati della pianta)") plant_summary = { "height_cm": height, "n_leaves": n_leaves, "n_internodes": n_internodes, "n_fruits": n_fruits, "initial_image": "output_initial.png", "final_image": "output_final.png", "time_series_output": str(path_project / "time_series.output"), "pickle_states": str(path_project / "*.pckl") } with open("plant_summary.json", "w", encoding="utf-8") as f: json.dump(plant_summary, f, indent=2, ensure_ascii=False) if __name__ == '__main__': main()