Mentions légales du service

Skip to content
Snippets Groups Projects
Commit fc6542f2 authored by LEGRAND Jonathan's avatar LEGRAND Jonathan
Browse files

Fix headers and imports

parent 1d2789cd
No related branches found
No related tags found
2 merge requests!3Improve lpy_tools,!2Add conda packaging
#!/usr/bin/env python #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from setuptools import setup, find_packages from setuptools import find_packages
from setuptools import setup
description = "Create figures automatically from LPy" description = "Create figures automatically from L-Py."
readme = open('README.md').read() readme = open('README.md').read()
# find packages # find packages
...@@ -19,9 +20,7 @@ setup_kwds = dict( ...@@ -19,9 +20,7 @@ setup_kwds = dict(
url='', url='',
license='LGPL-3.0', license='LGPL-3.0',
zip_safe=False, zip_safe=False,
packages=pkgs, packages=pkgs,
package_dir={'': 'src'}, package_dir={'': 'src'},
entry_points={}, entry_points={},
keywords='', keywords='',
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
### Main automating script for point sampling (generating labelled point cloud on virtual model) ### #!/usr/bin/env python3
### Usage: python generatePointCloud.py LpyModelFile labelDictionaryFile numberOfPoints ### # -*- coding: utf-8 -*-
### Example: python generatePointCloud.py Arabidopsis.lpy labelDictionary.txt 1000 ###
### The label dictionary file "labelDictionary.txt" should be updated accordingly for each model ### """
### Author: Ayan Chaudhury (ayanchaudhury.cs@gmail.com) ### Main automating script for point sampling (generating labelled point cloud on virtual model)
### INRIA team MOSAIC ### Usage: python generatePointCloud.py LpyModelFile labelDictionaryFile numberOfPoints
### Updated: August 2021 ### Example: python generatePointCloud.py Arabidopsis.lpy labelDictionary.txt 1000
The label dictionary file "labelDictionary.txt" should be updated accordingly for each model
Author: Ayan Chaudhury (ayanchaudhury.cs@gmail.com)
INRIA team MOSAIC
Updated: August 2021
"""
from openalea import lpy
from openalea.plantgl.all import *
import argparse import argparse
from openalea import lpy
from scan_utils import * from scan_utils import *
coloredPointCloudFileName = "pointsWithColor.xyz" coloredPointCloudFileName = "pointsWithColor.xyz"
rawPointCloudFileName = "rawPoints.xyz" rawPointCloudFileName = "rawPoints.xyz"
labelFileName = "rawLabels.txt" labelFileName = "rawLabels.txt"
#dictFileName = "labelDictionary.txt" # dictFileName = "labelDictionary.txt"
#model_filename = "Arabido.lpy" # model_filename = "Arabido.lpy"
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
...@@ -27,10 +34,8 @@ model_filename = args.InputFileName ...@@ -27,10 +34,8 @@ model_filename = args.InputFileName
dictFileName = args.InputLabelDictionary dictFileName = args.InputLabelDictionary
pointsToBeSampled = int(args.TotalNumberOfPoints) pointsToBeSampled = int(args.TotalNumberOfPoints)
lsys = lpy.Lsystem(model_filename) lsys = lpy.Lsystem(model_filename)
lstring = lsys.derive() lstring = lsys.derive()
lscene = lsys.sceneInterpretation(lstring) lscene = lsys.sceneInterpretation(lstring)
pointSampler(lstring, lscene, dictFileName, pointsToBeSampled, coloredPointCloudFileName, rawPointCloudFileName, labelFileName) pointSampler(lstring, lscene, dictFileName, pointsToBeSampled, coloredPointCloudFileName, rawPointCloudFileName,
labelFileName)
### This script contains the functions to tessalate the shape into triangles, and performs the point sampling ### #!/usr/bin/env python3
### Author: Ayan Chaudhury (ayanchaudhury.cs@gmail.com) ### # -*- coding: utf-8 -*-
### INRIA team MOSAIC ### """
### Updated: August 2021 ### This script contains the functions to tessellate the shape into triangles, and performs the point sampling.
Author: Ayan Chaudhury (ayanchaudhury.cs@gmail.com)
INRIA team MOSAIC
Updated: August 2021
"""
from openalea.plantgl.all import *
import numpy as np
from math import *
from utilities import *
import ast import ast
from openalea.plantgl.algo import Tesselator
from openalea.plantgl.math import Vector3
from openalea.plantgl.math import cross
from openalea.plantgl.scenegraph import Cylinder
from openalea.plantgl.scenegraph import Frustum
from openalea.plantgl.scenegraph import Oriented
from openalea.plantgl.scenegraph import Primitive
from openalea.plantgl.scenegraph import Sphere
from openalea.plantgl.scenegraph import Translated
from lpy_tools.point_sampler.utilities import addTriangleIdToGlobalList
from lpy_tools.point_sampler.utilities import addVertexToGlobalList
from lpy_tools.point_sampler.utilities import createLabelledPointForDisplay
from lpy_tools.point_sampler.utilities import determineInsideness
from lpy_tools.point_sampler.utilities import extractCoord
from lpy_tools.point_sampler.utilities import obtainTriangleIdxList
from lpy_tools.point_sampler.utilities import obtainVertexList
from lpy_tools.point_sampler.utilities import sampleRandomPoints
from lpy_tools.point_sampler.utilities import selectRandomTriangle
from lpy_tools.point_sampler.utilities import write2File
# Given a geometry in the lscene, the function performs tessalation to # Given a geometry in the lscene, the function performs tesselation to
# decompose the shape into triangles. Returns the list of points & the # decompose the shape into triangles. Returns the list of points & the
# corresponding triangle indices. # corresponding triangle indices.
def performTessalation(currentGeometry): def performTessalation(currentGeometry):
t = Tesselator() t = Tesselator()
currentGeometry.apply(t) currentGeometry.apply(t)
triangleset = t.result triangleset = t.result
ptList = triangleset.pointList ptList = triangleset.pointList
idxList = triangleset.indexList idxList = triangleset.indexList
return ptList, idxList return ptList, idxList
# This is the main function that performs the point sampling. It takes as argument the lstring, lscene coming # This is the main function that performs the point sampling. It takes as argument the lstring, lscene coming
# from the virtual model, the label dictionary as text file total number of points to be sampled, and the 3 # from the virtual model, the label dictionary as text file total number of points to be sampled, and the 3
# output file names # output file names
def pointSampler(lstring, lscene, dictionaryFile, totalNumberOfResampledPts, pointsWithColor, rawPoints, rawLabels): def pointSampler(lstring, lscene, dictionaryFile, totalNumberOfResampledPts, pointsWithColor, rawPoints, rawLabels):
#totalNumberOfResampledPts = 2048 # desired number of points # totalNumberOfResampledPts = 2048 # desired number of points
randomPointLabels = [] # stores the labels of all points randomPointLabels = [] # stores the labels of all points
globalVertexList = [] #stores all vertices (without repeatition) globalVertexList = [] # stores all vertices (without repetition)
globalTriangleIdList = [] #stores id of vertices (as in globalVertexList) for the triangles globalTriangleIdList = [] # stores id of vertices (as in globalVertexList) for the triangles
globalTriangleLabelList = [] #stores the label of each triangle of globalTriangleIdList globalTriangleLabelList = [] # stores the label of each triangle of globalTriangleIdList
globalGeometryInfoList = [] #stores the geometry of all primitives globalGeometryInfoList = [] # stores the geometry of all primitives
cyllist = [] # stores all cylinder primitives cyllist = [] # stores all cylinder primitives
geomInfoList = [] # stores geometry of all the primitives geomInfoList = [] # stores geometry of all the primitives
# reading the label dictionary from the file
with open(dictionaryFile) as f:
data = f.read()
# reconstructing the data as a dictionary
labelTable = ast.literal_eval(data)
# reading the label dictionary from the file # loop over all elements in the lscene
with open(dictionaryFile) as f: for shape in lscene:
data = f.read() botpoint = Vector3(0, 0, 0) # the model is based at the origin
# reconstructing the data as a dictionary heading = Vector3(0, 0, 1)
labelTable = ast.literal_eval(data) geometry = shape
id = shape.id
currentModule = lstring[id].name
labelCurrentModule = labelTable[currentModule]
[ptList, idxList] = performTessalation(shape.geometry) # get the triangle corresponding to the primitive
vertexList = obtainVertexList(ptList) # store the set of indices of vertices that form triangles (local index)
triangleList = obtainTriangleIdxList(idxList) # store the set of triangle indices
### Now perform the global storing operations ###
globalVertexList = addVertexToGlobalList(vertexList, globalVertexList)
[globalTriangleIdList, globalTriangleLabelList] = addTriangleIdToGlobalList(vertexList, globalVertexList,
triangleList, globalTriangleIdList,
globalTriangleLabelList,
[labelCurrentModule])
# the following loop runs over all the basic primitives we have considered in the model
while not isinstance(geometry, Primitive):
geometry = geometry.geometry
### When the primitive is a cylinder ###
if isinstance(geometry, Cylinder):
cyllist.append((botpoint, botpoint + heading * geometry.height, geometry.radius))
toppoint = botpoint + heading * geometry.height
rad = geometry.radius
# print("Cylinder with label:", lstring[id][2], "Bottom point coordinate:", botpoint, "Top point coordinate:", toppoint, "Radius:",rad)
# Now we store the label and geometry information of the primitive as the following tuple:
# (primitive label, bottom_x, bottom_y, bottom_z, top_x, top_y, top_z, radius)
primitiveLabel = [1] # the label for cylinder is given as '1'
geomInfoList.append(primitiveLabel)
[bot_x, bot_y, bot_z] = extractCoord(botpoint) # bottom point
l = len(geomInfoList)
geomInfoList[l - 1].append(bot_x)
geomInfoList[l - 1].append(bot_y)
geomInfoList[l - 1].append(bot_z)
[top_x, top_y, top_z] = extractCoord(toppoint) # top point
geomInfoList[l - 1].append(top_x)
geomInfoList[l - 1].append(top_y)
geomInfoList[l - 1].append(top_z)
geomInfoList[l - 1].append(rad) # radius
### When the primitive is a frustum ###
elif isinstance(geometry, Frustum):
frustumTopPt = botpoint + heading * geometry.height
frustumRad = geometry.radius
taperFactor = geometry.taper
topRad = frustumRad * taperFactor
# print("Frustum with label:", lstring[id][2], "Bottom point coordinate:", botpoint, "Top point coordinate:", frustumTopPt, "Base radius:", frustumRad, "Top radius:", topRad)
# Now we store the label and geometry information of the primitive as the following tuple:
# (primitive label, bottom_x, bottom_y, bottom_z, top_x, top_y, top_z, base radius, top radius)
primitiveLabel = [2] # the label for frustum is given as '2'
geomInfoList.append(primitiveLabel)
[bot_x, bot_y, bot_z] = extractCoord(botpoint) # bottom point
l = len(geomInfoList)
geomInfoList[l - 1].append(bot_x)
geomInfoList[l - 1].append(bot_y)
geomInfoList[l - 1].append(bot_z)
[top_x, top_y, top_z] = extractCoord(frustumTopPt) # top point
geomInfoList[l - 1].append(top_x)
geomInfoList[l - 1].append(top_y)
geomInfoList[l - 1].append(top_z)
geomInfoList[l - 1].append(frustumRad) # base radius
geomInfoList[l - 1].append(topRad) # top radius
### When the primitive is a sphere ###
elif isinstance(geometry, Sphere):
sphereRad = geometry.radius
# print("Sphere with label:", lstring[id][1], "Radius:", sphereRad)
# Now we store the label and geometry information of the primitive as the following tuple:
# (primitive label, sphere radius)
# So the tuple contains: (primitive label, sphere radius)
primitiveLabel = [3] # the label for sphere is given as '3'
geomInfoList.append(primitiveLabel)
l = len(geomInfoList)
geomInfoList[l - 1].append(sphereRad)
elif isinstance(geometry, Translated):
botpoint = geometry.translation
elif isinstance(geometry, Oriented):
heading = cross(geometry.primary, geometry.secondary)
# print(vertexList), print(triangleList), print(geomInfoList), print(globalVertexList), print(globalTriangleIdList), print(globalTriangleLabelList)
##### So at this point, we are done with storing all the labelled geometry primitives and the labelled vertices of the coarse mesh model #####
##### Next, we will do the point sampling to generate points on the surface of the model. #####
# loop over all elements in the lscene ######################## Basic point sampler ########################
for shape in lscene:
botpoint = Vector3(0,0,0) # the model is based at the origin
heading = Vector3(0,0,1)
geometry = shape
id = shape.id
currentModule = lstring[id].name
labelCurrentModule = labelTable[currentModule]
[ptList, idxList] = performTessalation(shape.geometry) # get the triangle corresponding to the primitive
vertexList = obtainVertexList(ptList) # store the set of indices of vertices that form triangles (local index)
triangleList = obtainTriangleIdxList(idxList) # store the set of triangle indices
### Now perform the global storing operations ###
globalVertexList = addVertexToGlobalList(vertexList, globalVertexList)
[globalTriangleIdList, globalTriangleLabelList] = addTriangleIdToGlobalList(vertexList, globalVertexList, triangleList, globalTriangleIdList, globalTriangleLabelList, [labelCurrentModule])
# the following loop runs over all the basic primitives we have considered in the model
while not isinstance(geometry,Primitive):
geometry = geometry.geometry
### When the primitive is a cylinder ###
if isinstance(geometry,Cylinder):
cyllist.append((botpoint,botpoint+heading*geometry.height,geometry.radius))
toppoint = botpoint+heading*geometry.height
rad = geometry.radius
#print("Cylinder with label:", lstring[id][2], "Bottom point coordinate:", botpoint, "Top point coordinate:", toppoint, "Radius:",rad)
# Now we store the label and geometry information of the primitive as the following tuple:
# (primitive label, bottom_x, bottom_y, bottom_z, top_x, top_y, top_z, radius)
primitiveLabel = [1] # the label for cylinder is given as '1'
geomInfoList.append(primitiveLabel)
[bot_x,bot_y,bot_z] = extractCoord(botpoint) #bottom point
l = len(geomInfoList)
geomInfoList[l-1].append(bot_x)
geomInfoList[l-1].append(bot_y)
geomInfoList[l-1].append(bot_z)
[top_x,top_y,top_z] = extractCoord(toppoint) #top point
geomInfoList[l-1].append(top_x)
geomInfoList[l-1].append(top_y)
geomInfoList[l-1].append(top_z)
geomInfoList[l-1].append(rad) #radius
### When the primitive is a frustum ###
elif isinstance(geometry,Frustum):
frustumTopPt = botpoint+heading*geometry.height
frustumRad = geometry.radius
taperFactor = geometry.taper
topRad = frustumRad * taperFactor
#print("Frustum with label:", lstring[id][2], "Bottom point coordinate:", botpoint, "Top point coordinate:", frustumTopPt, "Base radius:", frustumRad, "Top radius:", topRad)
# Now we store the label and geometry information of the primitive as the following tuple:
# (primitive label, bottom_x, bottom_y, bottom_z, top_x, top_y, top_z, base radius, top radius)
primitiveLabel = [2] # the label for frustum is given as '2'
geomInfoList.append(primitiveLabel)
[bot_x,bot_y,bot_z] = extractCoord(botpoint) #bottom point
l = len(geomInfoList)
geomInfoList[l-1].append(bot_x)
geomInfoList[l-1].append(bot_y)
geomInfoList[l-1].append(bot_z)
[top_x,top_y,top_z] = extractCoord(frustumTopPt) #top point
geomInfoList[l-1].append(top_x)
geomInfoList[l-1].append(top_y)
geomInfoList[l-1].append(top_z)
geomInfoList[l-1].append(frustumRad) #base radius
geomInfoList[l-1].append(topRad) #top radius
### When the primitive is a sphere ###
elif isinstance(geometry,Sphere):
sphereRad = geometry.radius
#print("Sphere with label:", lstring[id][1], "Radius:", sphereRad)
# Now we store the label and geometry information of the primitive as the following tuple:
# (primitive label, sphere radius)
#So the tuple contains: (primitive label, sphere radius)
primitiveLabel = [3] # the label for sphere is given as '3'
geomInfoList.append(primitiveLabel)
l = len(geomInfoList)
geomInfoList[l-1].append(sphereRad)
elif isinstance(geometry,Translated):
botpoint = geometry.translation
elif isinstance(geometry,Oriented):
heading = cross(geometry.primary, geometry.secondary)
#print(vertexList), print(triangleList), print(geomInfoList), print(globalVertexList), print(globalTriangleIdList), print(globalTriangleLabelList)
##### So at this point, we are done with storing all the labelled geometry primitives and the labelled vertices of the coarse mesh model #####
##### Next, we will do the point sampling to generate points on the surface of the model. #####
######################## Basic point sampler ########################
### Generate exactly totalNumberOfResampledPts number of points ### ### Generate exactly totalNumberOfResampledPts number of points ###
finalSampledPoints = [] finalSampledPoints = []
finalRandomPointLabels = [] finalRandomPointLabels = []
totalSampledPointsSoFar = 0 totalSampledPointsSoFar = 0
initialPointRequirement = totalNumberOfResampledPts initialPointRequirement = totalNumberOfResampledPts
while(totalNumberOfResampledPts != totalSampledPointsSoFar): while (totalNumberOfResampledPts != totalSampledPointsSoFar):
randomPointLabels = [] randomPointLabels = []
randomTriangleList = selectRandomTriangle(globalTriangleIdList, globalVertexList, initialPointRequirement) # stores a list of random triangles with 'totalNumberOfResampledPts' number of elements. Next, we will sample one point per triangle to generate the point cloud randomTriangleList = selectRandomTriangle(globalTriangleIdList, globalVertexList,
[newSampledPoints, randomPointLabels] = sampleRandomPoints(randomTriangleList, globalTriangleIdList, globalVertexList, initialPointRequirement, globalTriangleLabelList, randomPointLabels) # samples a random point on each triangle in the list 'randomTriangleList' initialPointRequirement) # stores a list of random triangles with 'totalNumberOfResampledPts' number of elements. Next, we will sample one point per triangle to generate the point cloud
[ultimateSampledPoints, ultimateRandomPointLabels] = determineInsideness(geomInfoList, newSampledPoints, randomPointLabels) # perform insideness testing of the generated points & discard the points which are inside any primitive [newSampledPoints, randomPointLabels] = sampleRandomPoints(randomTriangleList, globalTriangleIdList,
currentNumberOfPoints = len(ultimateSampledPoints) globalVertexList, initialPointRequirement,
totalSampledPointsSoFar = totalSampledPointsSoFar + currentNumberOfPoints globalTriangleLabelList,
pointDifference = totalNumberOfResampledPts - totalSampledPointsSoFar randomPointLabels) # samples a random point on each triangle in the list 'randomTriangleList'
initialPointRequirement = pointDifference [ultimateSampledPoints, ultimateRandomPointLabels] = determineInsideness(geomInfoList, newSampledPoints,
#finalSampledPoints = ultimateSampledPoints randomPointLabels) # perform insideness testing of the generated points & discard the points which are inside any primitive
#finalRandomPointLabels = ultimateRandomPointLabels currentNumberOfPoints = len(ultimateSampledPoints)
newPtLen = len(ultimateSampledPoints) totalSampledPointsSoFar = totalSampledPointsSoFar + currentNumberOfPoints
for l in range(newPtLen): pointDifference = totalNumberOfResampledPts - totalSampledPointsSoFar
finalSampledPoints.append(ultimateSampledPoints[l]) initialPointRequirement = pointDifference
finalRandomPointLabels.append(ultimateRandomPointLabels[l]) # finalSampledPoints = ultimateSampledPoints
if(totalSampledPointsSoFar > totalNumberOfResampledPts): # finalRandomPointLabels = ultimateRandomPointLabels
break newPtLen = len(ultimateSampledPoints)
for l in range(newPtLen):
finalSampledPoints.append(ultimateSampledPoints[l])
finalRandomPointLabels.append(ultimateRandomPointLabels[l])
if (totalSampledPointsSoFar > totalNumberOfResampledPts):
break
[onlyPoints, onlyLabels,finalLabelledPoints] = createLabelledPointForDisplay(finalSampledPoints, finalRandomPointLabels) #this is after insidenss testing [onlyPoints, onlyLabels, finalLabelledPoints] = createLabelledPointForDisplay(finalSampledPoints,
write2File(pointsWithColor, finalLabelledPoints) # the data format is: x, y, z, r, g, b (each r,g,b combination is unique for a specific label) finalRandomPointLabels) # this is after insidenss testing
write2File(rawPoints, onlyPoints) # the data format is: x, y, z write2File(pointsWithColor,
write2File(rawLabels, onlyLabels) # the data format is: label finalLabelledPoints) # the data format is: x, y, z, r, g, b (each r,g,b combination is unique for a specific label)
write2File(rawPoints, onlyPoints) # the data format is: x, y, z
write2File(rawLabels, onlyLabels) # the data format is: label
This diff is collapsed.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# -*- python -*- #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# File author(s): # File author(s):
...@@ -13,37 +13,41 @@ ...@@ -13,37 +13,41 @@
# #
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
''' """
Library of tools to take snapshots of the result of a l-system simulations Library of tools to take snapshots of the result of a l-system simulations
Authors: Christophe Godin, Inria, 2021 Authors: Christophe Godin, Inria, 2021
Licence: Open source LGPL Licence: Open source LGPL
The lscene_snapshot library offers 2 main functions: The lscene_snapshot library offers 2 main functions:
simulate_and_shoot(model_filename, variables, suffix, cam_settings = camdict) simulate_and_shoot(model_filename, variables, suffix, cam_settings = camdict)
grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed_variables_dict, cam_settings = cam_setting_fun1, short_names = variable_short_names) grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed_variables_dict, cam_settings = cam_setting_fun1, short_names = variable_short_names)
''' """
import os import os
from numpy import arange
from openalea.plantgl.all import *
from openalea import lpy
from math import pi from math import pi
from matplotlib.offsetbox import TextArea, DrawingArea, OffsetImage, AnnotationBbox
import matplotlib.pyplot as plt
import matplotlib.image as mpimg import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from numpy import arange
from openalea import lpy
from openalea.plantgl.algo import ZBufferEngine
from openalea.plantgl.algo import eColorBased
from openalea.plantgl.math import Matrix3
from openalea.plantgl.math import Vector3
from openalea.plantgl.math import norm
from openalea.plantgl.scenegraph import BoundingBox
from openalea.plantgl.scenegraph import Color3
def read_camera(filename): def read_camera(filename):
''' Camera file contains """ Camera file contains
e.g.: e.g.:
104 10 4 -0.583715 -0.430251 35.4873 149.352 -0.430251 35.4873 92 -2.2 -1.8 40.0189 480.226 0.600283 30 79.7913 1 1 104 10 4 -0.583715 -0.430251 35.4873 149.352 -0.430251 35.4873 92 -2.2 -1.8 40.0189 480.226 0.600283 30 79.7913 1 1
interpreted as: interpreted as:
azimuth, Elevation, ?4, Center(3-uple), Eye(3-uple), Zoom, Translation(2-uple),?40.0189, zfar, znear, DefaultViewAngle(deg), CurrentViewAngle(deg), ?1, ?1 azimuth, Elevation, ?4, Center(3-uple), Eye(3-uple), Zoom, Translation(2-uple),?40.0189, zfar, znear, DefaultViewAngle(deg), CurrentViewAngle(deg), ?1, ?1
''' """
with open(filename, 'r') as file: with open(filename, 'r') as file:
data = file.read().replace('\n', '') data = file.read().replace('\n', '')
tokens = data.split() tokens = data.split()
...@@ -63,10 +67,10 @@ def read_camera(filename): ...@@ -63,10 +67,10 @@ def read_camera(filename):
'znear': float(tokens[14]), 'znear': float(tokens[14]),
'DefaultViewAngle': (float(tokens[15])), 'DefaultViewAngle': (float(tokens[15])),
'CurrentViewAngle': (float(tokens[16])), 'CurrentViewAngle': (float(tokens[16])),
'projection_mode': int(tokens[17]), # Flag othographic, pers 'projection_mode': int(tokens[17]), # Flag orthographic, pers
'geomsys': int(tokens[18]), # Flag PlanGL frame (Z up) / OpenGL (Y up) 'geomsys': int(tokens[18]), # Flag PlanGL frame (Z up) / OpenGL (Y up)
} }
''' """
target_point = None # looks a bit above z = 0. Value is a 3-uple (x,y,z) target_point = None # looks a bit above z = 0. Value is a 3-uple (x,y,z)
zoomcoef = 1. # increase to zoom out zoomcoef = 1. # increase to zoom out
camdist = 1. # increase to widen the observation window camdist = 1. # increase to widen the observation window
...@@ -82,15 +86,15 @@ def read_camera(filename): ...@@ -82,15 +86,15 @@ def read_camera(filename):
ambiant = (255, 255, 255) ambiant = (255, 255, 255)
diffuse = (0, 0, 0) diffuse = (0, 0, 0)
specular = (0, 0, 0)) specular = (0, 0, 0))
''' """
return camdict return camdict
def get_bb(viewer): def get_bb(viewer):
''' """
gets the bounding box of a scene contained in a LPy viewer. gets the bounding box of a scene contained in a LPy viewer.
''' """
sc = viewer.getCurrentScene() sc = viewer.getCurrentScene()
return BoundingBox(sc) return BoundingBox(sc)
...@@ -98,7 +102,7 @@ def get_bb(viewer): ...@@ -98,7 +102,7 @@ def get_bb(viewer):
# No longer used (prefer offline equivalent function below) # No longer used (prefer offline equivalent function below)
def take_snapshot(viewer, filename_prefix=".", suffix="", def take_snapshot(viewer, filename_prefix=".", suffix="",
cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}): cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}):
''' """
take a snapshot of a computed lpy_scene, with camera attributes defined in cam_settings: take a snapshot of a computed lpy_scene, with camera attributes defined in cam_settings:
- target_point is the point at which the camera is looking (Vector3) - target_point is the point at which the camera is looking (Vector3)
- camdist fixes the distance of the camera to the target point (in screen units) - camdist fixes the distance of the camera to the target point (in screen units)
...@@ -108,7 +112,7 @@ def take_snapshot(viewer, filename_prefix=".", suffix="", ...@@ -108,7 +112,7 @@ def take_snapshot(viewer, filename_prefix=".", suffix="",
filename_prefix: A prefix directory may be defined (default is current directory '.') filename_prefix: A prefix directory may be defined (default is current directory '.')
suffix: name of the image suffix: name of the image
''' """
if 'camdist' in cam_settings: if 'camdist' in cam_settings:
camdist = cam_settings['camdist'] camdist = cam_settings['camdist']
...@@ -173,7 +177,7 @@ def take_snapshot(viewer, filename_prefix=".", suffix="", ...@@ -173,7 +177,7 @@ def take_snapshot(viewer, filename_prefix=".", suffix="",
# Set beckground Color # Set beckground Color
viewer.frameGL.setBgColor(Color3(255, 255, 255)) viewer.frameGL.setBgColor(Color3(255, 255, 255))
# Sets the size of the PlantGL window in pixels # Sets the size of the PlantGL window in pixels
viewer.frameGL.setSize((400, 400)) viewer.frameGL.setSize(400, 400)
# Defines the new camera position and orientation as # Defines the new camera position and orientation as
# shooting direction = c-np # shooting direction = c-np
...@@ -187,8 +191,8 @@ def take_snapshot(viewer, filename_prefix=".", suffix="", ...@@ -187,8 +191,8 @@ def take_snapshot(viewer, filename_prefix=".", suffix="",
def take_offline_snapshot(lscene, filename_prefix=".", suffix="", def take_offline_snapshot(lscene, filename_prefix=".", suffix="",
cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}): cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}):
""" take a snapshot of a computed lpy_scene without the need of running LPy. """
take a snapshot of a computed lpy_scene without the need of running LPy.
Camera attributes defined in cam_settings: Camera attributes defined in cam_settings:
- target_point is the point at which the camera is looking (Vector3) - target_point is the point at which the camera is looking (Vector3)
- camdist fixes the distance of the camera to the target point (in screen units) - camdist fixes the distance of the camera to the target point (in screen units)
...@@ -218,7 +222,6 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="", ...@@ -218,7 +222,6 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="",
# for key, val in d.items(): # for key, val in d.items():
# exec(key + '=val') # exec(key + '=val')
if 'camdist' in cam_settings: if 'camdist' in cam_settings:
camdist = cam_settings['camdist'] camdist = cam_settings['camdist']
else: else:
...@@ -280,7 +283,7 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="", ...@@ -280,7 +283,7 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="",
else: else:
specular = (0, 0, 0) specular = (0, 0, 0)
# Determine the point to look at # Determine the point to look at
if target_point == None: if target_point == None:
# define bounding box used to take the picture # define bounding box used to take the picture
if bb == None: if bb == None:
...@@ -293,9 +296,9 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="", ...@@ -293,9 +296,9 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="",
else: else:
c = target_point # target point to look at is given as an argument c = target_point # target point to look at is given as an argument
# DISPLAY WINDOW # DISPLAY WINDOW
# rendering engine (alternative offline to the viewer # rendering engine (alternative offline to the viewer
zb = ZBufferEngine(width, height, (255, 255, 255), renderingStyle=eColorBased) zb = ZBufferEngine(width, height, (255, 255, 255), renderingStyle=eColorBased)
zb.multithreaded = False zb.multithreaded = False
...@@ -341,11 +344,11 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="", ...@@ -341,11 +344,11 @@ def take_offline_snapshot(lscene, filename_prefix=".", suffix="",
# !!!!!!!!!!! NEW VERSION NOT YET TESTED --> TO BE TESTED # !!!!!!!!!!! NEW VERSION NOT YET TESTED --> TO BE TESTED
def take_circular_snapshots(viewer, delta_a=36, filename_prefix=".", suffix="", def take_circular_snapshots(viewer, delta_a=36, filename_prefix=".", suffix="",
cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}): cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}):
''' """
take a snapshot of a computed lpy_scene contained in the viewer. take a snapshot of a computed lpy_scene contained in the viewer.
- delta_a is the increment angle in degrees - delta_a is the increment angle in degrees
''' """
if 'camdist' in cam_settings: if 'camdist' in cam_settings:
camdist = cam_settings['camdist'] camdist = cam_settings['camdist']
...@@ -453,10 +456,10 @@ def simulate_and_shoot(model_filename, variables, suffix, cam_settings): ...@@ -453,10 +456,10 @@ def simulate_and_shoot(model_filename, variables, suffix, cam_settings):
def build_suffix(var, short_names=None): def build_suffix(var, short_names=None):
''' """
takes a dict of variables and constructs a str suffix identifying uniquely this set of parameter takes a dict of variables and constructs a str suffix identifying uniquely this set of parameter
(for further defining a name corresponding to this set of parameters for storage on disk of corresponding results) (for further defining a name corresponding to this set of parameters for storage on disk of corresponding results)
''' """
sep = ' ' # could also be ' ', '_' or '#' sep = ' ' # could also be ' ', '_' or '#'
stg = '' stg = ''
index = 0 index = 0
...@@ -478,7 +481,7 @@ def build_suffix(var, short_names=None): ...@@ -478,7 +481,7 @@ def build_suffix(var, short_names=None):
def build_variables_dict(x, y, free_variable_list, fixed_variables): def build_variables_dict(x, y, free_variable_list, fixed_variables):
''' """
builds a dictionary of variables by blending free variables (made of two variables) builds a dictionary of variables by blending free variables (made of two variables)
- x,y are the values of the two free free_variables - x,y are the values of the two free free_variables
...@@ -486,7 +489,7 @@ def build_variables_dict(x, y, free_variable_list, fixed_variables): ...@@ -486,7 +489,7 @@ def build_variables_dict(x, y, free_variable_list, fixed_variables):
- fixed_variables is a dict of variables with already defined values (i.e. fixed) - fixed_variables is a dict of variables with already defined values (i.e. fixed)
Precondition: len(free_variable_list) >= 2 Precondition: len(free_variable_list) >= 2
''' """
assert len(free_variable_list) >= 2 # (at list names for x and y should be defined) assert len(free_variable_list) >= 2 # (at list names for x and y should be defined)
vardict = fixed_variables.copy() vardict = fixed_variables.copy()
...@@ -499,7 +502,7 @@ def build_variables_dict(x, y, free_variable_list, fixed_variables): ...@@ -499,7 +502,7 @@ def build_variables_dict(x, y, free_variable_list, fixed_variables):
def grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed_variables, def grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed_variables,
cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None}, cam_settings={'camdist': 1., 'zoomcoef': 1., 'bb': None, 'target_point': None},
short_names=None): short_names=None):
''' """
launches simulations of the lpy model model_filename for free parameters values defined in simpoints, launches simulations of the lpy model model_filename for free parameters values defined in simpoints,
- simpoints is a dict whose keys are the y values and the values are lists of x-values for each y key - simpoints is a dict whose keys are the y values and the values are lists of x-values for each y key
- free variable names are given in free_variable_list and - free variable names are given in free_variable_list and
...@@ -510,7 +513,7 @@ def grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed ...@@ -510,7 +513,7 @@ def grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed
or a function returning a dict for args = (x,y) = pair of values of the free parameters or a function returning a dict for args = (x,y) = pair of values of the free parameters
cam_settings(x,y) --> {'camdist':val1, 'zoomcoef':val2, 'bb':val3, 'target_point':val4} cam_settings(x,y) --> {'camdist':val1, 'zoomcoef':val2, 'bb':val3, 'target_point':val4}
''' """
# create list of variable names # create list of variable names
fixed_variable_list = fixed_variables.keys() fixed_variable_list = fixed_variables.keys()
...@@ -560,17 +563,18 @@ def grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed ...@@ -560,17 +563,18 @@ def grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed
index_list.append(xi * XMAX + yi + 1) # these indexes must be shifted by 1 as they start at 1 index_list.append(xi * XMAX + yi + 1) # these indexes must be shifted by 1 as they start at 1
print("array dim = ", YMAX, XMAX) print("array dim = ", YMAX, XMAX)
print("index_list(", len(index_list), ") = ", index_list) print("index_list(", len(index_list), ") = ", index_list)
plot_images(image_name_list, index_list, dir=".", size=(YMAX, XMAX)) plot_images(image_name_list, index_list, dir=".", size=(YMAX, XMAX))
def plot_images(image_name_list, index_list=None, dir='.', size=(1, 1)): def plot_images(image_name_list, index_list=None, dir='.', size=(1, 1)):
''' """
Plots the grid of png images @ grid positions defined by index_list Plots the grid of png images @ grid positions defined by index_list
- index_list = 1 dimensional position = flattened 2D position in a grid of size[0]xsize[1] - index_list = 1 dimensional position = flattened 2D position in a grid of size[0]xsize[1]
- dir specifies the directory where to print - dir specifies the directory where to print
- size is the dimensions of the underlying 2D grid - size is the dimensions of the underlying 2D grid
''' """
# A figure is a canvas that contains axes (= places on which to plot) # A figure is a canvas that contains axes (= places on which to plot)
# by default the figure has one axis # by default the figure has one axis
...@@ -582,12 +586,12 @@ def plot_images(image_name_list, index_list=None, dir='.', size=(1, 1)): ...@@ -582,12 +586,12 @@ def plot_images(image_name_list, index_list=None, dir='.', size=(1, 1)):
dim1 = min(size[1] * 3, 15) dim1 = min(size[1] * 3, 15)
print("Image: grid size= ", size[1], size[0], " image --> width,heigth = ", dim1, dim2) print("Image: grid size= ", size[1], size[0], " image --> width,heigth = ", dim1, dim2)
fig = plt.figure(figsize=(dim1, dim2)) fig = plt.figure(figsize=(dim1, dim2))
print("Coucou")
i = 1 i = 1
for iname in image_name_list: for iname in image_name_list:
# image = mpimg.imread(dir + '/' + iname)
image = mpimg.imread(dir + '/' + iname) image = mpimg.imread(iname)
if not index_list == None: if not index_list == None:
k = index_list[i - 1] k = index_list[i - 1]
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Take automaticaly pictures of scenes generated by a Lsystem
Authors: Christophe Godin, Inria, 2021
Licence: Open source LGPL
See README.md in lpy_snapshot module for documentation
Launch with:
shell> ipython --gui=qt test-snapshots.py
This should display a graphical window with a figure containing 4 subfigures
"""
import matplotlib
matplotlib.use('tkagg')
print(f"Using {matplotlib.get_backend()} backend for Matplotlib!")
from openalea.plantgl.all import Vector3
from lpy_tools.snapshots.lscene_snapshots import grid_simulate_and_shoot
model_filename = 'test.lpy'
##############################
# Input variables
##############################
Narray = [1, 2, 3, 4]
###########################################
# Simulate the plant and generate the scans
###########################################
# def build_suffix(var):
# return "O"+str(var["MAX_ORDER"])+"-D"+str(var["NB_DAYS"])+"-MD"+str(var["MD"])+'+' if str(var["SHOW_MERISTEMS"]) else '-'
# Definition of shortnames for variables (used for generating small image names)
variable_short_names = {}
# Set fixed variables input to the L-system for all the simulations here:
# Set variables x,y that you want to vary in the L-system to build the figure
# x = [x1,x2,.. ]
# this is made using a dictionary providing for each md the list of x values to simulate
# y = dict key,
# x list = dict values giving for each key the list of x for which a
# simulation sim(x,y) must be computed
fixed_variables_dict = {}
free_variable_list = ['N', 'cst'] # Should contain the two variables which will vary (simpoints) to make the grid
simpoints = {0: Narray}
# Building of the image
# setting camera options
target_point = Vector3(0, 0, 0.) # looks a bit above z = 0
zoomcoef = 0.5 # increase to zoom out
camdist = 100. # increase to widen the observation window
# camdict = {'camdist':camdist, 'zoomcoef':zoomcoef, 'bb':None, 'target_point':target_point}
def cam_setting_fun1(x, y):
"""Defines the camera setting values for each pair of parameter values (x,y).
Parameters
----------
x represents time
y represents meristem delay
"""
t = target_point
z = zoomcoef
c = camdist
return {'camdist': c, 'zoomcoef': z, 'bb': None, 'target_point': t, 'elevation': 0.0}
# Test for reusing a camera file recorded from L-py
# camdict_save = read_camera('camA')
# print(camdict_save)
# grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed_variables_dict, cam_settings = camdict_save) #short_names = variable_short_names)
grid_simulate_and_shoot(simpoints, model_filename, free_variable_list, fixed_variables_dict,
cam_settings=cam_setting_fun1) # short_names = variable_short_names)
extern(N=2)
extern(cst=0)
Axiom: _(0.1)-(90)G(10)
derivation length: N
production:
G(x) --> G(x/3)+G(x/3)--G(x/3)+G(x/3)
interpretation:
G(x) :
nproduce F(x)
endlsystem
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment