Salome HOME
Copyright update 2022
[modules/paravis.git] / src / Macro / annotate_groups.py
1 # Copyright (C) 2014-2022  CEA/DEN, EDF R&D
2 #
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
7 #
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # Lesser General Public License for more details.
12 #
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19 # Author : Maxim Glibin
20
21 from paraview.simple import *
22 from paraview.servermanager import *
23 from vtk import *
24 paraview.simple._DisableFirstRenderCameraReset()
25
26 import os
27 import sys
28 import colorsys
29
30 # Separator of family name
31 ZE_SEP = "@@][@@"
32
33 # Available families
34 FAMILY_CELL = "FamilyIdCell"
35 FAMILY_NODE = "FamilyIdNode"
36
37 ## Extract information about groups, families and IDs of these families from active source proxy.
38 #  @param smProxy The server manager proxy.
39 #  @param mapFamilies The returned map of families and its IDs.
40 #  @param mapGroups The returned map of groups and its families.
41 #  @param mapRelations The returned map of relations between families and groups.
42 #  @return True if all data are generated without errors, False is otherwise.
43 def ExctractSILInformation(smProxy, mapFamilies, mapGroups, mapRelations):
44   # Check access to arguments
45   if not isinstance(mapFamilies, dict) or not isinstance(mapGroups, dict) or not isinstance(mapRelations, dict):
46     raise TypeError("Returned arguments have inappropriate type.")
47
48   # Reset returned values
49   mapFamilies.clear()
50   mapGroups.clear()
51   mapRelations.clear()
52
53   # Gather information about server manager proxy.
54   # Fills up 'silInfo' information with details about VTK object.
55   silInfo = vtkPVSILInformation()
56   smproxy.GatherInformation(silInfo)
57
58   # Get SIL graph (an editable directed graph) as vtkMutableDirectedGraph
59   graph = silInfo.GetSIL()
60   if graph == None:
61     raise RuntimeError("No SIL graph found.")
62
63   # Get vertex data as vtkDataSetAttrbutes
64   vertexData = graph.GetVertexData()
65   if vertexData.GetNumberOfArrays() < 1:
66     raise RuntimeError("No data arrays found.")
67
68   # 'Names' array has 0 index
69   indexNames = 0
70   stringArray = graph.GetVertexData().GetAbstractArray(vertexData.GetArrayName(indexNames))
71   if stringArray == None:
72     raise RuntimeError("Abstract array with '%s' name is not found." % vertexData.GetArrayName(indexNames))
73
74   # Search index for families and groups
75   idx = None
76   isFound = False
77   for index in range(stringArray.GetNumberOfValues()):
78     if stringArray.GetValue(index) == 'MeshesFamsGrps':
79       isFound = True
80       idx = index
81       break
82
83   if not isFound or not idx:
84     raise RuntimeError("No 'MeshesFamsGrps' value in 'Names' array.")
85
86   # Initialize the adjacent vertex iterator to iterate over all outgoing vertices from vertex 'idx',
87   # i.e. the vertices which may be reached by traversing an out edge of the 'idx' vertex.
88   adjacentIterator = vtkAdjacentVertexIterator()
89   adjacentIterator.Initialize(graph, idx)
90   if adjacentIterator.GetVertex() != idx:
91     raise RuntimeError("Initialize the adjacent vertex iterator failed (main '%s')." % idx)
92   
93   while (adjacentIterator.HasNext()):
94     vIdMesh = adjacentIterator.Next()
95     meshName = stringArray.GetValue(vIdMesh)
96
97     adjacentIt_Mesh = vtkAdjacentVertexIterator()
98     graph.GetAdjacentVertices(vIdMesh, adjacentIt_Mesh);
99     if adjacentIt_Mesh.GetVertex() != vIdMesh:
100       raise RuntimeError("Initialize the adjacent vertex iterator failed (mesh '%s')." % vIdMesh)
101
102     # Next edge in the graph associated with groups and its families
103     vId_Groups = adjacentIt_Mesh.Next() # 'zeGrps'
104
105     # Next edge in the graph associated with families and its IDs
106     vId_Families = adjacentIt_Mesh.Next() # 'zeFamIds'
107
108     adjacentIt_Families = vtkAdjacentVertexIterator()
109     graph.GetAdjacentVertices(vId_Families, adjacentIt_Families);
110     if adjacentIt_Families.GetVertex() != vId_Families:
111       raise RuntimeError("Initialize the adjacent vertex iterator failed (families '%s')." % vId_Families)
112
113     # Iterate over all families
114     while adjacentIt_Families.HasNext():
115       vIdFamily = adjacentIt_Families.Next()
116       rawFamilyName = stringArray.GetValue(vIdFamily)
117
118       # Get family name and its ID from raw string
119       splitFamily = rawFamilyName.split(ZE_SEP)
120       if len(splitFamily) != 2:
121         raise RuntimeError("No valid family name [%s]" % rawFamilyName)
122
123       familyName = splitFamily[0]
124       familyID = splitFamily[1]
125       if familyID.lstrip("+-").isdigit() == False:
126         raise RuntimeError("Family [%s] ID is not digit: %s" % (familyName, familyID))
127
128       # Save families and IDs in map
129       mapFamilies[familyName] = int(familyID)
130
131     adjacentIt_Groups = vtkAdjacentVertexIterator()
132     graph.GetAdjacentVertices(vId_Groups, adjacentIt_Groups);
133     if adjacentIt_Groups.GetVertex() != vId_Groups:
134       raise RuntimeError("Initialize the adjacent vertex iterator failed (groups '%s')." % vId_Groups)
135
136     # Iterate over all groups
137     while adjacentIt_Groups.HasNext():
138       vIdGroup = adjacentIt_Groups.Next()
139       groupName = stringArray.GetValue(vIdGroup)
140
141       adjacentIt_FamiliesOnGroups = vtkAdjacentVertexIterator()
142       graph.GetAdjacentVertices(vIdGroup, adjacentIt_FamiliesOnGroups);
143       if adjacentIt_FamiliesOnGroups.GetVertex() != vIdGroup:
144         raise RuntimeError("Initialize the adjacent vertex iterator failed (group '%s')." % vIdGroup)
145
146       familiesOnGroups = []
147       # Iterate over all families on group
148       while adjacentIt_FamiliesOnGroups.HasNext():
149         vIdFamilyOnGroup = adjacentIt_FamiliesOnGroups.Next()
150         familyNameOnGroup = stringArray.GetValue(vIdFamilyOnGroup)
151         familiesOnGroups.append(familyNameOnGroup)
152
153       # Save groups and its families in map
154       mapGroups[groupName] = familiesOnGroups
155
156   # Establish the relations between families and groups
157   for family_name, family_id in mapFamilies.items():
158     groupNames = []
159     for group_name, family_name_on_group in mapGroups.items():
160       if family_name in family_name_on_group:
161         groupNames.append(group_name)
162     if len(groupNames) > 0:
163       mapRelations[family_name] = groupNames
164
165   return True
166
167
168 # Get active source
169 source = GetActiveSource()
170 if source == None:
171   raise RuntimeError("No active source.")
172
173 # Get server manager proxy
174 smproxy = source.SMProxy
175
176 # Check MEDReader class
177 if smproxy.GetVTKClassName() != 'vtkMEDReader':
178   raise RuntimeError("VTK reader type is not supported (%s)." % smproxy.GetVTKClassName())
179
180 # Get render view in use or create new RenderView
181 renderView = GetActiveViewOrCreate('RenderView')
182 if renderView == None:
183   raise RuntimeError("No render view found.")
184
185 # Get representation of active source and view
186 representation = GetDisplayProperties(source, renderView)
187 if not representation:
188   raise RuntimeError("No representation found.")
189
190 # Visibility of source object
191 representation.Visibility = 1
192
193 # Get active or set default colour array name property
194 associationType = None
195 associationColorArray = representation.ColorArrayName.GetAssociation()
196 nameColorArray = representation.ColorArrayName.GetArrayName()
197 if not nameColorArray:
198   # Reset colour array name property
199   representation.ColorArrayName.SetElement(3, None)
200   representation.ColorArrayName.SetElement(4, None)
201
202   nameColorArray = FAMILY_CELL
203   associationType = GetAssociationFromString('CELLS')
204 else:
205   if associationColorArray != None:
206     associationType = GetAssociationFromString(associationColorArray)
207
208 if nameColorArray not in [FAMILY_CELL, FAMILY_NODE]:
209   raise RuntimeError("Selected data array [%s] is not valid." % nameColorArray)
210
211 # Get data information
212 data = Fetch(source)
213 dataArrayValues = []
214 scalarBarlabel = None
215 activeRepresentation = 'Surface'
216 if data.GetDataObjectType() == vtkDataObjectTypes.GetTypeIdFromClassName("vtkMultiBlockDataSet"):
217   if data.GetNumberOfBlocks() < 1:
218     raise RuntimeError("No blocks.")
219
220   blockID = 0
221   dataObject = data.GetBlock(blockID)
222   if not dataObject.IsA("vtkDataSet"):
223     raise RuntimeError("Data object has inappropriate type (%s)" % dataObject.GetDataObjectType())
224
225   if associationType == GetAssociationFromString("CELLS"):
226     cellData = dataObject.GetCellData()
227     if not cellData.HasArray(FAMILY_CELL):
228       raise RuntimeError("Cell data array has no '%s'." % FAMILY_CELL)
229
230     scalarBarlabel = "CELLS"
231     activeRepresentation = 'Surface'
232
233     dataArray = cellData.GetArray(FAMILY_CELL)
234     for tupleId in range(dataArray.GetNumberOfTuples()):
235       dataArrayValues.append(dataArray.GetValue(tupleId))
236
237   elif associationType == GetAssociationFromString("POINTS"):
238     pointData = dataObject.GetPointData()
239     if not pointData.HasArray(FAMILY_NODE):
240       raise RuntimeError("Point data array has no '%s'." % FAMILY_NODE)
241
242     scalarBarlabel = "POINTS"
243     
244     # Check that PointSprite plugin is available
245     if hasattr(representation, "MaxPixelSize"):
246         activeRepresentation = 'Point Sprite'
247         if representation.MaxPixelSize == 64:
248             representation.MaxPixelSize = 8
249     else:
250         activeRepresentation = 'Points'
251
252     dataArray = pointData.GetArray(FAMILY_NODE)
253     for tupleId in range(dataArray.GetNumberOfTuples()):
254       dataArrayValues.append(dataArray.GetValue(tupleId))
255
256   else:
257     raise RuntimeError("Not implemented yet (%s)." % GetAssociationAsString(associationType))
258
259 mapFamilies = dict()
260 mapGroups = dict()
261 mapRelations = dict()
262
263 if not ExctractSILInformation(smproxy, mapFamilies, mapGroups, mapRelations):
264   raise RuntimeError("Extraction SIL graph failed.")
265
266 # Sort families array by ID
267 sortedArray = sorted(list(mapFamilies.values()))
268
269 # Prepare 'Annotation' list for lookup-table
270 numberValues = 0
271 annotationList = []
272 for idFamily in sortedArray:
273   if idFamily not in dataArrayValues:
274     continue
275
276   if associationType == GetAssociationFromString("CELLS"):
277     if idFamily > 0:
278       continue
279   elif associationType == GetAssociationFromString("POINTS"):
280     if idFamily < 0:
281       continue
282   else:
283     raise RuntimeError("Not implemented yet (%s)." % GetAssociationAsString(associationType))
284
285   annotationList.append(str(idFamily))
286   numberValues += 1
287
288   # Iterate over all families to get group(s) by family name
289   for famName, famID in mapFamilies.items():
290     if idFamily == famID:
291       if famName in mapRelations:
292         annotationList.append(str(', ').join(mapRelations.get(famName)))
293       else:
294         annotationList.append(str('No group'))
295
296 # Generate indexed colour for array
297 indexedColor = []
298 # Generate HSV colour from red to blue
299 if numberValues > 1:
300   stepHue = int(240/(numberValues-1))
301 else:
302   stepHue = 0.
303 for i in range(numberValues):
304   indexedColor.extend(colorsys.hsv_to_rgb(float(i*stepHue)/360, 1, 1))
305
306 # Set scalar colouring
307 ColorBy(representation, (GetAssociationAsString(associationType), nameColorArray))
308
309 # Rescale colour and/or opacity maps used to include current data range
310 representation.RescaleTransferFunctionToDataRange(True)
311
312 # Show colour bar/colour legend
313 representation.SetScalarBarVisibility(renderView, True)
314
315 # Change representation type
316 representation.SetPropertyWithName("Representation", activeRepresentation)
317
318 # Get colour transfer function/colour map for 'FamilyIdCell' or 'FamilyIdNode'
319 lutFamily = GetLookupTableForArray(nameColorArray, 1)
320 lutFamily.SetPropertyWithName("ColorSpace", "RGB")
321
322 # Modify lookup table
323 lutFamily.InterpretValuesAsCategories = 1
324 lutFamily.Annotations = annotationList
325 lutFamily.IndexedColors = indexedColor
326 lutFamily.NumberOfTableValues = numberValues
327
328 # Modify scalar bar of view
329 lutScalarBar = GetScalarBar(lutFamily, renderView)
330 lutScalarBar.AddRangeAnnotations = 1
331 lutScalarBar.AddRangeLabels = 0
332 lutScalarBar.DrawAnnotations = 1
333 lutScalarBar.Title = 'Groups of %s' % scalarBarlabel
334
335 Render()