Salome HOME
Make SMESH mesh not up-to-date if only group is updated.
[modules/shaper_study.git] / src / PY / SHAPERSTUDY_Object.py
1 # Copyright (C) 2019-2020  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 SHAPERSTUDY_ORB
21 import SHAPERSTUDY_ORB__POA
22 import GEOM
23 from SHAPERSTUDY_utils import getEngine, getStudy
24 import salome
25
26 import StudyData_Swig
27
28 # converter from the integer values to idl shape_type enumerations
29 __shape_types__ = {
30   0:GEOM.COMPOUND, 1:GEOM.COMPSOLID, 2:GEOM.SOLID,
31   3:GEOM.SHELL, 4:GEOM.FACE, 5:GEOM.WIRE,
32   6:GEOM.EDGE, 7:GEOM.VERTEX, 8:GEOM.SHAPE, 9:GEOM.FLAT}
33
34 class SHAPERSTUDY_GenericObject:
35     """
36     Implement methods of SALOME::GenericObj
37     """
38     def __init__(self):
39         self.cnt=1
40
41     def Register(self):
42         """
43         Increase the reference count (mark as used by another object).
44         """
45         #print(self.GetEntry())
46         self.cnt+=1
47         #print("Register() --------- ", id(self), self.cnt)
48         return
49
50     def UnRegister(self):
51         """
52         Decrease the reference count (release by another object)
53         """
54         self.cnt-=1
55         #print("UnRegister() --------- ", id(self), self.cnt)
56         if self.cnt <= 0:
57             from SHAPERSTUDY_utils import getPOA
58             poa = getPOA()
59             oid=poa.servant_to_id(self)
60             poa.deactivate_object(oid)
61             if hasattr(self,"SetSO"):
62                 self.SetSO(None) # release a GenericObject SO
63             #print("UnRegister() --------- OK")
64         return
65
66     def Destroy(self):
67         """
68         Obsolete, left for compatibility reasons only. Use UnRegister() instead
69         """
70         self.UnRegister()
71         return
72
73     pass
74
75
76 class SHAPERSTUDY_Object(SHAPERSTUDY_ORB__POA.SHAPER_Object,
77                          SHAPERSTUDY_GenericObject):
78     """
79     Constructs an instance of SHAPERSTUDY Object.
80     """
81     def __init__ ( self, *args):
82         SHAPERSTUDY_GenericObject.__init__(self)
83         self.SO = None
84         self.data = None
85         self.entry = ""
86         self.type = 1 # by default it is a shape (Import feature in GEOMImpl_Types.hxx)
87         pass
88
89     def GetShapeType( self ):
90         """
91         Get a GEOM.shape_type of the object value.
92         """
93         if self.data is None:
94             return GEOM.SHAPE
95         global __shape_types__
96         return __shape_types__[self.data.type()];
97
98     def IsMainShape( self ):
99         """
100         Returns True if this object is not a sub-shape of another object.
101         """
102         return True
103
104     def GetSubShapeIndices( self ):
105         """
106         Get a list of ID's of sub-shapes in the main shape.
107         """
108         return []
109
110     def GetMainShape( self ):
111         """
112         Get a main shape object to which this object is a sub-shape.
113         """
114         return getShape()
115
116     def getShape( self ):
117         """
118         Get the TopoDS_Shape, for collocated case only.
119         Called by GEOM_Client to get TopoDS_Shape pointer
120         """
121         if self.data is None:
122             return 0
123         return self.data.shape()
124
125     def GetShapeStream( self ):
126         """
127         Get geometric shape of the object as a byte stream in BRep format
128         """
129         if self.data is None:
130             return b''
131         return self.data.shapeStream().encode()
132
133     def GetOldShapeStream( self ):
134         """
135         Get geometric shape of the object as a byte stream in BRep format
136         """
137         if self.data is None:
138             return b''
139         return self.data.oldShapeStream().encode()
140
141     def SetShapeByStream(self, theStream):
142         """
143         Sets geometric shape content of the object as a byte stream in BRep format
144         """
145         if self.data:
146           self.data.updateShape(theStream)
147         else:
148           self.data = StudyData_Swig.StudyData_Object(theStream)
149
150     """
151     Methods from BaseObject
152     """
153     def GetName( self ):
154         """
155         Get name of the object associated with this object.
156         """
157         return self.SO.GetName()
158
159     def SetEntry( self, theInternalEntry ):
160         """
161         Sets internal (unique) entry of the object in the component's data tree.
162         """
163         self.entry = theInternalEntry
164
165     def GetEntry( self ):
166         """
167         Get internal (unique) entry of the object in the component's data tree.
168         """
169         return self.entry
170
171     def GetType( self ):
172         """
173         Get internal type of operation created this object.
174         In SMESH is used to find out if an object is GROUP (type == 37)
175         """
176         return self.type
177
178     def SetType( self, theType ):
179         """
180         Sets internal type of operation created this object.
181         In SMESH is used to find out if an object is GROUP (type == 37, for shape it is default=1)
182         """
183         self.type = theType
184
185     def GetTick( self ):
186         """
187         Get value of a modification counter of the object
188         """
189         if self.data:
190           return self.data.getTick()
191         return 0
192
193     def SetTick( self, theValue ):
194         """
195         Sets value of a modification counter of the object
196         """
197         if self.data:
198           return self.data.setTick(theValue)
199         return 0
200
201     def GetStudyEntry( self ):
202         """
203         Get a Study entry where this object was published.
204         """
205         if self.SO:
206             return self.SO.GetID()
207         return ""
208
209     def IsShape( self ):
210         """
211         Return true if geom object represents a shape.
212         For example, method return false for GEOM_MARKER
213         """
214         return True
215
216     def IsSame( self, other ):
217         """
218         Return true if passed object is identical to this object
219         """
220         return self.GetType() == other.GetType() and self.GetEntry() == other.GetEntry()
221
222     def GetGen( self ):
223         """
224         Return the engine creating this object
225         """
226         e = getEngine()
227         return e._duplicate( e )
228
229     def SetSO( self, theSO ):
230         """
231         Sets SObject of this object (when it is published)
232         """
233         if theSO:
234             theSO.Register() # I hold a GenericObject!
235         if self.SO:
236             self.SO.UnRegister()
237         self.SO = theSO
238
239     def GetSO( self ):
240         """
241         Returns SObject of this object
242         """
243         return self.SO
244
245     def IsParametrical(self):
246         """
247         Returns true if the current object has connection to a parametrical model
248         which can be modified by parameters change.
249         """
250         return not self.IsDead() and self.type == 1 # only break link for shapes are accessible now
251
252     def IsDead(self):
253         """
254         Returns true if the shape is dead - no parametrical link to the SHAPER exists
255         """
256         return self.GetEntry().startswith("dead")
257
258     def MakeDead(self):
259         """
260         Makes the dead-copy of the shape and returns it.
261         """
262         aStudy = getStudy()
263         aBuilder = aStudy.NewBuilder()
264         aRes, aHistSO = self.SO.FindSubObject(10000)
265         if not aRes: # create a "history" folder if it does not exist
266           aHistSO = aBuilder.NewObjectToTag(self.SO, 10000)
267           aHistSO.SetAttrString("AttributeName", "History")
268
269         aDeadSO = aBuilder.NewObject(aHistSO)
270         anIndex = aDeadSO.Tag()
271         aDeadSO.SetAttrString("AttributeName", self.SO.GetName() + " (" + str(anIndex) + ")")
272         aRes, aPixMap = aBuilder.FindAttribute(self.SO, "AttributePixMap")
273         if aRes:
274           aDeadPixMap = aBuilder.FindOrCreateAttribute(aDeadSO, "AttributePixMap")
275           aDeadPixMap.SetPixMap(aPixMap.GetPixMap())
276         aDead = SHAPERSTUDY_Object()
277         aDeadEntry = "dead" + str(anIndex) + "_" + self.GetEntry()
278         aDead.SetEntry(aDeadEntry)
279         aDead.SetShapeByStream(self.data.oldShapeStream())
280         aDeadObj = aDead._this()
281         anIOR = salome.orb.object_to_string(aDeadObj)
282         aDeadSO.SetAttrString("AttributeIOR", anIOR)
283         aDead.SetSO(aDeadSO)
284         if self.GetTick() > 2:
285           aDead.data.setTick(self.GetTick() - 1) # set the tick of an old shape
286         # make dead-copy also sub-groups
287         aSOIter = aStudy.NewChildIterator(self.SO)
288         while aSOIter.More():
289           aGroupSO = aSOIter.Value()
290           anIOR = aGroupSO.GetIOR()
291           if len(anIOR):
292             aGroup = salome.orb.string_to_object(anIOR)
293             if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group) or \
294                isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Field):
295               if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Group):
296                 aDeadGroup = SHAPERSTUDY_Group()
297               else:
298                 aDeadGroup = SHAPERSTUDY_Field()
299               aDeadGroupEntry = "dead" + str(anIndex) + "_" + aGroup.GetEntry()
300               aDeadGroup.SetEntry(aDeadGroupEntry)
301               aDeadGroup.SetSelectionType(aGroup.GetSelectionType())
302               anOldSelection = aGroup.GetSelectionOld()
303               if len(anOldSelection) == 0: # in case there is no old modification, get the current, same as in shape
304                 anOldSelection = aGroup.GetSelection()
305               aDeadGroup.SetSelection(anOldSelection)
306               if isinstance(aGroup, SHAPERSTUDY_ORB._objref_SHAPER_Field): # additional field data
307                 aDeadGroup.SetValuesType(aGroup.GetValuesType())
308                 aDeadGroup.SetSteps(aGroup.GetSteps())
309                 aDeadGroup.SetComponents(aGroup.GetComponents())
310                 for aStep in aGroup.GetSteps():
311                   aStepObj = aGroup.GetStep(aStep)
312                   aDeadGroup.AddFieldStep(aStepObj.GetStamp(), aStep, aStepObj.GetValues())
313               aDeadGroupSO = aBuilder.NewObject(aDeadSO)
314               aDeadGroup.SetSO(aDeadGroupSO)
315               # 15.01.20 groups and fields names stays the same
316               #aDeadGroupSO.SetAttrString("AttributeName", aGroupSO.GetName() + " (" + str(anIndex) + ")")
317               aDeadGroupSO.SetAttrString("AttributeName", aGroupSO.GetName())
318               aRes, aPixMap = aBuilder.FindAttribute(aGroupSO, "AttributePixMap")
319               if aRes:
320                 aDeadPixMap = aBuilder.FindOrCreateAttribute(aDeadGroupSO, "AttributePixMap")
321                 aDeadPixMap.SetPixMap(aPixMap.GetPixMap())
322               aDeadGroupObj = aDeadGroup._this()
323               anIOR = salome.orb.object_to_string(aDeadGroupObj)
324               aDeadGroupSO.SetAttrString("AttributeIOR", anIOR)
325           aSOIter.Next()
326
327         return aDeadObj
328     
329     def SetShapeByPointer(self, theShape):
330         """
331         Sets the shape by the pointer to the TopoDS_Shape
332         """
333         if not self.data:
334           self.data = StudyData_Swig.StudyData_Object()
335         self.data.SetShapeByPointer(theShape)
336         return
337
338     ### unnecessary methods that can be accidentally called from any module
339     def GetTopologyType(self, *args): return GEOM.SHAPE
340     def GetMinShapeType(self, *args): return GEOM.SHAPE
341     def GetMaxShapeType(self, *args): return GEOM.SHAPE
342     def GetSubShapeName(self, *args): return ""
343     def SetColor(self, *args): return
344     def GetColor(self, *args): import SALOMEDS; return SALOMEDS.Color( 0,0,0 )
345     def SetAutoColor(self, *args): return 
346     def GetAutoColor(self, *args): return False
347     def SetMarkerStd(self, *args): return 
348     def SetMarkerTexture(self, *args): return 
349     def GetMarkerType(self, *args): return GEOM.MT_NONE
350     def GetMarkerSize(self, *args): return GEOM.MS_NONE
351     def GetMarkerTexture(self, *args): return 0
352
353     pass
354
355 class SHAPERSTUDY_Group(SHAPERSTUDY_ORB__POA.SHAPER_Group, SHAPERSTUDY_Object):
356     """
357     Constructs an instance of SHAPERSTUDY Group
358     """
359     def __init__ ( self, *args):
360         SHAPERSTUDY_GenericObject.__init__(self)
361         self.seltype = None
362         self.selection = []
363         self.selectionTick = -2 # tick of the main shape when the current selection is set
364         self.selectionOld = [] # keep selection for breaking link
365         self.SO = None
366         self.data = None
367         self.entry = ""
368         self.type = 37 # a group type
369         pass
370
371     def SetSelectionType(self, theType):
372         """
373         Sets what is returned in the GEOM_IGroupOperations::GetType
374         """
375         self.seltype = theType
376
377     def GetSelectionType(self):
378         """
379         Returns the type of the selected sub-shapes
380         """
381         return self.seltype
382
383     def SetSelection(self, theSelection):
384         """
385         Sets what is returned in the GEOM_IGroupOperations::GetObjects
386         """
387         aTick = -2
388         if self.SO:
389           aMainShape = self.GetMainShape()
390           if aMainShape:
391             aTick = aMainShape.GetTick()
392         if aTick > self.selectionTick or aTick == -2:
393           self.selectionOld = self.selection
394           self.selection = theSelection
395           self.selectionTick = aTick
396           #print("Set selection " + self.entry + " old = " + str(self.selectionOld) + " new = " + str(self.selection) + " tick = " + str(aTick))
397         elif self.selection != theSelection:
398           self.selectionOld = self.selection
399           self.selection = theSelection
400           if self.selectionTick < 0:
401             self.selectionTick = aTick + 1
402           else:
403             self.selectionTick = self.selectionTick + 1 # when the group is changed, but the main shape stays the same, make tick + 1
404           #print("Set selection " + self.entry + " old = " + str(self.selectionOld) + " new = " + str(self.selection) + " tick = " + str(self.selectionTick))
405         pass
406
407     def GetSelection(self):
408         """
409         Returns the selected sub-shapes indices
410         """
411         return self.selection
412
413     def GetSelectionOld(self):
414         """
415         Returns the previously selected sub-shapes indices
416         """
417         #print("get selection OLD " + self.entry + " old = " + str(self.selectionOld) + " new = " + str(self.selection))
418         return self.selectionOld
419
420     def IsMainShape( self ):
421         """
422         Returns True if this object is not a sub-shape of another object.
423         """
424         return False
425
426     def GetMainShape( self ):
427         """
428         Main shape is groups owner
429         """
430         return self.SO.GetFather().GetObject()
431
432     def GetSubShapeIndices( self ):
433         """
434         Get a list of ID's of sub-shapes in the main shape.
435         """
436         return self.selection
437
438     def getShape( self ):
439         """
440         Redefinition of the getShape method: here it creates a shape by the
441         main shape and the group index.
442         """
443         if not self.data:
444           self.data = StudyData_Swig.StudyData_Object()
445         # convert selection to long list
446         anArg = StudyData_Swig.LongList()
447         for l in self.selection:
448           anArg.append(l)
449         return self.data.groupShape(self.GetMainShape().getShape(), anArg)
450
451     def GetShapeType( self ):
452         """
453         Group shape type is always compound.
454         """
455         return GEOM.COMPOUND;
456
457     pass
458
459     def GetTick( self ):
460         """
461         Get value of a modification counter of the group
462         """
463         return self.selectionTick
464
465     def SetTick( self, theValue ):
466         """
467         Sets value of a modification counter of the group
468         """
469         #print("Set tick " + self.entry + " tick = " + str(theValue))
470         self.selectionTick = theValue
471
472 class SHAPERSTUDY_Field(SHAPERSTUDY_ORB__POA.SHAPER_Field, SHAPERSTUDY_Group):
473     """
474     Constructs an instance of SHAPERSTUDY Field (inherits selection from a Group object)
475     """
476     def __init__ ( self, *args):
477         SHAPERSTUDY_GenericObject.__init__(self)
478         self.seltype = None
479         self.selection = []
480         self.selectionTick = -2 # tick of the main shape when the current selection is set
481         self.selectionOld = [] # keep selection for breaking link
482         self.SO = None
483         self.data = None
484         self.entry = None
485         self.type = 52 # a field type
486         self.valtype = None # type of the values
487         self.steps = [] # list of long
488         self.components = [] # string array, names of the components
489         self.name = None # name, string
490         self.fieldsteps = {} # FieldSteps objects identified by step ID
491         pass
492
493     def SetValuesType( self, theType ):
494       """
495       Sets the type of values in the field
496       """
497       self.valtype = theType
498
499     def GetValuesType( self ):
500       """
501       Returns the type of values in the field
502       """
503       return self.valtype
504
505
506     def GetDataType( self ):
507       """
508       Returns the type of values in the field in terms of GEOM enumeration
509       """
510       if self.valtype == 0:
511         return GEOM.FDT_Bool
512       elif self.valtype == 1:
513         return GEOM.FDT_Int
514       elif self.valtype == 2:
515         return GEOM.FDT_Double
516       elif self.valtype == 3:
517         return GEOM.FDT_String
518       return None # unknown case
519
520     def GetShape ( self ):
521       """
522       Returns the shape the field lies on
523       """
524       return super().GetMainShape()
525
526     def SetSteps( self, theSteps ):
527       self.steps = theSteps
528
529     def GetSteps( self ):
530       return self.steps
531
532     def SetComponents( self, theComponents ):
533       self.components = theComponents
534     
535     def GetComponents( self ):
536       return self.components
537
538     def GetDimension( self ):
539       aShapeType = super().GetSelectionType()
540       if aShapeType == 8:
541         return -1 # whole part
542       elif aShapeType == 7:
543         return 0 # vertex
544       elif aShapeType == 6:
545         return 1 # edge
546       elif aShapeType == 4:
547         return 2 # face
548       elif aShapeType == 2:
549         return 3 # solid
550       return None # unknown case
551
552     def ClearFieldSteps( self ):
553        self.fieldsteps = {}
554
555     def AddFieldStep( self, theStampID, theStepID, theValues):
556       aFieldStep = None
557       if self.valtype == 0:
558         aFieldStep = SHAPER_BoolFieldStep()
559       elif self.valtype == 1:
560         aFieldStep = SHAPER_IntFieldStep()
561       elif self.valtype == 2:
562         aFieldStep = SHAPER_DoubleFieldStep()
563       
564       aFieldStep.SetStep(theStampID, theStepID, theValues)
565       self.fieldsteps[theStepID] = aFieldStep._this()
566
567     def GetStep( self, theStepID ):
568        return self.fieldsteps[theStepID]
569
570     pass
571
572 class SHAPER_FieldStep:
573     """
574     Base class for all step-classes
575     """
576     def __init__ ( self, *args):
577         self.stamp = None  # long, ID of stamp
578         self.step = None   # long, ID of step
579         self.values = None # array of values of the needed type
580
581     """
582     Defines all parameters of the step
583     """
584     def SetStep( self, theStamp, theStep, theValues ):
585         self.stamp = theStamp
586         self.step = theStep
587         self.values = theValues
588      
589     """
590     Returns stamp ID
591     """
592     def GetStamp( self ):
593         return self.stamp
594     """
595     Returns step ID
596     """
597     def GetID( self ):
598         return self.step
599     """
600     Returns a name of a sub-shape if the sub-shape is published in the study
601     """
602     def GetSubShape(self, theSubID):
603         # the SHAPER study does not support sub-shapes for now
604         return ""
605         
606
607 class SHAPER_DoubleFieldStep(SHAPERSTUDY_ORB__POA.SHAPER_DoubleFieldStep, SHAPER_FieldStep):
608     """
609     Constructs an instance of SHAPERSTUDY Field step of type Double
610     """
611     def __init__ ( self, *args):
612         pass
613
614     """
615     Returns values as an array of the needed type
616     """
617     def GetValues( self ):
618         aResult = [] # to make any type of result, create a corba-type
619         for i in self.values:
620           aResult.append(float(i))
621         return aResult
622
623     pass
624
625 class SHAPER_IntFieldStep(SHAPERSTUDY_ORB__POA.SHAPER_IntFieldStep, SHAPER_FieldStep):
626     """
627     Constructs an instance of SHAPERSTUDY Field step of type Double
628     """
629     def __init__ ( self, *args):
630         pass
631
632     """
633     Returns values as an array of the needed type
634     """
635     def GetValues( self ):
636         aResult = [] # to make any type of result, create a corba-type
637         for i in self.values:
638           aResult.append(int(i))
639         return aResult
640
641     pass
642
643 class SHAPER_BoolFieldStep(SHAPERSTUDY_ORB__POA.SHAPER_BoolFieldStep, SHAPER_FieldStep):
644     """
645     Constructs an instance of SHAPERSTUDY Field step of type Double
646     """
647     def __init__ ( self, *args):
648         pass
649
650     """
651     Returns values as an array of the needed type
652     """
653     def GetValues( self ):
654         aResult = [] # to make any type of result, create a corba-type
655         for i in self.values:
656           aResult.append(int(i))
657         return aResult
658
659     pass
660