Salome HOME
updated copyright message
[modules/med.git] / src / MEDCalc / tui / medpresentation.py
1 # Copyright (C) 2011-2023  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
20 import medcalc
21 import MEDCALC, SALOME
22 from medcalc.medevents import notifyGui_addPresentation, notifyGui_removePresentation, notifyGui_error, notifyGui_modifyPresentation, notifyGui_visibilityChanged
23 from functools import reduce
24 import pvsimple as pvs
25
26 __manager = medcalc.medcorba.factory.getPresentationManager()
27 DEFAULT_VISIBILITY = True
28 DEFAULT_SCALAR_BAR_VISIBILITY = True
29 DEFAULT_USE_CUSTOM_RANGE = False
30 DEFAULT_SCALAR_BAR_RANGE = [0.0, 100.0]
31 DEFAULT_PLANE_NORMAL = [0.0, 0.0, 1.0]
32 DEFAULT_PLANE_POS = 1.0
33 DEFAULT_SCALE_FACTOR = 0.2
34 DEFAULT_CUT_POINT1 = [0.0, 0.0, 0.0]
35 DEFAULT_CUT_POINT2 = [1.0, 1.0, 1.0]
36 DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE = False
37 DEFAULT_CUSTOM_SCALE_FACTOR = False
38 DEFAULT_CONTOUR_COMPONENT = ""
39
40 def MakeMeshView(meshID,
41                  viewMode=MEDCALC.VIEW_MODE_DEFAULT,
42                  meshMode=MEDCALC.MESH_MODE_DEFAULT):
43   # Create the presentation instance in CORBA engine
44   # The engine in turn creates the ParaView pipeline elements
45   visibility=True
46   params = MEDCALC.MeshViewParameters(meshID, meshMode, visibility)
47   try:
48     presentation_id = __manager.makeMeshView(params, viewMode)
49     notifyGui_addPresentation(meshID, presentation_id)
50     return presentation_id
51   except SALOME.SALOME_Exception as e:
52     notifyGui_error("An error occurred while creating the mesh view:\n" + e.details.text)
53     raise Exception(e.details.text)
54
55
56 def MakeScalarMap(proxy,
57                   viewMode=MEDCALC.VIEW_MODE_DEFAULT,
58                   displayedComponent=MEDCALC.DISPLAY_DEFAULT,
59                   scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
60                   colorMap=MEDCALC.COLOR_MAP_DEFAULT
61                   ):
62   # Create the presentation instance in CORBA engine
63   # The engine in turn creates the ParaView pipeline elements
64   visibility = DEFAULT_VISIBILITY
65   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
66   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
67   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
68   params = MEDCALC.ScalarMapParameters(proxy.id, displayedComponent, scalarBarRange, colorMap, visibility,
69                                        scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange)
70   try:
71     presentation_id = __manager.makeScalarMap(params, viewMode)
72     notifyGui_addPresentation(proxy.id, presentation_id)
73     return presentation_id
74   except SALOME.SALOME_Exception as e:
75     notifyGui_error("An error occurred while creating the scalar map:\n" + e.details.text)
76     raise Exception(e.details.text)
77
78 def MakeContour(proxy,
79                 viewMode=MEDCALC.VIEW_MODE_DEFAULT,
80                 scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
81                 colorMap=MEDCALC.COLOR_MAP_DEFAULT,
82                 nbContours=MEDCALC.NB_CONTOURS_DEFAULT
83                 ):
84   visibility = DEFAULT_VISIBILITY
85   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
86   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
87   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
88   contourComponent = DEFAULT_CONTOUR_COMPONENT
89   params = MEDCALC.ContourParameters(proxy.id, scalarBarRange, colorMap, visibility, scalarBarVisibility,
90                                      scalarBarRangeArray, hideDataOutsideCustomRange, nbContours, contourComponent)
91   try:
92     presentation_id = __manager.makeContour(params, viewMode)
93     notifyGui_addPresentation(proxy.id, presentation_id)                           
94     return presentation_id
95   except SALOME.SALOME_Exception as e:
96     notifyGui_error("An error occurred while creating the contour:\n" + e.details.text)
97     raise Exception(e.details.text)
98
99 #
100
101 def MakeVectorField(proxy,
102                   viewMode=MEDCALC.VIEW_MODE_DEFAULT,
103                   scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
104                   colorMap=MEDCALC.COLOR_MAP_DEFAULT
105                   ):
106   # Create the presentation instance in CORBA engine
107   # The engine in turn creates the ParaView pipeline elements
108   visibility = DEFAULT_VISIBILITY
109   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
110   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
111   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
112   scaleFactor = DEFAULT_SCALE_FACTOR
113   customScaleFactor = DEFAULT_CUSTOM_SCALE_FACTOR
114   params = MEDCALC.VectorFieldParameters(proxy.id, scalarBarRange, colorMap, visibility, scalarBarVisibility,
115                                          scalarBarRangeArray, hideDataOutsideCustomRange, scaleFactor, customScaleFactor)
116   try:
117     presentation_id = __manager.makeVectorField(params, viewMode)
118     notifyGui_addPresentation(proxy.id, presentation_id)
119     return presentation_id
120   except SALOME.SALOME_Exception as e:
121     notifyGui_error("An error occurred while creating the vector field:\n" + e.details.text)
122     raise Exception(e.details.text)
123
124 def MakeSlices(proxy,
125                 viewMode=MEDCALC.VIEW_MODE_DEFAULT,
126                 displayedComponent=MEDCALC.DISPLAY_DEFAULT,
127                 scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
128                 colorMap=MEDCALC.COLOR_MAP_DEFAULT,
129                 sliceOrientation=MEDCALC.SLICE_ORIENTATION_DEFAULT,
130                 nbSlices=MEDCALC.NB_SLICES_DEFAULT):
131   # Create the presentation instance in CORBA engine
132   # The engine in turn creates the ParaView pipeline elements
133   visibility = DEFAULT_VISIBILITY
134   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
135   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
136   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
137   params = MEDCALC.SlicesParameters(proxy.id, displayedComponent,scalarBarRange, colorMap, visibility,
138                                     scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange,
139                                     sliceOrientation, nbSlices)
140   try:
141     presentation_id = __manager.makeSlices(params, viewMode)
142     notifyGui_addPresentation(proxy.id, presentation_id)
143     return presentation_id
144   except SALOME.SALOME_Exception as e:
145     notifyGui_error("An error occurred while creating the slices:\n" + e.details.text)
146     raise Exception(e.details.text)
147
148
149 def MakeDeflectionShape(proxy,
150                   viewMode=MEDCALC.VIEW_MODE_DEFAULT,
151                   scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
152                   colorMap=MEDCALC.COLOR_MAP_DEFAULT
153                   ):
154   # Create the presentation instance in CORBA engine
155   # The engine in turn creates the ParaView pipeline elements
156   visibility = DEFAULT_VISIBILITY
157   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
158   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
159   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
160   params = MEDCALC.DeflectionShapeParameters(proxy.id, scalarBarRange, colorMap, visibility,
161                                     scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange)
162   try:
163     presentation_id = __manager.makeDeflectionShape(params, viewMode)
164     notifyGui_addPresentation(proxy.id, presentation_id)
165     return presentation_id
166   except SALOME.SALOME_Exception as e:
167     notifyGui_error("An error occurred while creating the deflection shape:\n" + e.details.text)
168     raise Exception(e.details.text)
169
170
171 def MakePointSprite(proxy,
172                   viewMode=MEDCALC.VIEW_MODE_DEFAULT,
173                   displayedComponent=MEDCALC.DISPLAY_DEFAULT,
174                   scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
175                   colorMap=MEDCALC.COLOR_MAP_DEFAULT
176                   ):
177   # Create the presentation instance in CORBA engine
178   # The engine in turn creates the ParaView pipeline elements
179   visibility = DEFAULT_VISIBILITY
180   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
181   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
182   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
183   params = MEDCALC.PointSpriteParameters(proxy.id, displayedComponent, scalarBarRange, colorMap, visibility,
184                                          scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange)
185   try:
186     presentation_id = __manager.makePointSprite(params, viewMode)
187     notifyGui_addPresentation(proxy.id, presentation_id)
188     return presentation_id
189   except SALOME.SALOME_Exception as e:
190     notifyGui_error("An error occurred while creating the point sprite:\n" + e.details.text)
191     raise Exception(e.details.text)
192
193 # sphinx doc: begin of MakePlot3D
194 def MakePlot3D(proxy,
195               viewMode=MEDCALC.VIEW_MODE_DEFAULT,
196               scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
197               colorMap=MEDCALC.COLOR_MAP_DEFAULT
198               ):
199   # Create the presentation instance in CORBA engine
200   # The engine in turn creates the ParaView pipeline elements
201   visibility = DEFAULT_VISIBILITY
202   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
203   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
204   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
205   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
206   planeNormal = DEFAULT_PLANE_NORMAL
207   planePos = DEFAULT_PLANE_POS
208   params = MEDCALC.Plot3DParameters(proxy.id, scalarBarRange, colorMap, visibility,
209                                     scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange, planeNormal, planePos)
210   try:
211     presentation_id = __manager.makePlot3D(params, viewMode)
212     notifyGui_addPresentation(proxy.id, presentation_id)
213     return presentation_id
214   except SALOME.SALOME_Exception as e:
215     notifyGui_error("An error occurred while creating the Plot3D:\n" + e.details.text)
216     raise Exception(e.details.text)
217 # sphinx doc: end of MakePlot3D
218
219 def MakeStreamLines(proxy,
220               viewMode=MEDCALC.VIEW_MODE_DEFAULT,
221               scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
222               colorMap=MEDCALC.COLOR_MAP_DEFAULT
223               ):
224   # Create the presentation instance in CORBA engine
225   # The engine in turn creates the ParaView pipeline elements
226   visibility = DEFAULT_VISIBILITY
227   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
228   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
229   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
230   integrDir = MEDCALC.INTEGRATION_DIR_DEFAULT
231   params = MEDCALC.StreamLinesParameters(proxy.id, scalarBarRange, colorMap, visibility,
232                                     scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange, integrDir)
233   try:
234     presentation_id = __manager.makeStreamLines(params, viewMode)
235     notifyGui_addPresentation(proxy.id, presentation_id)
236     return presentation_id
237   except SALOME.SALOME_Exception as e:
238     notifyGui_error("An error occurred while creating the StreamLines:\n" + e.details.text)
239     raise Exception(e.details.text)
240
241
242 def MakeCutSegment(proxy,
243               viewMode=MEDCALC.VIEW_MODE_DEFAULT,
244               scalarBarRange=MEDCALC.SCALAR_BAR_RANGE_DEFAULT,
245               colorMap=MEDCALC.COLOR_MAP_DEFAULT
246               ):
247   # Create the presentation instance in CORBA engine
248   # The engine in turn creates the ParaView pipeline elements
249   visibility = DEFAULT_VISIBILITY
250   scalarBarVisibility = DEFAULT_SCALAR_BAR_VISIBILITY
251   hideDataOutsideCustomRange = DEFAULT_HIDE_DATA_OUTSIDE_CUSTOM_RANGE
252   scalarBarRangeArray = DEFAULT_SCALAR_BAR_RANGE
253   point1 = DEFAULT_CUT_POINT1
254   point2 = DEFAULT_CUT_POINT2
255   params = MEDCALC.CutSegmentParameters(proxy.id, scalarBarRange, colorMap, visibility,
256                                         scalarBarVisibility, scalarBarRangeArray, hideDataOutsideCustomRange, point1, point2)
257   try:
258     presentation_id = __manager.makeCutSegment(params, viewMode)
259     notifyGui_addPresentation(proxy.id, presentation_id)
260     return presentation_id
261   except SALOME.SALOME_Exception as e:
262     notifyGui_error("An error occurred while creating the CutSegment:\n" + e.details.text)
263     raise Exception(e.details.text)
264
265
266 def RemovePresentation(presentation_id):
267   ok = __manager.removePresentation(presentation_id)
268   if ok:
269     notifyGui_removePresentation(presentation_id)
270 #
271
272 def __GetGENERICParameters(tag, presentation_id):
273   exec("params = __manager.get%sParameters(presentation_id)" % tag)
274   return locals()['params']
275
276 GetMeshViewParameters = lambda pres_id: __GetGENERICParameters("MeshView", pres_id)
277 GetScalarMapParameters = lambda pres_id: __GetGENERICParameters("ScalarMap", pres_id)
278 GetContourParameters = lambda pres_id: __GetGENERICParameters("Contour", pres_id)
279 GetSlicesParameters = lambda pres_id: __GetGENERICParameters("Slices", pres_id)
280 GetPointSpriteParameters = lambda pres_id: __GetGENERICParameters("PointSprite", pres_id)
281 GetVectorFieldParameters = lambda pres_id: __GetGENERICParameters("VectorField", pres_id)
282 GetDeflectionShapeParameters = lambda pres_id: __GetGENERICParameters("DeflectionShape", pres_id)
283 # sphinx doc: begin of GetPlot3DParameters
284 GetPlot3DParameters = lambda pres_id: __GetGENERICParameters("Plot3D", pres_id)
285 # sphinx doc: end of GetPlot3DParameters
286 GetStreamLinesParameters = lambda pres_id: __GetGENERICParameters("StreamLines", pres_id)
287 GetCutSegmentParameters = lambda pres_id: __GetGENERICParameters("CutSegment", pres_id)
288
289
290 def __UpdateGENERIC(tag, presentation_id, params):
291   old_params = __GetGENERICParameters(tag, presentation_id)
292   exec("__manager.update%s(presentation_id, params)" % tag)
293   notifyGui_modifyPresentation(presentation_id)
294   if old_params.visibility != params.visibility:
295     # visibility is changed
296     notifyGui_visibilityChanged(presentation_id)
297
298 UpdateMeshView = lambda pres_id, params: __UpdateGENERIC("MeshView", pres_id, params)
299 UpdateScalarMap = lambda pres_id, params: __UpdateGENERIC("ScalarMap", pres_id, params)
300 UpdateContour = lambda pres_id, params: __UpdateGENERIC("Contour", pres_id, params)
301 UpdateSlices = lambda pres_id, params: __UpdateGENERIC("Slices", pres_id, params)
302 UpdateVectorField = lambda pres_id, params: __UpdateGENERIC("VectorField", pres_id, params)
303 UpdatePointSprite = lambda pres_id, params: __UpdateGENERIC("PointSprite", pres_id, params)
304 UpdateDeflectionShape = lambda pres_id, params: __UpdateGENERIC("DeflectionShape", pres_id, params)
305 # sphinx doc: begin of UpdatePlot3D
306 UpdatePlot3D = lambda pres_id, params: __UpdateGENERIC("Plot3D", pres_id, params)
307 # sphinx doc: end of UpdatePlot3D
308 UpdateStreamLines = lambda pres_id, params: __UpdateGENERIC("StreamLines", pres_id, params)
309 UpdateCutSegment = lambda pres_id, params: __UpdateGENERIC("CutSegment", pres_id, params)
310
311
312 def get_bound_project(bound_box, planeNormal):
313   """Get bounds projection"""
314   EPS = 1E-3
315
316   def dot_product(a, b):
317     """Dot product of two 3-vectors."""
318     dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
319     return dot
320
321   bound_points = [[bound_box[1], bound_box[2], bound_box[4]],
322                   [bound_box[0], bound_box[3], bound_box[4]],
323                   [bound_box[0], bound_box[2], bound_box[5]]]
324   print(bound_points)
325
326   bound_prj = [0.0, 0.0, 0.0]
327
328   for i in range(0, 3):
329     tmp = dot_product(planeNormal, bound_points[i])
330     bound_prj[i] = tmp
331
332   return bound_prj
333
334
335 def GetPositions(obj, planeNormal, displacement):
336   """Compute plane positions."""
337   positions = []
338   bounds = obj.GetDataInformation().GetBounds()
339   bound_prj = get_bound_project(bounds, planeNormal)
340   positions = [i * displacement for i in bound_prj]
341   return positions
342
343 def IsPlanarObj(obj):
344   """
345   Check if the given input is planar
346   """
347   bounds_info = obj.GetDataInformation().GetBounds()
348   FLT_MIN = 1E-37
349
350   if (abs(bounds_info[0] - bounds_info[1]) <= FLT_MIN or
351     abs(bounds_info[2] - bounds_info[3]) <= FLT_MIN or
352     abs(bounds_info[4] - bounds_info[5]) <= FLT_MIN):
353     return True
354
355   return False
356
357 def GetPlaneNormalVector(obj):
358   """Get Normal Vector"""
359   bounds = obj.GetDataInformation().GetBounds()
360   FLT_MIN = 1E-37
361
362   if abs(bounds[4] - bounds[5]) <= FLT_MIN:
363     p0 = [bounds[0], bounds[2], 0]
364     p1 = [bounds[1], bounds[2], 0]
365     p2 = [bounds[0], bounds[3], 0]
366   elif abs(bounds[2] - bounds[3]) <= FLT_MIN:
367     p0 = [bounds[0], 0, bounds[4]]
368     p1 = [bounds[1], 0, bounds[4]]
369     p2 = [bounds[0], 0, bounds[5]]
370   else:
371     p0 = [0, bounds[2], bounds[4]]
372     p1 = [0, bounds[3], bounds[4]]
373     p2 = [0, bounds[2], bounds[5]]
374   
375   x0, y0, z0 = p0
376   x1, y1, z1 = p1
377   x2, y2, z2 = p2
378   ux, uy, uz = u = [x1-x0, y1-y0, z1-z0]
379   vx, vy, vz = v = [x2-x0, y2-y0, z2-z0]
380   u_cross_v = [uy*vz-uz*vy, uz*vx-ux*vz, ux*vy-uy*vx]
381
382   return u_cross_v
383
384 def ComputeCellAverageSize(obj):
385   """
386   @return the average cell size
387   """
388   bb, nCells = obj.GetDataInformation().GetBounds(), obj.GetDataInformation().GetNumberOfCells()
389   bb = list(zip(bb[::2], bb[1::2]))
390   deltas = [x[1]-x[0] for x in bb]
391   ## Filter out null dimensions:
392   avgDelta = sum(deltas) / 3.0
393   deltas = [d for d in deltas if abs(d) > 1.0e-12*avgDelta]
394   ##
395   vol = reduce(lambda x,y:x*y, deltas, 1.0) 
396   cellSize = (vol/nCells)**(1.0/float(len(deltas)))
397   return cellSize
398
399 def GetDomainCenter(obj):
400   """
401   @return the center of the domain as the central point of the bounding box
402   """
403   bb = obj.GetDataInformation().GetBounds()
404   bb = list(zip(bb[::2], bb[1::2]))
405   mids = [x[0] + 0.5*(x[1]-x[0]) for x in bb]
406   return mids
407
408 def GetSliceOrigins(obj, nbSlices, normal):
409   """
410   Compute all origin points for the position of the slices.
411   @param normal is a list of 3 floats either 0 or 1 indicating the normal vector of the slices
412   """
413   from math import sqrt
414   bb = obj.GetDataInformation().GetBounds()
415   bb = list(zip(bb[::2], bb[1::2]))
416   origin = [x[0] + 0.5*(x[1]-x[0]) for x in bb]
417   deltas = [x[1]-x[0] for x in bb]
418   # Compute extent of slices:
419   l = [normal[i]*deltas[i]**2 for i in range(3)]   # either the X extend, or the XY diagonal, or the XYZ diagonal
420   plus = lambda x,y: x+y
421   extent = sqrt(reduce(plus, l, 0.0))
422   norm = sqrt(reduce(plus, normal, 0.0))
423   normal = [normal[i]/norm for i in range(3)]
424   origins = []
425   step = extent/nbSlices
426   for j in range(nbSlices):
427     orig_j = [origin[i]+normal[i]*(-0.5*extent + step*(0.5+j)) for i in range(3)]
428     origins.append(orig_j)
429   return origins
430
431 def SelectSourceField(obj, meshName, fieldName, discretisation):
432   """
433   Properly set the AllArrays property of a MEDReader source to point to the correct field.
434   Setting the fieldName to void string is allowed (meaning we work on the mesh only).
435   """
436   if fieldName == "":
437     return
438   tree = obj.GetProperty("FieldsTreeInfo")[::2]
439   it = None
440   for t in tree:
441     arr = t.split("/")
442     arr = arr[:-1] + arr[-1].split("@@][@@")
443     if arr[1] == meshName and arr[3] == fieldName and arr[4] == discretisation:
444       obj.FieldsStatus = [t]
445       return
446   raise Exception("Field not found")
447
448
449 def FindOrCreateView(vtype):
450   """
451   Find and active or create a view with type vtype
452   """
453   result = None
454   view = pvs.GetActiveView()
455   if not view:
456     result = pvs.GetActiveViewOrCreate(vtype)
457   else:  
458     if view.SMProxy.GetXMLName() == vtype:
459       result = view
460     else:
461       layout1 = pvs.GetLayout(view)
462       views = pvs.GetViewsInLayout(layout1)
463       view = next((v for v in views if v.SMProxy.GetXMLName() == vtype), None)
464       if view is None:
465         result = pvs.CreateView(vtype)
466         pvs.AssignViewToLayout(view=view, layout=layout1, hint=0)
467       else:
468         pvs.SetActiveView(view)
469         result = view
470   return result