3. Geometric inputs

3.1. Content

  • input formats

    • Dict of triangles

    • PlantGL scene

    • VGX file

    • Voxels grid

    • MTG object from adelwheat

    • RATP inputs

    • RiRi5 inputs

  • organization levels: species and organs

  • stems management

  • geometric transformations

3.2. Introduction

The main purpose of this tool was to merge several geometric scenes in various formats and apply a radiative modelling on it. Here, we will precise the different possiblities for manipulating geometry.

[1]:
from lightvegemanager.LVM import LightVegeManager
from pgljupyter import SceneWidget
[2]:
# Environment parameters for this notebook
longitude = 2.
latitude = 46.
timezone = 1
coordinates = [latitude, longitude, timezone]
infinite = False
reflected = False
direct = False
diffuse = True
sky = "turtle46"

environment = {
                "coordinates": coordinates ,
                "infinite": infinite,
                "reflected": reflected,
                "direct": direct,
                "diffuse": diffuse,
                "sky": sky
                }

3.3. Inputs Formats

In this section, we won’t present single triangle and list of triangles as input geometry, as they were present in the tool_basics.ipynb notebook. Also, these two formats can be direct inputs of the geometry argument of the build method, unlike the following formats which needs to be included in a list, such as:

geometry = { "scenes": [scene1, scene2, ...] }

3.3.1. dict of triangles

A mesh of triangles can be represented as a dict, where each key is an organ ID and its value, a list of triangles belonging to the organ. A triangle is a list of a 3 vertices represented by (x,y,z)points.

In this example, we will generate random 3D triangles for 3 differents organs.

[12]:
from lightvegemanager.trianglesmesh import random_triangle_generator

spheresize = (10., 2.)
organized_triangles = {
    111: [random_triangle_generator(spheresize=spheresize, worldsize=(0,20)) for i in range(20)],
    222: [random_triangle_generator(spheresize=spheresize, worldsize=(20,50)) for i in range(30)],
    333: [random_triangle_generator(spheresize=spheresize, worldsize=(50,100)) for i in range(10)],
}

Input geometry looks like:

[4]:
geometry = {
    "scenes": [organized_triangles]
}

Then, we compute lighting and run a visualization of the scene.

Note: elements_outputs method will return a Dataframe where results are integrated on each organ.

[5]:
lighting = LightVegeManager(lightmodel="caribu", environment=environment)
lighting.build(geometry=geometry)

# compute the lighting
energy = 500.
hour = 15
day = 264
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True),
            position=(-50.0, -50.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 100,
            axes_helper=True)
   Day  Hour  Organ  VegetationType        Area    par Eabs      par Ei
0  264    15    111               0  812.660080  254.783023  299.744733
1  264    15    222               0  906.791550  326.191765  383.755017
2  264    15    333               0  456.917637  368.655503  433.712356
[5]:

3.3.2. PlantGL scene

A plantGL Scene is a list of plantGL Shape which can be considered as organ. The ID of the plantGL Shape are stored as organs ID.

[7]:
import openalea.plantgl.all as pgl

pgl_scene = pgl.Scene([pgl.Shape(pgl.Box(), pgl.Material(), 888),
                        pgl.Shape(pgl.Translated((0,0,1), pgl.Cylinder()), pgl.Material(), 999)])
[8]:
geometry = {
    "scenes": [pgl_scene]
}
lighting = LightVegeManager(lightmodel="caribu", environment=environment)
lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 5,
            axes_helper=True)
   Day  Hour  Organ  VegetationType      Area    par Eabs      par Ei
0  264    15    888               0  6.000000  159.643042  187.815343
1  264    15    999               0  4.475681  185.076017  217.736490
[8]:

3.3.3. VGX file

The tool can read a VGX file as an input entry. It extracts triangles which are considered as leaves, following its colors, if Red != 42 . All triangles are stored in the same organ, where its ID is set to 0.

[5]:
import os

vgx_path = os.path.join(os.path.dirname(os.path.abspath("")), "data", "NICatObs1P2.vgx")
vgx_path
[5]:
'C:\\Users\\mwoussen\\cdd\\codes\\dev\\lightvegemanager\\data\\NICatObs1P2.vgx'
[7]:
geometry = {
    "scenes": [vgx_path]
}
# compute the lighting
energy = 500.
hour = 15
day = 264
lighting = LightVegeManager(lightmodel="caribu", environment=environment)
lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 100,
            axes_helper=True)
   Day  Hour  Organ  VegetationType         Area    par Eabs      par Ei
