Ejemplo n.º 1
0
def scene2grid(scene, gridSize):
    """
  Convert a scene into a matrix-grid where non-zero values are the coresponding surface included in the coresponding voxel
  """
    bbox = pgl.BoundingBox(scene)
    epsilon = pgl.Vector3(0.01, 0.01, 0.01)
    origin = bbox.lowerLeftCorner - epsilon
    step = (bbox.getSize() + epsilon) * 2 / (gridSize)
    """
  getSize is a radius vector whereas gridSize is the voxel number desired per dimension, hence the gridSize must be *2
  """
    print "Bbox size : ", bbox.getSize() * 2
    print "Step : ", step, "    gridSize : ", gridSize
    grid = {}
    tgl_list = surfPerTriangle(scene)
    for tgl in tgl_list:
        pos = gridIndex(tgl[0] - origin, step)
        if grid.has_key(pos):
            grid[pos] += tgl[1]
        else:
            grid[pos] = tgl[1]
    print "nbTgl : ", len(tgl_list), "  <--->   nbVoxel : ", len(grid)
    kize = grid.keys()
    kize.sort()
    pts = []
    mass = []
    for k in kize:
        pts.append(list(k))
        mass.append(grid[k])
    return (pts, mass, step)  #gridSize )
Ejemplo n.º 2
0
def projectedBBox(bbx, direction, up):
    from itertools import product
    proj = getProjectionMatrix(direction, up)
    pts = [
        proj * pt
        for pt in product([bbx.getXMin(), bbx.getXMax()],
                          [bbx.getYMin(), bbx.getYMax()],
                          [bbx.getZMin(), bbx.getZMax()])
    ]
    projbbx = pgl.BoundingBox(pgl.PointSet(pts))
    return projbbx
Ejemplo n.º 3
0
def directionalInterceptionGL(scene,
                              directions,
                              north=0,
                              horizontal=False,
                              screenwidth=600):

    pgl.Viewer.display(scene)
    redrawPol = pgl.Viewer.redrawPolicy
    pgl.Viewer.redrawPolicy = False
    pgl.Viewer.frameGL.maximize(True)

    #pgl.Viewer.widgetGeometry.setSize(screenwidth, screenwidth)
    pgl.Viewer.frameGL.setSize(screenwidth, screenwidth)

    cam_pos, cam_targ, cam_up = pgl.Viewer.camera.getPosition()
    pgl.Viewer.camera.setOrthographic()
    pgl.Viewer.grids.set(False, False, False, False)
    bbox = pgl.BoundingBox(scene)
    d_factor = max(bbox.getXRange(), bbox.getYRange(), bbox.getZRange())
    shapeLight = {}

    for az, el, wg in directions:
        if (az != None and el != None):
            dir = azel2vect(az, el, north)
            if horizontal:
                wg /= sin(radians(el))

        else:
            dir = -pgl.Viewer.camera.getPosition()[1]
            assert not horizontal

        pgl.Viewer.camera.lookAt(
            bbox.getCenter() + dir * (-2.5) * d_factor,
            bbox.getCenter())  #2.5 is for a 600x600 GLframe

        values = pgl.Viewer.frameGL.getProjectionPerShape()
        if not values is None:
            nbpixpershape, pixsize = values
            pixsize = pixsize * pixsize
            for key, val in nbpixpershape:
                if key in shapeLight:
                    shapeLight[key] += val * pixsize * wg
                else:
                    shapeLight[key] = val * pixsize * wg
    #valist = [shapeLight[key] for key in shapeLight.keys() ]
    #print "Min value : ", min(valist)
    #print "Max value : ", max(valist)
    pgl.Viewer.camera.lookAt(cam_pos, cam_targ)
    pgl.Viewer.redrawPolicy = redrawPol

    return shapeLight
