02_user_tutorials:02_growth_modelling:leaf-triangulation
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| 02_user_tutorials:02_growth_modelling:leaf-triangulation [2025/01/24 15:41] – removed - external edit (Unknown date) 127.0.0.1 | 02_user_tutorials:02_growth_modelling:leaf-triangulation [2025/01/24 16:31] (current) – tim2 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | {{howhard> | ||
| + | ====== Leaf triangulation ====== | ||
| + | |||
| + | Triangulation is the process where a (ordered) set of triangles is generated out of a (unordered) set of points. The result is a set of triangles, now called faces, that can be directly drawn. | ||
| + | |||
| + | |||
| + | == == | ||
| + | |||
| + | Let's see the following set of 2D point: | ||
| + | |||
| + | s={(0, 0), (-2.85, 4), (0, 10), (2.85, 3.1)} | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | When connecting the points (P_0, P_1, P_2) and (P_1, P_3, P_2) we obtain two triangles. And by doing so, we already did our first (2D) triangulation. In computer graphics such a set of triangles - from now on called faces - is called mesh. | ||
| + | |||
| + | Note: Triangulation is not unique. Meaning there can be different triangulations for the same set of points. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | To draw a mesh in GroIMP, all we need to do is to define the point and the faces. The used geometrical object we need to visualize the so-called // | ||
| + | |||
| + | The code to generate a simple two faces mesh could look like this: | ||
| + | |||
| + | <code java> | ||
| + | import de.grogra.xl.util.IntList; | ||
| + | import de.grogra.xl.util.FloatList; | ||
| + | |||
| + | const float[] p0 = {0,0,0}; | ||
| + | const float[] p1 = {-2.85, | ||
| + | const float[] p2 = {0,10,0}; | ||
| + | const float[] p3 = {2.85, | ||
| + | |||
| + | const FloatList vertexDataLeaflet = new FloatList(new float[] { | ||
| + | //left | ||
| + | p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2],//T1 | ||
| + | //right | ||
| + | p0[0], p0[1], p0[2], p2[0], p2[1], p2[2], p3[0], p3[1], p3[2]//T2 | ||
| + | }); | ||
| + | |||
| + | const PolygonMesh polygonMesh = new PolygonMesh(); | ||
| + | static { | ||
| + | int[] tmp = new int[vertexDataLeaflet.size()/ | ||
| + | for(int i = 0; i< | ||
| + | // set a list of the indices of the used list of vertices | ||
| + | // normally = {0, | ||
| + | polygonMesh.setIndexData(new IntList(tmp)); | ||
| + | // set the list of vertices | ||
| + | polygonMesh.setVertexData(vertexDataLeaflet); | ||
| + | } | ||
| + | |||
| + | protected void init() [ | ||
| + | Axiom ==> Scale(0.007) | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | The output of the above code could then look like this. Note: The blue lines to highlight the edges are just added to increase understanding - they will be not shown when running the above code.: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | For convex shapes, the //Library// function //leaf3d// can be used to generate a triangulation like the above one. It assumes that the first point is the origin of all faces and builds a series of triangles from this point on. In XL this could look like this: | ||
| + | |||
| + | <code java> | ||
| + | const float[] pointlist = new float[] {0, | ||
| + | |||
| + | protected void init() [ | ||
| + | Axiom ==> leaf3d(pointlist); | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | Coming back to the // | ||
| + | |||
| + | <code java> | ||
| + | static MeshNode LeafletMesh; | ||
| + | static { | ||
| + | LeafletMesh = getMesh(vertexDataLeaflet); | ||
| + | } | ||
| + | |||
| + | protected void init() [ | ||
| + | Axiom ==> Scale(0.007) LeafletMesh.(setShader(GREEN)); | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | |||
| + | Now, let's take a tomato leaflet for example, | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | and when placed behind our points, the above triangulation could be already a very rough simplification of this particular leaflet. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Well, a very rough indeed. So, let's add some more points and also add the the third dimension to give the leaflet some 3D shape. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | For the seek of laziness/ | ||
| + | |||
| + | To do so within GroIMP, we just need to add the new points and apply some values for the Z-dimension. A simple curve like this may do: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | |||
| + | The complete code to generate the leaflet mesh looks like this: | ||
| + | |||
| + | <code java> | ||
| + | import de.grogra.xl.util.IntList; | ||
| + | import de.grogra.xl.util.FloatList; | ||
| + | |||
| + | const float[] p0 = {0,0,0}; | ||
| + | const float[] p1 = {-0.1, | ||
| + | const float[] p2 = {-0.2, | ||
| + | const float[] p3 = {-0.25, | ||
| + | const float[] p4 = {0, | ||
| + | const float[] p5 = {-0.285, | ||
| + | const float[] p6 = {0, | ||
| + | const float[] p7 = {-0.22, | ||
| + | const float[] p8 = {0, | ||
| + | const float[] p9 = {0,1,1.0}; | ||
| + | |||
| + | const FloatList vertexDataLeaflet = new FloatList(new float[] { | ||
| + | //left | ||
| + | p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2],//T1 | ||
| + | p0[0], p0[1], p0[2], p2[0], p2[1], p2[2], p3[0], p3[1], p3[2],//T2 | ||
| + | p0[0], p0[1], p0[2], p3[0], p3[1], p3[2], p4[0], p4[1], p4[2],//T3 | ||
| + | p3[0], p3[1], p3[2], p4[0], p4[1], p4[2], p5[0], p5[1], p5[2],//T4 | ||
| + | p4[0], p4[1], p4[2], p5[0], p5[1], p5[2], p6[0], p6[1], p6[2],//T5 | ||
| + | p5[0], p5[1], p5[2], p6[0], p6[1], p6[2], p7[0], p7[1], p7[2],//T6 | ||
| + | p6[0], p6[1], p6[2], p7[0], p7[1], p7[2], p8[0], p8[1], p8[2],//T7 | ||
| + | p7[0], p7[1], p7[2], p8[0], p8[1], p8[2], p9[0], p9[1], p9[2],//T8 | ||
| + | //right | ||
| + | -p0[0], p0[1], p0[2], -p1[0], p1[1], p1[2], -p2[0], p2[1], p2[2],//T9 | ||
| + | -p0[0], p0[1], p0[2], -p2[0], p2[1], p2[2], -p3[0], p3[1], p3[2],//T10 | ||
| + | -p0[0], p0[1], p0[2], -p3[0], p3[1], p3[2], -p4[0], p4[1], p4[2],//T11 | ||
| + | -p3[0], p3[1], p3[2], -p4[0], p4[1], p4[2], -p5[0], p5[1], p5[2],//T12 | ||
| + | -p4[0], p4[1], p4[2], -p5[0], p5[1], p5[2], -p6[0], p6[1], p6[2],//T13 | ||
| + | -p5[0], p5[1], p5[2], -p6[0], p6[1], p6[2], -p7[0], p7[1], p7[2],//T14 | ||
| + | -p6[0], p6[1], p6[2], -p7[0], p7[1], p7[2], -p8[0], p8[1], p8[2],//T15 | ||
| + | -p7[0], p7[1], p7[2], -p8[0], p8[1], p8[2], -p9[0], p9[1], p9[2]//T16 | ||
| + | }); | ||
| + | |||
| + | static MeshNode LeafletMesh; | ||
| + | static { | ||
| + | LeafletMesh = getMesh(vertexDataLeaflet); | ||
| + | } | ||
| + | |||
| + | protected void init() [ | ||
| + | Axiom ==> Scale(0.07, 0.07, 0.01) LeafletMesh.(setShader(GREEN)); | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | The output of the above code could then look like this: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | The last step would now be to pack the leaflet mesh into a module and integrate it further into a leaf module (not shown here). For the first aspect, we can define a module like this: | ||
| + | |||
| + | <code java> | ||
| + | module Leaflet(float length) ==> | ||
| + | Scale(length, | ||
| + | </ | ||
| + | |||
| + | After integration in to a leaf module the final 3D result could look like this | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | as it was used within Zhang //et al.// 2021 (High resolution 3D simulation of light climate and thermal performance of a solar greenhouse model under tomato canopy structure; //Renewable Energy//, 160, 730-745, doi: [[https:// | ||
| + | |||
| + | GroIMP provides a few predefined 3D leaves that can be accessed using the Library function leaf3d(id). There are shapes for: " | ||
| + | |||
| + | The code below will generate them one by one next to each other. | ||
| + | |||
| + | <code java> | ||
| + | protected void init() [ | ||
| + | Axiom ==> | ||
| + | for(int i=0; i< | ||
| + | [ Null(i*0.3, | ||
| + | ) | ||
| + | ] | ||
| + | </ | ||
| + | |||
| + | The predefined 3D leaf shapes will look as shown below: | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | |||
| + | |||
| + | |||
