Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add option to serialize all vtkDataset arrays #1596

Merged
merged 5 commits into from
Sep 28, 2020
Merged
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
12 changes: 5 additions & 7 deletions panel/models/vtk/vtkfollower.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ if(vtk) {
const vtkActor = vtk.Rendering.Core.vtkActor

function vtkFollower(publicAPI: any, model: any) {
console.log("Hello")
// Set our className
model.classHierarchy.push('vtkFollower')

Expand Down Expand Up @@ -113,22 +112,21 @@ if(vtk) {
Follower = {
newInstance: macro.newInstance((publicAPI: any, model: any, initialValues = {}) => {
Object.assign(model, DEFAULT_VALUES, initialValues)

// Inheritance
vtkActor.extend(publicAPI, model, initialValues)

model.followerMatrix = mat4.create()
model.camera = vtk.Rendering.Core.vtkCamera.newInstance()
mat4.identity(model.followerMatrix)

// Build VTK API
macro.setGet(publicAPI, model, ['useViewUp', 'camera'])

macro.setGetArray(publicAPI, model, ['viewUp'], 3)

// Object methods
vtkFollower(publicAPI, model);
}, 'vtkFollower')
}

}
197 changes: 136 additions & 61 deletions panel/pane/vtk/synchronizable_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import zipfile

from vtk.vtkCommonCore import vtkTypeUInt32Array, vtkTypeInt32Array
from vtk.vtkFiltersGeometry import vtkCompositeDataGeometryFilter
from vtk.vtkFiltersGeometry import vtkGeometryFilter
from vtk.vtkFiltersGeometry import vtkCompositeDataGeometryFilter, vtkGeometryFilter
from vtk.vtkRenderingCore import vtkColorTransferFunction

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -99,7 +98,62 @@ def dataTableToList(dataTable):
return [data[idx*nbComponents:(idx+1)*nbComponents]
for idx in range(nbValues//nbComponents)]

# -----------------------------------------------------------------------------

def getScalars(mapper, dataset):
scalars = None
cell_flag = 0
scalar_mode = mapper.GetScalarMode()
array_access_mode = mapper.GetArrayAccessMode()
array_id = mapper.GetArrayId()
array_name = mapper.GetArrayName()
pd = dataset.GetPointData()
cd = dataset.GetCellData()
fd = dataset.GetFieldData()
if scalar_mode == 0: # VTK_SCALAR_MODE_DEFAULT
scalars = pd.GetScalars()
cell_flag = 0
if scalars is None:
scalars = cd.GetScalars()
cell_flag = 1
elif scalar_mode == 1: # VTK_SCALAR_MODE_USE_POINT_DATA
scalars = pd.GetScalars()
cell_flag = 0
elif scalar_mode == 2: # VTK_SCALAR_MODE_USE_CELL_DATA
scalars = cd.GetScalars()
cell_flag = 1
elif scalar_mode == 3: # VTK_SCALAR_MODE_USE_POINT_FIELD_DATA
if array_access_mode == 0: # VTK_GET_ARRAY_BY_ID
scalars = pd.GetAbstractArray(array_id)
else: # VTK_GET_ARRAY_BY_NAME
scalars = pd.GetAbstractArray(array_name)
cell_flag = 0
elif scalar_mode == 4: # VTK_SCALAR_MODE_USE_CELL_FIELD_DATA
if array_access_mode == 0: # VTK_GET_ARRAY_BY_ID
scalars = cd.GetAbstractArray(array_id)
else: # VTK_GET_ARRAY_BY_NAME
scalars = cd.GetAbstractArray(array_name)
cell_flag = 1
else: # VTK_SCALAR_MODE_USE_FIELD_DATA
if array_access_mode == 0: # VTK_GET_ARRAY_BY_ID
scalars = fd.GetAbstractArray(array_id)
else: # VTK_GET_ARRAY_BY_NAME
scalars = fd.GetAbstractArray(array_name)
cell_flag = 2
return scalars, cell_flag


def retrieveArrayName(mapper_instance, scalar_mode):
colorArrayName = None
try:
ds = [deps for deps in mapper_instance['dependencies'] if deps['id'].endswith('dataset')][0]
location = "pointData" if scalar_mode in (1, 3) else "cellData"
for arrayMeta in ds['properties']['fields']:
if arrayMeta["location"] == location and arrayMeta.get("registration", None) == "setScalars":
colorArrayName = arrayMeta["name"]
except Exception:
pass
return colorArrayName


def linspace(start, stop, num):
delta = (stop - start)/(num-1)
Expand All @@ -113,7 +167,8 @@ def linspace(start, stop, num):

class SynchronizationContext():

def __init__(self, id_root=None, debug=False):
def __init__(self, id_root=None, serialize_all_data_arrays=False, debug=False):
self.serializeAllDataArrays = serialize_all_data_arrays
self.dataArrayCache = {}
self.lastDependenciesMapping = {}
self.ingoreLastDependencies = False
Expand Down Expand Up @@ -241,7 +296,7 @@ def initializeSerializers():
registerInstanceSerializer('vtkOpenGLActor', genericActorSerializer)
registerInstanceSerializer('vtkFollower', genericActorSerializer)
registerInstanceSerializer('vtkPVLODActor', genericActorSerializer)


# Mappers
registerInstanceSerializer(
Expand Down Expand Up @@ -407,47 +462,56 @@ def getArrayDescription(array, context):
# -----------------------------------------------------------------------------


def extractAllDataArrays(extractedFields, dataset, context):
pointData = dataset.GetPointData()
for id_arr in range(pointData.GetNumberOfArrays()):
arrayMeta = getArrayDescription(pointData.GetArray(id_arr), context)
if arrayMeta:
arrayMeta['location'] = 'pointData'
extractedFields.append(arrayMeta)
cellData = dataset.GetCellData()
for id_arr in range(cellData.GetNumberOfArrays()):
arrayMeta = getArrayDescription(cellData.GetArray(id_arr), context)
if arrayMeta:
arrayMeta['location'] = 'cellData'
extractedFields.append(arrayMeta)
fieldData = dataset.GetCellData()
for id_arr in range(fieldData.GetNumberOfArrays()):
arrayMeta = getArrayDescription(fieldData.GetArray(id_arr), context)
if arrayMeta:
arrayMeta['location'] = 'fieldData'
extractedFields.append(arrayMeta)

# -----------------------------------------------------------------------------


def extractRequiredFields(extractedFields, parent, dataset, context, requestedFields=['Normals', 'TCoords']):
# FIXME should evolve and support funky mapper which leverage many arrays
if parent.IsA('vtkMapper') or parent.IsA('vtkVolumeMapper'):
mapper = parent
scalarVisibility = 1 if mapper.IsA('vtkVolumeMapper') else mapper.GetScalarVisibility()
arrayAccessMode = mapper.GetArrayAccessMode()
colorArrayName = mapper.GetArrayName() if arrayAccessMode == 1 else mapper.GetArrayId()
# colorMode = mapper.GetColorMode()
scalarMode = mapper.GetScalarMode()
if scalarVisibility and scalarMode in (1, 3):
arrayMeta = getArrayDescription(
dataset.GetPointData().GetArray(colorArrayName), context)
if arrayMeta:
arrayMeta['location'] = 'pointData'
extractedFields.append(arrayMeta)
elif dataset.GetPointData().GetScalars():
arrayMeta = getArrayDescription(
dataset.GetPointData().GetScalars(), context)
arrayMeta['location'] = 'pointData'
arrayMeta['registration'] = 'setScalars'
extractedFields.append(arrayMeta)
if scalarVisibility and scalarMode in (2, 4):
arrayMeta = getArrayDescription(
dataset.GetCellData().GetArray(colorArrayName), context)
if arrayMeta:
arrayMeta['location'] = 'cellData'
extractedFields.append(arrayMeta)
elif dataset.GetCellData().GetScalars():
arrayMeta = getArrayDescription(
dataset.GetCellData().GetScalars(), context)
arrayMeta['location'] = 'cellData'
if any(parent.IsA(cls) for cls in ['vtkMapper', 'vtkVolumeMapper', 'vtkImageSliceMapper', 'vtkTexture']):
if parent.IsA("vtkAbstractMapper"): # GetScalars method should exists
scalarVisibility = 1 if not hasattr(parent, "GetScalarVisibility") else parent.GetScalarVisibility()
scalars, cell_flag = getScalars(parent, dataset)
if context.serializeAllDataArrays:
extractAllDataArrays(extractedFields, dataset, context)
if scalars:
for arrayMeta in extractedFields:
if arrayMeta['name'] == scalars.GetName():
arrayMeta['registration'] = 'setScalars'
elif scalars and scalarVisibility and not context.serializeAllDataArrays:
arrayMeta = getArrayDescription(scalars, context)
if cell_flag == 0:
arrayMeta['location'] = 'pointData'
elif cell_flag == 1:
arrayMeta['location'] = 'cellData'
else:
raise NotImplementedError("Scalars on field data not handled")
arrayMeta['registration'] = 'setScalars'
extractedFields.append(arrayMeta)

elif ((parent.IsA('vtkTexture') or parent.IsA('vtkImageSliceMapper'))
and dataset.GetPointData().GetScalars()):
arrayMeta = getArrayDescription(
dataset.GetPointData().GetScalars(), context)
arrayMeta['location'] = 'pointData'
arrayMeta['registration'] = 'setScalars'
extractedFields.append(arrayMeta)
elif dataset.GetPointData().GetScalars():
arrayMeta = getArrayDescription(dataset.GetPointData().GetScalars(), context)
arrayMeta['location'] = 'pointData'
arrayMeta['registration'] = 'setScalars'
extractedFields.append(arrayMeta)

# Normal handling
if 'Normals' in requestedFields:
Expand Down Expand Up @@ -487,7 +551,7 @@ def genericPropSerializer(parent, prop, popId, context, depth):
print('This volume does not have a GetMapper method')
else:
mapper = prop.GetMapper()

if mapper:
mapperId = context.getReferenceId(mapper)
mapperInstance = serializeInstance(
Expand All @@ -510,7 +574,7 @@ def genericPropSerializer(parent, prop, popId, context, depth):
if propertyInstance:
dependencies.append(propertyInstance)
calls.append(['setProperty', [wrapId(propId)]])

# Handle texture if any
texture = None
if hasattr(prop, 'GetTexture'):
Expand All @@ -533,7 +597,7 @@ def genericPropSerializer(parent, prop, popId, context, depth):
'visibility': prop.GetVisibility(),
'pickable': prop.GetPickable(),
'dragable': prop.GetDragable(),
'useBounds': prop.GetUseBounds(),
'useBounds': prop.GetUseBounds(),
},
'calls': calls,
'dependencies': dependencies
Expand All @@ -545,17 +609,17 @@ def genericPropSerializer(parent, prop, popId, context, depth):
def genericProp3DSerializer(parent, prop3D, prop3DId, context, depth):
# This kind of actor has some position properties to add
instance = genericPropSerializer(parent, prop3D, prop3DId, context, depth)

if not instance: return

instance['properties'].update({
# vtkProp3D
'origin': prop3D.GetOrigin(),
'position': prop3D.GetPosition(),
'scale': prop3D.GetScale(),
'orientation': prop3D.GetOrientation(),
})

if prop3D.GetUserMatrix():
instance['properties'].update({
'userMatrix': [prop3D.GetUserMatrix().GetElement(i%4,i//4) for i in range(16)],
Expand All @@ -566,11 +630,24 @@ def genericProp3DSerializer(parent, prop3D, prop3DId, context, depth):


def genericActorSerializer(parent, actor, actorId, context, depth):
# may have texture and
# may have texture and
instance = genericProp3DSerializer(parent, actor, actorId, context, depth)

if not instance: return

# # actor may have a backface property instance (not used by vtkjs rendering)
# # https://github.com/Kitware/vtk-js/issues/1545

# backfaceProperties = actor.GetBackfaceProperty()

# if backfaceProperties:
# backfacePropId = context.getReferenceId(backfaceProperties)
# backPropertyInstance = serializeInstance(
# actor, backfaceProperties, backfacePropId, context, depth + 1)
# if backPropertyInstance:
# instance['dependencies'].append(backPropertyInstance)
# instance['calls'].append(['setBackfaceProperty', [wrapId(backfacePropId)]])

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we can keep this if vtkjs is going to support backface color we won't have to rethink about it

instance['properties'].update({
# vtkActor
'forceOpaque': actor.GetForceOpaque(),
Expand Down Expand Up @@ -653,18 +730,15 @@ def genericPolyDataMapperSerializer(parent, mapper, mapperId, context, depth):

if not instance: return

colorArrayName = mapper.GetArrayName(
) if mapper.GetArrayAccessMode() == 1 else mapper.GetArrayId()

instance['type'] = mapper.GetClassName()
instance['properties'].update({
'resolveCoincidentTopology': mapper.GetResolveCoincidentTopology(),
'renderTime': mapper.GetRenderTime(),
'arrayAccessMode': mapper.GetArrayAccessMode(),
'arrayAccessMode': 1, # since we can't set mapper arrayId on vtkjs, we force acess mode by name and use retrieve name function
'scalarRange': mapper.GetScalarRange(),
'useLookupTableScalarRange': 1 if mapper.GetUseLookupTableScalarRange() else 0,
'scalarVisibility': mapper.GetScalarVisibility(),
'colorByArrayName': colorArrayName,
'colorByArrayName': retrieveArrayName(instance, mapper.GetScalarMode()),
'colorMode': mapper.GetColorMode(),
'scalarMode': mapper.GetScalarMode(),
'interpolateScalarsBeforeMapping': 1 if mapper.GetInterpolateScalarsBeforeMapping() else 0
Expand All @@ -680,8 +754,8 @@ def genericVolumeMapperSerializer(parent, mapper, mapperId, context, depth):
if not instance: return

imageSampleDistance = (
mapper.GetImageSampleDistance()
if hasattr(mapper, 'GetImageSampleDistance')
mapper.GetImageSampleDistance()
if hasattr(mapper, 'GetImageSampleDistance')
else 1
)
instance['type'] = mapper.GetClassName()
Expand Down Expand Up @@ -716,12 +790,12 @@ def textureSerializer(parent, texture, textureId, context, depth):
def imageSliceMapperSerializer(parent, mapper, mapperId, context, depth):
# On vtkjs side : vtkImageMapper connected to a vtkImageReslice filter

instance = genericMapperSerializer(parent, mapper, mapperId, context, depth)
instance = genericMapperSerializer(parent, mapper, mapperId, context, depth)

if not instance: return

instance['type'] = mapper.GetClassName()

return instance

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -769,7 +843,7 @@ def lookupTableSerializer(parent, lookupTable, lookupTableId, context, depth):
'vectorComponent': lookupTable.GetVectorComponent(),
'vectorMode': lookupTable.GetVectorMode(),
'indexedLookup': lookupTable.GetIndexedLookup(),
},
},
'arrays': arrays,
}

Expand Down Expand Up @@ -890,7 +964,7 @@ def imagePropertySerializer(parent, propObj, propObjId, context, depth):
dependencies = []

lookupTable = propObj.GetLookupTable()
if lookupTable:
if lookupTable:
ctfun = lookupTableToColorTransferFunction(lookupTable)
ctfunId = context.getReferenceId(ctfun)
ctfunInstance = serializeInstance(
Expand Down Expand Up @@ -1134,7 +1208,8 @@ def rendererSerializer(parent, instance, objId, context, depth):
'useShadows': instance.GetUseShadows(),
'useDepthPeeling': instance.GetUseDepthPeeling(),
'occlusionRatio': instance.GetOcclusionRatio(),
'maximumNumberOfPeels': instance.GetMaximumNumberOfPeels()
'maximumNumberOfPeels': instance.GetMaximumNumberOfPeels(),
'interactive': instance.GetInteractive(),
},
'dependencies': dependencies,
'calls': calls
Expand Down
Loading