Ejemplo n.º 4
0
def directionalInterception(scene,
                            directions,
                            north=0,
                            horizontal=False,
                            screenresolution=1,
                            verbose=False,
                            multithreaded=True):

    bbox = pgl.BoundingBox(scene)
    d_factor = max(bbox.getXRange(), bbox.getYRange(), bbox.getZRange())
    shapeLight = {}
    pixsize = screenresolution * screenresolution

    for az, el, wg in directions:
        if (az != None and el != None):
            dir = azel2vect(az, el, north)
            if horizontal:
                wg /= sin(radians(el))

        up = dir.anOrthogonalVector()
        pjbbx = projectedBBox(bbox, dir, up)
        worldWidth = pjbbx.getXRange()
        worldheight = pjbbx.getYRange()
        w, h = max(2,
                   int(ceil(worldWidth / screenresolution)) + 1), max(
                       2,
                       int(ceil(worldheight / screenresolution)) + 1)
        if verbose:
            print('direction :', dir)
            print('image size :', w, 'x', h)
        worldWidth = w * screenresolution
        worldheight = h * screenresolution
        noid = pgl.Shape.NOID
        z = pgl.ZBufferEngine(w, h, noid)
        z.multithreaded = multithreaded
        z.setOrthographicCamera(-worldWidth / 2., worldWidth / 2.,
                                -worldheight / 2., worldheight / 2., d_factor,
                                3 * d_factor)
        eyepos = bbox.getCenter() - dir * d_factor * 2
        z.lookAt(eyepos, bbox.getCenter(), up)
        z.process(scene)
        img = z.getImage()
        values = img.histogram()
        if not values is None:
            for shid, val in values:
                if shid != noid:
                    shapeLight[shid] = shapeLight.get(shid,
                                                      0) + val * pixsize * wg

    return shapeLight
Ejemplo n.º 5
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
Ejemplo n.º 6
0
def prepareScene(scene, width=150, height=150, az=None, el=None, dist_factor=8):
  if( az != None and el != None):
    dir = azel2vect(az, el)
  else :
    dir = -pgl.Viewer.camera.getPosition()[1]
    dir.normalize()
  pgl.Viewer.start()
  pgl.Viewer.animation( True )
  pgl.Viewer.frameGL.maximize(True)
  pgl.Viewer.widgetGeometry.setSize(width, height)
  pgl.Viewer.display(scene)
  bbox=pgl.BoundingBox( scene )
  pgl.Viewer.grids.set(False,False,False,False)
  pgl.Viewer.camera.setOrthographic()
  d_factor = max(bbox.getXRange() , bbox.getYRange() , bbox.getZRange())
  pgl.Viewer.camera.lookAt(bbox.getCenter() + dir*(-dist_factor)*d_factor, bbox.getCenter())
  pgl.Viewer.frameGL.setSize(width,height)
  return dir
Ejemplo n.º 7
0
def directionalInterception(scene, directions):

    redrawPol = pgl.Viewer.redrawPolicy
    pgl.Viewer.redrawPolicy = False
    pgl.Viewer.frameGL.maximize(True)
    pgl.Viewer.widgetGeometry.setSize(600, 600)
    pgl.Viewer.frameGL.setSize(600, 600)

    pgl.Viewer.camera.setOrthographic()
    pgl.Viewer.grids.set(False, False, False, False)
    bbox = pgl.BoundingBox(scene)
    d_factor = max(bbox.getXRange(), bbox.getYRange(), bbox.getZRange())
    cam_pos, cam_targ, cam_up = pgl.Viewer.camera.getPosition()
    shapeLight = {}

    for d in directions:
        az, el, wg = d
        if (az != None and el != None):
            dir = azel2vect(az, el)
        else:
            dir = -pgl.Viewer.camera.getPosition()[1]

        pgl.Viewer.camera.lookAt(
            bbox.getCenter() + dir * (-2.5) * d_factor,
            bbox.getCenter())  #2.5 is for a 600x600 GLframe

        values = pgl.Viewer.frameGL.getProjectionPerShape()
        if not values is None:
            nbpixpershape, pixsize = values
            pixsize = pixsize * pixsize
            for key, val in nbpixpershape:
                if shapeLight.has_key(key):
                    shapeLight[key] += val * pixsize * wg
                else:
                    shapeLight[key] = val * pixsize * wg
    #valist = [shapeLight[key] for key in shapeLight.keys() ]
    #print "Min value : ", min(valist)
    #print "Max value : ", max(valist)
    pgl.Viewer.camera.lookAt(cam_pos, cam_targ)
    pgl.Viewer.redrawPolicy = redrawPol
    return shapeLight
