Source code for openalea.plantscan3d.sca

from openalea.plantgl.all import *

from .mtgmanip import pgltree2mtg


[docs] def adaptivespacecolonization_method( mtg, startfrom, pointList, densities, mingrowthlength, maxgrowthlength, growthlengthfunc, killradiusratio, perceptionradiusratio, min_nb_pt_per_bud, filter_short_branch=False, angle_between_trunk_and_lateral=60, ): """ Reconstruct a tree skeleton using adaptive space colonization with density-dependent growth. Parameters ~~~~~~~~~~ mtg: openalea.mtg.MTG MTG object to add the reconstructed tree to. startfrom: int Starting node id in the MTG. pointList: list of Vector3 Input point cloud. densities: list of float Density values per point for adaptive growth length. mingrowthlength: float Minimum growth length. maxgrowthlength: float Maximum growth length. growthlengthfunc: callable Function mapping normalised density to a growth length factor. killradiusratio: float Ratio of growth length for the kill radius. perceptionradiusratio: float Ratio of growth length for the perception radius. min_nb_pt_per_bud: int Minimum number of points per bud. filter_short_branch: bool If True, remove branches with no children. angle_between_trunk_and_lateral: float Angle threshold in degrees for edge type determination. Returns ~~~~~~~ openalea.mtg.MTG MTG of the reconstructed tree. """ rootpos = Vector3(mtg.property("position")[startfrom]) mindensity, maxdensity = densities.getMinAndMax() deltadensity = maxdensity - mindensity growthlengthfunc.clamped = False normeddensity = lambda x: growthlengthfunc(abs(x - mindensity) / deltadensity) deltabinlength = maxgrowthlength - mingrowthlength binlength = lambda x: mingrowthlength + deltabinlength * normeddensity(x) print( maxgrowthlength, maxgrowthlength * killradiusratio, maxgrowthlength * perceptionradiusratio, ) class CustomSCA(SpaceColonization): def __init__(self, *args): SpaceColonization.__init__(self, *args) def node_buds_preprocess(self, nid): pos = self.node_position(nid) components = self.node_attractors(nid) # print nid, self.parents[nid], pos, components aid, aidist = findClosestFromSubset(pos, pointList, components) adensity = densities[aid] l = binlength(adensity) assert l >= mingrowthlength self.setLengths(l, killradiusratio, perceptionradiusratio) sc = CustomSCA( pointList, maxgrowthlength, maxgrowthlength * killradiusratio, maxgrowthlength * perceptionradiusratio, rootpos, ) sc.min_nb_pt_per_bud = min_nb_pt_per_bud sc.run() nodes = sc.nodes parents = sc.parents pgltree2mtg( mtg, startfrom, parents, nodes, None, filter_short_branch, angle_between_trunk_and_lateral, ) return mtg
[docs] def spacecolonization_method( mtg, startfrom, pointList, growthlength, killradiusratio, perceptionradiusratio, min_nb_pt_per_bud, filter_short_branch=False, angle_between_trunk_and_lateral=60, ): """ Reconstruct a tree skeleton using space colonization. Parameters ~~~~~~~~~~ mtg: openalea.mtg.MTG MTG object to add the reconstructed tree to. startfrom: int Starting node id in the MTG. pointList: list of Vector3 Input point cloud. growthlength: float Growth length for each iteration. killradiusratio: float Ratio of growth length for the kill radius. perceptionradiusratio: float Ratio of growth length for the perception radius. min_nb_pt_per_bud: int Minimum number of points per bud. filter_short_branch: bool If True, remove branches with no children. angle_between_trunk_and_lateral: float Angle threshold in degrees for edge type determination. Returns ~~~~~~~ openalea.mtg.MTG MTG of the reconstructed tree. """ rootpos = Vector3(mtg.property("position")[startfrom]) sc = SpaceColonization( pointList, growthlength, growthlength * killradiusratio, growthlength * perceptionradiusratio, rootpos, ) sc.min_nb_pt_per_bud = min_nb_pt_per_bud sc.run() nodes = sc.nodes parents = sc.parents pgltree2mtg( mtg, startfrom, parents, nodes, None, filter_short_branch, angle_between_trunk_and_lateral, ) return mtg