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