0  264    15      0               0  6062.836763  193.704509  227.887658
[7]:

3.3.4. Grid of voxels

A voxel grid is represented as a dict of two entries: - "LA" corresponding to leaf area, is a table (numpy.array) of dimension $:nbsphinx-math:text{number of species} \times `:nbsphinx-math:text{number of z layers}` \times `:nbsphinx-math:text{number of x layers}` \times `:nbsphinx-math:text{number of y layers}` $ - "distrib" corresponding to leaf angle distribution, is a list of list, where is entered a leaf angle distribution for each specy

Grid dimensions and voxel size are set in the input parameters of RATP.

[7]:
import numpy

l_scene = {"LA": numpy.ones([2, 3, 4, 4]), "distrib": [[0.5, 0.5], [0.3, 0.7]]}
[16]:
geometry = {
    "scenes": [vgx_path]
}
ratp_parameters = {
    "voxel size" : [20.] * 3
}
lighting = LightVegeManager(lightmodel="ratp", environment=environment, lightmodel_parameters=ratp_parameters)
lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True, printtriangles=False, printvoxels=True),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 100,
            axes_helper=True)
     Day  Hour  Organ  VegetationType         Area        PARa  Intercepted  \
0  264.0  15.0      0               1  6062.836763  307.604456   215.922903

   Transmitted   SunlitPAR  SunlitArea   ShadedPAR  ShadedArea
0   215.922903  307.604461  252.377915  307.604461  126.601372
[16]:

3.3.5. MTG object from adelwheat

Finally, you can also give a MTG object with a "scene" property. The package adelwheat offers such objects.

[8]:
from alinea.adel.adel_dynamic import AdelDyn
from alinea.adel.echap_leaf import echap_leaves
INPUTS_DIRPATH = os.path.join(os.path.dirname(os.path.abspath("")), "data")
adel_wheat = AdelDyn(seed=1, scene_unit="m", leaves=echap_leaves(xy_model="Soissons_byleafclass"))
g = adel_wheat.load(dir=INPUTS_DIRPATH)
[18]:
geometry = {
    "scenes": [g]
}
lighting = LightVegeManager(lightmodel="caribu", environment=environment)
lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 0.1,
            axes_helper=True)
   Day  Hour  Organ  VegetationType      Area    par Eabs      par Ei
0  264    15     19               0  0.000228  159.208612  187.304249
1  264    15     34               0  0.000013   80.953500   95.239412
2  264    15    813               0  0.000194  385.317031  453.314154
3  264    15    814               0  0.000240  367.646906  432.525772
4  264    15     51               0  0.000284  347.458387  408.774573
[18]:

3.3.6. RATP inputs

All the above scenes can be geometric inputs if the lightmodel argument is set to "ratp".

[21]:
geometry = {
    "scenes": [g]
}
lighting = LightVegeManager(lightmodel="ratp", environment=environment)
lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True, printvoxels=True),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 0.1,
            axes_helper=True)
     Day  Hour  Organ  VegetationType      Area        PARa  Intercepted  \
0  264.0  15.0     19               1  0.000228  435.713379     0.000693
1  264.0  15.0     34               1  0.000013  435.713379     0.000693
2  264.0  15.0    813               1  0.000194  435.713379     0.000693
3  264.0  15.0    814               1  0.000240  441.368498     0.000288
4  264.0  15.0     51               1  0.000284  435.713379     0.000693

   Transmitted   SunlitPAR  SunlitArea   ShadedPAR  ShadedArea
0     0.000693  435.713379    0.000776  435.713379    0.000019
1     0.000693  435.713379    0.000776  435.713379    0.000019
2     0.000693  435.713379    0.000776  435.713379    0.000019
3     0.000288  441.368498    0.000322  441.368498    0.000007
4     0.000693  435.713379    0.000776  435.713379    0.000019
[21]:

3.3.7. RiRi5 inputs

RiRi5 can have the same inputs as RATP.

A scene grid of voxels must have exactly 9 angle classes for its leaf angle distribution, and at least one empty layer above the canopy.

Triangles mesh inputs are processed through the RATP pipeline, then is converted to RiRi5.

