1 # Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE
3 # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 import SHAPERSTUDY_ORB__POA
24 import SHAPERSTUDY_ORB
25 import SALOME_ComponentPy
26 import SALOME_DriverPy
28 from SHAPERSTUDY_utils import findOrCreateComponent, moduleName, getStudy, getORB
30 import SHAPERSTUDY_Object
31 import SHAPERSTUDY_IOperations
38 __entry2DumpName__ = {}
40 class SHAPERSTUDY(SHAPERSTUDY_ORB__POA.Gen,
41 SALOME_ComponentPy.SALOME_ComponentPy_i,
42 SALOME_DriverPy.SALOME_DriverPy_i):
45 ShapeType = {"AUTO":-1, "COMPOUND":0, "COMPSOLID":1, "SOLID":2, "SHELL":3, "FACE":4, "WIRE":5, "EDGE":6, "VERTEX":7, "SHAPE":8, "FLAT":9}
47 ShaperIcons = {GEOM.COMPOUND:"SHAPER_ICON_COMPSOLID",
48 GEOM.COMPSOLID:"SHAPER_ICON_COMPSOLID",
49 GEOM.SOLID:"SHAPER_ICON_SOLID",
50 GEOM.SHELL:"SHAPER_ICON_SHELL",
51 GEOM.FACE:"SHAPER_ICON_FACE",
52 GEOM.WIRE:"SHAPER_ICON_WIRE",
53 GEOM.EDGE:"SHAPER_ICON_EDGE",
54 GEOM.VERTEX:"SHAPER_ICON_VERTEX",
55 GEOM.SHAPE:"SHAPER_ICON_SOLID",
56 GEOM.FLAT:"SHAPER_ICON_FACE"
59 def __init__ ( self, orb, poa, contID, containerName, instanceName, interfaceName ):
61 Construct an instance of SHAPERSTUDY module engine.
62 The class SHAPERSTUDY implements CORBA interface Gen (see SHAPERSTUDY_Gen.idl).
63 It is inherited (via GEOM_Gen) from the classes SALOME_ComponentPy_i (implementation of
64 Engines::EngineComponent CORBA interface - SALOME component) and SALOME_DriverPy_i
65 (implementation of SALOMEDS::Driver CORBA interface - SALOME module's engine).
67 SALOME_ComponentPy.SALOME_ComponentPy_i.__init__(self, orb, poa,
68 contID, containerName, instanceName, interfaceName, False)
69 SALOME_DriverPy.SALOME_DriverPy_i.__init__(self, interfaceName)
71 #self._naming_service = SALOME_ComponentPy.SALOME_NamingServicePy_i( self._orb )
75 def FindOrCreateShape( self, theInternalEntry ):
77 Searches existing or creates a new SHAPERSTUDY_Object to interact with SHAPER
79 # Searching in the study tree
80 aComponent = findOrCreateComponent()
81 aSOIter = getStudy().NewChildIterator(aComponent)
85 anObj = salome.orb.string_to_object(anIOR)
86 if isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
87 if anObj.GetEntry() == theInternalEntry:
91 aShapeObj = SHAPERSTUDY_Object.SHAPERSTUDY_Object()
92 aShapeObj.SetEntry(theInternalEntry)
93 return aShapeObj._this()
95 def AddInStudy( self, theObject, theName, theFather ):
97 Adds in theStudy a object theObject under theFather with a name theName,
98 if theFather is not NULL the object is placed under theFather's SObject.
99 Returns a SObject where theObject is placed
101 if not theObject.GetEntry():
102 return None # object not existing in shaper
104 aBuilder = aStudy.NewBuilder()
105 isGroup = theObject.GetType() == 37 or theObject.GetType() == 52
108 return None # Group may be added only under the shape-father
109 theFatherSO = findOrCreateComponent()
111 theFatherSO = theFather.GetSO()
113 if isGroup: # add group to the third sub-label or later to keep space for reference and "History"
115 anIter = aStudy.NewChildIterator(theFatherSO)
117 aCurrentTag = anIter.Value().Tag() + 1
118 if aTag < aCurrentTag:
121 aResultSO = aBuilder.NewObjectToTag(theFatherSO, aTag)
123 aResultSO = aBuilder.NewObject(theFatherSO);
124 aResultSO.SetAttrString("AttributeName", theName)
125 if theObject is not None:
126 anIOR = salome.orb.object_to_string(theObject)
127 aResultSO.SetAttrString("AttributeIOR", anIOR)
128 theObject.SetSO(aResultSO)
130 aAttr = aBuilder.FindOrCreateAttribute(aResultSO, "AttributePixMap")
131 aPixmap = aAttr._narrow(salome.SALOMEDS.AttributePixMap)
134 aType = SHAPERSTUDY_Object.__shape_types__[theObject.GetSelectionType()]
136 aType = theObject.GetShapeType()
137 aPixmap.SetPixMap(self.ShaperIcons[aType])
139 # add a red-reference that means that this is an active reference to SHAPER result
141 aSub = aBuilder.NewObjectToTag(aResultSO, 1)
142 aBuilder.Addreference(aSub, aResultSO)
146 def AddSubShape( theMainShape, theIndices ):
148 Add a sub-shape defined by indices in theIndices
149 (contains unique IDs of sub-shapes inside theMainShape)
151 # no sub-shapes for the moment
152 go = SHAPERSTUDY_Object()._this()
155 # For now it is impossible to remove anything from the SHAPER-STUDY
156 def RemoveObject( self, theObject ):
158 Removes the object from the component
160 # can not be removed for the moment
163 def GetIFieldOperations( self ):
166 return SHAPERSTUDY_IOperations.SHAPERSTUDY_IFieldOperations()._this()
168 def GetIGroupOperations( self ):
171 return SHAPERSTUDY_IOperations.SHAPERSTUDY_IGroupOperations()._this()
173 def GetIShapesOperations( self ):
176 return SHAPERSTUDY_IOperations.SHAPERSTUDY_IShapesOperations()._this()
178 def GetIMeasureOperations( self ):
181 return SHAPERSTUDY_IOperations.SHAPERSTUDY_IMeasureOperations()._this()
183 def GetStringFromIOR( self, theObject ):
185 Returns a string which contains an IOR of the SHAPERSTUDY_Object
188 if theObject and getORB():
189 IOR = getORB().object_to_string( theObject )
193 def Save( self, component, URL, isMultiFile ):
195 Saves data: all objects into one file
197 aResult = "" # string-pairs of internal entries and shape streams
199 # get all sub-SObjects with IOR defined
200 anIters = [aStudy.NewChildIterator(findOrCreateComponent())]
203 aLast = anIters[len(anIters) - 1]
209 anIters.append(aStudy.NewChildIterator(aSO))
212 anIters.remove(aLast)
214 for aSO in aSOList: # for each sobject export shapes stream if exists
218 anObj = salome.orb.string_to_object(anIOR)
219 if type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Group:
221 aResult = aResult + '|'
222 # store internal entry, type and list of indices of the group selection (separated by spaces)
223 aResult = aResult + anObj.GetEntry() + "|" + str(anObj.GetSelectionType())
224 aSelList = anObj.GetSelection()
225 aResult = aResult + "|" + str(' '.join(str(anI) for anI in aSelList))
226 elif type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Field:
228 aResult = aResult + '|'
229 # same as for group, but in addition to the second string part - field specifics
230 aResult = aResult + anObj.GetEntry() + "|" + str(anObj.GetSelectionType())
231 aResult = aResult + " " + str(anObj.GetDataType()) # values type
232 aSteps = anObj.GetSteps()
233 aResult = aResult + " " + str(len(aSteps)) # number of steps
234 aComps = anObj.GetComponents()
235 aResult = aResult + " " + str(len(aComps)) # number of components
236 for aComp in aComps: # components strings: but before remove spaces and '|'
237 aCoded = aComp.replace(" ", "__space__").replace("|", "__vertical_bar__")
238 aResult = aResult + " " + aCoded
239 for aStepNum in range(len(aSteps)):
240 aVals = anObj.GetStep(aStepNum + 1).GetValues()
242 aResult = aResult + " " + str(len(aVals)) # first the number of values in the step
243 aResult = aResult + " " + str(anObj.GetStep(aStepNum + 1).GetStamp()) # ID of stamp in step
245 aResult = aResult + " " + str(aVal) # all values of step
246 aSelList = anObj.GetSelection()
247 aResult = aResult + "|" + str(' '.join(str(anI) for anI in aSelList))
248 elif isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
250 aResult = aResult + '|'
251 # store internal entry, current and old shapes in BRep format
252 aResult = aResult + anObj.GetEntry() + "|" + anObj.GetShapeStream().decode()
253 aResult = aResult + "|" + anObj.GetOldShapeStream().decode()
255 return aResult.encode()
257 def Load( self, component, stream, URL, isMultiFile ):
262 __entry2IOR__.clear()
263 aList=stream.decode().split('|')
272 aNewShapeStream = aSub
274 else: # create objects by 3 arguments
276 if anId.startswith('group') or (anId.startswith('dead') and anId.count("group") > 0): # group object
277 anObj = SHAPERSTUDY_Object.SHAPERSTUDY_Group()
279 anObj.SetSelection([int(anI) for anI in aSub.split(' ')])
280 anObj.SetSelectionType(int(aNewShapeStream))
281 elif anId.startswith('field') or (anId.startswith('dead') and anId.count("field") > 0): # field object
282 anObj = SHAPERSTUDY_Object.SHAPERSTUDY_Field()
284 anObj.SetSelection([int(anI) for anI in aSub.split(' ')])
285 aParams = aNewShapeStream.split(" ")
286 anObj.SetSelectionType(int(aParams[0]))
287 aTypeStr = aParams[1]
288 if (aTypeStr == "FDT_Bool"):
289 anObj.SetValuesType(0)
290 elif (aTypeStr == "FDT_Int"):
291 anObj.SetValuesType(1)
292 elif (aTypeStr == "FDT_Double"):
293 anObj.SetValuesType(2)
294 elif (aTypeStr == "FDT_String"):
295 anObj.SetValuesType(3)
297 aNumSteps = int(aParams[2])
298 for aVal in range(aNumSteps):
299 aSteps.append(aVal + 1)
300 anObj.SetSteps(aSteps)
301 aCompNum = int(aParams[3])
303 for aCompNameIndex in range(aCompNum):
304 aCompName = aParams[4 + aCompNameIndex].replace("__space__", " ").replace("__vertical_bar__", "|")
305 aCompNames.append(aCompName)
306 anObj.SetComponents(aCompNames)
307 aNumValsInStep = int(aParams[4 + aCompNum])
308 for aStepNum in range(aNumSteps):
309 aStepStartIndex = 4 + aCompNum + aStepNum * (aNumValsInStep + 1) + 1
310 aStampId = int(aParams[aStepStartIndex])
312 for aValIndex in range(aNumValsInStep):
313 aVals.append(float(aParams[aStepStartIndex + aValIndex + 1]))
314 anObj.AddFieldStep(aStampId, aStepNum + 1, aVals)
315 else: # shape object by BRep in the stream: set old first then new
316 anObj = SHAPERSTUDY_Object.SHAPERSTUDY_Object()
318 anObj.SetShapeByStream(aSub)
319 anObj.SetShapeByStream(aNewShapeStream)
322 anIOR = salome.orb.object_to_string(anObj._this())
323 __entry2IOR__[anId] = anIOR
327 def IORToLocalPersistentID(self, sobject, IOR, isMultiFile, isASCII):
329 Gets persistent ID for the CORBA object.
330 The internal entry of the Object is returned.
332 anObj = salome.orb.string_to_object(IOR)
333 if anObj and (isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object) or \
334 isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Field)):
335 return anObj.GetEntry()
338 def LocalPersistentIDToIOR(self, sobject, persistentID, isMultiFile, isASCII):
339 "Converts persistent ID of the object to its IOR."
341 if persistentID in __entry2IOR__:
342 aRes = __entry2IOR__[persistentID]
343 if len(aRes): # set SO from the study, the sobject param is temporary, don't store it
344 salome.orb.string_to_object(aRes).SetSO(getStudy().FindObjectID(sobject.GetID()))
348 def UniqueDumpName( self, theBaseName, theID ):
350 Returns a unique name from the theBaseName. Keeps theBaseName if it was not used yet.
351 Stores the newly generated name into the global map __entry2DumpName__.
353 global __entry2DumpName__
355 # to avoid spaces and parenthesis in the variable name
356 aBaseName = theBaseName.replace(" ", "_").replace("(", "").replace(")", "")
358 while aName in __entry2DumpName__:
359 aName = aBaseName + "_" + str(aPrefix)
360 aPrefix = aPrefix + 1
361 __entry2DumpName__[theID] = aName
365 def DumpPython( self, isPublished, isMultiFile ):
367 Dump module data to the Python script.
369 global __entry2DumpName__
370 __entry2DumpName__.clear()
372 # collect all shape-objects in the SHAPERSTUDY tree
375 aRoots = aStudy.NewChildIterator(findOrCreateComponent())
380 anObj = salome.orb.string_to_object(anIOR)
381 if anObj and type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Object:
382 aShapeObjects.append(anObj)
385 if len(aShapeObjects):
386 script.append("if 'model' in globals():")
387 script.append("\tmodel.publishToShaperStudy()")
388 script.append("import SHAPERSTUDY")
389 for aShapeObj in aShapeObjects:
390 # check this shape also has sub-groups and fields
392 aSOIter = aStudy.NewChildIterator(anObj.GetSO())
393 while aSOIter.More():
394 aGroupSO = aSOIter.Value()
395 anIOR = aGroupSO.GetIOR()
397 aGroup = salome.orb.string_to_object(anIOR)
398 if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group) or \
399 isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Field):
400 aGroupVarName = self.UniqueDumpName(aGroup.GetName(), aGroupSO.GetID())
401 aGroupVarNames.append(aGroupVarName)
403 aShapeVar = self.UniqueDumpName(anObj.GetName(), anObj.GetSO().GetID())
404 aShapeStr = aShapeVar + ", "
405 for aGName in aGroupVarNames:
406 aShapeStr = aShapeStr + aGName + ", "
407 aShapeStr = aShapeStr + "= SHAPERSTUDY.shape(\"" + anObj.GetEntry() +"\")"
408 script.append(aShapeStr)
409 # dump also dead-shapes with groups and fields in the XAO format
410 aRes, aHistSO = aShapeObj.GetSO().FindSubObject(2) # the History folder
412 aDeads = aStudy.NewChildIterator(aHistSO)
414 aDSO = aDeads.Value()
415 aDIOR = aDSO.GetIOR()
417 aDeadShape = salome.orb.string_to_object(aDIOR)
418 if aDeadShape and type(aDeadShape) == SHAPERSTUDY_ORB._objref_SHAPER_Object:
420 aXAO = StudyData_Swig.StudyData_XAO()
421 aXAO.SetShape(aDeadShape.getShape())
422 anArchiveName = "archive_" + str(anArchiveNum) + ".xao"
423 anArchiveNum = anArchiveNum + 1
424 aDeadVarName = self.UniqueDumpName(aDeadShape.GetName(), aDSO.GetID())
425 aDeadString = aDeadString + aDeadVarName + ", "
426 aDGroupIter = aStudy.NewChildIterator(aDSO)
427 while aDGroupIter.More():
428 aDeadGroup = aDGroupIter.Value().GetObject()
429 if isinstance(aDeadGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group):
430 aDGroupVarName = self.UniqueDumpName(aDeadGroup.GetName(), aDGroupIter.Value().GetID())
431 aDeadString = aDeadString + aDGroupVarName + ", "
432 aGroupID = aXAO.AddGroup(aDeadGroup.GetSelectionType(), aDGroupVarName)
433 for aSel in aDeadGroup.GetSelection():
434 aXAO.AddGroupSelection(aGroupID, aSel)
436 aXAO.Export(anArchiveName)
437 aDeadString = aDeadString + " = SHAPERSTUDY.archive(" + aShapeVar + ", \"" + anArchiveName + "\")"
438 script.append(aDeadString)
442 script.append("") # to have an end-line in the end
443 result_str = "\n".join(script)
444 encoded_str = result_str.encode() + b'\0' # to avoid garbage symbols in the end
445 return (encoded_str, 1)
447 def GetAllDumpNames( self ):
449 Returns all names with which Object's was dumped
450 into python script to avoid the same names in SMESH script
452 global __entry2DumpName__
454 for anEntry in __entry2DumpName__:
455 aResultList.append(__entry2DumpName__[anEntry])
458 def GetDumpName( self, theStudyEntry ):
460 Returns a name with which a GEOM_Object was dumped into python script
463 theStudyEntry is an entry of the Object in the study
465 global __entry2DumpName__
466 if theStudyEntry in __entry2DumpName__:
467 return __entry2DumpName__[theStudyEntry]
470 def IsFather(theFather, theChild):
472 Returns true if theChild SObject is a child of theFather SObject
474 aChild = theChild.GetFather()
475 while aChild.Depth() > theFather.Depth():
476 aChild = aChild.GetFather()
477 return aChild.GetID() == theFather.GetID()
479 def BreakLink(self, theEntry):
481 Breaks links to not-dead shape, make the shape as dead
484 aSO = aStudy.FindObjectID(theEntry)
487 aRes, aSSO = aSO.ReferencedObject()
489 return # only SObjects referenced to the SHAPEr STUDY objects are allowed
490 anIOR = aSSO.GetIOR()
492 return # must be referenced to the SHAPER STUDY shape
493 anObj = salome.orb.string_to_object(anIOR)
494 if not anObj or not isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
497 return # do nothing for reference to already dead shape
498 aDeadShape = anObj.MakeDead()
500 aMeshSObject = aSO.GetFather()
501 aMeshObject = aMeshSObject.GetObject()
503 aBuilder = aStudy.NewBuilder()
504 aBuilder.RemoveReference(aSO) # reset reference to the dead shape
505 aBuilder.Addreference(aSO, aDeadShape.GetSO())
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)]
512 aLast = anIters[len(anIters) - 1]
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))
523 anIters.remove(aLast)
525 # associate the number of sub-objects of the referenced objects
526 aMapSubEntryToIndex = {}
527 aSSOIter = aStudy.NewChildIterator(aSSO)
529 while aSSOIter.More():
530 aSub = aSSOIter.Value()
532 aMapSubEntryToIndex[aSub.GetID()] = anIndex
533 anIndex = anIndex + 1
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
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()
550 # aSubMeshObject.ReplaceShape(aDeadSubSO.GetObject())
551 aBuilder.RemoveReference(aSubSO) # reset reference to the dead shape
552 aBuilder.Addreference(aSubSO, aDeadSubSO)
555 # Replace shape object in the parent mesh
556 aMeshObject.ReplaceShape(aDeadShape)
560 Searches a shape object by the SHAPER entry. Used in the python dump script
563 aRoots = aStudy.NewChildIterator(findOrCreateComponent())
568 anObj = salome.orb.string_to_object(anIOR)
569 if anObj and type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Object and anObj.GetEntry() == theEntry:
571 # add groups and fields to the result
572 aSOIter = aStudy.NewChildIterator(aSO)
573 while aSOIter.More():
574 aGroupSO = aSOIter.Value()
575 anIOR = aGroupSO.GetIOR()
577 aGroup = salome.orb.string_to_object(anIOR)
578 if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group) or \
579 isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Field):
580 aRes = aRes + (aGroup,)
583 return None # not found
585 def archive(theShape, theXAOFile):
587 Creates a dead shapes under the theShape and restores these dead objects state basing on theXAOFile
591 # searching for the last dead
592 aDeads = aStudy.NewChildIterator(theShape.GetSO().FindSubObject(2)[1])
593 aLastDeadSO = aDeads.Value()
595 aLastDeadSO = aDeads.Value()
598 aDShape = aLastDeadSO.GetObject()
600 aXAO = StudyData_Swig.StudyData_XAO()
601 anError = aXAO.Import(theXAOFile)
603 print("Error of XAO file import: " + anError)
605 aDShape.SetShapeByPointer(aXAO.GetShape())
607 # add groups and fields to the result
609 aSOIter = aStudy.NewChildIterator(aLastDeadSO)
610 while aSOIter.More():
611 aGroupSO = aSOIter.Value()
612 anIOR = aGroupSO.GetIOR()
614 aGroup = salome.orb.string_to_object(anIOR)
615 if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group):
616 aRes = aRes + (aGroup,)
617 aGroup.SetSelectionType(aXAO.GetGroupDimension(aGroupIndex))
619 for aSel in aXAO.GetGroupSelection(aGroupIndex):
620 aSelection.append(aSel)
621 aGroup.SetSelection(aSelection)
622 aGroupIndex = aGroupIndex + 1
623 elif isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Field):
624 aRes = aRes + (aGroup,)
627 return None # not found