Ejemplo n.º 8
0
 def __contains__(self,pos):
     return pgl.BoundingBox(self.getLowerCorner(),self.getUpperCorner()-(1e-5,1e-5,1e-5)).contains(pos)
Ejemplo n.º 9
0
def centerScene( scene ):
  bbox = pgl.BoundingBox(scene)
  return pgl.Scene([pgl.Shape(pgl.Translated(-bbox.getCenter(),i.geometry),i.appearance,i.id) for i in scene])
Ejemplo n.º 10
0
def extract_architecture(mtg_file_path,
                         scene,
                         nom_arbre,
                         date,
                         variete,
                         SLA,
                         densite_MS_rameaux,
                         TMS_fruits,
                         SR,
                         userEllipse=True,
                         charge_fruits=None,
                         seed=None):
    '''
    Converti un fichier .mtg généré par MAppleT en une architecure au format Qualitree. Le script .sql est renvoyé en sorti de cette fonction (il faudra l'enregistrer dans un fichier),
    des fichiers .csv correspondants aux tables de la bdd Qualitree sont aussi générés (cela permet de visualiser le résultat plus facilement qu'en SQL).

    mtg_file : chemin vers le .mtg que l'on souhaite convertir.
    nom_arbre : le nom à donner à l'architecture dans la base de données de qualitree.
    date : date à indiquer dans la base de données de qualitree (date de début de simulation)
    variete : variété, tel que notée dans le fichier parametres.xml
    SLA : specific leaf area
    densite_MS_rameaux : densité du bois en g.m-3
    TMS_fruits : teneur en matière sèche des fruits
    SR : shoot-root ratio utilisé pour calculer la masse des jeunes ou vieilles racines en fonction de celle des pousses feuillées ou du vieux bois+tiges de rameaux mixtes (respectivement)
    charge_fruits : par défaut les fruits sont ceux indiqués dans le .mtg. Si une valeur est indiquée (entre 0. et 1.), elle défini la proportion d'inflorescences portant un fruit (0.: pas de fruits, 1.: un fruit par inflorescence).  
    La masse des fruits quand la charge est fixée est égale à la moyenne de la masses des fruits dans le .mtg
    seed : graine du générateur de nombre pseudo aléatoire utilisé pour déterminer quelles inflorescences portent un fruit, par défaut la graine est aléatoire.
    '''

    #Open the MTG file, only the first plant/tree will be considered in case of multiple plants in the same file
    m = MTG(mtg_file_path)
    plants = VtxList(Scale=1)

    #Get the ordered list of GU year of appearance, fruiting unit are the before last-year ones
    annees = sorted(list(set([an(x) for x in uc(plants[0])])))

    ram_mixtes = rameaux(plants[0])  #rameaux mixtes

    #Les rameaux mixtes doivent être des UC de l'année précédente, sinon la condition de qualitree comme quoi un rameau mixte ne peut pas porter de ramifications n'est pas respectée, hors des bugs de MAppleT peuvent entrainer que certaines feuilles ne tombent pas ou que plusieurs UC soient produites dans la même année, les rameaux non conformes sont supprimés.
    for r in [x for x in ram_mixtes if an(x) != annees[-2]]:
        print 'ERREUR : rameaux mixte ' + Class(r) + str(
            Index(r)) + ' avec pour année de croissance ' + str(
                an(r)) + '. Ce rameau ne sera pas considéré comme mixte'

    ram_mixtes = [x for x in ram_mixtes if an(x) == annees[-2]]

    #Getting all the branches, i.e fruiting units + old wood
    rm = ram_mixtes
    while True:
        rm_new = list(set([Father(x)
                           for x in rm] + rm))  #On ajoutte le vieux bois
        if len(rm_new) == len(
                rm
        ):  #On s'arrête quand on ne trouve plus de nouveaux rameaux.
            break
        else:
            rm = rm_new
    rm = [x for x in rm if x != None]

    #Generate the GU names according to QualiTree naming convention
    names = qualitree_nom_rameaux(rm)

    #Getting the QualiTree metamer info, i.e. length between the current GU and the previous one on the bearing shoot
    metameres_qualitree = qualitree_metamer(rm, names)

    #=====================================#
    # Generate info for architecture table#
    #=====================================#

    #QualiTree does not allow shoot positions to be below ground whereas it may results from MAppleT bending
    base_sous_sol = [x for x in rm if zz(Components(x)[0]) <= 0]
    sommet_sous_sol = [x for x in rm if zz(Components(x)[-1]) <= 0]
    for r in base_sous_sol:
        print 'ERREUR : la base de l\'UC ' + Class(r) + str(
            Index(r)) + ' est sous le plan horizontal, Y1 sera fixé à 0.1'
    for r in sommet_sous_sol:
        print 'ERREUR : le sommet de l\'UC ' + Class(r) + str(
            Index(r)) + ' est sous le plan horizontal, Y2 sera fixé à 0.1'

    tab_architecture = [
        [
            niveau(names[x]),  #Order(x),#marche pas?
            names[x],
            topdia(Components(x)[0]),  #diametre_base
            topdia(Components(x)[-1]),  #diametre_ext
            metameres_qualitree[x],  #metameres
            round(xx(Components(x)[0]) * 1000, 1),
            round((zz(Components(x)[0]) if
                   (zz(Components(x)[0]) > 0.0) else 0.0001) * 1000, 1),
            round(
                -yy(Components(x)[0]) * 1000, 1
            ),  #x1, y1, z1 #Conversion repère MappleT (m) à reprère Qualitree (q) : Xq=Xm Yq=Zm Zq=-Ym, conversion m -> mm. On s'assure que Y > 0 sinon on le fixe à 0 (condition qualitree).
            round(xx(Components(x)[-1]) * 1000, 1),
            round((zz(Components(x)[-1])
                   if zz(Components(x)[-1]) > 0.0 else 0.0001) * 1000, 1),
            round(-yy(Components(x)[-1]) * 1000, 1),
            round(length_uc(x) * 1000, 1),
            Class(x) + str(Index(x)),
        ] for x in rm
    ]
    #save(tab_architecture,'test.csv')

    #=====================================#
    # Generate info for remeauxmixte table#
    #=====================================#

    if charge_fruits == None:
        tab_rameauxmixte = [
            [
                names[x],
                vol_uc(x) * densite_MS_rameaux,
                fruit_ram(x),
                fruit_ram_ms(x),
                nb_leafy_rameau_cat(x, 'small'),
                la_rameau_cat(x, 'small') / SLA + vol_rameau_cat(x, 'small') *
                densite_MS_rameaux,  #MS feuilles + tiges des pousses feuillées
                nb_leafy_rameau_cat(x, 'medium'),
                la_rameau_cat(x, 'medium') / SLA +
                vol_rameau_cat(x, 'medium') *
                densite_MS_rameaux,  #MS feuilles + tiges des pousses feuillées
                nb_leafy_rameau_cat(x, 'large'),
                la_rameau_cat(x, 'large') / SLA + vol_rameau_cat(x, 'large') *
                densite_MS_rameaux,  #MS feuilles + tiges des pousses feuillées
                Index(x),
                TMS_fruits,
            ] for x in ram_mixtes
        ]
        #save(tab_rameauxmixte,'test2.csv')
    else:
        charge_fruits = float(charge_fruits)
        assert (0. <= charge_fruits and charge_fruits <= 1.)
        if seed != None:
            random.seed(seed)
        ms_moy_fruit = float(sum([fruit_ram_ms(x) for x in ram_mixtes])) / sum(
            [fruit_ram(x) for x in ram_mixtes])
        nb_I = [
            len([y for y in Sons(x) if Class(y) == "I"]) for x in ram_mixtes
        ]
        nb_F = int(round(sum(nb_I) * charge_fruits))

        inflos = []
        for x, i in zip(ram_mixtes, nb_I):
            inflos += [x] * i
        random.shuffle(inflos)
        inflos = inflos[
            0:nb_F]  #On choisi au hasard les inflorescences portant un fruit.
        ram_mixte_nb_F = {x: inflos.count(x) for x in ram_mixtes}

        tab_rameauxmixte = [
            [
                names[x],
                vol_uc(x) * densite_MS_rameaux,
                ram_mixte_nb_F[x],
                ram_mixte_nb_F[x] * ms_moy_fruit,
                nb_leafy_rameau_cat(x, 'small'),
                la_rameau_cat(x, 'small') / SLA + vol_rameau_cat(x, 'small') *
                densite_MS_rameaux,  #MS feuilles + tiges des pousses feuillées
                nb_leafy_rameau_cat(x, 'medium'),
                la_rameau_cat(x, 'medium') / SLA +
                vol_rameau_cat(x, 'medium') *
                densite_MS_rameaux,  #MS feuilles + tiges des pousses feuillées
                nb_leafy_rameau_cat(x, 'large'),
                la_rameau_cat(x, 'large') / SLA + vol_rameau_cat(x, 'large') *
                densite_MS_rameaux,  #MS feuilles + tiges des pousses feuillées
                Index(x),
                TMS_fruits,
            ] for x in ram_mixtes
        ]

    #=====================================#
    #   Generate info for arbre table     #
    #=====================================#
    vb_masse_seche = sum(
        [vol_uc(x) * densite_MS_rameaux for x in rm if not x in ram_mixtes])
    vb_masse_seche = vb_masse_seche if vb_masse_seche != None else 0  #Pour les arbres jeunes (sans vieux bois), sum([]) = None
    vr_masse_seche = sum(
        [vol_uc(x) * densite_MS_rameaux for x in rm]
    ) / SR  #La masse sèche de vieilles racines est calculée en fonction de la masse des UC en croissance secondaire (vieux bois+tiges de rameaux mixte) et du shoot-root ratio.
    jr_masse_seche = sum([
        la_rameaux(x) / SLA + sum([vol_uc(y)
                                   for y in Sons(x)]) * densite_MS_rameaux
        for x in ram_mixtes
    ]) / SR  #La masse sèche des jeunes racines est calculée en fonction de la masse des pousses feuillées (tige+feuilles) et du shoot-root ratio.

    #delete MTG in memory
    del m

    if userEllipse:
        #To get an estimation of the ellipse we use PlantGL algorithms, hence the need of the 3D scene
        #The scene should be a pgl.Scene but could also be the path to a saved bgeom scene
        if type(scene) == str:
            sc = pgl.Scene(scene)
        else:
            sc = scene

        assert type(sc) == pgl.Scene

        #The scene should only contains the leaves
        #in MAppleT it can be obtained using their specific colorname
        #lvs = getLeavesOnly(sc)

        #Computing the ellipse
        #ell = computeBoundingShape(lvs)
        ell = computeBoundingShape(sc)

        #Retrieving the info of that ellipse
        cx, cy, cz, rx, ry, rz, angle_y = ellipseDesc(ell)
        #For the moment the high and low cutting planes are defined at the top and bottom of the ellipse
        coupe_h = cy + ry
        #coupe_b = cy-ry
        #trying to use the leaves BBox to define the low cutting plane
        bbox = pgl.BoundingBox(lvs)
        coupe_b = bbox.getZMin() * 100

        tab_arbre = [
            variete, vr_masse_seche, jr_masse_seche, vb_masse_seche, cx, cy,
            cz, rx, ry, rz, coupe_h, coupe_b, angle_y
        ]
        tree_sql(nom_arbre,
                 date,
                 tab_arbre,
                 tab_architecture,
                 tab_rameauxmixte,
                 ellipseIN=True)
    else:
        tab_arbre = [variete, vr_masse_seche, jr_masse_seche, vb_masse_seche]
        tree_sql(nom_arbre,
                 date,
                 tab_arbre,
                 tab_architecture,
                 tab_rameauxmixte,
                 ellipseIN=False)

    tree_csv(nom_arbre, date, variete, vr_masse_seche, jr_masse_seche,
             vb_masse_seche, tab_architecture, tab_rameauxmixte)