[9]:
import numpy

l_scene = {"LA": numpy.ones([2, 3, 4, 4]), "distrib": [[0.1, 0.2, 0.1, 0.1, 0.05, 0.05, 0.1, 0.2, 0.1],
                                                        [0.1, 0.1, 0.1, 0.1, 0.05, 0.1, 0.2, 0.2, 0.05]]}
for i in range(4):
    for j in range(4):
        l_scene["LA"][0][0][i][j] = 0.
        l_scene["LA"][1][0][i][j] = 0.
[10]:
geometry = {
    "scenes": [l_scene]
}
lighting = LightVegeManager(lightmodel="riri5", environment=environment)
lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
[21]:
print(lighting.riri5_intercepted_light)
[[[[  0.           0.           0.           0.        ]
   [  0.           0.           0.           0.        ]
   [  0.           0.           0.           0.        ]
   [  0.           0.           0.           0.        ]]

  [[208.05400092 208.05400092 208.05400092 208.05400092]
   [208.05400092 208.05400092 208.05400092 208.05400092]
   [208.05400092 208.05400092 208.05400092 208.05400092]
   [208.05400092 208.05400092 208.05400092 208.05400092]]

  [[ 33.75896074  33.75896074  33.75896074  33.75896074]
   [ 33.75896074  33.75896074  33.75896074  33.75896074]
   [ 33.75896074  33.75896074  33.75896074  33.75896074]
   [ 33.75896074  33.75896074  33.75896074  33.75896074]]]


 [[[  0.           0.           0.           0.        ]
   [  0.           0.           0.           0.        ]
   [  0.           0.           0.           0.        ]
   [  0.           0.           0.           0.        ]]

  [[207.34450322 207.34450322 207.34450322 207.34450322]
   [207.34450322 207.34450322 207.34450322 207.34450322]
   [207.34450322 207.34450322 207.34450322 207.34450322]
   [207.34450322 207.34450322 207.34450322 207.34450322]]

  [[ 33.2079505   33.2079505   33.2079505   33.2079505 ]
   [ 33.2079505   33.2079505   33.2079505   33.2079505 ]
   [ 33.2079505   33.2079505   33.2079505   33.2079505 ]
   [ 33.2079505   33.2079505   33.2079505   33.2079505 ]]]]
[22]:
print(lighting.riri5_transmitted_light)
[[[500.         500.         500.         500.        ]
  [500.         500.         500.         500.        ]
  [500.         500.         500.         500.        ]
  [500.         500.         500.         500.        ]]

 [[ 84.60149586  84.60149586  84.60149586  84.60149586]
  [ 84.60149586  84.60149586  84.60149586  84.60149586]
  [ 84.60149586  84.60149586  84.60149586  84.60149586]
  [ 84.60149586  84.60149586  84.60149586  84.60149586]]

 [[ 17.63458462  17.63458462  17.63458462  17.63458462]
  [ 17.63458462  17.63458462  17.63458462  17.63458462]
  [ 17.63458462  17.63458462  17.63458462  17.63458462]
  [ 17.63458462  17.63458462  17.63458462  17.63458462]]]
[12]:
geometry = {
    "scenes": [organized_triangles]
}

lighting.build(geometry=geometry)
lighting.run(energy=energy, hour=hour, day=day)
[13]:
print(lighting.riri5_intercepted_light)
[[[[0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   ...
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]]

  [[0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   ...
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]]

  [[0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   ...
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]]

  ...

  [[0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   ...
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]]

  [[0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   ...
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]]

  [[0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   ...
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]
   [0. 0. 0. ... 0. 0. 0.]]]]
[14]:
print(lighting.riri5_transmitted_light)
[[[500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  ...
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]]

 [[500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  ...
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]]

 [[500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  ...
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]]

 ...

 [[500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  ...
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]]

 [[500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  ...
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]]

 [[500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  ...
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]
  [500. 500. 500. ... 500. 500. 500.]]]

3.4. Organizing the inputs

They are two levels of possible organization: - species - organs

Each triangle are bound to a specy ID and a organ ID. Each specy is represented as a input scene. The organs ID are set inside each scene depending on its format.

indices.png

An example with several scenes with the same organs ID and CARIBU.

