r"""This module is used by vtkPythonExtractSelection to extract query-based selections. It relies on the python-calculator (vtkPythonCalculator), specifically, the Python code used by that class, to compute a mask array from the query expression. Once the mask array is obtained, this filter will either extract the selected ids, or mark those elements as requested. """ try: import numpy as np except ImportError: raise RuntimeError, "'numpy' module is not found. numpy is needed for "\ "this functionality to work. Please install numpy and try again." import re import vtk import vtk.numpy_interface.dataset_adapter as dsa import vtk.numpy_interface.algorithms as algos from paraview import calculator def _create_id_array(dataobject, attributeType): """Returns a VTKArray or VTKCompositeDataArray for the ids""" if not dataobject: raise RuntimeError, "dataobject cannot be None" if dataobject.IsA("vtkCompositeDataSet"): ids = [] for ds in dataobject: ids.append(_create_id_array(ds, attributeType)) return dsa.VTKCompositeDataArray(ids) else: return dsa.VTKArray(\ np.arange(dataobject.GetNumberOfElements(attributeType))) def maskarray_is_valid(maskArray): """Validates that the maskArray is either a VTKArray or a VTKCompositeDataArrays or a NoneArray other returns false.""" return maskArray is dsa.NoneArray or \ isinstance(maskArray, dsa.VTKArray) or \ isinstance(maskArray, dsa.VTKCompositeDataArray) def execute(self): inputDO = self.GetInputDataObject(0, 0) inputSEL = self.GetInputDataObject(1, 0) outputDO = self.GetOutputDataObject(0) assert inputSEL.GetNumberOfNodes() >= 1 selectionNode = inputSEL.GetNode(0) field_type = selectionNode.GetFieldType() if field_type == selectionNode.CELL: attributeType = vtk.vtkDataObject.CELL elif field_type == selectionNode.POINT: attributeType = vtk.vtkDataObject.POINT elif field_type == selectionNode.ROW: attributeType = vtk.vtkDataObject.ROW else: raise RuntimeError, "Unsupported field attributeType %r" % field_type # evaluate expression on the inputDO. # this is equivalent to executing the Python Calculator on the input dataset # to produce a mask array. inputs = [] inputs.append(dsa.WrapDataObject(inputDO)) query = selectionNode.GetQueryString() # get a dictionary for arrays in the dataset attributes. We pass that # as the variables in the eval namespace for calculator.compute(). elocals = calculator.get_arrays(inputs[0].GetAttributes(attributeType)) if not elocals.has_key("id") and re.search(r'\bid\b', query): # add "id" array if the query string refers to id. # This is a temporary fix. We should look into # accelerating id-based selections in the future. elocals["id"] = _create_id_array(inputs[0], attributeType) try: maskArray = calculator.compute(inputs, query, ns=elocals) except: from sys import stderr print >> stderr, "Error: Failed to evaluate Expression '%s'. "\ "The following exception stack should provide additional developer "\ "specific information. This typically implies a malformed "\ "expression. Verify that the expression is valid.\n" % query raise if not maskarray_is_valid(maskArray): raise RuntimeError,\ "Expression '%s' did not produce a valid mask array. The value "\ "produced is of the type '%s'. This typically implies a malformed "\ "expression. Verify that the expression is valid." % \ (query, type(maskArray)) # if inverse selection is requested, just logical_not the mask array. if selectionNode.GetProperties().Has(selectionNode.INVERSE()) and \ selectionNode.GetProperties().Get(selectionNode.INVERSE()) == 1: maskArray = algos.logical_not(maskArray) output = dsa.WrapDataObject(outputDO) if self.GetPreserveTopology(): # when preserving topology, just add the mask array as # vtkSignedCharArray to the output. vtkPythonExtractSelection should # have already ensured that the input is shallow copied over properly # before this method gets called. # note: since mask array is a bool-array, we multiply it by int8(1) to # make it a type of array that can be represented as vtkSignedCharArray. output.GetAttributes(attributeType).append(maskArray * np.int8(1), "vtkInsidedness") else: # handle extraction. # flatnonzero() will give is array of indices where the arrays is # non-zero (or non-False in our case). We then pass that to # vtkPythonExtractSelection to extract the selected ids. nonzero_indices = algos.flatnonzero(maskArray) output.FieldData.append(nonzero_indices, "vtkSelectedIds"); #print output.FieldData["vtkSelectedIds"] self.ExtractElements(attributeType, inputDO, outputDO) del nonzero_indices del maskArray