# Version: $Id$
#
#
# Commentary:
#
#
# Change Log:
#
#
# Code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import vtk
from vtk.util.numpy_support import numpy_to_vtk, vtk_to_numpy, get_vtk_array_type
from cellcomplex.property_topomesh.analysis import compute_topomesh_property
from cellcomplex.utils import array_dict
from cellcomplex.property_topomesh.visualization.vtk_tools import vtk_combine_polydatas, face_scalar_vertex_property_polydata
from cellcomplex.property_topomesh.visualization.vtk_tools import vtk_lookuptable_from_mpl_cmap, vtk_glyph_polydata
from cellcomplex.property_topomesh.visualization.vtk_tools import vertex_scalar_property_polydata, edge_scalar_property_polydata, face_scalar_property_polydata, vertex_vector_property_polydata, vertex_tensor_property_polydata
from time import time as current_time
import logging
[docs]class VtkActorTopomesh():
def __init__(self, topomesh=None, degree=None, property_name=None, property_degree=None, **kwargs):
"""
Parameters
----------
topomesh
degree
property_name
kwargs
"""
self.topomesh = topomesh
self._degree = degree
self._property_name = property_name
self._property_degree = property_degree if property_degree is not None else self._degree
self._modified = True
self.tensor_glyph = kwargs.get('tensor_glyph', 'ellipsoid')
self.vector_glyph = kwargs.get('vector_glyph','arrow')
self.point_glyph= kwargs.get('point_glyph','sphere')
self.line_glyph = kwargs.get('line_glyph','line')
self.glyph_scale = kwargs.get('glyph_scale',1.)
self.polydata = None
self.display_polydata = None
self.actor = None
self.scalar_mode = None
@property
def degree(self):
return self._degree
@degree.setter
def degree(self, value):
logging.info("Setting degree :"+str(self._degree)+" --> "+str(value))
if self._degree != value:
self._modified = True
self._degree = value
if self._property_degree is None:
self._property_degree = self.degree
@property
def property_name(self):
return self._property_name
@property_name.setter
def property_name(self, value):
logging.info("Setting property name :"+str(self._property_name)+" --> "+str(value))
if self.property_name != value:
if self.topomesh is not None:
if self.topomesh.has_wisp_property(self._property_name, self.degree, is_computed=True):
property_data = self.topomesh.wisp_property(self._property_name, self.degree).values()
ndim = property_data.ndim
else:
ndim = 1
if self.topomesh.has_wisp_property(value, self.degree, is_computed=True):
property_data = self.topomesh.wisp_property(value, self.degree).values()
new_ndim = property_data.ndim
else:
new_ndim = 1
self._modified = ndim != new_ndim
self._property_name = value
[docs] def set_topomesh(self, topomesh, degree, property_name=None):
self.topomesh = topomesh
self._degree = degree
if self._property_degree is None:
self._property_degree = degree
self.property_name = property_name
[docs] def update_polydata(self):
logging.info("--> Update polydata (modified="+str(self._modified)+")")
self.display_polydata = None
self._modified = True
if self.degree == 3:
positions = self.topomesh.wisp_property("barycenter", 0)
compute_topomesh_property(self.topomesh,"oriented_vertices",2)
if self.topomesh.has_wisp_property(self.property_name,3,is_computed=True):
cell_property = self.topomesh.wisp_property(self.property_name,3)
else:
cell_property = array_dict(dict(zip(self.topomesh.wisps(3),np.ones(self.topomesh.nb_wisps(3)))))
if cell_property.values().ndim == 1:
cell_polydatas = []
for cid in self.topomesh.wisps(3):
face_vertices = self.topomesh.wisp_property("oriented_vertices", 2).values(list(self.topomesh.borders(3,cid)))
property_data = np.array([cell_property[cid] for fid in self.topomesh.borders(3,cid)])
cell_polydata = face_scalar_property_polydata(positions, face_vertices, property_data)
wisp_ids = numpy_to_vtk(np.array([cid for fid in self.topomesh.borders(3,cid)]), deep=True, array_type=vtk.VTK_LONG)
wisp_ids.SetName("WispId")
cell_polydata.GetCellData().AddArray(wisp_ids)
cell_polydatas += [cell_polydata]
self.polydata = vtk_combine_polydatas(cell_polydatas)
self.scalar_mode = 'cell_data'
else:
compute_topomesh_property(self.topomesh,"barycenter",3)
positions = self.topomesh.wisp_property("barycenter", 3)
property_data = cell_property.values(list(self.topomesh.wisps(3)))
wisp_ids = numpy_to_vtk(np.array([cid for cid in self.topomesh.wisps(3)]), deep=True, array_type=vtk.VTK_LONG)
wisp_ids.SetName("WispId")
if property_data.ndim == 3:
if property_data.shape[1] == 3 and property_data.shape[2] == 3:
self.polydata = vertex_tensor_property_polydata(positions, property_data, self.polydata)
self.scalar_mode = 'point_data'
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata,tensor_glyph=self.tensor_glyph, glyph_scale=self.glyph_scale)
elif property_data.ndim == 2:
self.polydata = vertex_vector_property_polydata(positions, property_data, self.polydata, update_polydata=self._modified)
self.scalar_mode = 'point_data'
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata,vector_glyph=self.vector_glyph, glyph_scale=self.glyph_scale)
wisp_ids.SetName("WispId")
if self.scalar_mode == 'point_data':
self.polydata.GetPointData().AddArray(wisp_ids)
elif self.scalar_mode == 'cell_data':
self.polydata.GetCellData().AddArray(wisp_ids)
elif self.degree == 2:
wisp_ids = numpy_to_vtk(np.array([fid for fid in self.topomesh.wisps(2)]), deep=True, array_type=vtk.VTK_LONG)
wisp_ids.SetName("WispId")
positions = self.topomesh.wisp_property("barycenter", 0)
compute_topomesh_property(self.topomesh,"oriented_vertices",2)
face_vertices = self.topomesh.wisp_property("oriented_vertices", 2).values()
if self._property_degree == self.degree:
if self.topomesh.has_wisp_property(self.property_name,2,is_computed=True):
property_data = self.topomesh.wisp_property(self.property_name,2).values()
else:
# property_data = np.ones(self.topomesh.nb_wisps(2))
property_data = np.array(list(self.topomesh.wisps(2)))
if property_data.ndim == 3:
compute_topomesh_property(self.topomesh, 'barycenter', 2)
positions = self.topomesh.wisp_property("barycenter", 2)
if property_data.shape[1] == 3 and property_data.shape[2] == 3:
self.polydata = vertex_tensor_property_polydata(positions, property_data, self.polydata)
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata, tensor_glyph=self.tensor_glyph, glyph_scale=self.glyph_scale)
self.scalar_mode = 'point_data'
elif property_data.ndim == 2:
print("VERTEX VECTOR PROP")
compute_topomesh_property(self.topomesh, 'barycenter', 2)
positions = self.topomesh.wisp_property("barycenter", 2)
self.polydata = vertex_vector_property_polydata(positions, property_data, self.polydata, update_polydata=self._modified)
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata, vector_glyph=self.vector_glyph, glyph_scale=self.glyph_scale)
self.scalar_mode = 'point_data'
elif property_data.ndim == 1:
self.polydata = face_scalar_property_polydata(positions, face_vertices, property_data, self.polydata, update_polydata=self._modified)
self.polydata.GetCellData().AddArray(wisp_ids)
self.scalar_mode = 'cell_data'
else:
if self.topomesh.has_wisp_property(self.property_name,self._property_degree,is_computed=True):
property_data = self.topomesh.wisp_property(self.property_name,self._property_degree).values()
if property_data.ndim == 1:
self.polydata = face_scalar_vertex_property_polydata(positions, face_vertices, property_data, self.polydata, update_polydata=self._modified)
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata, vector_glyph=self.vector_glyph, glyph_scale=self.glyph_scale)
self.scalar_mode = 'point_data'
elif self.degree == 1:
wisp_ids = numpy_to_vtk(np.array([fid for fid in self.topomesh.wisps(1)]), deep=True, array_type=vtk.VTK_LONG)
positions = self.topomesh.wisp_property("barycenter", 0)
compute_topomesh_property(self.topomesh,"vertices",1)
edge_vertices = self.topomesh.wisp_property("vertices", 1).values(list(self.topomesh.wisps(1)))
if self.topomesh.has_wisp_property(self.property_name, 1, is_computed=True):
property_data = self.topomesh.wisp_property(self.property_name,1).values(list(self.topomesh.wisps(1)))
else:
property_data = np.ones(self.topomesh.nb_wisps(1))
self.polydata = edge_scalar_property_polydata(positions, edge_vertices, property_data, self.polydata, line_glyph=self.line_glyph, glyph_scale=self.glyph_scale)
self.scalar_mode = 'point_data'
wisp_ids.SetName("WispId")
if self.scalar_mode == 'point_data':
self.polydata.GetPointData().AddArray(wisp_ids)
elif self.scalar_mode == 'cell_data':
self.polydata.GetCellData().AddArray(wisp_ids)
elif self.degree == 0:
wisp_ids = numpy_to_vtk(np.array([pid for pid in self.topomesh.wisps(0)]), deep=True, array_type=vtk.VTK_LONG)
wisp_ids.SetName("WispId")
positions = array_dict(dict(zip(self.topomesh.wisps(0),self.topomesh.wisp_property("barycenter", 0).values(list(self.topomesh.wisps(0))))))
if self.topomesh.has_wisp_property(self.property_name,0,is_computed=True):
property_data = self.topomesh.wisp_property(self.property_name,0).values(positions.keys())
print(len(property_data))
if property_data.ndim == 3:
if property_data.shape[1] == 3 and property_data.shape[2] == 3:
self.polydata = vertex_tensor_property_polydata(positions, property_data)
self.scalar_mode = 'point_data'
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata,tensor_glyph=self.tensor_glyph,glyph_scale=self.glyph_scale)
elif property_data.ndim == 2:
self.polydata = vertex_vector_property_polydata(positions, property_data)
self.scalar_mode = 'point_data'
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata,vector_glyph=self.vector_glyph, glyph_scale=self.glyph_scale)
elif property_data.ndim == 1:
self.polydata = vertex_scalar_property_polydata(positions, property_data)
self.scalar_mode = 'point_data'
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata, point_glyph=self.point_glyph, glyph_scale=self.glyph_scale)
else:
property_data = np.ones(self.topomesh.nb_wisps(0))
self.polydata = vertex_scalar_property_polydata(positions, property_data)
self.scalar_mode = 'point_data'
self.polydata.GetPointData().AddArray(wisp_ids)
self.display_polydata = vtk_glyph_polydata(self.polydata, point_glyph=self.point_glyph, glyph_scale=self.glyph_scale)
[docs] def update_actor(self, colormap='viridis', value_range=None, opacity=1, linewidth=1):
print("Value range:",value_range)
if value_range is None:
if self.polydata.GetCellData().GetNumberOfArrays()>0:
scalars = vtk_to_numpy(self.polydata.GetCellData().GetArray(0))
value_range = (np.nanmin(scalars),np.nanmax(scalars))
elif self.polydata.GetPointData().GetNumberOfArrays()>0:
scalars = vtk_to_numpy(self.polydata.GetPointData().GetArray(0))
value_range = (np.nanmin(scalars),np.nanmax(scalars))
else:
value_range = (0,1)
print("Value range:",value_range)
logging.info("--> Value range : "+str(value_range))
lut = vtk_lookuptable_from_mpl_cmap(colormap, value_range)
mapper = vtk.vtkPolyDataMapper()
if self.scalar_mode == 'cell_data':
mapper.SetScalarModeToUseCellData()
elif self.scalar_mode == 'point_data':
mapper.SetScalarModeToUsePointData()
if self.display_polydata is not None:
mapper.SetInputData(self.display_polydata)
else:
mapper.SetInputData(self.polydata)
mapper.SetLookupTable(lut)
if self.actor is None:
self.actor = vtk.vtkActor()
self.actor.SetMapper(mapper)
self.actor.GetProperty().SetOpacity(opacity)
self.actor.GetProperty().SetLineWidth(linewidth)
[docs] def update(self, colormap='viridis',value_range=None, opacity=1, linewidth=1):
self.update_polydata()
self.update_actor(colormap=colormap, value_range=value_range, opacity=opacity, linewidth=linewidth)
self._modified = False
[docs] def clean(self):
self.polydata.Initialize()