1 # Copyright (C) 2014-2024 CEA, EDF
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.
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.
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
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 # ExportFeature class definition
30 from salome.shaper import model
32 import SHAPERSTUDY_ORB
33 import SHAPERSTUDY_utils
36 # Feature to export all shapes and groups into the GEOM module
37 class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
41 ModelAPI.ModelAPI_Feature.__init__(self)
45 ## Export kind. Static.
47 return "PublishToStudy"
49 ## Returns the kind of a feature.
51 return PublishToStudyFeature.ID()
53 ## This feature is action: has no property panel and executes immediately.
57 ## This feature has no attributes, as it is action.
58 def initAttributes(self):
61 ## Exports all shapes and groups into the GEOM module.
63 aSession = ModelAPI.ModelAPI_Session.get()
64 aPartSet = aSession.moduleDocument()
65 # check that the PartSet document current feature is the last to avoid problems with all
67 if aPartSet.size(model.ModelAPI_Feature.group()) > 0:
68 aLastFeature = ModelAPI.objectToFeature(aPartSet.object(model.ModelAPI_Feature.group(), aPartSet.size(model.ModelAPI_Feature.group()) - 1))
69 aCurrentFeature = aPartSet.currentFeature(True)
70 if aLastFeature.data().featureId() != aCurrentFeature.data().featureId():
71 EventsAPI.Events_InfoMessage("PublishToStudy", "Not all PartSet parts are up-to-date, nothing is published. Please, make the last PartSet feature as current.", self).send()
73 # find a shaper-study component
74 salome.salome_init(embedded=True)
75 aComponent = SHAPERSTUDY_utils.findOrCreateComponent()
76 anEngine = SHAPERSTUDY_utils.getEngine()
77 # collect all processed internal entries to break the link of unprocessed later
80 # iterate all parts and all results to publish them in SHAPER_STUDY
81 for aPartId in range(aPartSet.size(model.ModelAPI_ResultPart.group())):
82 aPartObject = aPartSet.object(model.ModelAPI_ResultPart.group(), aPartId)
83 aPartRes = ModelAPI.modelAPI_ResultPart(ModelAPI.modelAPI_Result(aPartObject))
84 aPartDoc = aPartRes.partDoc()
85 if aPartDoc is None and aPartObject is not None:
86 EventsAPI.Events_InfoMessage("PublishToStudy", "To publish to SHAPER-STUDY, activate Parts in SHAPER", self).send()
88 aPartFeatureId = aPartSet.feature(aPartRes.original()).data().featureId()
89 # Collects all features of exported results to find results of the same features and extend id.
90 # Map from feature index to index of result. If index is zero (initial), no surrfix to entry is added.
92 for aResId in range(aPartDoc.size(model.ModelAPI_ResultBody.group())):
93 aResObject = aPartDoc.object(model.ModelAPI_ResultBody.group(), aResId)
94 aRes = model.objectToResult(aResObject)
96 if aRes.hasTexture() is True:
98 aResFeatureId = str(aPartDoc.feature(aRes).data().featureId())
99 if aResFeatureId in aFeaturesIndices:
100 aFeaturesIndices[aResFeatureId] += 1
101 aResFeatureId += ":" + str(aFeaturesIndices[aResFeatureId])
103 aFeaturesIndices[aResFeatureId] = 0
104 aSSEntry = str(aPartFeatureId) + ":" + aResFeatureId
105 aSShape = anEngine.FindOrCreateShape(aSSEntry)
106 aSShape.SetShapeByStream(aRes.shape().getShapeStream(False))
107 if not aSShape.GetSO(): # publish in case it is a new shape
108 anEngine.AddInStudy(aSShape, aRes.data().name(), None)
109 else: # restore a red reference if it was deleted
110 aDone, aSO2 = aSShape.GetSO().FindSubObject(1)
112 aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
113 aBuilder.SetName(aSShape.GetSO(),aRes.data().name())
114 aDone, aRef = aSO2.ReferencedObject()
116 aBuilder.Addreference(aSO2, aSShape.GetSO())
117 allProcessed.append(aSSEntry)
119 self.processGroups(aRes, anEngine, aPartFeatureId, aSShape, False)
121 self.processGroups(aRes, anEngine, aPartFeatureId, aSShape, True)
123 # process all SHAPER-STUDY shapes to find dead
124 aSOIter = SHAPERSTUDY_utils.getStudy().NewChildIterator(aComponent)
125 while aSOIter.More():
126 aSO = aSOIter.Value()
127 aSOIter.Next() # here because there is continue inside the loop
130 anObj = salome.orb.string_to_object(anIOR)
131 if isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Object):
132 anEntry = anObj.GetEntry()
133 if len(anEntry) == 0:
135 elif anEntry not in allProcessed: # found a removed shape: make it dead for the moment
136 # remove the reference - red node
137 aRes, aSO2 = aSO.FindSubObject(1)
139 aRes, aRef = aSO2.ReferencedObject()
141 aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
142 aBuilder.RemoveReference(aSO2)
143 # if the object is not marked as dead, mark it (#3201) to make all entries unique
144 aDependancies = SHAPERSTUDY_utils.getStudy().FindDependances(aSO)
145 hasLinkedMesh = False
146 for aDep in aDependancies:
147 aComp = aDep.GetFatherComponent()
148 type = aComp.ComponentDataType()
152 if not hasLinkedMesh:
153 aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
154 aBuilder.RemoveObjectWithChildren(aSO)
156 aDeadEntry = anObj.GetEntry()
157 if not aDeadEntry.startswith("dead"):
159 anObj.SetEntry("dead0" + str(anIndex) + "_" + aDeadEntry)
160 anEngine.SetDeadPixmapToDeadObject(anObj) #set crossed pixmap to distinguish dead object in GUI
162 aGrSOIter = SHAPERSTUDY_utils.getStudy().NewChildIterator(aSO)
163 while aGrSOIter.More():
164 aGroupSO = aGrSOIter.Value()
166 anIOR = aGroupSO.GetIOR()
168 aGroup = salome.orb.string_to_object(anIOR)
169 if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group) or \
170 isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Field):
171 if not aGroup.GetEntry().startswith("dead"):
172 aDeadGroupEntry = "dead0" + str(anIndex) + "_" + aGroup.GetEntry()
173 aGroup.SetEntry(aDeadGroupEntry)
174 anEngine.SetDeadPixmapToDeadObject(aGroup) #set crossed pixmap to distinguish dead object in GUI
176 # Part of the "execute" method: processes the Groups of theRes result publication.
177 # If theFields is true, the same is performed for Fields.
178 def processGroups(self, theRes, theEngine, thePartFeatureId, theStudyShape, theFields):
179 allGroupsProcessed = []
182 allRefGroups.append(ModelAPI.referencedFeatures(theRes, "Field", True))
184 allRefGroups.append(ModelAPI.referencedFeatures(theRes, "Group", True))
185 allRefGroups.append(ModelAPI.referencedFeatures(theRes, "Shared_faces", True))
186 aResShape = theRes.shape()
187 aMapOfShape = GeomAPI_IndexedMapOfShape(aResShape)
188 for aRefGroups in allRefGroups:
189 for aRef in aRefGroups:
193 aSelList = aRef.selectionList("selected")
195 aSelList = aRef.selectionList("group_list")
196 aSelType = GeomAPI_Shape.shapeTypeByStr(aSelList.selectionType())
197 for aGroupRes in aRef.results():
198 aShape = aGroupRes.shape()
199 anExplorer = GeomAPI_ShapeExplorer(aShape, aSelType)
200 while anExplorer.more():
201 anId = aMapOfShape.FindIndexEqualLocations(anExplorer.current())
202 if anId > 0 and not anId in aGroupHasIndex:
203 aGroupIndices.append(anId)
204 aGroupHasIndex[anId] = 0
206 if len(aGroupIndices): # create group
207 aGroupFeatureId = aRef.data().featureId()
209 aFieldOp = theEngine.GetIFieldOperations()
210 aGroupEntry = "field" + str(thePartFeatureId) + ":" + str(aGroupFeatureId)
211 aGroup = aFieldOp.FindField(theStudyShape, aGroupEntry)
213 aGroupOp = theEngine.GetIGroupOperations()
214 aGroupEntry = "group" + str(thePartFeatureId) + ":" + str(aGroupFeatureId)
215 aGroup = aGroupOp.FindGroup(theStudyShape, aGroupEntry)
216 if not aGroup: # create a new
218 aGroup = aFieldOp.CreateFieldByType(theStudyShape, aSelType)
220 aGroup = aGroupOp.CreateGroup(theStudyShape, aSelType)
221 aGroup.SetEntry(aGroupEntry)
222 theEngine.AddInStudy(aGroup, aRef.firstResult().data().name(), theStudyShape)
224 aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
225 aBuilder.SetName(aGroup.GetSO(),aRef.firstResult().data().name())
226 aGroup.SetSelection(aGroupIndices)
228 self.fillField(aGroup, aRef, theEngine, aGroupIndices)
229 # a group takes shape from the main result
230 #aGroup.SetShapeByStream(aRef.firstResult().shape().getShapeStream(False)) # group shape
231 allGroupsProcessed.append(aGroupEntry)
232 # check all existing groups: if some does not processed, remove it from the tree
233 aSOIter = SHAPERSTUDY_utils.getStudy().NewChildIterator(theStudyShape.GetSO())
234 while aSOIter.More():
235 aSO = aSOIter.Value()
238 anObj = salome.orb.string_to_object(anIOR)
239 if (theFields and isinstance(anObj, SHAPERSTUDY_ORB._objref_SHAPER_Field)) or \
240 (not theFields and type(anObj) == SHAPERSTUDY_ORB._objref_SHAPER_Group):
241 anEntry = anObj.GetEntry()
242 if anEntry not in allGroupsProcessed: # found a removed group => remove
243 aDependancies = SHAPERSTUDY_utils.getStudy().FindDependances(aSO)
244 hasLinkedMesh = False
245 for aDep in aDependancies:
246 aComp = aDep.GetFatherComponent()
247 typeComp = aComp.ComponentDataType()
248 if typeComp == "SMESH":
252 if not anEntry.startswith("dead"):
254 aDeadGroupEntry = "dead0" + str(anIndex) + "_" + anEntry
255 anObj.SetEntry(aDeadGroupEntry)
256 theEngine.SetDeadPixmapToDeadObject(anObj)
258 aBuilder = SHAPERSTUDY_utils.getStudy().NewBuilder()
259 aBuilder.RemoveObject(anObj.GetSO())
262 # Part of the "execute" method: theFiled fields filling.
263 def fillField(self, theField, theFeature, theEngine, theSelectionIndices):
264 aTables = theFeature.tables("values")
265 aValType = aTables.type() # type of the values
266 aValTypeToSet = aValType
267 if aValType == 3: # strings do not supported by SMESH, so, make them empty boolean table
269 theField.SetValuesType(aValTypeToSet)
270 aNumSteps = aTables.tables() # number of steps is number of tables
272 for aVal in range(aNumSteps):
273 aSteps.append(aVal + 1)
274 theField.SetSteps(aSteps)
276 aCompNamesAttr = theFeature.stringArray("components_names")
277 for anIndex in range(aCompNamesAttr.size()):
278 aCompNames.append(aCompNamesAttr.value(anIndex))
279 theField.SetComponents(aCompNames)
280 # prepare the sub-shapes indices: all values for all sub-shapes must be defined
281 aShapeOp = theEngine.GetIShapesOperations()
282 allIndices = aShapeOp.GetAllSubShapesIDs(theField.GetShape(), theField.GetSelectionType(), False)
284 theField.ClearFieldSteps()
285 for aVal in range(aNumSteps):
287 for aCol in range(aTables.columns()):
288 #for aRow in range(aTables.rows()):
289 for anIndex in allIndices:
290 if anIndex in theSelectionIndices:
291 aRow = theSelectionIndices.index(anIndex) + 1 # starting from the first line
293 aRow = 0 # default value
294 aStrVal = aTables.valueStr(aRow, aCol, aVal)
295 if aValType == 0: # boolean
296 if aStrVal == "True":
300 elif aValType == 1: # int
301 aVals.append(int(aStrVal))
302 elif aValType == 2: # double
303 aVals.append(float(aStrVal))
304 theField.AddFieldStep(theFeature.intArray("stamps").value(aVal), aVal + 1, aVals)