Ejemplo n.º 11
0
def getbbx(scene):
    bbx = pgl.BoundingBox(scene)
    return bbx.lowerLeftCorner, bbx.upperRightCorner
Ejemplo n.º 12
0
def voxelize(scene, gridSize, density=True):
    """
  Generate the scene resulting of grid discretization
  
  :Parameters:
    - `Scene` : PlantGL scene
    - `Division Factor` : Division factor of the bounding box
    - `Density` : Taking density into account

  :Types:
    - `Scene` : Pgl scene
    - `Division Factor` : int 
    - `Density` : boolean

  :returns:
    - `Voxel size` : List of intercepted voxels size
    - `Centers` : List of intercepted voxels centers
    - `Densities` : List of intercepted voxels densities
    - `VoxScene` : Scene of intercepted voxels

  :returntype:
    - `Voxel size` : [ float ] 
    - `Centers` : [ ( float ) ]
    - `Densities` :  [ float ]
    - `VoxScene` : Plg scene
  """

    #scene = pgl.Scene(sceneFile)
    bbox = pgl.BoundingBox(scene)
    epsilon = pgl.Vector3(0.01, 0.01, 0.01)
    origin = bbox.lowerLeftCorner - epsilon
    step = (bbox.getSize() + epsilon) * 2 / (gridSize)
    origin_center = origin + step / 2.

    tgl_list = surfPerTriangle(scene)

    grid = {}
    for tgl in tgl_list:
        pos = gridIndex(tgl[0] - origin, step)
        assert (pos[0] < gridSize and pos[1] < gridSize and pos[2] < gridSize)

        if grid.has_key(pos):
            grid[pos] += tgl[1]
        else:
            grid[pos] = tgl[1]

    kize = grid.keys()
    kize.sort()
    pts = []
    mass = []
    for k in kize:
        pts.append(list(k))
        mass.append(grid[k])

    massort = deepcopy(mass)
    massort.sort()
    qlist = [25, 50, 75]
    quants = [massort[int(len(massort) * q / 100.0)] for q in qlist]

    voxSize = step / 2.
    vox = pgl.Box(voxSize)
    vox.setName('voxel')

    mat1 = color(47, 255, 0, trans=True, name='c_green')
    mat2 = color(255, 255, 0, trans=True, name='c_yellow')
    mat3 = color(255, 170, 0, trans=True, name='c_orange')
    mat4 = color(255, 0, 0, trans=True, name='c_red')

    #sc = pgl.Scene()
    ctrs = []
    for i in xrange(len(pts)):
        pt = pts[i]
        vect = pgl.Vector3(origin_center.x + (pt[0] * step.x),
                           origin_center.y + (pt[1] * step.y),
                           origin_center.z + (pt[2] * step.z))
        ctrs.append(vect)
        geometry = pgl.Translated(vect, vox)
        if (density):
            if (mass[i] < quants[0]):
                sh = pgl.Shape(geometry, mat1, i)
            elif (mass[i] < quants[1]):
                sh = pgl.Shape(geometry, mat2, i)
            elif (mass[i] < quants[2]):
                sh = pgl.Shape(geometry, mat3, i)
            else:
                sh = pgl.Shape(geometry, mat4, i)
        else:
            sh = pgl.Shape(geometry, mat1, i)
        scene.add(sh)

    vxls = Voxels(voxSize, ctrs, mass)

    #return (vxls, scene)
    return (voxSize, ctrs, mass, scene)