1 7
import base64
2 7
import hashlib
3 7
import io
4 7
import struct
5 7
import sys
6 7
import time
7 7
import zipfile
8

9 7
from vtk.vtkCommonCore import vtkTypeUInt32Array, vtkTypeInt32Array
10 7
from vtk.vtkFiltersGeometry import vtkCompositeDataGeometryFilter, vtkGeometryFilter
11 7
from vtk.vtkRenderingCore import vtkColorTransferFunction
12

13
# -----------------------------------------------------------------------------
14
# Python compatibility handling 2.6, 2.7, 3+
15
# -----------------------------------------------------------------------------
16

17 7
py3 = sys.version_info >= (3, 0)
18

19 7
if py3:
20 7
    def iteritems(d, **kwargs):
21 0
        return iter(d.items(**kwargs))
22
else:
23 0
    def iteritems(d, **kwargs):
24 0
        return d.iteritems(**kwargs)
25

26 7
if sys.version_info >= (2, 7):
27 7
    buffer = memoryview
28 7
    base64Encode = lambda x: base64.b64encode(x).decode('utf-8')
29
else:
30 0
    buffer = buffer
31 0
    base64Encode = lambda x: x.encode('base64')
32

33
# -----------------------------------------------------------------------------
34
# Array helpers
35
# -----------------------------------------------------------------------------
36

37 7
arrayTypesMapping = [
38
    ' ',  # VTK_VOID                0
39
    ' ',  # VTK_BIT                 1
40
    'b',  # VTK_CHAR                2
41
    'B',  # VTK_UNSIGNED_CHAR       3
42
    'h',  # VTK_SHORT               4
43
    'H',  # VTK_UNSIGNED_SHORT      5
44
    'i',  # VTK_INT                 6
45
    'I',  # VTK_UNSIGNED_INT        7
46
    'l',  # VTK_LONG                8
47
    'L',  # VTK_UNSIGNED_LONG       9
48
    'f',  # VTK_FLOAT               10
49
    'd',  # VTK_DOUBLE              11
50
    'L',  # VTK_ID_TYPE             12
51
    ' ',  # VTK_STRING              13
52
    ' ',  # VTK_OPAQUE              14
53
    ' ',  # UNDEFINED
54
    'l',  # VTK_LONG_LONG           16
55
    'L',  # VTK_UNSIGNED_LONG_LONG  17
56
]
57

58 7
javascriptMapping = {
59
    'b': 'Int8Array',
60
    'B': 'Uint8Array',
61
    'h': 'Int16Array',
62
    'H': 'UInt16Array',
63
    'i': 'Int32Array',
64
    'I': 'Uint32Array',
65
    'l': 'Int32Array',
66
    'L': 'Uint32Array',
67
    'f': 'Float32Array',
68
    'd': 'Float64Array'
69
}
70

71

72 7
def hashDataArray(dataArray):
73 7
    return hashlib.md5(buffer(dataArray)).hexdigest()
74

75

76 7
def getJSArrayType(dataArray):
77 7
    return javascriptMapping[arrayTypesMapping[dataArray.GetDataType()]]
78

79

80 7
def zipCompression(name, data):
81 7
    with io.BytesIO() as in_memory:
82 7
        with zipfile.ZipFile(in_memory, mode="w") as zf:
83 7
            zf.writestr('data/%s' % name,
84
                        data, zipfile.ZIP_DEFLATED)
85 7
        in_memory.seek(0)
86 7
        return in_memory.read()
87

88

89 7
def dataTableToList(dataTable):
90 0
    dataType = arrayTypesMapping[dataTable.GetDataType()]
91 0
    elementSize = struct.calcsize(dataType)
92 0
    nbValues = dataTable.GetNumberOfValues()
93 0
    nbComponents = dataTable.GetNumberOfComponents()
94 0
    nbytes = elementSize * nbValues
95 0
    if dataType != ' ':
96 0
        with io.BytesIO(buffer(dataTable)) as stream:
97 0
            data = list(struct.unpack(dataType*nbValues ,stream.read(nbytes)))
