Salome HOME
Fix smesh update upon BreakLink
[modules/shaper_study.git] / src / PY / SHAPERSTUDY.py
1 # Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
2 #
3 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 #
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 #
22
23 import SHAPERSTUDY_ORB__POA
24 import SHAPERSTUDY_ORB
25 import SALOME_ComponentPy
26 import SALOME_DriverPy
27 import SALOMEDS
28 from SHAPERSTUDY_utils import findOrCreateComponent, moduleName, getStudy, getORB
29 import salome
30 import SHAPERSTUDY_Object
31 import SHAPERSTUDY_IOperations
32 import GEOM
33 import SMESH
34
35 __entry2IOR__ = {}
36
37
38 class SHAPERSTUDY(SHAPERSTUDY_ORB__POA.Gen,
39                   SALOME_ComponentPy.SALOME_ComponentPy_i,
40                   SALOME_DriverPy.SALOME_DriverPy_i):
41
42
43     ShapeType = {"AUTO":-1, "COMPOUND":0, "COMPSOLID":1, "SOLID":2, "SHELL":3, "FACE":4, "WIRE":5, "EDGE":6, "VERTEX":7, "SHAPE":8, "FLAT":9}
44     
45     ShaperIcons = {GEOM.COMPOUND:"SHAPER_ICON_COMPSOLID",
46         GEOM.COMPSOLID:"SHAPER_ICON_COMPSOLID",
47         GEOM.SOLID:"SHAPER_ICON_SOLID",
48         GEOM.SHELL:"SHAPER_ICON_SHELL",
49         GEOM.FACE:"SHAPER_ICON_FACE",
50         GEOM.WIRE:"SHAPER_ICON_WIRE",
51         GEOM.EDGE:"SHAPER_ICON_EDGE",
52         GEOM.VERTEX:"SHAPER_ICON_VERTEX",
53         GEOM.SHAPE:"SHAPER_ICON_SOLID",
54         GEOM.FLAT:"SHAPER_ICON_FACE"
55         }
56
57     def __init__ ( self, orb, poa, contID, containerName, instanceName, interfaceName ):
58         """
59         Construct an instance of SHAPERSTUDY module engine.
60         The class SHAPERSTUDY implements CORBA interface Gen (see SHAPERSTUDY_Gen.idl).
61         It is inherited (via GEOM_Gen) from the classes SALOME_ComponentPy_i (implementation of
62         Engines::EngineComponent CORBA interface - SALOME component) and SALOME_DriverPy_i
63         (implementation of SALOMEDS::Driver CORBA interface - SALOME module's engine).
64         """
65         SALOME_ComponentPy.SALOME_ComponentPy_i.__init__(self, orb, poa,
66                     contID, containerName, instanceName, interfaceName, False)
67         SALOME_DriverPy.SALOME_DriverPy_i.__init__(self, interfaceName)
68         #
69         #self._naming_service = SALOME_ComponentPy.SALOME_NamingServicePy_i( self._orb )
70         #
71         pass
72
73     def FindOrCreateShape( self, theInternalEntry ):
74         """
75         Searches existing or creates a new SHAPERSTUDY_Object to interact with SHAPER
76         """
77         # Searching in the study tree
78         aComponent = findOrCreateComponent()
79         aSOIter = getStudy().NewChildIterator(aComponent)
80         while aSOIter.More():
81           aSO = aSOIter.Value()
82           anIOR = aSO.GetIOR()
83           anObj = salome.orb.string_to_object(anIOR)
84           if isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
85             if anObj.GetEntry() == theInternalEntry:
86               return anObj
87           aSOIter.Next()
88
89         aShapeObj = SHAPERSTUDY_Object.SHAPERSTUDY_Object()
90         aShapeObj.SetEntry(theInternalEntry)
91         return aShapeObj._this()
92
93     def AddInStudy( self, theObject, theName, theFather ):
94         """
95         Adds in theStudy a object theObject under theFather with a name theName,
96         if theFather is not NULL the object is placed under theFather's SObject.
97         Returns a SObject where theObject is placed
98         """
99         aStudy = getStudy()
100         aBuilder = aStudy.NewBuilder()
101         isGroup = theObject.GetType() == 37 or theObject.GetType() == 52
102         if not theFather:
103           if isGroup:
104             return None # Group may be added only under the shape-father
105           theFatherSO = findOrCreateComponent()
106         else:
107           theFatherSO = theFather.GetSO()
108         aResultSO = None
109         if isGroup: # add group to the third sub-label or later to keep space for reference and "History"
110           aTag = 3
111           anIter = aStudy.NewChildIterator(theFatherSO)
112           while anIter.More():
113             aCurrentTag = anIter.Value().Tag() + 1
114             if aTag < aCurrentTag:
115               aTag = aCurrentTag
116             anIter.Next()
117           aResultSO = aBuilder.NewObjectToTag(theFatherSO, aTag)
118         else:
119           aResultSO = aBuilder.NewObject(theFatherSO);
120         aResultSO.SetAttrString("AttributeName", theName)
121         if theObject is not None:
122             anIOR = salome.orb.object_to_string(theObject)
123             aResultSO.SetAttrString("AttributeIOR", anIOR)
124             theObject.SetSO(aResultSO)
125           
126             aAttr = aBuilder.FindOrCreateAttribute(aResultSO, "AttributePixMap")
127             aPixmap = aAttr._narrow(salome.SALOMEDS.AttributePixMap)
128             aType = 0
129             if isGroup:
130               aType = SHAPERSTUDY_Object.__shape_types__[theObject.GetSelectionType()]
131             else:
132               aType = theObject.GetShapeType()
133             aPixmap.SetPixMap(self.ShaperIcons[aType])
134             
135         # add a red-reference that means that this is an active reference to SHAPER result
136         if not isGroup:
137           aSub = aBuilder.NewObjectToTag(aResultSO, 1)
138           aBuilder.Addreference(aSub, aResultSO)
139
140         return aResultSO
141
142     def AddSubShape( theMainShape, theIndices ):
143         """
144         Add a sub-shape defined by indices in theIndices
145         (contains unique IDs of sub-shapes inside theMainShape)
146         """
147         # no sub-shapes for the moment
148         go = SHAPERSTUDY_Object()._this()
149         return go
150
151     # For now it is impossible to remove anything from the SHAPER-STUDY
152     def RemoveObject( self, theObject ):
153         """
154         Removes the object from the component
155         """
156         # can not be removed for the moment
157         return
158
159     def GetIFieldOperations( self ):
160         """
161         """
162         return SHAPERSTUDY_IOperations.SHAPERSTUDY_IFieldOperations()._this()
163
164     def GetIGroupOperations( self ):
165         """
166         """
167         return SHAPERSTUDY_IOperations.SHAPERSTUDY_IGroupOperations()._this()
168
169     def GetIShapesOperations( self ):
170         """
171         """
172         return SHAPERSTUDY_IOperations.SHAPERSTUDY_IShapesOperations()._this()
173
174     def GetIMeasureOperations( self ):
175         """
176         """
177         return SHAPERSTUDY_IOperations.SHAPERSTUDY_IMeasureOperations()._this()
178
179     def GetStringFromIOR( self, theObject ):
180         """
181         Returns a string which contains an IOR of the SHAPERSTUDY_Object
182         """
183         IOR = ""
184         if theObject and getORB():
185             IOR = getORB().object_to_string( theObject )
186             pass
187         return IOR
188
189     def GetAllDumpNames( self ):
190         """
191         Returns all names with which Object's was dumped
192         into python script to avoid the same names in SMESH script
193         """
194         return []
195
196     def GetDumpName( self, theStudyEntry ):
197         """
198         Returns a name with which a GEOM_Object was dumped into python script
199
200         Parameters:
201             theStudyEntry is an entry of the Object in the study
202         """
203         return "test"
204
205     def Save( self, component, URL, isMultiFile ):
206         """
207         Saves data: all objects into one file
208         """
209         aResult = "" # string-pairs of internal entries and shape streams
210         aStudy = getStudy()
211         # get all sub-SObjects with IOR defined
212         anIters = [aStudy.NewChildIterator(findOrCreateComponent())]
213         aSOList = []
214         while len(anIters):
215           aLast = anIters[len(anIters) - 1]
216           if aLast.More():
217             aSO = aLast.Value()
218             anIOR = aSO.GetIOR()
219             if len(anIOR):
220               aSOList.append(aSO)
221             anIters.append(aStudy.NewChildIterator(aSO))
222             aLast.Next()
223           else:
224             anIters.remove(aLast)
225
226         for aSO in aSOList: # for each sobject export shapes stream if exists
227           anIOR = aSO.GetIOR()
228           if not len(anIOR):
229             continue
230           anObj = salome.orb.string_to_object(anIOR)
231           if type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Group:
232             if len(aResult):
233               aResult = aResult + '|'
234             # store internal entry, type and list of indices of the group selection (separated by spaces)
235             aResult = aResult + anObj.GetEntry() + "|" + str(anObj.GetSelectionType())
236             aSelList = anObj.GetSelection()
237             aResult = aResult + "|" + str(' '.join(str(anI) for anI in aSelList))
238           elif type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Field:
239             if len(aResult):
240               aResult = aResult + '|'
241             # same as for group, but in addition to the second string part - field specifics
242             aResult = aResult + anObj.GetEntry() + "|" + str(anObj.GetSelectionType())
243             aResult = aResult + " " + str(anObj.GetDataType()) # values type
244             aSteps = anObj.GetSteps()
245             aResult = aResult + " " + str(len(aSteps)) # number of steps
246             aComps = anObj.GetComponents()
247             aResult = aResult + " " + str(len(aComps)) # number of components
248             for aComp in aComps: # components strings: but before remove spaces and '|'
249               aCoded = aComp.replace(" ", "__space__").replace("|", "__vertical_bar__")
250               aResult = aResult + " " + aCoded
251             for aStepNum in range(len(aSteps)):
252               aVals = anObj.GetStep(aStepNum + 1).GetValues()
253               if aStepNum == 0:
254                 aResult = aResult + " " + str(len(aVals)) # first the number of values in the step
255               aResult = aResult + " " + str(anObj.GetStep(aStepNum + 1).GetStamp()) # ID of stamp in step
256               for aVal in aVals:
257                 aResult = aResult + " " + str(aVal) # all values of step
258             aSelList = anObj.GetSelection()
259             aResult = aResult + "|" + str(' '.join(str(anI) for anI in aSelList))
260           elif isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
261             if len(aResult):
262               aResult = aResult + '|'
263             # store internal entry, current and old shapes in BRep format
264             aResult = aResult + anObj.GetEntry() + "|" + anObj.GetShapeStream().decode()
265             aResult = aResult + "|" + anObj.GetOldShapeStream().decode()
266
267         return aResult.encode()
268
269     def Load( self, component, stream, URL, isMultiFile ):
270         """
271         Loads data
272         """
273         global __entry2IOR__
274         __entry2IOR__.clear()
275         aList=stream.decode().split('|')
276         aSubNum = 1
277         anId = ""
278         aNewShapeStream = ""
279         for aSub in aList:
280           if aSubNum == 1:
281             anId = aSub
282             aSubNum = 2
283           elif aSubNum == 2:
284             aNewShapeStream = aSub
285             aSubNum = 3
286           else: # create objects by 3 arguments
287             anObj = None
288             if anId.startswith('group') or (anId.startswith('dead') and anId.count("group") > 0): # group object
289               anObj = SHAPERSTUDY_Object.SHAPERSTUDY_Group()
290               if len(aSub):
291                 anObj.SetSelection([int(anI) for anI in aSub.split(' ')])
292               anObj.SetSelectionType(int(aNewShapeStream))
293             elif anId.startswith('field') or (anId.startswith('dead') and anId.count("field") > 0): # field object
294               anObj = SHAPERSTUDY_Object.SHAPERSTUDY_Field()
295               if len(aSub):
296                 anObj.SetSelection([int(anI) for anI in aSub.split(' ')])
297               aParams = aNewShapeStream.split(" ")
298               anObj.SetSelectionType(int(aParams[0]))
299               aTypeStr = aParams[1]
300               if (aTypeStr == "FDT_Bool"):
301                 anObj.SetValuesType(0)
302               elif (aTypeStr == "FDT_Int"):
303                 anObj.SetValuesType(1)
304               elif (aTypeStr == "FDT_Double"):
305                 anObj.SetValuesType(2)
306               elif (aTypeStr == "FDT_String"):
307                 anObj.SetValuesType(3)
308               aSteps = []
309               aNumSteps = int(aParams[2])
310               for aVal in range(aNumSteps):
311                 aSteps.append(aVal + 1)
312               anObj.SetSteps(aSteps)
313               aCompNum = int(aParams[3])
314               aCompNames = []
315               for aCompNameIndex in range(aCompNum):
316                 aCompName = aParams[4 + aCompNameIndex].replace("__space__", " ").replace("__vertical_bar__", "|")
317                 aCompNames.append(aCompName)
318               anObj.SetComponents(aCompNames)
319               aNumValsInStep = int(aParams[4 + aCompNum])
320               for aStepNum in range(aNumSteps):
321                 aStepStartIndex = 4 + aCompNum + aStepNum * (aNumValsInStep + 1) + 1
322                 aStampId = int(aParams[aStepStartIndex])
323                 aVals = []
324                 for aValIndex in range(aNumValsInStep):
325                   aVals.append(float(aParams[aStepStartIndex + aValIndex + 1]))
326                 anObj.AddFieldStep(aStampId, aStepNum + 1, aVals)
327             else: # shape object by BRep in the stream: set old first then new
328               anObj = SHAPERSTUDY_Object.SHAPERSTUDY_Object()
329               if len(aSub):
330                 anObj.SetShapeByStream(aSub)
331               anObj.SetShapeByStream(aNewShapeStream)
332             if anObj:
333               anObj.SetEntry(anId)
334               anIOR = salome.orb.object_to_string(anObj._this())
335               __entry2IOR__[anId] = anIOR
336             aSubNum = 1
337         return 1
338         
339     def IORToLocalPersistentID(self, sobject, IOR, isMultiFile, isASCII):
340         """
341         Gets persistent ID for the CORBA object.
342         The internal entry of the Object is returned.
343         """
344         anObj = salome.orb.string_to_object(IOR)
345         if anObj and (isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object) or \
346                       isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Field)):
347           return anObj.GetEntry()
348         return ""
349
350     def LocalPersistentIDToIOR(self, sobject, persistentID, isMultiFile, isASCII):
351         "Converts persistent ID of the object to its IOR."
352         global __entry2IOR__
353         if persistentID in __entry2IOR__:
354           aRes = __entry2IOR__[persistentID]
355           if len(aRes): # set SO from the study, the sobject param is temporary, don't store it
356             salome.orb.string_to_object(aRes).SetSO(getStudy().FindObjectID(sobject.GetID()))
357           return aRes
358         return ""
359
360     def DumpPython( self, isPublished, isMultiFile ):
361         """
362         Dump module data to the Python script.
363         """
364         return ("# SHAPER STUDY DUMP".encode(), 1)
365
366
367
368     def CreateGroup( self, theMainShape, theShapeType ):
369         """
370         Creates a new group which will store sub-shapes of theMainShape
371         """
372         return GetIGroupOperations().CreateGroup( theMainShape, theShapeType );
373
374     def ExtractShapes( self, aShape, aType, isSorted = False ):
375         """
376         Extract shapes (excluding the main shape) of given type.
377
378         Parameters:
379             aShape The shape.
380             aType  The shape type (see geompy.ShapeType)
381             isSorted Boolean flag to switch sorting on/off.
382
383         Returns:
384             List of sub-shapes of type aType, contained in aShape.
385         """
386         return [ SHAPERSTUDY_Object()._this() ]
387
388     def GetSubShape( self, aShape, ListOfID ):
389         """
390         Obtain a composite sub-shape of aShape, composed from sub-shapes
391         of aShape, selected by their unique IDs inside aShape
392
393         Parameters:
394             aShape Shape to get sub-shape of.
395             ListOfID List of sub-shapes indices.
396         """
397         return SHAPERSTUDY_Object()._this()
398
399     def GetSubShapeID( self, aShape, aSubShape ):
400         """
401         Obtain unique ID of sub-shape aSubShape inside aShape
402         of aShape, selected by their unique IDs inside aShape
403
404         Parameters:
405            aShape Shape to get sub-shape of.
406            aSubShape Sub-shapes of aShape.
407         """
408         return 1
409
410     def MinDistance( self, theShape1, theShape2 ):
411         """
412         Get minimal distance between the given shapes.
413         """
414         return 0.
415
416     def NumberOfEdges( self, theShape ):
417         """
418         Gives quantity of edges in the given shape.
419         """
420         return 0
421
422     def NumberOfFaces( self,  ):
423         """
424         Gives quantity of faces in the given shape.
425         """
426         return 0
427
428     def PointCoordinates( self, theVertex ):
429         """
430         Get point coordinates
431         """
432         return 0,0,0
433
434     def SubShapeAll( self, aShape, aType ):
435         """
436         Explode a shape on sub-shapes of a given type.
437         If the shape itself matches the type, it is also returned.
438         """
439         return [ SHAPERSTUDY_Object()._this() ]
440
441     def SubShapeName( self, aSubObj, aMainObj ):
442         """
443         Get name for sub-shape aSubObj of shape aMainObj
444         """
445         return ""
446
447     def SubShapes( self, aShape, anIDs ):
448         """
449         Get a set of sub-shapes defined by their unique IDs inside theMainShape
450         """
451         return  [ SHAPERSTUDY_Object()._this() ]
452
453     def Tolerance( self, theShape ):
454         """
455         Get min and max tolerances of sub-shapes of theShape
456
457         Returns:
458             [FaceMin,FaceMax, EdgeMin,EdgeMax, VertMin,VertMax]
459         """
460         return [0,0, 0,0, 0,0]
461
462     def UnionList( self, theGroup, theSubShapes ):
463         """
464         Adds to the group all the given shapes. No errors, if some shapes are already included.
465         """
466         return GetIGroupOperations().UnionList( theGroup, theSubShapes )
467
468     def IsFather(theFather, theChild):
469         """
470         Returns true if theChild SObject is a child of theFather SObject
471         """
472         aChild = theChild.GetFather()
473         while aChild.Depth() > theFather.Depth():
474           aChild = aChild.GetFather()
475         return aChild.GetID() == theFather.GetID()
476
477     def BreakLink(self, theEntry):
478         """
479         Breaks links to not-dead shape, make the shape as dead
480         """
481         aStudy = getStudy()
482         aSO = aStudy.FindObjectID(theEntry)
483         if not aSO:
484           return
485         aRes, aSSO = aSO.ReferencedObject()
486         if not aRes:
487           return # only SObjects referenced to the SHAPEr STUDY objects are allowed
488         anIOR = aSSO.GetIOR()
489         if not anIOR:
490           return # must be referenced to the SHAPER STUDY shape
491         anObj = salome.orb.string_to_object(anIOR)
492         if not anObj or not isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
493           return
494         if anObj.IsDead():
495           return # do nothing for reference to already dead shape
496         aDeadShape = anObj.MakeDead()
497         
498         aBuilder = aStudy.NewBuilder()
499         aBuilder.RemoveReference(aSO) # reset reference to the dead shape
500         aBuilder.Addreference(aSO, aDeadShape.GetSO())
501
502         # Replace shape object in the parent mesh
503         aMeshSObject = aSO.GetFather()
504         aMeshObject = aMeshSObject.GetObject()
505         aMeshObject.ReplaceShape(aDeadShape)
506        
507         # check also sub-structure of the mesh to find references to sub-objects that become dead
508         aRoot = aSO.GetFather()
509         anIters = [aStudy.NewChildIterator(aRoot)]
510         aSubList = []
511         while len(anIters):
512           aLast = anIters[len(anIters) - 1]
513           if aLast.More():
514             aSub = aLast.Value()
515             aRes, aSubRef = aSub.ReferencedObject()
516             if aRes and SHAPERSTUDY.IsFather(aSSO, aSubRef):
517               aReferenced = aSubRef.GetObject()
518               if aReferenced and not aReferenced.IsDead():
519                 aSubList.append(aSub)
520             anIters.append(aStudy.NewChildIterator(aSub))
521             aLast.Next()
522           else:
523             anIters.remove(aLast)
524         if len(aSubList):
525           # associate the number of sub-objects of the referenced objects
526           aMapSubEntryToIndex = {}
527           aSSOIter = aStudy.NewChildIterator(aSSO)
528           anIndex = 1
529           while aSSOIter.More():
530             aSub = aSSOIter.Value()
531             if aSub.GetIOR():
532               aMapSubEntryToIndex[aSub.GetID()] = anIndex
533               anIndex = anIndex + 1
534             aSSOIter.Next()
535           for aSubSO in aSubList:
536             aRes, aSubRef = aSubSO.ReferencedObject()
537             if aRes and aSubRef.GetID() in aMapSubEntryToIndex:
538               anIndex = aMapSubEntryToIndex[aSubRef.GetID()]
539               aDeadIter = aStudy.NewChildIterator(aDeadShape.GetSO())
540               while aDeadIter.More(): # iterate dead subs to find object with the same index
541                 aDeadSubSO = aDeadIter.Value()
542                 if aDeadSubSO.GetIOR():
543                   anIndex = anIndex - 1
544                   if anIndex == 0:
545                     # for a submesh there is no ReplaceShape, but the shape is not updated
546                     # anyway, so no need to update it here
547                     #aSubMeshSO = aSubSO.GetFather() # Replace shape object in the parent mesh
548                     #aSubMeshObject = aSubMeshSO.GetObject()
549                     #if aSubMeshObject:
550                     #  aSubMeshObject.ReplaceShape(aDeadSubSO.GetObject())
551                     aBuilder.RemoveReference(aSubSO) # reset reference to the dead shape
552                     aBuilder.Addreference(aSubSO, aDeadSubSO)
553                 aDeadIter.Next()