Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conda/meta.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% set version = "2.0.0" %}
{% set version = "2.1.0" %}

package:
name: alinea.astk
Expand Down
1 change: 1 addition & 0 deletions src/alinea/astk/scene/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""A collection of simple scene objects that can be maped to/from PlanGL scenes"""
63 changes: 63 additions & 0 deletions src/alinea/astk/scene/color_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
class ColorMap(object):
"""A RGB color map, between 2 colors defined in HSV code
"""

def __init__(self, minval=0., maxval=1.):
self.minval = float(minval)
self.maxval = float(maxval)

def color(self, normedU):
"""

:param normedU: todo

"""
inter = 1 / 5.
winter = int(normedU / inter)
a = (normedU % inter) / inter
b = 1 - a

if winter < 0:
col = (self.coul2, self.coul2, self.coul1)
elif winter == 0:
col = (self.coul2, self.coul2 * b + self.coul1 * a, self.coul1)
elif winter == 1:
col = (self.coul2, self.coul1, self.coul1 * b + self.coul2 * a)
elif winter == 2:
col = (self.coul2 * b + self.coul1 * a, self.coul1, self.coul2)
elif winter == 3:
col = (self.coul1, self.coul1 * b + self.coul2 * a, self.coul2)
elif winter > 3:
col = (self.coul1, self.coul2, self.coul2)
return (int(col[0]), int(col[1]), int(col[2]))

def greycolor(self, normedU):
"""

:param normedU: todo
:returns: todo
"""
return (int(255 * normedU), int(255 * normedU), int(255 * normedU))

def grey(self, u):
"""
:param u:
:returns: todo
"""
return self.greycolor(self.normU(u))

def normU(self, u):
"""
:param u:
:returns: todo
"""
if self.minval == self.maxval:
return 0.5
return (u - self.minval) / (self.maxval - self.minval)

def __call__(self, u, minval=0, maxval=1, coul1=80, coul2=20):
self.coul1 = coul1
self.coul2 = coul2
self.minval = float(minval)
self.maxval = float(maxval)
return self.color(self.normU(u))
65 changes: 65 additions & 0 deletions src/alinea/astk/scene/display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import warnings
from itertools import chain
from math import isnan

import alinea.astk.scene.pgl_scene as pgls
from alinea.astk.scene.color_map import ColorMap


def jet_colors(x, minval=None, maxval=None):
""" return jet colors associated to a vector of values"""
if minval is None:
minval = min(x)
if maxval is None:
maxval = max(x)
cmap = ColorMap()

return map(lambda v: cmap(v, minval, maxval, 250., 20.), x)


def nan_to_zero(values):
return [0 if isnan(x) else x for x in values]


def property_as_colors(a_property, minval=None, maxval=None, gamma=None):
""" transform a scalar property in a color property of same kind

property is a {shape_id: value} or {shape_id: list of values} dict
"""

values = a_property.values()
if isinstance(values[0], list):
values = list(chain.from_iterable(values))
values = nan_to_zero(values)
if minval is None:
minval = min(values)
if maxval is None:
maxval = max(values)
if gamma is None:
gamma = 1
norm = 0.5
if minval != maxval:
norm = maxval - minval
values = map(lambda x: ((x - minval) / float(norm)) ** gamma, values)
colors = jet_colors(values, 0, 1)
color_property = {}
for k, v in a_property.iteritems():
if isinstance(v, list):
color_property[k] = []
for i in range(len(v)):
color_property[k].append(colors.pop(0))
else:
color_property[k] = colors.pop(0)

return color_property


def display_property(scene_mesh, property, minval=None, maxval=None):
colors = property_as_colors(property, minval=minval, maxval=maxval)
if pgls.pgl_imported:
scene = pgls.from_scene_mesh(scene_mesh, colors)
return pgls.display(scene)
else:
warnings.warn('PlanGL not found, no display available!!')
return scene_mesh

104 changes: 104 additions & 0 deletions src/alinea/astk/scene/pgl_scene.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
""" Interfaces for PlantGL scene / PlantGL display"""

import numpy

pgl_imported = False
try:
import openalea.plantgl.all as pgl
pgl_imported = True
except ImportError:
pgl = None


def bbox(pgl_scene, scene_unit='m'):
""" Bounding box of a pgl scene"""
tesselator = pgl.Tesselator()
bbc = pgl.BBoxComputer(tesselator)
bbc.process(pgl_scene)
box = bbc.result
xmin, ymin, zmin = box.getXMin(), box.getYMin(), box.getZMin()
xmax, ymax, zmax = box.getXMax(), box.getYMax(), box.getZMax()
if scene_unit != 'm':
units = {'mm': 0.001, 'cm': 0.01, 'dm': 0.1, 'm': 1, 'dam': 10,
'hm': 100,
'km': 1000}
convert = units.get(scene_unit, 1)
xmin, ymin, zmin = numpy.array((xmin, ymin, zmin)) * convert
xmax, ymax, zmax = numpy.array((xmax, ymax, zmax)) * convert

return (xmin, ymin, zmin), (xmax, ymax, zmax)


def shape_mesh(pgl_shape, tesselator=None):
if tesselator is None:
tesselator = pgl.Tesselator()
tesselator.process(pgl_shape)
tset = tesselator.result
return numpy.array(tset.pointList), numpy.array(tset.indexList)


def as_scene_mesh(pgl_scene):
""" Transform a PlantGL scene / PlantGL shape dict to a scene_mesh"""
tesselator = pgl.Tesselator()

if isinstance(pgl_scene, pgl.Scene):
sm = {}

def _concat_mesh(mesh1,mesh2):
v1, f1 = mesh1
v2, f2 = mesh2
v = numpy.array(v1.tolist() + v2.tolist())
offset = len(v1)
f = numpy.array(f1.tolist() + [[i + offset, j + offset, k + offset] for i, j, k
in f2.tolist()])
return v, f

for pid, pgl_objects in pgl_scene.todict().iteritems():
sm[pid] = reduce(_concat_mesh, [shape_mesh(pgl_object, tesselator) for pgl_object in
pgl_objects])
return sm
elif isinstance(pgl_scene, dict):
return {sh_id: shape_mesh(sh,tesselator) for sh_id, sh in
pgl_scene.iteritems()}
else:
return pgl_scene


def from_scene_mesh(scene_mesh, colors=None):
plant_color = (0, 180, 0)

if colors is None:
colors = {k: plant_color for k in scene_mesh}

scene = pgl.Scene()
for sh_id, mesh in scene_mesh.iteritems():
vertices, faces = mesh
if isinstance(colors[sh_id], tuple):
r, g, b = colors[sh_id]
color_list = [pgl.Color4(r, g, b, 0)] * len(faces)
else:
color_list = [pgl.Color4(r, g, b, 0) for r, g, b in colors[sh_id]]
shape = pgl.TriangleSet(vertices, faces)
shape.colorList = color_list
shape.colorPerVertex = False
shape.id = sh_id
scene += shape

return scene


def display(scene):
""" display a scene"""
pgl.Viewer.display(scene)
return scene


def unit_sphere_scene():
return pgl.Scene([pgl.Sphere()])


def is_pgl_scene(scene):
if not pgl_imported:
return False
else:
return isinstance(scene, pgl.Scene)
Loading