98 0
        return [data[idx*nbComponents:(idx+1)*nbComponents]
99
                    for idx in range(nbValues//nbComponents)]
100

101

102 7
def getScalars(mapper, dataset):
103 7
    scalars = None
104 7
    cell_flag = 0
105 7
    scalar_mode = mapper.GetScalarMode()
106 7
    array_access_mode = mapper.GetArrayAccessMode()
107 7
    array_id = mapper.GetArrayId()
108 7
    array_name = mapper.GetArrayName()
109 7
    pd = dataset.GetPointData()
110 7
    cd = dataset.GetCellData()
111 7
    fd = dataset.GetFieldData()
112 7
    if scalar_mode == 0: # VTK_SCALAR_MODE_DEFAULT
113 7
        scalars = pd.GetScalars()
114 7
        cell_flag = 0
115 7
        if scalars is None:
116 7
            scalars = cd.GetScalars()
117 7
            cell_flag = 1
118 7
    elif scalar_mode == 1: # VTK_SCALAR_MODE_USE_POINT_DATA
119 7
        scalars = pd.GetScalars()
120 7
        cell_flag = 0
121 7
    elif scalar_mode == 2: # VTK_SCALAR_MODE_USE_CELL_DATA
122 7
        scalars = cd.GetScalars()
123 7
        cell_flag = 1
124 7
    elif scalar_mode == 3: # VTK_SCALAR_MODE_USE_POINT_FIELD_DATA
125 0
        if array_access_mode == 0: # VTK_GET_ARRAY_BY_ID
126 0
            scalars = pd.GetAbstractArray(array_id)
127
        else: # VTK_GET_ARRAY_BY_NAME
128 0
            scalars = pd.GetAbstractArray(array_name)
129 0
        cell_flag = 0
130 7
    elif scalar_mode == 4: # VTK_SCALAR_MODE_USE_CELL_FIELD_DATA
131 0
        if array_access_mode == 0: # VTK_GET_ARRAY_BY_ID
132 0
            scalars = cd.GetAbstractArray(array_id)
133
        else: # VTK_GET_ARRAY_BY_NAME
134 0
            scalars = cd.GetAbstractArray(array_name)
135 0
        cell_flag = 1
136
    else: # VTK_SCALAR_MODE_USE_FIELD_DATA
137 7
        if array_access_mode == 0: # VTK_GET_ARRAY_BY_ID
138 7
            scalars = fd.GetAbstractArray(array_id)
139
        else: # VTK_GET_ARRAY_BY_NAME
140 0
            scalars = fd.GetAbstractArray(array_name)
141 7
        cell_flag = 2
142 7
    return scalars, cell_flag
143

144

145 7
def retrieveArrayName(mapper_instance, scalar_mode):
146 7
    colorArrayName = None
147 7
    try:
148 7
        ds = [deps for deps in mapper_instance['dependencies'] if deps['id'].endswith('dataset')][0]
149 7
        location = "pointData" if scalar_mode in (1, 3) else "cellData"
150 7
        for arrayMeta in ds['properties']['fields']:
151 7
            if arrayMeta["location"] == location and arrayMeta.get("registration", None) == "setScalars":
152 7
                colorArrayName = arrayMeta["name"]
153 0
    except Exception:
154 0
        pass
155 7
    return colorArrayName
156

157

158 7
def linspace(start, stop, num):
159 0
    delta = (stop - start)/(num-1)
160 0
    return [start + i*delta for i in range(num)]
161

162
# -----------------------------------------------------------------------------
163
# Convenience class for caching data arrays, storing computed sha sums, keeping
164
# track of valid actors, etc...
165
# -----------------------------------------------------------------------------
166

167

168 7
class SynchronizationContext():
169

170 7
    def __init__(self, id_root=None, serialize_all_data_arrays=False, debug=False):
171 7
        self.serializeAllDataArrays = serialize_all_data_arrays
172 7
        self.dataArrayCache = {}
173 7
        self.lastDependenciesMapping = {}
174 7
        self.ingoreLastDependencies = False
175 7
        self.idRoot = id_root
176 7
        self.debugSerializers = debug
177 7
        self.debugAll = debug
178

179 7
    def getReferenceId(self, instance):
180 7
        if not self.idRoot or (hasattr(instance, 'IsA') and instance.IsA('vtkCamera')):
181 7
            return getReferenceId(instance)
182
        else:
183 7
            return self.idRoot + getReferenceId(instance)
184

185 7
    def setIgnoreLastDependencies(self, force):
186 0
        self.ingoreLastDependencies = force
187

188 7
    def cacheDataArray(self, pMd5, data):
189 7
        self.dataArrayCache[pMd5] = data
190

191 7
    def getCachedDataArray(self, pMd5, binary=False, compression=False):
192 7
        cacheObj = self.dataArrayCache[pMd5]
193 7
        array = cacheObj['array']
194 7
        cacheTime = cacheObj['mTime']
195

196 7
        if cacheTime != array.GetMTime():
197 0
            if context.debugAll:
198 0
                print(' ***** ERROR: you asked for an old cache key! ***** ')
199

200 7
        if array.GetDataType() in (12, 16, 17):
201 7
            arraySize = array.GetNumberOfTuples() * array.GetNumberOfComponents()
202 7
            if array.GetDataType() in (12, 17):
203
                # IdType and unsigned long long need to be converted to Uint32
204 7
                newArray = vtkTypeUInt32Array()
205
            else:
206
                #  long long need to be converted to Int32
207 0
                newArray = vtkTypeInt32Array()
208 7
            newArray.SetNumberOfTuples(arraySize)
209 7
            for i in range(arraySize):
210 7
                newArray.SetValue(i, -1 if array.GetValue(i)
211
                                  < 0 else array.GetValue(i))
212 7
            pBuffer = buffer(newArray)
213
        else:
214 7
            pBuffer = buffer(array)
215

216 7
        if binary:
217
            # Convert the vtkUnsignedCharArray into a bytes object, required by
218
            # Autobahn websockets
219 7
            return pBuffer.tobytes() if not compression else zipCompression(pMd5, pBuffer.tobytes())
220

221 7
        return base64Encode(pBuffer if not compression else zipCompression(pMd5, pBuffer.tobytes()))
222

223 7
    def checkForArraysToRelease(self, timeWindow=20):
224 7
        cutOffTime = time.time() - timeWindow
225 7
        shasToDelete = []
226 7
        for sha in self.dataArrayCache:
227 7
            record = self.dataArrayCache[sha]
228 7
            array = record['array']
229 7
            count = array.GetReferenceCount()
230

231 7
            if count == 1 and record['ts'] < cutOffTime:
232 7
                shasToDelete.append(sha)
233

234 7
        for sha in shasToDelete:
235 7
            del self.dataArrayCache[sha]
236

237 7
    def getLastDependencyList(self, idstr):
238 7
        lastDeps = []
239 7
        if idstr in self.lastDependenciesMapping and not self.ingoreLastDependencies:
240 7
            lastDeps = self.lastDependenciesMapping[idstr]
241 7
        return lastDeps
242

243 7
    def setNewDependencyList(self, idstr, depList):
244 7
        self.lastDependenciesMapping[idstr] = depList
245

246 7
    def buildDependencyCallList(self, idstr, newList, addMethod, removeMethod):
247 7
        oldList = self.getLastDependencyList(idstr)
248

249 7
        calls = []
250 7
        calls += [[addMethod, [wrapId(x)]]
251
                  for x in newList if x not in oldList]
252 7
        calls += [[removeMethod, [wrapId(x)]]
253
                  for x in oldList if x not in newList]
254

255 7
        self.setNewDependencyList(idstr, newList)
256 7
        return calls
257

258
# -----------------------------------------------------------------------------
259
# Global variables
260
# -----------------------------------------------------------------------------
261

262 7
SERIALIZERS = {}
263 7
context = None
264

265
# -----------------------------------------------------------------------------
266
# Global API
267
# -----------------------------------------------------------------------------
268

269

270 7
def registerInstanceSerializer(name, method):
271
    global SERIALIZERS
272 7
    SERIALIZERS[name] = method
273

274
# -----------------------------------------------------------------------------
275

276

277 7
def serializeInstance(parent, instance, instanceId, context, depth):
278 7
    instanceType = instance.GetClassName()
279 7
    serializer = SERIALIZERS[
280
        instanceType] if instanceType in SERIALIZERS else None
281

282 7
    if serializer:
283 7
        return serializer(parent, instance, instanceId, context, depth)
284

285 7
    if context.debugSerializers:
286 0
        print('%s!!!No serializer for %s with id %s' %
287
              (pad(depth), instanceType, instanceId))
288

289
# -----------------------------------------------------------------------------
290

291

292 7
def initializeSerializers():
293
    # Actors/viewProps
294 7
    registerInstanceSerializer('vtkImageSlice', genericProp3DSerializer)
295 7
    registerInstanceSerializer('vtkVolume', genericProp3DSerializer)
296 7
    registerInstanceSerializer('vtkOpenGLActor', genericActorSerializer)
297 7
    registerInstanceSerializer('vtkFollower', genericActorSerializer)
298 7
    registerInstanceSerializer('vtkPVLODActor', genericActorSerializer)
299

300

301
    # Mappers
302 7
    registerInstanceSerializer(
303
        'vtkOpenGLPolyDataMapper', genericPolyDataMapperSerializer)
304 7
    registerInstanceSerializer(
305
        'vtkCompositePolyDataMapper2', genericPolyDataMapperSerializer)
306 7
    registerInstanceSerializer('vtkDataSetMapper', genericPolyDataMapperSerializer)
307 7
    registerInstanceSerializer(
308
        'vtkFixedPointVolumeRayCastMapper', genericVolumeMapperSerializer)
309 7
    registerInstanceSerializer(
310
        'vtkSmartVolumeMapper', genericVolumeMapperSerializer)
311 7
    registerInstanceSerializer(
312
        'vtkOpenGLImageSliceMapper', imageSliceMapperSerializer)
313

314
    # LookupTables/TransferFunctions
315 7
    registerInstanceSerializer('vtkLookupTable', lookupTableSerializer)
316 7
    registerInstanceSerializer(
317
        'vtkPVDiscretizableColorTransferFunction', colorTransferFunctionSerializer)
318 7
    registerInstanceSerializer(
319
        'vtkColorTransferFunction', colorTransferFunctionSerializer)
320

321
    # opacityFunctions
322 7
    registerInstanceSerializer(
323
        'vtkPiecewiseFunction', piecewiseFunctionSerializer)
324

325
    # Textures
326 7
    registerInstanceSerializer('vtkOpenGLTexture', textureSerializer)
327

328
    # Property
329 7
    registerInstanceSerializer('vtkOpenGLProperty', propertySerializer)
330 7
    registerInstanceSerializer('vtkVolumeProperty', volumePropertySerializer)
331 7
    registerInstanceSerializer('vtkImageProperty', imagePropertySerializer)
332

333
    # Datasets
334 7
    registerInstanceSerializer('vtkPolyData', polydataSerializer)
335 7
    registerInstanceSerializer('vtkImageData', imageDataSerializer)
336 7
    registerInstanceSerializer(
337
        'vtkStructuredGrid', mergeToPolydataSerializer)
338 7
    registerInstanceSerializer(
339
        'vtkUnstructuredGrid', mergeToPolydataSerializer)
340 7
    registerInstanceSerializer(
341
        'vtkMultiBlockDataSet', mergeToPolydataSerializer)
342

343
    # RenderWindows
344 7
    registerInstanceSerializer('vtkCocoaRenderWindow', renderWindowSerializer)
345 7
    registerInstanceSerializer(
346
        'vtkXOpenGLRenderWindow', renderWindowSerializer)
347 7
    registerInstanceSerializer(
348
        'vtkWin32OpenGLRenderWindow', renderWindowSerializer)
349 7
    registerInstanceSerializer('vtkEGLRenderWindow', renderWindowSerializer)
350 7
    registerInstanceSerializer('vtkOpenVRRenderWindow', renderWindowSerializer)
351 7
    registerInstanceSerializer(
352
        'vtkGenericOpenGLRenderWindow', renderWindowSerializer)
353 7
    registerInstanceSerializer(
354
        'vtkOSOpenGLRenderWindow', renderWindowSerializer)
355 7
    registerInstanceSerializer('vtkOpenGLRenderWindow', renderWindowSerializer)
356 7
    registerInstanceSerializer('vtkIOSRenderWindow', renderWindowSerializer)
357 7
    registerInstanceSerializer(
358
        'vtkExternalOpenGLRenderWindow', renderWindowSerializer)
359

360
    # Renderers
361 7
    registerInstanceSerializer('vtkOpenGLRenderer', rendererSerializer)
362

363
    # Cameras
364 7
    registerInstanceSerializer('vtkOpenGLCamera', cameraSerializer)
365

366

367
# -----------------------------------------------------------------------------
368
# Helper functions
369
# -----------------------------------------------------------------------------
370

371

372 7
def pad(depth):
373 0
    padding = ''
374 0
    for _ in range(depth):
375 0
        padding += '  '
376 0
    return padding
377

378
# -----------------------------------------------------------------------------
379

380

381 7
def wrapId(idStr):
382 7
    return 'instance:${%s}' % idStr
383

384
# -----------------------------------------------------------------------------
385

386

387 7
def getReferenceId(ref):
388 7
    if ref:
389 7
        try:
390 7
            return ref.__this__[1:17]
391 0
        except Exception:
392 0
            idStr = str(ref)[-12:-1]
393 0
            print('====> fallback ID %s for %s' % (idStr, ref))
394 0
            return idStr
395 7
    return '0x0'
396

397
# -----------------------------------------------------------------------------
398

399 7
dataArrayShaMapping = {}
400

401

402 7
def digest(array):
403 7
    objId = getReferenceId(array)
404

405 7
    record = None
406 7
    if objId in dataArrayShaMapping:
407 7
        record = dataArrayShaMapping[objId]
408

409 7
    if record and record['mtime'] == array.GetMTime():
410 7
        return record['sha']
411

412 7
    record = {
413
        'sha': hashDataArray(array),
414
        'mtime': array.GetMTime()
415
    }
416

417 7
    dataArrayShaMapping[objId] = record
418 7
    return record['sha']
419

420
# -----------------------------------------------------------------------------
421

422

423 7
def getRangeInfo(array, component):
424 7
    r = array.GetRange(component)
425 7
    compRange = {}
426 7
    compRange['min'] = r[0]
427 7
    compRange['max'] = r[1]
428 7
    compRange['component'] = array.GetComponentName(component)
429 7
    return compRange
430

431
# -----------------------------------------------------------------------------
432

433

434 7
def getArrayDescription(array, context):
435 7
    if not array:
436 0
        return None
437

438 7
    pMd5 = digest(array)
439 7
    context.cacheDataArray(pMd5, {
440
        'array': array,
441
        'mTime': array.GetMTime(),
442
        'ts': time.time()
443
    })
444

445 7
    root = {}
446 7
    root['hash'] = pMd5
447 7
    root['vtkClass'] = 'vtkDataArray'
448 7
    root['name'] = array.GetName()
449 7
    root['dataType'] = getJSArrayType(array)
450 7
    root['numberOfComponents'] = array.GetNumberOfComponents()
451 7
    root['size'] = array.GetNumberOfComponents() * array.GetNumberOfTuples()
452 7
    root['ranges'] = []
453 7
    if root['numberOfComponents'] > 1:
454 7
        for i in range(root['numberOfComponents']):
455 7
            root['ranges'].append(getRangeInfo(array, i))
456 7
        root['ranges'].append(getRangeInfo(array, -1))
457
    else:
458 7
        root['ranges'].append(getRangeInfo(array, 0))
459

460 7
    return root
461

462
# -----------------------------------------------------------------------------
463

464

465 7
def extractAllDataArrays(extractedFields, dataset, context):
466 0
    pointData = dataset.GetPointData()
467 0
    for id_arr in range(pointData.GetNumberOfArrays()):
468 0
        arrayMeta = getArrayDescription(pointData.GetArray(id_arr), context)
469 0
        if arrayMeta:
470 0
            arrayMeta['location'] = 'pointData'
471 0
            extractedFields.append(arrayMeta)
472 0
    cellData = dataset.GetCellData()
473 0
    for id_arr in range(cellData.GetNumberOfArrays()):
474 0
        arrayMeta = getArrayDescription(cellData.GetArray(id_arr), context)
475 0
        if arrayMeta:
476 0
            arrayMeta['location'] = 'cellData'
477 0
            extractedFields.append(arrayMeta)
478 0
    fieldData = dataset.GetCellData()
479 0
    for id_arr in range(fieldData.GetNumberOfArrays()):
480 0
        arrayMeta = getArrayDescription(fieldData.GetArray(id_arr), context)
481 0
        if arrayMeta:
482 0
            arrayMeta['location'] = 'fieldData'
483 0
            extractedFields.append(arrayMeta)
484

485
# -----------------------------------------------------------------------------
486

487

488 7
def extractRequiredFields(extractedFields, parent, dataset, context, requestedFields=['Normals', 'TCoords']):
489
    # FIXME should evolve and support funky mapper which leverage many arrays
490 7
    if any(parent.IsA(cls) for cls in ['vtkMapper', 'vtkVolumeMapper', 'vtkImageSliceMapper', 'vtkTexture']):
491 7
        if parent.IsA("vtkAbstractMapper"): # GetScalars method should exists
492 7
            scalarVisibility = 1 if not hasattr(parent, "GetScalarVisibility") else parent.GetScalarVisibility()
493 7
            scalars, cell_flag = getScalars(parent, dataset)
494 7
            if context.serializeAllDataArrays:
495 0
                extractAllDataArrays(extractedFields, dataset, context)
496 0
                if scalars:
497 0
                    for arrayMeta in extractedFields:
498 0
                        if arrayMeta['name'] == scalars.GetName():
499 0
                            arrayMeta['registration'] = 'setScalars'
500 7
            elif scalars and scalarVisibility and not context.serializeAllDataArrays:
501 7
                arrayMeta = getArrayDescription(scalars, context)
502 7
                if cell_flag == 0:
503 7
                    arrayMeta['location'] = 'pointData'
504 7
                elif cell_flag == 1:
505 7
                    arrayMeta['location'] = 'cellData'
506
                else:
507 0
                    raise NotImplementedError("Scalars on field data not handled")
508 7
                arrayMeta['registration'] = 'setScalars'
509 7
                extractedFields.append(arrayMeta)
510 7
        elif dataset.GetPointData().GetScalars():
511 7
            arrayMeta = getArrayDescription(dataset.GetPointData().GetScalars(), context)
512 7
            arrayMeta['location'] = 'pointData'
513 7
            arrayMeta['registration'] = 'setScalars'
514 7
            extractedFields.append(arrayMeta)
515

516
    # Normal handling
517 7
    if 'Normals' in requestedFields:
518 7
        normals = dataset.GetPointData().GetNormals()
519 7
        if normals:
520 7
            arrayMeta = getArrayDescription(normals, context)
521 7
            if arrayMeta:
522 7
                arrayMeta['location'] = 'pointData'
523 7
                arrayMeta['registration'] = 'setNormals'
524 7
                extractedFields.append(arrayMeta)
525

526
    # TCoord handling
527 7
    if 'TCoords' in requestedFields:
528 7
        tcoords = dataset.GetPointData().GetTCoords()
529 7
        if tcoords:
530 7
            arrayMeta = getArrayDescription(tcoords, context)
531 7
            if arrayMeta:
532 7
                arrayMeta['location'] = 'pointData'
533 7
                arrayMeta['registration'] = 'setTCoords'
534 7
                extractedFields.append(arrayMeta)
535

536
# -----------------------------------------------------------------------------
537
# Concrete instance serializers
538
# -----------------------------------------------------------------------------
539

540 7
def genericPropSerializer(parent, prop, popId, context, depth):
541
    # This kind of actor has two "children" of interest, a property and a
542
    # mapper (optionnaly a texture)
543 7
    mapperInstance = None
544 7
    propertyInstance = None
545 7
    calls = []
546 7
    dependencies = []
547

548 7
    mapper = None
549 7
    if not hasattr(prop, 'GetMapper'):
550 0
        if context.debugAll:
551 0
            print('This volume does not have a GetMapper method')
552
    else:
553 7
        mapper = prop.GetMapper()
554

555 7
    if mapper:
556 7
        mapperId = context.getReferenceId(mapper)
557 7
        mapperInstance = serializeInstance(
558
            prop, mapper, mapperId, context, depth + 1)
559 7
        if mapperInstance:
560 7
            dependencies.append(mapperInstance)
561 7
            calls.append(['setMapper', [wrapId(mapperId)]])
562

563 7
    properties = None
564 7
    if hasattr(prop, 'GetProperty'):
565 7
        properties = prop.GetProperty()
566
    else:
567 0
        if context.debugAll:
568 0
            print('This image does not have a GetProperty method')
569

570 7
    if properties:
571 7
        propId = context.getReferenceId(properties)
572 7
        propertyInstance = serializeInstance(
573
            prop, properties, propId, context, depth + 1)
574 7
        if propertyInstance:
575 7
            dependencies.append(propertyInstance)
576 7
            calls.append(['setProperty', [wrapId(propId)]])
577

578
    # Handle texture if any
579 7
    texture = None
580 7
    if hasattr(prop, 'GetTexture'):
581 7
        texture = prop.GetTexture()
582

583 7
    if texture:
584 7
        textureId = context.getReferenceId(texture)
585 7
        textureInstance = serializeInstance(
586
            prop, texture, textureId, context, depth + 1)
587 7
        if textureInstance:
588 7
            dependencies.append(textureInstance)
589 7
            calls.append(['addTexture', [wrapId(textureId)]])
590

591 7
    return {
592
        'parent': context.getReferenceId(parent),
593
        'id': popId,
594
        'type': prop.GetClassName(),
595
        'properties': {
596
            # vtkProp
597
            'visibility': prop.GetVisibility(),
598
            'pickable': prop.GetPickable(),
599
            'dragable': prop.GetDragable(),
600
            'useBounds': prop.GetUseBounds(),
601
        },
602
        'calls': calls,
603
        'dependencies': dependencies
604
    }
605

606
# -----------------------------------------------------------------------------
607

608

609 7
def genericProp3DSerializer(parent, prop3D, prop3DId, context, depth):
610
    # This kind of actor has some position properties to add
611 7
    instance = genericPropSerializer(parent, prop3D, prop3DId, context, depth)
612

613 7
    if not instance: return
614

615 7
    instance['properties'].update({
616
        # vtkProp3D
617
        'origin': prop3D.GetOrigin(),
618
        'position': prop3D.GetPosition(),
619
        'scale': prop3D.GetScale(),
620
        'orientation': prop3D.GetOrientation(),
621
    })
622

623 7
    if prop3D.GetUserMatrix():
624 0
        instance['properties'].update({
625
            'userMatrix': [prop3D.GetUserMatrix().GetElement(i%4,i//4) for i in range(16)],
626
        })
627 7
    return instance
628

629
# -----------------------------------------------------------------------------
630

631

632 7
def genericActorSerializer(parent, actor, actorId, context, depth):
633
    # may have texture and
634 7
    instance = genericProp3DSerializer(parent, actor, actorId, context, depth)
635

636 7
    if not instance: return
637

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

641
    # backfaceProperties = actor.GetBackfaceProperty()
642

643
    # if backfaceProperties:
644
    #     backfacePropId = context.getReferenceId(backfaceProperties)
645
    #     backPropertyInstance = serializeInstance(
646
    #         actor, backfaceProperties, backfacePropId, context, depth + 1)
647
    #     if backPropertyInstance:
648
    #         instance['dependencies'].append(backPropertyInstance)
649
    #         instance['calls'].append(['setBackfaceProperty', [wrapId(backfacePropId)]])
650

651 7
    instance['properties'].update({
652
        # vtkActor
653
        'forceOpaque': actor.GetForceOpaque(),
654
        'forceTranslucent': actor.GetForceTranslucent()
655
    })
656

657 7
    if actor.IsA('vtkFollower'):
658 7
        camera = actor.GetCamera()
659 7
        cameraId = context.getReferenceId(camera)
660 7
        cameraInstance = serializeInstance(
661
            actor, camera, cameraId, context, depth + 1)
662 7
        if cameraInstance:
663 7
            instance['dependencies'].append(cameraInstance)
664 7
            instance['calls'].append(['setCamera', [wrapId(cameraId)]])
665

666 7
    return instance
667

668
# -----------------------------------------------------------------------------
669

670

671 7
def genericMapperSerializer(parent, mapper, mapperId, context, depth):
672
    # This kind of mapper requires us to get 2 items: input data and lookup
673
    # table
674 7
    dataObject = None
675 7
    dataObjectInstance = None
676 7
    lookupTableInstance = None
677 7
    calls = []
678 7
    dependencies = []
679

680 7
    if hasattr(mapper, 'GetInputDataObject'):
681 7
        dataObject = mapper.GetInputDataObject(0, 0)
682
    else:
683 0
        if context.debugAll:
684 0
            print('This mapper does not have GetInputDataObject method')
685

686 7
    if dataObject:
687 7
        dataObjectId = '%s-dataset' % mapperId
688 7
        if parent.IsA('vtkActor') and not mapper.IsA('vtkTexture'):
689
            # vtk-js actors can render only surfacic datasets
690
            # => we ensure to convert the dataset in polydata
691 7
            dataObjectInstance = mergeToPolydataSerializer(
692
                mapper, dataObject, dataObjectId, context, depth + 1)
693
        else:
694 7
            dataObjectInstance = serializeInstance(
695
                mapper, dataObject, dataObjectId, context, depth + 1)
696 7
        if dataObjectInstance:
697 7
            dependencies.append(dataObjectInstance)
698 7
            calls.append(['setInputData', [wrapId(dataObjectId)]])
699

700 7
    lookupTable = None
701

702 7
    if hasattr(mapper, 'GetLookupTable'):
703 7
        lookupTable = mapper.GetLookupTable()
704 7
    elif parent.IsA('vtkActor'):
705 0
        if context.debugAll:
706 0
            print('This mapper actor not have GetLookupTable method')
707

708 7
    if lookupTable:
709 7
        lookupTableId = context.getReferenceId(lookupTable)
710 7
        lookupTableInstance = serializeInstance(
711
            mapper, lookupTable, lookupTableId, context, depth + 1)
712 7
        if lookupTableInstance:
713 7
            dependencies.append(lookupTableInstance)
714 7
            calls.append(['setLookupTable', [wrapId(lookupTableId)]])
715

716 7
    if dataObjectInstance:
717 7
        return {
718
            'parent': context.getReferenceId(parent),
719
            'id': mapperId,
720
            'properties': {},
721
            'calls': calls,
722
            'dependencies': dependencies
723
        }
724

725
# -----------------------------------------------------------------------------
726

727

728 7
def genericPolyDataMapperSerializer(parent, mapper, mapperId, context, depth):
729 7
    instance = genericMapperSerializer(parent, mapper, mapperId, context, depth)
730

731 7
    if not instance: return
732

733 7
    instance['type'] = mapper.GetClassName()
734 7
    instance['properties'].update({
735
        'resolveCoincidentTopology': mapper.GetResolveCoincidentTopology(),
736
        'renderTime': mapper.GetRenderTime(),
737
        'arrayAccessMode': 1, # since we can't set mapper arrayId on vtkjs, we force acess mode by name and use retrieve name function
738
        'scalarRange': mapper.GetScalarRange(),
739
        'useLookupTableScalarRange': 1 if mapper.GetUseLookupTableScalarRange() else 0,
740
        'scalarVisibility': mapper.GetScalarVisibility(),
741
        'colorByArrayName': retrieveArrayName(instance, mapper.GetScalarMode()),
742
        'colorMode': mapper.GetColorMode(),
743
        'scalarMode': mapper.GetScalarMode(),
744
        'interpolateScalarsBeforeMapping': 1 if mapper.GetInterpolateScalarsBeforeMapping() else 0
745
    })
746 7
    return instance
747

748
# -----------------------------------------------------------------------------
749

750

751 7
def genericVolumeMapperSerializer(parent, mapper, mapperId, context, depth):
752 7
    instance = genericMapperSerializer(parent, mapper, mapperId, context, depth)
753

754 7
    if not instance: return
755

756 7
    imageSampleDistance = (
757
        mapper.GetImageSampleDistance()
758
        if hasattr(mapper, 'GetImageSampleDistance')
759
        else 1
760
    )
761 7
    instance['type'] = mapper.GetClassName()
762 7
    instance['properties'].update({
763
        'sampleDistance': mapper.GetSampleDistance(),
764
        'imageSampleDistance': imageSampleDistance,
765
        # 'maximumSamplesPerRay',
766
        'autoAdjustSampleDistances': mapper.GetAutoAdjustSampleDistances(),
767
        'blendMode': mapper.GetBlendMode(),
768
    })
769 7
    return instance
770

771
# -----------------------------------------------------------------------------
772

773

774 7
def textureSerializer(parent, texture, textureId, context, depth):
775 7
    instance = genericMapperSerializer(parent, texture, textureId, context, depth)
776

777 7
    if not instance: return
778

779 7
    instance['type'] = texture.GetClassName()
780 7
    instance['properties'].update({
781
        'interpolate': texture.GetInterpolate(),
782
        'repeat': texture.GetRepeat(),
783
        'edgeClamp': texture.GetEdgeClamp(),
784
    })
785 7
    return instance
786

787
# -----------------------------------------------------------------------------
788

789

790 7
def imageSliceMapperSerializer(parent, mapper, mapperId, context, depth):
791
    # On vtkjs side : vtkImageMapper connected to a vtkImageReslice filter
792

793 0
    instance = genericMapperSerializer(parent, mapper, mapperId, context, depth)
794

795 0
    if not instance: return
796

797 0
    instance['type'] = mapper.GetClassName()
798

799 0
    return instance
800

801
# -----------------------------------------------------------------------------
802

803

804 7
def lookupTableSerializer(parent, lookupTable, lookupTableId, context, depth):
805
    # No children in this case, so no additions to bindings and return empty list
806
    # But we do need to add instance
807 7
    arrays = []
808 7
    lookupTableRange = lookupTable.GetRange()
809

810 7
    lookupTableHueRange = [0.5, 0]
811 7
    if hasattr(lookupTable, 'GetHueRange'):
812 7
        try:
813 7
            lookupTable.GetHueRange(lookupTableHueRange)
814 7
        except Exception:
815 7
            pass
816

817 7
    lutSatRange = lookupTable.GetSaturationRange()
818
    # lutAlphaRange = lookupTable.GetAlphaRange()
819 7
    if lookupTable.GetTable():
820 7
        arrayMeta = getArrayDescription(lookupTable.GetTable(), context)
821 7
        if arrayMeta:
822 7
            arrayMeta['registration'] = 'setTable'
823 7
            arrays.append(arrayMeta)
824

825 7
    return {
826
        'parent': context.getReferenceId(parent),
827
        'id': lookupTableId,
828
        'type': lookupTable.GetClassName(),
829
        'properties': {
830
            'numberOfColors': lookupTable.GetNumberOfColors(),
831
            'valueRange': lookupTableRange,
832
            'range': lookupTableRange,
833
            'hueRange': lookupTableHueRange,
834
            # 'alphaRange': lutAlphaRange,  # Causes weird rendering artifacts on client
835
            'saturationRange': lutSatRange,
836
            'nanColor': lookupTable.GetNanColor(),
837
            'belowRangeColor': lookupTable.GetBelowRangeColor(),
838
            'aboveRangeColor': lookupTable.GetAboveRangeColor(),
839
            'useAboveRangeColor': True if lookupTable.GetUseAboveRangeColor() else False,
840
            'useBelowRangeColor': True if lookupTable.GetUseBelowRangeColor() else False,
841
            'alpha': lookupTable.GetAlpha(),
842
            'vectorSize': lookupTable.GetVectorSize(),
843
            'vectorComponent': lookupTable.GetVectorComponent(),
844
            'vectorMode': lookupTable.GetVectorMode(),
845
            'indexedLookup': lookupTable.GetIndexedLookup(),
846
        },
847
        'arrays': arrays,
848
    }
849

850
# -----------------------------------------------------------------------------
851

852

853 7
def lookupTableToColorTransferFunction(lookupTable):
854 0
    dataTable = lookupTable.GetTable()
855 0
    table = dataTableToList(dataTable)
856 0
    if table:
857 0
        ctf = vtkColorTransferFunction()
858 0
        tableRange = lookupTable.GetTableRange()
859 0
        points = linspace(*tableRange, num=len(table))
860 0
        for x, rgba in zip(points, table):
861 0
            ctf.AddRGBPoint(x, *[x/255 for x in rgba[:3]])
862 0
        return ctf
863

864
# -----------------------------------------------------------------------------
865

866

867 7
def lookupTableSerializer2(parent, lookupTable, lookupTableId, context, depth):
868 0
    ctf = lookupTableToColorTransferFunction(lookupTable)
869 0
    if ctf:
870 0
        return colorTransferFunctionSerializer(parent, ctf, lookupTableId, context, depth)
871

872
# -----------------------------------------------------------------------------
873

874

875 7
def propertySerializer(parent, propObj, propObjId, context, depth):
876 7
    representation = propObj.GetRepresentation() if hasattr(
877
        propObj, 'GetRepresentation') else 2
878 7
    colorToUse = propObj.GetDiffuseColor() if hasattr(
879
        propObj, 'GetDiffuseColor') else [1, 1, 1]
880 7
    if representation == 1 and hasattr(propObj, 'GetColor'):
881 0
        colorToUse = propObj.GetColor()
882

883 7
    return {
884
        'parent': context.getReferenceId(parent),
885
        'id': propObjId,
886
        'type': propObj.GetClassName(),
887
        'properties': {
888
            'representation': representation,
889
            'diffuseColor': colorToUse,
890
            'color': propObj.GetColor(),
891
            'ambientColor': propObj.GetAmbientColor(),
892
            'specularColor': propObj.GetSpecularColor(),
893
            'edgeColor': propObj.GetEdgeColor(),
894
            'ambient': propObj.GetAmbient(),
895
            'diffuse': propObj.GetDiffuse(),
896
            'specular': propObj.GetSpecular(),
897
            'specularPower': propObj.GetSpecularPower(),
898
            'opacity': propObj.GetOpacity(),
899
            'interpolation': propObj.GetInterpolation(),
900
            'edgeVisibility': 1 if propObj.GetEdgeVisibility() else 0,
901
            'backfaceCulling': 1 if propObj.GetBackfaceCulling() else 0,
902
            'frontfaceCulling': 1 if propObj.GetFrontfaceCulling() else 0,
903
            'pointSize': propObj.GetPointSize(),
904
            'lineWidth': propObj.GetLineWidth(),
905
            'lighting': 1 if propObj.GetLighting() else 0,
906
        }
907
    }
908

909
# -----------------------------------------------------------------------------
910

911 7
def volumePropertySerializer(parent, propObj, propObjId, context, depth):
912 7
    dependencies = []
913 7
    calls = []
914
    # TODO: for the moment only component 0 handle
915

916
    #OpactiyFunction
917 7
    ofun = propObj.GetScalarOpacity()
918 7
    if ofun:
919 7
        ofunId = context.getReferenceId(ofun)
920 7
        ofunInstance = serializeInstance(
921
            propObj, ofun, ofunId, context, depth + 1)
922 7
        if ofunInstance:
923 7
            dependencies.append(ofunInstance)
924 7
            calls.append(['setScalarOpacity', [0, wrapId(ofunId)]])
925

926
    # ColorTranferFunction
927 7
    ctfun = propObj.GetRGBTransferFunction()
928 7
    if ctfun:
929 7
        ctfunId = context.getReferenceId(ctfun)
930 7
        ctfunInstance = serializeInstance(
931
            propObj, ctfun, ctfunId, context, depth + 1)
932 7
        if ctfunInstance:
933 7
            dependencies.append(ctfunInstance)
934 7
            calls.append(['setRGBTransferFunction', [0, wrapId(ctfunId)]])
935

936 7
    calls += [
937
        ['setScalarOpacityUnitDistance', [0, propObj.GetScalarOpacityUnitDistance(0)]],
938
        ['setComponentWeight', [0, propObj.GetComponentWeight(0)]],
939
        ['setUseGradientOpacity', [0, int(not propObj.GetDisableGradientOpacity())]],
940
    ]
941

942 7
    return {
943
        'parent': context.getReferenceId(parent),
944
        'id': propObjId,
945
        'type': propObj.GetClassName(),
946
        'properties': {
947
            'independentComponents': propObj.GetIndependentComponents(),
948
            'interpolationType': propObj.GetInterpolationType(),
949
            'ambient': propObj.GetAmbient(),
950
            'diffuse': propObj.GetDiffuse(),
951
            'shade': propObj.GetShade(),
952
            'specular': propObj.GetSpecular(0),
953
            'specularPower': propObj.GetSpecularPower(),
954
        },
955
        'dependencies': dependencies,
956
        'calls': calls,
957
    }
958

959
# -----------------------------------------------------------------------------
960

961

962 7
def imagePropertySerializer(parent, propObj, propObjId, context, depth):
963 0
    calls = []
964 0
    dependencies = []
965

966 0
    lookupTable = propObj.GetLookupTable()
967 0
    if lookupTable:
968 0
        ctfun = lookupTableToColorTransferFunction(lookupTable)
969 0
        ctfunId = context.getReferenceId(ctfun)
970 0
        ctfunInstance = serializeInstance(
971
            propObj, ctfun, ctfunId, context, depth + 1)
972 0
        if ctfunInstance:
973 0
            dependencies.append(ctfunInstance)
974 0
            calls.append(['setRGBTransferFunction', [wrapId(ctfunId)]])
975

976 0
    return {
977
        'parent': context.getReferenceId(parent),
978
        'id': propObjId,
979
        'type': propObj.GetClassName(),
980
        'properties': {
981
            'interpolationType': propObj.GetInterpolationType(),
982
            'colorWindow': propObj.GetColorWindow(),
983
            'colorLevel': propObj.GetColorLevel(),
984
            'ambient': propObj.GetAmbient(),
985
            'diffuse': propObj.GetDiffuse(),
986
            'opacity': propObj.GetOpacity(),
987
        },
988
        'dependencies': dependencies,
989
        'calls': calls,
990
    }
991

992
# -----------------------------------------------------------------------------
993

994

995 7
def imageDataSerializer(parent, dataset, datasetId, context, depth):
996 7
    datasetType = dataset.GetClassName()
997

998 7
    if hasattr(dataset, 'GetDirectionMatrix'):
999 7
        direction = [dataset.GetDirectionMatrix().GetElement(0, i)
1000
                     for i in range(9)]
1001
    else:
1002 0
        direction = [1, 0, 0,
1003
                     0, 1, 0,
1004
                     0, 0, 1]
1005

1006
    # Extract dataset fields
1007 7
    arrays = []
1008 7
    extractRequiredFields(arrays, parent, dataset, context)
1009

1010 7
    return {
1011
        'parent': context.getReferenceId(parent),
1012
        'id': datasetId,
1013
        'type': datasetType,
1014
        'properties': {
1015
            'spacing': dataset.GetSpacing(),
1016
            'origin': dataset.GetOrigin(),
1017
            'dimensions': dataset.GetDimensions(),
1018
            'direction': direction,
1019
        },
1020
        'arrays': arrays
1021
    }
1022

1023
# -----------------------------------------------------------------------------
1024

1025

1026 7
def polydataSerializer(parent, dataset, datasetId, context, depth):
1027 7
    datasetType = dataset.GetClassName()
1028

1029 7
    if dataset and dataset.GetPoints():
1030 7
        properties = {}
1031

1032
        # Points
1033 7
        points = getArrayDescription(dataset.GetPoints().GetData(), context)
1034 7
        points['vtkClass'] = 'vtkPoints'
1035 7
        properties['points'] = points
1036

1037
        # Verts
1038 7
        if dataset.GetVerts() and dataset.GetVerts().GetData().GetNumberOfTuples() > 0:
1039 0
            _verts = getArrayDescription(dataset.GetVerts().GetData(), context)
1040 0
            properties['verts'] = _verts
1041 0
            properties['verts']['vtkClass'] = 'vtkCellArray'
1042

1043
        # Lines
1044 7
        if dataset.GetLines() and dataset.GetLines().GetData().GetNumberOfTuples() > 0:
1045 0
            _lines = getArrayDescription(dataset.GetLines().GetData(), context)
1046 0
            properties['lines'] = _lines
1047 0
            properties['lines']['vtkClass'] = 'vtkCellArray'
1048

1049
        # Polys
1050 7
        if dataset.GetPolys() and dataset.GetPolys().GetData().GetNumberOfTuples() > 0:
1051 7
            _polys = getArrayDescription(dataset.GetPolys().GetData(), context)
1052 7
            properties['polys'] = _polys
1053 7
            properties['polys']['vtkClass'] = 'vtkCellArray'
1054

1055
        # Strips
1056 7
        if dataset.GetStrips() and dataset.GetStrips().GetData().GetNumberOfTuples() > 0:
1057 0
            _strips = getArrayDescription(
1058
                dataset.GetStrips().GetData(), context)
1059 0
            properties['strips'] = _strips
1060 0
            properties['strips']['vtkClass'] = 'vtkCellArray'
1061

1062
        # Fields
1063 7
        properties['fields'] = []
1064 7
        extractRequiredFields(properties['fields'], parent, dataset, context)
1065

1066 7
        return {
1067
            'parent': context.getReferenceId(parent),
1068
            'id': datasetId,
1069
            'type': datasetType,
1070
            'properties': properties
1071
        }
1072

1073 0
    if context.debugAll:
1074 0
        print('This dataset has no points!')
1075

1076
# -----------------------------------------------------------------------------
1077

1078

1079 7
def mergeToPolydataSerializer(parent, dataObject, dataObjectId, context, depth):
1080 7
    dataset = None
1081

1082 7
    if dataObject.IsA('vtkCompositeDataSet'):
1083 7
        gf = vtkCompositeDataGeometryFilter()
1084 7
        gf.SetInputData(dataObject)
1085 7
        gf.Update()
1086 7
        dataset = gf.GetOutput()
1087 7
    elif (dataObject.IsA('vtkUnstructuredGrid') or
1088
          dataObject.IsA('vtkStructuredGrid') or
1089
          dataObject.IsA('vtkImageData')):
1090 7
        gf = vtkGeometryFilter()
1091 7
        gf.SetInputData(dataObject)
1092 7
        gf.Update()
1093 7
        dataset = gf.GetOutput()
1094
    else:
1095 7
        dataset = parent.GetInput()
1096

1097 7
    return polydataSerializer(parent, dataset, dataObjectId, context, depth)
1098

1099
# -----------------------------------------------------------------------------
1100

1101

1102 7
def colorTransferFunctionSerializer(parent, instance, objId, context, depth):
1103 7
    nodes = []
1104

1105 7
    for i in range(instance.GetSize()):
1106
        # x, r, g, b, midpoint, sharpness
1107 7
        node = [0, 0, 0, 0, 0, 0]
1108 7
        instance.GetNodeValue(i, node)
1109 7
        nodes.append(node)
1110

1111 7
    return {
1112
        'parent': context.getReferenceId(parent),
1113
        'id': objId,
1114
        'type': instance.GetClassName(),
1115
        'properties': {
1116
            'clamping': 1 if instance.GetClamping() else 0,
1117
            'colorSpace': instance.GetColorSpace(),
1118
            'hSVWrap': 1 if instance.GetHSVWrap() else 0,
1119
            # 'nanColor': instance.GetNanColor(),                  # Breaks client
1120
            # 'belowRangeColor': instance.GetBelowRangeColor(),    # Breaks client
1121
            # 'aboveRangeColor': instance.GetAboveRangeColor(),    # Breaks client
1122
            # 'useAboveRangeColor': 1 if instance.GetUseAboveRangeColor() else 0,
1123
            # 'useBelowRangeColor': 1 if instance.GetUseBelowRangeColor() else 0,
1124
            'allowDuplicateScalars': 1 if instance.GetAllowDuplicateScalars() else 0,
1125
            'alpha': instance.GetAlpha(),
1126
            'vectorComponent': instance.GetVectorComponent(),
1127
            'vectorSize': instance.GetVectorSize(),
1128
            'vectorMode': instance.GetVectorMode(),
1129
            'indexedLookup': instance.GetIndexedLookup(),
1130
            'nodes': nodes
1131
        }
1132
    }
1133

1134
# -----------------------------------------------------------------------------
1135

1136

1137 7
def piecewiseFunctionSerializer(parent, instance, objId, context, depth):
1138 7
    nodes = []
1139

1140 7
    for i in range(instance.GetSize()):
1141
        # x, y, midpoint, sharpness
1142 7
        node = [0, 0, 0, 0]
1143 7
        instance.GetNodeValue(i, node)
1144 7
        nodes.append(node)
1145

1146 7
    return {
1147
        'parent': context.getReferenceId(parent),
1148
        'id': objId,
1149
        'type': instance.GetClassName(),
1150
        'properties': {
1151
            'clamping': instance.GetClamping(),
1152
            'allowDuplicateScalars': instance.GetAllowDuplicateScalars(),
1153
            'nodes': nodes,
1154
        }
1155
    }
1156
# -----------------------------------------------------------------------------
1157

1158

1159 7
def rendererSerializer(parent, instance, objId, context, depth):
1160 7
    dependencies = []
1161 7
    viewPropIds = []
1162 7
    calls = []
1163

1164
    # Camera
1165 7
    camera = instance.GetActiveCamera()
1166 7
    cameraId = context.getReferenceId(camera)
1167 7
    cameraInstance = serializeInstance(
1168
        instance, camera, cameraId, context, depth + 1)
1169 7
    if cameraInstance:
1170 7
        dependencies.append(cameraInstance)
1171 7
        calls.append(['setActiveCamera', [wrapId(cameraId)]])
1172

1173
    # View prop as representation containers
1174 7
    viewPropCollection = instance.GetViewProps()
1175 7
    for rpIdx in range(viewPropCollection.GetNumberOfItems()):
1176 7
        viewProp = viewPropCollection.GetItemAsObject(rpIdx)
1177 7
        viewPropId = context.getReferenceId(viewProp)
1178

1179 7
        viewPropInstance = serializeInstance(
1180
            instance, viewProp, viewPropId, context, depth + 1)
1181 7
        if viewPropInstance:
1182 7
            dependencies.append(viewPropInstance)
1183 7
            viewPropIds.append(viewPropId)
1184

1185 7
    calls += context.buildDependencyCallList('%s-props' %
1186
                                             objId, viewPropIds, 'addViewProp', 'removeViewProp')
1187

1188 7
    return {
1189
        'parent': context.getReferenceId(parent),
1190
        'id': objId,
1191
        'type': instance.GetClassName(),
1192
        'properties': {
1193
            'background': instance.GetBackground(),
1194
            'background2': instance.GetBackground2(),
1195
            'viewport': instance.GetViewport(),
1196
            # These commented properties do not yet have real setters in vtk.js
1197
            # 'gradientBackground': instance.GetGradientBackground(),
1198
            # 'aspect': instance.GetAspect(),
1199
            # 'pixelAspect': instance.GetPixelAspect(),
1200
            # 'ambient': instance.GetAmbient(),
1201
            'twoSidedLighting': instance.GetTwoSidedLighting(),
1202
            'lightFollowCamera': instance.GetLightFollowCamera(),
1203
            'layer': instance.GetLayer(),
1204
            'preserveColorBuffer': instance.GetPreserveColorBuffer(),
1205
            'preserveDepthBuffer': instance.GetPreserveDepthBuffer(),
1206
            'nearClippingPlaneTolerance': instance.GetNearClippingPlaneTolerance(),
1207
            'clippingRangeExpansion': instance.GetClippingRangeExpansion(),
1208
            'useShadows': instance.GetUseShadows(),
1209
            'useDepthPeeling': instance.GetUseDepthPeeling(),
1210
            'occlusionRatio': instance.GetOcclusionRatio(),
1211
            'maximumNumberOfPeels': instance.GetMaximumNumberOfPeels(),
1212
            'interactive': instance.GetInteractive(),
1213
        },
1214
        'dependencies': dependencies,
1215
        'calls': calls
1216
    }
1217

1218
# -----------------------------------------------------------------------------
1219

1220

1221 7
def cameraSerializer(parent, instance, objId, context, depth):
1222 7
    return {
1223
        'parent': context.getReferenceId(parent),
1224
        'id': objId,
1225
        'type': instance.GetClassName(),
1226
        'properties': {
1227
            'focalPoint': instance.GetFocalPoint(),
1228
            'position': instance.GetPosition(),
1229
            'viewUp': instance.GetViewUp(),
1230
            'clippingRange': instance.GetClippingRange(),
1231
        }
1232
    }
1233

1234
# -----------------------------------------------------------------------------
1235

1236

1237 7
def renderWindowSerializer(parent, instance, objId, context, depth):
1238 7
    dependencies = []
1239 7
    rendererIds = []
1240

1241 7
    rendererCollection = instance.GetRenderers()
1242 7
    for rIdx in range(rendererCollection.GetNumberOfItems()):
1243
        # Grab the next vtkRenderer
1244 7
        renderer = rendererCollection.GetItemAsObject(rIdx)
1245 7
        rendererId = context.getReferenceId(renderer)
1246 7
        rendererInstance = serializeInstance(
1247
            instance, renderer, rendererId, context, depth + 1)
1248 7
        if rendererInstance:
1249 7
            dependencies.append(rendererInstance)
1250 7
            rendererIds.append(rendererId)
1251

1252 7
    calls = context.buildDependencyCallList(
1253
        objId, rendererIds, 'addRenderer', 'removeRenderer')
1254

1255 7
    return {
1256
        'parent': context.getReferenceId(parent),
1257
        'id': objId,
1258
        'type': instance.GetClassName(),
1259
        'properties': {
1260
            'numberOfLayers': instance.GetNumberOfLayers()
1261
        },
1262
        'dependencies': dependencies,
1263
        'calls': calls,
1264
        'mtime': instance.GetMTime(),
1265
    }

Read our documentation on viewing source code .

Loading