[22]:
scene1 = {
    111: [random_triangle_generator(spheresize=spheresize) for i in range(20)],
    222: [random_triangle_generator(spheresize=spheresize) for i in range(30)],
    333: [random_triangle_generator(spheresize=spheresize) for i in range(10)],
}

scene2 = {
    111: [random_triangle_generator(spheresize=spheresize) for i in range(20)],
    222: [random_triangle_generator(spheresize=spheresize) for i in range(30)],
    333: [random_triangle_generator(spheresize=spheresize) for i in range(10)],
}

scene3 = {
    111: [random_triangle_generator(spheresize=spheresize) for i in range(20)],
    222: [random_triangle_generator(spheresize=spheresize) for i in range(30)],
    333: [random_triangle_generator(spheresize=spheresize) for i in range(10)],
}

We have 3 species

[23]:
scenes = [scene1, scene2, scene3]
geometry = { "scenes": scenes }
[24]:
lighting = LightVegeManager(lightmodel="caribu")
lighting.build(geometry=geometry)

# compute the lighting
energy = 500.
hour = 15
day = 264
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
   Day  Hour  Organ  VegetationType         Area    par Eabs      par Ei
0  264    15    111               0   865.848719  367.620782  432.495038
1  264    15    222               0   904.093391  343.903742  404.592638
2  264    15    333               0   500.476649  374.891932  441.049332
3  264    15    111               1   719.501340  330.624848  388.970410
4  264    15    222               1  1023.379192  351.641676  413.696090
5  264    15    333               1   129.105369  391.022326  460.026266
6  264    15    111               2  1047.414777  335.930702  395.212591
7  264    15    222               2  1174.044647  349.124635  410.734865
8  264    15    333               2   521.903258  361.052748  424.767939
[25]:
SceneWidget(lighting.to_plantGL(lighting=True),
            position=(-50.0, -50.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 100,
            axes_helper=True)
[25]:

The two level organization are also kept with RATP

[27]:
lighting = LightVegeManager(lightmodel="ratp")
lighting.build(geometry=geometry)

energy = 500.
hour = 15
day = 264
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
     Day  Hour  Organ  VegetationType         Area        PARa  Intercepted  \
0  264.0  15.0    111               1   865.848719  444.431609   438.050846
1  264.0  15.0    222               1   904.093391  439.138654   508.370824
2  264.0  15.0    333               1   500.476649  438.358519   466.758357
3  264.0  15.0    111               2   719.501340  441.984838   374.664274
4  264.0  15.0    222               2  1023.379192  436.324817   446.932608
5  264.0  15.0    333               2   129.105369  442.768841   373.148804
6  264.0  15.0    111               3  1047.414777  437.256257   728.403508
7  264.0  15.0    222               3  1174.044647  443.465415   536.007093
8  264.0  15.0    333               3   521.903258  432.082470   816.087594

   Transmitted   SunlitPAR  SunlitArea   ShadedPAR  ShadedArea
0   438.050846  450.722334  463.402916  356.222905   49.407779
1   508.370824  446.126727  538.617195  351.627301   58.372064
2   466.758357  446.387940  492.094716  351.888516   56.801907
3   374.664274  449.154416  395.429864  352.554837   42.809579
4   446.932608  444.042247  473.516975  347.442668   51.797538
5   373.148804  449.336097  395.819748  352.736518   45.454794
6   728.403508  444.694193  770.345275  349.806482   81.342446
7   536.007093  450.321284  565.173551  355.433568   58.993793
8   816.087594  440.468993  864.084337  345.581276   97.832614
c:\users\mwoussen\cdd\codes\dev\lightvegemanager\src\lightvegemanager\outputs.py:255: UserWarning: You are merging on int and float columns where the float values are not equal to their int representation.
  trianglesoutputs = pandas.merge(dftriangles, voxels_outputs)

3.5. Stems

If there are stems elements in the inputs, you can precise their ID and the tool will manage them, depending on the lightmodel: - with CARIBU, the optical parameters associated to the organ won’t have a transmission value (rays won’t cross the triangle) - with RATP, stems are separated in a new specy with its own leaf angle distribution and their leaf area is divided by 2

We reuse the wheat geometry given by adelwheat

[9]:
geometry = {
    "scenes": [g]
}

stems are stored in list where each element is a 2-tuple (organ ID, specy ID)

[10]:
stems = [(19, 0), (34, 0)]
geometry.update({"stems id": stems})
[11]:
lighting = LightVegeManager(lightmodel="caribu")
lighting.build(geometry=geometry)
SceneWidget(lighting.to_plantGL(),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 0.1,
            axes_helper=True)
[11]:
[32]:
lighting.run(energy=energy, hour=hour, day=day)
print(lighting.elements_outputs)
SceneWidget(lighting.to_plantGL(lighting=True),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 0.1,
            axes_helper=True)
   Day  Hour  Organ  VegetationType      Area    par Eabs      par Ei
0  264    15     19               0  0.000228  194.070089  215.633432
1  264    15     34               0  0.000013   93.806573  104.229526
2  264    15    813               0  0.000194  458.967637  539.961926
3  264    15    814               0  0.000240  392.729426  462.034618
4  264    15     51               0  0.000284  350.644177  412.522561
[32]:

3.6. Geometric transformations

You can apply geometric transformations on some of the inputs scenes. We have currently 3 available transformations - translation by a vector - rescale by a factor or following scenes metric unit - rotation on the xy plane

transform_geo.png

Transformations are stored in a dict, which is stored at key "transformations" in the geometry entry. Structure of transformations :

transformations = {
    "scenes unit": { specy ID: "metric unit", ...},
    "rescale": { specy ID: float, ...},
    "translate": { specy ID: 3-tuple (x,y,z), ...},
    "xyz orientation":  { specy ID: "x+ = NEWS", ...},
}

Main scenes

[13]:
spheresize = (2., 1.)
scene1 = {
    0: [random_triangle_generator(spheresize=spheresize, worldsize=(0,10)) for i in range(20)]
}
scene2 = {
    0: [random_triangle_generator(spheresize=spheresize, worldsize=(10,20)) for i in range(20)]
}

geometry = {"scenes": [scene1, scene2] }
[14]:
lighting = LightVegeManager(lightmodel="caribu")
lighting.build(geometry=geometry)
SceneWidget(lighting.to_plantGL(),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 50.,
            axes_helper=True)
[14]:

3.6.1. Translate

The translation vector is a 3-tuple (x,y,z). Transformations is a dict in the geometry dict.

[15]:
tvec = (10., -10., 10.)
transformations = {
    "translate": {
        0: tvec
    }
}
geometry = {"scenes": [scene1, scene2] , "transformations": transformations}
[16]:
lighting = LightVegeManager(lightmodel="caribu")
lighting.build(geometry=geometry)
SceneWidget(lighting.to_plantGL(),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 50.,
            axes_helper=True)
[16]:

3.6.2. Rescale following metric unit

You can precise the metric unit of each scene from this list: "mm", "cm", "dm", "m", "dam", "hm", "km". By default the merged scene is in m but you can change its unit when you create an instance.

[17]:
transformations = {
    "scenes unit": {
        0: "dm"
    }
}
geometry = {"scenes": [scene1, scene2] , "transformations": transformations}
[18]:
lighting = LightVegeManager(lightmodel="caribu", main_unit="m")
lighting.build(geometry=geometry)
SceneWidget(lighting.to_plantGL(),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 50.,
            axes_helper=True)
[18]:

3.6.3. Rescale by a scalar factor

[19]:
transformations = {
    "rescale": {
        0: 2.,
    }
}
geometry = {"scenes": [scene1, scene2] , "transformations": transformations}
[20]:
lighting = LightVegeManager(lightmodel="caribu")
lighting.build(geometry=geometry)
SceneWidget(lighting.to_plantGL(),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 50.,
            axes_helper=True)
[20]:

3.6.4. Rotate

Finally, you can also rotate the scene around the z axis, in order to match the x+ convention for each input scene. You have the choice between: - "x+ = N" - "x+ = S" - "x+ = E" - "x+ = W"

The merged scene convention is x+ = N, which the convention in RATP and CARIBU.

[21]:
transformations = {
    "xyz orientation": {
        0: "x+ = S",
        1: "x+ = E",
    }
}
geometry = {"scenes": [scene1, scene2] , "transformations": transformations}
[22]:
lighting = LightVegeManager(lightmodel="caribu")
lighting.build(geometry=geometry)
SceneWidget(lighting.to_plantGL(),
            position=(0.0, 0.0, 0.0),
            size_display=(600, 400),
            plane=True,
            size_world = 50.,
            axes_helper=True)
[22]: