def kdtree_closest(point, kdtree, depth=0): if isinstance(kdtree, KDNode): dim = kdtree.axis if point[dim] < kdtree.pivot[dim]: point_kdtree, opposite_kdtree = kdtree.left_child, kdtree.right_child else: point_kdtree, opposite_kdtree = kdtree.right_child, kdtree.left_child best_candidate = kdtree_closest(point, point_kdtree) best_distance = pgl.norm(point - best_candidate) if best_distance > abs(point[dim] - kdtree.pivot[dim]): if best_distance > pgl.norm(point - kdtree.pivot): best_candidate = kdtree.pivot best_distance = pgl.norm(point - best_candidate) opp_candidate = kdtree_closest(point, opposite_kdtree) opp_distance = pgl.norm(point - opp_candidate) if best_distance > opp_distance: best_candidate = opp_candidate else: best_candidate = brute_force_closest(point, kdtree) return best_candidate
def np_inertia_axis(points, verbose=False): assert len(points) > 0 import numpy as np import openalea.plantgl.all as pgl if type(points) != pgl.Point3Array: points = pgl.Point3Array(points) if verbose: print 'centering points' center = points.getCenter() npoints = pgl.Point3Array(points) if pgl.norm(center) > 1e-5: npoints.translate(- center) if verbose: print 'compute covariance' # compute 1/N*P.P^T # cov = 1./len(points)*np.dot(npoints.T,npoints) cov = pgl.pointset_covariance(npoints) cov = np.array([cov.getRow(i) for i in xrange(3)]) if verbose: print cov if verbose: print "compute eigen vectors" # Find the eigen values and vectors. eig_val, eig_vec = np.linalg.eig(cov) if verbose: for i in xrange(3): print eig_val[i], eig_vec[:, i] eig_vec = np.array(eig_vec).T eig_vec = np.array([eig_vec[i] for i in reversed(pgl.get_sorted_element_order(eig_val))]) eig_val = np.array([eig_val[i] for i in reversed(pgl.get_sorted_element_order(eig_val))]) return eig_val, eig_vec, center
def get_source_leaf_and_max_height(g, position='center', relative_height=2. / 3): tesselator = pgl.Tesselator() bbc = pgl.BBoxComputer(tesselator) leaves = get_leaves(g, label='LeafElement') centroids = g.property('centroid') geometries = g.property('geometry') targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys()) for vid in targets: if is_iterable(geometries[vid]): bbc.process(pgl.Scene(geometries[vid])) else: bbc.process(pgl.Scene([pgl.Shape(geometries[vid])])) center = bbc.result.getCenter() centroids[vid] = center zmax = max(centroids.items(), key=lambda x: x[1][2])[1][2] distances = { vid: pgl.norm(centroids[vid] - (0, 0, relative_height * zmax)) for vid in centroids } if position == 'center': return min(distances.items(), key=lambda x: x[1])[0], zmax elif position == 'border': return max(distances.items(), key=lambda x: x[1])[0], zmax
def stars(leaves, g, direction=Vector3(1, 1, 1), up=Vector3(0, 0, 1), right=Vector3(1, 1, 1), beam_radius=.1): from openalea.plantik.tools.convex import cvxHull from openalea.plantgl.all import BoundingBox, Viewer, norm hull = cvxHull(leaves) lad = surface(leaves) / volume(hull) print lad bbx = BoundingBox(hull) pos = bbx.upperRightCorner interception = 0. for rshift in range(bbx.getSize().y / beam_radius): for upshift in range(bbx.getSize().z / beam_radius): sx = 1 sy = 1 print pos - rshift * right - upshift * up intersections = Viewer.frameGL.castRays( pos - rshift * right - upshift * up, direction, Vector3(0.5, 0., 0), Vector3(0, 0.5, 0), sx, sy) print intersections p = 1 for intersection in intersections.flatten(): length = norm(intersection.out - getattr(intersection, 'in')) length = 1 p *= exp(-g * lad(length)) interception += (1. - p) * beam_radius**beam_radius return interception / surface(leaves)
def np_inertia_axis(points, verbose = False): assert len(points) > 0 import numpy as np import openalea.plantgl.all as pgl if type(points) != pgl.Point3Array: points = pgl.Point3Array(points) if verbose: print 'centering points' center = points.getCenter() npoints = pgl.Point3Array(points) if pgl.norm(center) < 1e-5: npoints.translate(- center) if verbose: print 'compute covariance' # compute 1/N*P.P^T #cov = 1./len(points)*np.dot(npoints.T,npoints) cov = pgl.pointset_covariance(npoints) cov = np.array([cov.getRow(i) for i in xrange(3)]) if verbose: print cov if verbose: print "compute eigen vectors" # Find the eigen values and vectors. eig_val, eig_vec = np.linalg.eig(cov) if verbose: for i in xrange(3): print eig_val[i], eig_vec[:,i] eig_vec = np.array(eig_vec).T eig_vec = np.array([eig_vec[i] for i in reversed(pgl.get_sorted_element_order(eig_val))]) eig_val = np.array([eig_val[i] for i in reversed(pgl.get_sorted_element_order(eig_val))]) return eig_val, eig_vec, center
def _common_init( self, **keys ): """ """ if keys.has_key("height"): self._height = keys[ "height" ] else: self._height = pgl.norm( keys[ "axis" ] ) self._radius = keys[ "radius" ]
def _common_init(self, **keys): """ """ if keys.has_key("height"): self._height = keys["height"] else: self._height = pgl.norm(keys["axis"]) self._radius = keys["radius"]
def _common_init( self, **keys ): """ """ if "height" in keys: self._height = keys[ "height" ] else: self._height = pgl.norm( keys[ "axis" ] ) self._radius = keys[ "radius" ]
def closestpoint(kdtree, p, depth): axis = depth % 3 if isinstance(kdtree, Kdnode): """ Move down the tree recursively """ if p[axis] > kdtree.location[axis]: candidat = closestpoint(kdtree.right_child, p, depth-1) else: candidat = closestpoint(kdtree.left_child, p, depth-1) """ Unwind the recursion of the tree """ if candidat == None or norm(p-kdtree.location) < norm(p-candidat): candidat = kdtree.location if norm(p-candidat) < abs(p[axis]-kdtree.location[axis]): return candidat else: if p[axis] > kdtree.location[axis]: other_candidat = closestpoint(kdtree.left_child, p, depth-1) else: other_candidat = closestpoint(kdtree.right_child, p, depth-1) if other_candidat == None or norm(p-candidat) < norm(p-other_candidat): return candidat else: return other_candidat else: """ Leaf node """ candidat = None for c in kdtree: if candidat == None or norm(p-c) < norm(p-candidat): candidat = c return candidat
def brute_force_closest(point, pointlist): """ Find the closest points of 'point' in 'pointlist' using a brute force approach """ import sys pid, d = -1, sys.maxint for i, p in enumerate(pointlist): nd = pgl.norm(point-p) if nd < d: d = nd pid = i return pointlist[pid]
def brute_force_closest(point, pointlist): """ Find the closest points of 'point' in 'pointlist' using a brute force approach """ import sys pid, d = -1, sys.maxint for p in pointlist: nd = norm(point-p) if nd < d: d = nd pid = p return pid
def test_ifs(): for i in xrange(5): ifs = pgl.IFS( randint(1, 3), [pgl.Transform4(randtransform()) for i in xrange(1, 4)], pgl.Sphere(radius=uniform(0.1, 1), slices=randint(4, 255), stacks=randint(4, 255))) res = eval_code(ifs, True) for j in xrange(len(ifs.transfoList)): for k in xrange(4): if pgl.norm( ifs.transfoList[j].getMatrix().getColumn(k) - res.transfoList[j].getMatrix().getColumn(k)) > 1e-3: print ifs.transfoList[j].getMatrix() print res.transfoList[j].getMatrix() print k, pgl.norm( ifs.transfoList[j].getMatrix().getColumn(k) - res.transfoList[j].getMatrix().getColumn(k)) warnings.warn( "Transformation retrieval from matrix4 failed.")
def mesh_distance(g1, g2): pts1 = g1.pointList pts2 = g2.pointList if pts1 and pts2: d = maxint for pt in pts2: p1, i = pts1.findClosest(pt) #p1 = pts1[i] d = min(pgl.norm(pt - p1), d) return d else: return maxint
def mesh_distance(g1, g2): pts1 = g1.pointList pts2 = g2.pointList if pts1 and pts2: d = maxint for pt in pts2: p1, i = pts1.findClosest(pt) # TODO: To Fix d = pgl.norm(pt - p1) return d else: return maxint
def _common_init( self, **keys ): """ """ if keys.has_key("height"): self._height = keys[ "height" ] else: self._height = pgl.norm( keys[ "axis" ] ) self._radius = keys[ "radius" ] self.shaft = pgl.Scaled(pgl.Vector3(1, 1, AARROW_SHAFT_PROPORTION), ACYLINDER_PRIMITIVE ) self.head = pgl.Translated(pgl.Vector3(0, 0, AARROW_SHAFT_PROPORTION), pgl.Scaled(pgl.Vector3( AARROW_HEAD_PROPORTION,AARROW_HEAD_PROPORTION,1-AARROW_SHAFT_PROPORTION), ACONE_PRIMITIVE) )
def _common_init( self, **keys ): """ """ if "height" in keys: self._height = keys[ "height" ] else: self._height = pgl.norm( keys[ "axis" ] ) self._radius = keys[ "radius" ] self.shaft = pgl.Scaled(pgl.Vector3(1, 1, AARROW_SHAFT_PROPORTION), ACYLINDER_PRIMITIVE ) self.head = pgl.Translated(pgl.Vector3(0, 0, AARROW_SHAFT_PROPORTION), pgl.Scaled(pgl.Vector3( AARROW_HEAD_PROPORTION,AARROW_HEAD_PROPORTION,1-AARROW_SHAFT_PROPORTION), ACONE_PRIMITIVE) )
def scale_and_center(points, mtg): import openalea.plantgl.all as pgl if type(mtg) != pgl.Point3Array: mtgpoints = pgl.Point3Array(mtg.property('position').values()) else: mtgpoints = mtg pointextent = pgl.norm(points.getExtent()) mtgextent = pgl.norm(mtgpoints.getExtent()) scaleratio = mtgextent / pointextent m_center = mtgpoints.getCenter() p_center = points.getCenter() from math import log scale = 1./pow(10, round(log(scaleratio,10))) def transform(v): return ((v - m_center) * scale) + p_center npos1 = dict([(vid, transform(pos)) for vid, pos in mtg.property('position').items()]) mtg.property('position').update(npos1)
def scale_and_center(points, mtg): import openalea.plantgl.all as pgl if type(mtg) != pgl.Point3Array: mtgpoints = pgl.Point3Array(list(mtg.property('position').values())) else: mtgpoints = mtg pointextent = pgl.norm(points.getExtent()) mtgextent = pgl.norm(mtgpoints.getExtent()) scaleratio = mtgextent / pointextent m_center = mtgpoints.getCenter() p_center = points.getCenter() from math import log scale = 1. / pow(10, round(log(scaleratio, 10))) def transform(v): return ((v - m_center) * scale) + p_center npos1 = dict([(vid, transform(pos)) for vid, pos in list(mtg.property('position').items())]) mtg.property('position').update(npos1)
def last_year_ancestors(i): ancestors = [i] l = 0 p = nodepos(i) while l < avg_length_gu: i = g.parent(i) if i: ancestors.append(i) try: np = toppos[i] l += norm(p-np) p = np except: pass else: break return ancestors
def last_year_ancestors(i): ancestors = [i] l = 0 p = nodepos(i) while l < avg_length_gu: i = g.parent(i) if i: ancestors.append(i) try: np = toppos[i] l += norm(p - np) p = np except: pass else: break return ancestors
def get_source_leaf(g, position_source=2./3): tesselator = pgl.Tesselator() bbc = pgl.BBoxComputer(tesselator) leaves = get_leaves(g, label='LeafElement') centroids = g.property('centroid') geometries = g.property('geometry') targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys()) for vid in targets: if isinstance(geometries[vid], collections.Iterable): bbc.process(pgl.Scene(geometries[vid])) else: bbc.process(pgl.Scene([pgl.Shape(geometries[vid])])) center = bbc.result.getCenter() centroids[vid] = center zmax = max(centroids.items(), key=lambda x:x[1][2])[1][2] distances = {vid:pgl.norm(centroids[vid]-(0,0,position_source*zmax)) for vid in centroids} return min(distances.items(), key=lambda x:x[1])[0]
def lidarscan(scene, a=90, z=1): pgl.Viewer.display(scene) sc = pgl.Viewer.getCurrentScene() bbx = pgl.BoundingBox(sc) c = bbx.getCenter() p, h, u = pgl.Viewer.camera.getPosition() pts = pgl.PointSet([], []) for a in arange(0, 360, a): np = (c + pgl.Matrix3.axisRotation( (0, 0, 1), a) * pgl.Vector3(1, 0, 0) * pgl.norm(p - c)) pgl.Viewer.camera.lookAt(np / z, c) pi, ci = pgl.Viewer.frameGL.grabZBufferPoints() pts.pointList += pi pts.colorList += ci return pts
def to_js(scene): bbx = BoundingBox(scene) center = bbx.getCenter() objsize = norm(bbx.getSize()) code = template_code_begin.format(objcenter=(center.x, center.y, center.z), objsize=objsize, lightposition=tuple(center + (0, 0, 5 * objsize))) if isinstance(scene, Geometry): code += sh2js(Shape(scene, Material.DEFAULT_MATERIAL)) elif isinstance(scene, Shape): code += sh2js(scene) else: for sh in scene: code += sh2js(sh) code += template_code_end return code
def get_source_leaf_and_max_height(g, position='center', relative_height=2./3): tesselator = pgl.Tesselator() bbc = pgl.BBoxComputer(tesselator) leaves = get_leaves(g, label='LeafElement') centroids = g.property('centroid') geometries = g.property('geometry') targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys()) for vid in targets: if is_iterable(geometries[vid]): bbc.process(pgl.Scene(geometries[vid])) else: bbc.process(pgl.Scene([pgl.Shape(geometries[vid])])) center = bbc.result.getCenter() centroids[vid] = center zmax = max(centroids.items(), key=lambda x:x[1][2])[1][2] distances = {vid:pgl.norm(centroids[vid]-(0,0,relative_height*zmax)) for vid in centroids} if position=='center': return min(distances.items(), key=lambda x:x[1])[0], zmax elif position=='border': return max(distances.items(), key=lambda x:x[1])[0], zmax
def c_determine_colorindex(fruiting_structures, mtg, scene): from openalea.plantgl.all import norm import numpy from random import randint allinflos = sum([inflos for inflos, gus in fruiting_structures], []) inflopos = inflo_positions(fruiting_structures, mtg, scene) idmap = mtg.property('_axial_id') pos = [inflopos[i] for i in inflopos] distances = numpy.array([[norm(p1 - p2) for p1 in pos] for p2 in pos]) #print distances maxdist = numpy.amax(distances) mindist = numpy.amin(distances) distances -= mindist distances /= (maxdist - mindist) nbcolors = len(pos) index = list(range(nbcolors)) print(distances) def cost(index, distances): return sum([ sum([distances[i, j] * abs(vi - vj) for j, vj in enumerate(index)]) for i, vi in enumerate(index) ]) def swap(index, i=None, j=None): assert i != j or i == None nindex = list(index) i1, i2 = randint(0, nbcolors - 1) if i is None else i, randint(0, nbcolors - 1) if j is None else j if i1 == i2: return swap(index, i, j) nindex[i1], nindex[i2] = index[i2], index[i1] return nindex def bestswap(index, distances): bcost = cost(index, distances) bindex = index for i in range(len(index) - 2): for j in range(i + 1, len(index) - 1): nindex = swap(index, i, j) ccost = cost(nindex, distances) if ccost < bcost: bcost = ccost bindex = nindex return bindex def bestswapi(index, distances, i): bcost = cost(index, distances) bindex = index for j in range(0, len(index) - 1): if j != i: nindex = swap(index, i, j) ccost = cost(nindex, distances) if ccost < bcost: bcost = ccost bindex = nindex return bindex def shuffle(index): from numpy.random import shuffle as nshuffle nindex = list(index) nshuffle(nindex) return nindex bcost = cost(index, distances) print(bcost) bindex = index bestiter = None for i in range(10): success = True index = shuffle(index) icost = cost(index, distances) while success: nindex = bestswapi(index, distances, randint(0, nbcolors - 1)) cicost = cost(nindex, distances) if cicost < icost: index = nindex icost = cicost print(icost) else: success = False if icost < bcost: bcost = icost bindex = index print('bestiter', i) bestiter = i print(bcost) result = {} i = 0 for inflos, gus in fruiting_structures: for inflo in inflos: result[inflo] = index[i] i += 1 nindex.append(result[inflos[0]]) print(bestiter) #print result return result
def nodelength(i): try: return norm(toppos[i] - nodepos(g.parent(i))) except: return 0
def _surf(ind,pts): A,B,C = [pts[i] for i in ind] return pgl.norm(pgl.cross(B-A, C-A)) / 2.0
def alignGlobally(points, mtg, verbose = False): import openalea.plantgl.all as pgl import numpy as np from pointprocessing import np_inertia_axis mtgpoints = pgl.Point3Array(mtg.property('position').values()) axispoints = np_inertia_axis(points, verbose=verbose) axismtg = np_inertia_axis(mtgpoints, verbose=verbose) p_eval, p_edir, p_center = axispoints m_eval, m_edir, m_center = axismtg pointextent = pgl.norm(points.getExtent()) mtgextent = pgl.norm(mtgpoints.getExtent()) scaleratio = mtgextent / pointextent from math import log scale = 1./pow(10, round(log(scaleratio,10))) normalizeorientation = True checkorientation = True if normalizeorientation: def normalize_frame(edir): a, b = edir[0], edir[1] c = np.cross(a,b) return np.array([a, np.cross(c,a), c]) p_edir = normalize_frame(p_edir) m_edir = normalize_frame(m_edir) if verbose: print 'Point center :', p_center print 'MTG center :', m_center print 'Point axis :',p_edir print 'MTG axis :',m_edir print 'Point variance :',p_eval print 'MTG variance :',m_eval def transform(v,t_edir): v = (v - m_center) nval = [ pgl.dot(v,ed) for ed in m_edir] nv = sum([val * ed for val, ed in zip(nval, t_edir)],pgl.Vector3(0,0,0)) return (nv + p_center) ppos = mtg.property('position').copy() npos1 = dict([(vid, transform(pos, p_edir)) for vid, pos in ppos.items()]) #npos1 = dict([(vid, pos*scale) for vid, pos in ppos.items()]) mtg.property('position').update(npos1) if checkorientation: if verbose: print 'check orientation' from mtgmanip import mtg2pgltree nodes, parents, vertex2node = mtg2pgltree(mtg) dist1 = pgl.average_distance_to_shape(points, nodes, parents, [0 for i in xrange(len(nodes))]) if verbose: print 'check flipped orientation' p_edir2 = np.array([-p_edir[0], -p_edir[1], np.cross(-p_edir[0], -p_edir[1])]) npos2 = dict([(vid, transform(pos, p_edir2)) for vid, pos in ppos.items()]) mtg.property('position').update(npos2) nodes, parents, vertex2node = mtg2pgltree(mtg) dist2 = pgl.average_distance_to_shape(points, nodes, parents, [0 for i in xrange(len(nodes))]) if verbose: print dist1, dist2 if dist1 < dist2: if verbose: print 'Use first orientation' mtg.property('position').update(npos1) else: if verbose: print 'Use flipped orientation'
def lovel_distance(g1, g2): p1 = base(g1) p2 = top(g2) return pgl.norm(p2 - p1)
def alignGlobally(points, mtg, verbose=False): import openalea.plantgl.all as pgl import numpy as np from .pointprocessing import np_inertia_axis mtgpoints = pgl.Point3Array(list(mtg.property('position').values())) axispoints = np_inertia_axis(points, verbose=verbose) axismtg = np_inertia_axis(mtgpoints, verbose=verbose) p_eval, p_edir, p_center = axispoints m_eval, m_edir, m_center = axismtg pointextent = pgl.norm(points.getExtent()) mtgextent = pgl.norm(mtgpoints.getExtent()) scaleratio = mtgextent / pointextent from math import log scale = 1. / pow(10, round(log(scaleratio, 10))) normalizeorientation = True checkorientation = True if normalizeorientation: def normalize_frame(edir): a, b = edir[0], edir[1] c = np.cross(a, b) return np.array([a, np.cross(c, a), c]) p_edir = normalize_frame(p_edir) m_edir = normalize_frame(m_edir) if verbose: print('Point center :', p_center) print('MTG center :', m_center) print('Point axis :', p_edir) print('MTG axis :', m_edir) print('Point variance :', p_eval) print('MTG variance :', m_eval) def transform(v, t_edir): v = (v - m_center) nval = [pgl.dot(v, ed) for ed in m_edir] nv = sum([val * ed for val, ed in zip(nval, t_edir)], pgl.Vector3(0, 0, 0)) return (nv + p_center) ppos = mtg.property('position').copy() npos1 = dict([(vid, transform(pos, p_edir)) for vid, pos in list(ppos.items())]) #npos1 = dict([(vid, pos*scale) for vid, pos in ppos.items()]) mtg.property('position').update(npos1) if checkorientation: if verbose: print('check orientation') from .mtgmanip import mtg2pgltree nodes, parents, vertex2node = mtg2pgltree(mtg) dist1 = pgl.average_distance_to_shape(points, nodes, parents, [0 for i in range(len(nodes))]) if verbose: print('check flipped orientation') p_edir2 = np.array( [-p_edir[0], -p_edir[1], np.cross(-p_edir[0], -p_edir[1])]) npos2 = dict([(vid, transform(pos, p_edir2)) for vid, pos in list(ppos.items())]) mtg.property('position').update(npos2) nodes, parents, vertex2node = mtg2pgltree(mtg) dist2 = pgl.average_distance_to_shape(points, nodes, parents, [0 for i in range(len(nodes))]) if verbose: print(dist1, dist2) if dist1 < dist2: if verbose: print('Use first orientation') mtg.property('position').update(npos1) else: if verbose: print('Use flipped orientation')
def nodelength(i): try: return norm(toppos[i]-nodepos(g.parent(i))) except: return 0
def disperse(self, g, dispersal_units, time_control = None): """ Compute distribution of dispersal units by rain splash. 1. Upward dispersal: For each source of dispersal units, create a semi-sphere of dispersal normal to the surface of source leaf. In the semi-sphere, target leaves are sorted according to the distance from the source. Then distribute dispersal units from the closer target to the more far. The number of dispersal units by target leaf is computed as in Robert et al. 2008 2. Downward dispersal: Get leaves in a cylinder whose dimensions are related to the dimesions of the semi-sphere in step 1. Then distribute dispersal units from top to bottom. Parameters ---------- g: MTG MTG representing the canopy (and the soil) dispersal_units : dict Dispersal units emitted by the lesions on leaves Returns ------- deposits : dict Dispersal units deposited on new position on leaves """ try: dt = time_control.dt except: dt = 1 deposits = {} if dt>0: from alinea.astk.plantgl_utils import get_area_and_normal from alinea.alep.architecture import get_leaves from openalea.plantgl import all as pgl from collections import OrderedDict from math import exp, pi, cos, sin, tan from random import shuffle import numpy as np from copy import copy dmax = self.distance_max tesselator = pgl.Tesselator() bbc = pgl.BBoxComputer(tesselator) leaves = get_leaves(g, label=self.label) centroids = g.property('centroid') geometries = g.property('geometry') _, norm = get_area_and_normal(geometries) areas = g.property('area') def centroid(vid): if is_iterable(geometries[vid]): bbc.process(pgl.Scene(geometries[vid])) else: bbc.process(pgl.Scene([pgl.Shape(geometries[vid])])) center = bbc.result.getCenter() centroids[vid] = center for source, dus in dispersal_units.iteritems(): nb_tri = len(norm[source]) borders = np.linspace(0,1,num=nb_tri) dus_by_tri = {k:filter(lambda x: borders[k]<x.position[0]<=borders[k+1], dus) for k in range(nb_tri-1) if len(filter(lambda x: borders[k]<x.position[0]<=borders[k+1], dus))>0.} for k,v in dus_by_tri.iteritems(): source_normal = norm[source][k] ## UPWARD ## # All leaves except the source are potential targets targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys()) targets.remove(source) # Compute centroids centroid(source) for vid in targets: centroid(vid) # Sort the vids based on the direction # TODO : modify source angle Origin = centroids[source] vects = {vid:(centroids[vid]-Origin) for vid in targets if (centroids[vid]-Origin)*source_normal >= 0} # Sort the vids based on the distance distances = {vid:pgl.norm(vects[vid]) for vid in vects if pgl.norm(vects[vid])<dmax} distances = OrderedDict(sorted(distances.iteritems(), key=lambda x: x[1])) # Distribute the dispersal units if len(distances.values())>0: shuffle(v) n = len(v) sphere_area = 2*pi*distances.values()[-1]**2 for leaf_id in distances: area_factor = areas[leaf_id]/sphere_area distance_factor = exp(-self.k * distances[leaf_id]) qc = min(n, (n * area_factor * distance_factor)) deposits[leaf_id] = v[:int(qc)] del v[:int(qc)] # if len(dus) < 1 or len(deposits[leafid]) < 1: if len(v) < 1: for d in v: d.disable() # break ## DOWNWARD ## vects2 = {vid:(centroids[vid]-Origin) for vid in targets if not vid in vects} projection = {} alpha = pgl.angle(source_normal, (1,0,0)) if alpha>=pi/2. or (alpha<pi/2. and source_normal[2]>=0): alpha+=pi/2. beta = pgl.angle(source_normal, (0,0,1)) a = dmax b = dmax*cos(beta) for leaf in vects2: if (centroids[leaf]-Origin)*(source_normal[0], source_normal[1], 0) >= 0: # Big side of the projection semi circle copy_centroid = copy(centroids[leaf]) copy_origin = copy(Origin) copy_centroid[2] = 0. copy_origin[2] = 0. if pgl.norm(copy_centroid-copy_origin) < dmax: projection[leaf] = vects2[leaf] else: # Small side of the projection semi ellipse x = vects2[leaf][0] y = vects2[leaf][1] x2 = x*cos(alpha)+y*sin(alpha) y2 = -x*sin(alpha)+y*cos(alpha) if (x2**2)/(a**2) + (y2**2)/(b**2) < 1 : projection[leaf] = vects2[leaf] projection = OrderedDict(sorted(projection.items(), key=lambda x:x[1][2], reverse=True)) if len(projection)>0: shuffle(v) n = len(v) n_big = int(n*(beta+pi/2.)/pi) n_small = n - n_big for leaf in projection: copy_centroid = copy(centroids[leaf]) copy_origin = copy(Origin) copy_centroid[2] = 0. copy_origin[2] = 0. if (centroids[leaf]-Origin)*(source_normal[0],source_normal[1],0) >= 0: area_factor = areas[leaf]/(pi*dmax**2/2.) dist = pgl.norm(copy_centroid-copy_origin) distance_factor = exp(-self.k * dist) qc = min(n_big, (n_big * area_factor * distance_factor)) g.node(leaf).color = (0, 180, 0) else: area_factor = areas[leaf]/(pi*a*b/2.) dist = pgl.norm(copy_centroid-copy_origin)/abs(cos(pgl.angle(source_normal, (1,0,0))+pi/2.)) distance_factor = exp(-self.k * dist) qc = min(n_small, (n_small * area_factor * distance_factor)) g.node(leaf).color = (0, 0, 180) # import pdb # pdb.set_trace() deposits[leaf] = v[:int(qc)] del v[:int(qc)] for leaf in distances: g.node(leaf).color = (180, 0, 0) # Temp # from alinea.adel.mtg_interpreter import plot3d # from openalea.plantgl.all import Viewer # g.node(source).color=(230, 62, 218) # scene = plot3d(g) # Viewer.display(scene) # import pdb # pdb.set_trace() return deposits
def _surf(ind, pts): A, B, C = [pts[i] for i in ind] return pgl.norm(pgl.cross(B - A, C - A)) / 2.0
def _surf(ind, pts): from openalea.plantgl.all import norm, cross, Vector3 A, B, C = [Vector3(pts[i]) for i in ind] return norm(cross(B - A, C - A)) / 2.0
def disperse(self, g, dispersal_units, time_control = None): """ Compute dispersal of spores of powdery mildew by wind in a cone. For each source of dispersal units, create a cone of dispersal in which target leaves are sorted: 1. according to the wind direction 2. according to the angle a0 3. according to the distance from the source Then distribute dispersal units from the closer target to the more far. The number of dispersal units by target leaf is computed as in Calonnec et al. 2008. Parameters ---------- g: MTG MTG representing the canopy (and the soil) dispersal_units : dict Dispersal units emitted by the lesions on leaves Returns ------- deposits : dict Dispersal units deposited on new position on leaves """ try: dt = time_control.dt except: dt = 1 deposits = {} if dt > 0: from alinea.alep.architecture import get_leaves from openalea.plantgl import all as pgl from random import shuffle from math import degrees, exp, tan, pi, radians from collections import OrderedDict geometries = g.property('geometry') centroids = g.property('centroid') areas = g.property('area') wind_directions = g.property('wind_direction') tesselator = pgl.Tesselator() bbc = pgl.BBoxComputer(tesselator) leaves = get_leaves(g, label=self.label) def centroid(vid): if is_iterable(geometries[vid]): bbc.process(pgl.Scene(geometries[vid])) else: bbc.process(pgl.Scene([pgl.Shape(geometries[vid])])) center = bbc.result.getCenter() centroids[vid] = center def area(vid): # areas[vid] = pgl.surface(geometries[vid][0])*1000 areas[vid] = pgl.surface(geometries[vid][0]) for source, dus in dispersal_units.iteritems(): # TODO: Special computation for interception by source leaf # All other leaves are potential targets targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys()) targets.remove(source) # Compute centroids centroid(source) for vid in targets: centroid(vid) # surface(vid) # Sort the vids based on the direction Origin = centroids[source] vects = {vid:(centroids[vid]-Origin) for vid in targets if (centroids[vid]-Origin)*wind_directions[source] >= 0} # Sort the vids based on the angle angles = {vid:degrees(pgl.angle(vect, wind_directions[source])) for vid, vect in vects.iteritems() if degrees(pgl.angle(vect, wind_directions[source]))<= self.a0} # Sort the vids based on the distance distances = {vid:pgl.norm(vects[vid]) for vid in angles} distances = OrderedDict(sorted(distances.iteritems(), key=lambda x: x[1])) # Beer law inside cone to take into account leaf coverage shuffle(dus) n = len(dus) if len(distances.values())>0: for leaf in distances: # qc = min(n, (n * (areas[leaf]/self.reduction) * # exp(-self.cid * distances[leaf]) * # (self.a0 - angles[leaf])/self.a0)) surf_base_cone = pi*(tan(radians(self.a0))*distances[leaf])**2 area_factor = min(1, areas[leaf]/surf_base_cone) # import pdb # pdb.set_trace() qc = min(n, (n * area_factor * exp(-self.cid * distances[leaf]) * (self.a0 - angles[leaf])/self.a0)) # if qc < 1: # for d in dus: # d.disable() # break deposits[leaf] = dus[:int(qc)] del dus[:int(qc)] # if len(dus) < 1 or len(deposits[leaf]) < 1: if len(dus) < 1: for d in dus: d.disable() break return deposits
""" Gather different strategies for modeling dispersal of fungus propagules.
def _surf(mesh, iface): A, B, C = [mesh.pointList[i] for i in mesh.indexAt(iface)] return pgl.norm(pgl.cross(B - A, C - A)) / 2.0
def isincylinder(point, base, dir, radius, height): return 0 <= dot(point - base, pgl.Vector3(dir).normed()) <= height and pgl.norm( cross(point - base, pgl.Vector3(dir).normed())) < radius