Source code for openalea.rsml.continuous

"""
Conversion from discrete to continuous mtg, and vice versa.

In practice, here continuous mtg means the mtg equivalent to rsml.

"""
from openalea.mtg.algo import local_axis
from openalea.mtg.algo import traversal

[docs] def discrete_to_continuous(g, position='position'): """ Convert the "discrete mtg" `g` to continuous form **in-place** Discrete mtg `g` is expected to: - have the 3 scales: Plant (1), Axe (2), Segment (3) - have a position defined for all segmeent vertices The argument `position` defines how to retrieve its value: - it can be the name of the mtg property the position is stored in - or a function(g,vid) that returns the position of vertex `vid` - An axe components is one sequence of successors (edge_type='<') The given mtg is then converted to continuous form: - the vertices at higher scale (i.e. the segments) are removed and their position are added in a list which is stored in the 'geometry' property of their complex. - branch axes which are connected to their parent at the segment scale (ie. the 1st segment has its parent on the parent axe) will have their 'parent_node' property set to the index of the respective node in the parent geometry. The position of the parent node is added at the beginning of the branch todo: - setter for PO, label, (...?) => function for label_axis on continuous g - convert "discrete" functions (such as diameter) - convert continuous functions? """ from openalea.rsml.metadata import add_property_definition # accessor of the segment position property if isinstance(position, str): g_pos = g.property(position) position = lambda g,vid: g_pos[vid] # get/initialize "continuous" properties geometry = g.properties().setdefault('geometry',{}) parent_node = g.properties().setdefault('parent-node',{}) # mapping to recover parent-node axe_branch = {} # axe id => branch node geom_index = {} # node id => index in geometry[axe] # process all axes # in reverse topological order so 'remove_tree' don't del subroots # construct geometry property # remove segments for axe in toporder(g, g.max_scale()-1)[::-1]: node0 = g.component_roots(axe) if len(node0)==0: continue else: node0 = node0[0] # branch node branch_node = g.parent(node0) if branch_node: axe_branch[axe] = branch_node geom = [position(g,branch_node)] else: geom = [] # axe node for vid in traversal.pre_order2(g,node0): geom_index[vid] = len(geom) geom.append(position(g,vid)) geometry[axe] = geom g.remove_tree(node0) # set parent-node property for axe,p_node in axe_branch.items(): parent_node[axe] = geom_index[p_node] add_property_definition(g,label='parent-node', type=int) return g
[docs] def continuous_to_discrete(g): """ Convert mtg `g` from continuous to discrete form **in-place** Does the reverse of `discrete_to_continuous`: - Add a sequence of segments to all axes from their `geometry` attribute todo: - functions """ geometry = g.property('geometry') parent_node = g.property('parent-node') axe_segments = {} for axe in toporder(g, g.max_scale()): # get segment on parent branch p_axe = g.parent(axe) # create 1st segment position = geometry[axe] if axe in parent_node: p_seg = axe_segments[(p_axe,parent_node[axe])] seg = g.add_component(axe, edge_type='/', position=position[1]) g.add_child(p_seg,seg, edge_type='+') axe_segments[(axe,0)] = p_seg shift = 1 else: seg = g.add_component(axe, edge_type='/', position=position[0]) shift = 0 axe_segments[(axe,shift)] = seg # create the other segments for i,pos in enumerate(position[(1+shift):]): seg = g.add_child(seg,edge_type='<', position=pos) axe_segments[(axe,i+1)] = seg geometry.pop(axe) parent_node.pop(axe,None) return g
[docs] def toporder(g, scale): """ Return the list of `g` vertices at scale `scale` in topological order """ axes = [] list(map(axes.extend,(traversal.pre_order2(g,vid) for vid in g.vertices(scale=scale) if not g.parent(vid)))) return axes