Salome HOME
f2f92d6a1940d8cd1f4e01af8a837a84f4e9b2aa
[modules/geom.git] / src / GEOM_PY / geomtools.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2007-2023  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22 ## \defgroup geomtools geomtools - Tools to access GEOM engine and objects 
23 #  \{ 
24 #  \details
25 #  This module provides tools to facilitate the use of geom engine and geom
26 #  objects in Salome.
27 #  \}
28
29 """
30 This module provides tools to facilitate the use of geom engine and geom
31 objects in Salome.
32 """
33
34 import salome
35 GEOM = None    # GEOM module is loaded only when needed
36
37 from salome.kernel.logger import Logger
38 from salome.kernel import termcolor
39 logger = Logger("salome.geom.geomtools", color = termcolor.RED)
40
41 from salome.kernel.studyedit import getStudyEditor
42 from salome.kernel.services import IDToObject, IDToSObject
43 from salome.kernel.deprecation import is_called_by_sphinx
44 from salome.geom import geomBuilder
45
46 try:
47     if not is_called_by_sphinx():
48         from salome.gui import helper as guihelper
49         pass
50     pass
51 except:
52     pass
53
54 _geompy = geomBuilder.New()
55
56 ## Return an object behaving exactly like geompy module.
57 #  \ingroup geomtools
58 def getGeompy():
59     """
60     Return an object behaving exactly like geompy module.
61     """
62     salome.salome_init()
63     return _geompy
64
65
66 ModeWireFrame = 0
67 ModeShading = 1
68 DisplayMode=ModeShading
69 PreviewColor=[236,163,255]
70
71 ## This class provides several methods to manipulate geom objects in Salome study. 
72 #  The parameter <em>studyEditor</em> defines a \b StudyEditor
73 #  object used to access the study. If \b None, the method returns a 
74 #  \b StudyEditor object on the current study.
75 #
76 #  \b editor  
77
78 #  This instance attribute contains the underlying \b StudyEditor object. 
79 #  It can be used to access the study but the attribute itself should not be modified.
80 #  \ingroup geomtools
81 class GeomStudyTools:
82     """
83     This class provides several methods to manipulate geom objects in Salome
84     study. The parameter `studyEditor` defines a
85     :class:`~salome.kernel.studyedit.StudyEditor` object used to access the study. If
86     :const:`None`, the method returns a :class:`~salome.kernel.studyedit.StudyEditor`
87     object on the current study.
88
89     .. attribute:: editor
90     
91        This instance attribute contains the underlying
92        :class:`~salome.kernel.studyedit.StudyEditor` object. It can be used to access
93        the study but the attribute itself should not be modified.
94
95     """
96
97     def __init__(self, studyEditor = None):
98         global GEOM
99         if GEOM is None:
100             GEOM = __import__("GEOM")
101         if studyEditor is None:
102             studyEditor = getStudyEditor()
103         self.editor = studyEditor
104
105     # ======================================================================
106     # Helper functions to add/remove a geometrical shape in/from the study
107     # ======================================================================
108     ## Add a GEOM shape in the study. It returns the associated entry
109     #  that corresponds to the identifier of the entry in the study. This
110     #  entry can be used to retrieve an object in the study. A folderName
111     #  can be specified. In this case, a folder with this name is first
112     #  created in the Geometry part of the study, and the shape study
113     #  object is stored in this folder of the study. 
114     #
115     #    \param  shape (GEOM object) the GEOM object defining the shape
116     #    \param  shapeName (string) the name for this shape in the study 
117     #    \param  folderName (string) the name of a folder in the GEOM part of the study
118     def addShapeToStudy(self, shape,shapeName,folderName=None):
119         """
120         Add a GEOM shape in the study. It returns the associated entry
121         that corresponds to the identifier of the entry in the study. This
122         entry can be used to retrieve an object in the study. A folderName
123         can be specified. In this case, a folder with this name is first
124         created in the Geometry part of the study, and the shape study
125         object is stored in this folder of the study. 
126
127         :type   shape: GEOM object
128         :param  shape: the GEOM object defining the shape
129
130         :type   shapeName: string
131         :param  shapeName: the name for this shape in the study 
132
133         :type   folderName: string
134         :param  folderName: the name of a folder in the GEOM part of the study
135         """
136         study   = self.editor.study
137         geompy  = getGeompy()
138
139         if folderName is None:
140             # Insert the shape in the study by the standard way
141             entry = geompy.addToStudy( shape, shapeName )
142         else:
143             # A folder name has been specified to embed this shape. Find
144             # or create a folder with this name in the Geometry study, and
145             # then store the shape in this folder.
146             geomStudyFolder = self.editor.findOrCreateComponent("GEOM")
147             shapeStudyFolder = self.editor.findOrCreateItem(geomStudyFolder,folderName)
148             
149             shapeIor = salome.orb.object_to_string(shape)
150             geomgui = salome.ImportComponentGUI("GEOM")
151             shapeIcon = geomgui.getShapeTypeIcon(shapeIor)
152             
153             shapeStudyObject = self.editor.createItem(shapeStudyFolder,
154                                                       name=shapeName,
155                                                       IOR=shapeIor,
156                                                       icon=shapeIcon)
157             entry = shapeStudyObject.GetID()
158
159         return entry
160     
161     ## This removes the specified entry from the study. Note that this
162     #  operation does not destroy the underlying GEOM object, neither
163     #  erase the drawing in the viewer.
164     #  The underlying GEOM object is returned (so that it can be destroyed)
165     def removeFromStudy(self, shapeStudyEntry):
166         """
167         This removes the specified entry from the study. Note that this
168         operation does not destroy the underlying GEOM object, neither
169         erase the drawing in the viewer.
170         The underlying GEOM object is returned (so that it can be destroyed)
171         """
172         study = self.editor.study
173         shape = self.getGeomObjectFromEntry(shapeStudyEntry)    
174         studyObject = IDToSObject(shapeStudyEntry)
175         self.editor.removeItem(studyObject,True)
176         return shape
177
178     # ======================================================================
179     # Helper functions to display/erase a shape in/from the viewer. The
180     # shape must be previously put in the study and the study entry must
181     # be known. Note also that these function works implicitly on the
182     # active study (WARN: it does not ensure consistency with the
183     # study associated to the studyEditor used to initiate this
184     # object. It's up to you to be self-consistent (or to improve this
185     # python source code). 
186     # ======================================================================
187
188     ## Display the geometrical shape whose name in the study is <em>shapeName</em>. 
189     #
190     #  \param shapeName (string) name of the geometrical shape
191     #  \param color (tuple) RGB components of the color of the shape
192     #  \return True if the shape was found, False otherwise
193     def displayShapeByName(self, shapeName, color = None, fit=True):
194         """
195         Display the geometrical shape whose name in the study is `shapeName`.
196         
197         :type   shapeName: string
198         :param  shapeName: name of the geometrical shape
199         
200         :type   color: tuple (triplet)
201         :param  color: RGB components of the color of the shape
202         
203         :return: True if the shape was found, False otherwise
204         """
205         logger.debug("displayShapeByName in PAL: %s with color %s" %
206                      (shapeName, color))
207         listSO = self.editor.study.FindObjectByName(shapeName, "GEOM")
208         for sObj in listSO:
209             entry = sObj.GetID()
210             geomObj = self.editor.getOrLoadObject(sObj)
211             if geomObj:
212                 shape = geomObj._narrow(GEOM.GEOM_Object)
213                 if shape:
214                     return self.displayShapeByEntry(entry,color,fit)
215         return False
216
217     ## Display the geometrical shape whose entry is given by \em entry. 
218     #  You should prefer use this function instead of the
219     #  displayShapeByName() which can have an unpredictable behavior in 
220     #  the case where several objects exist with the same name in the study.
221     def displayShapeByEntry(self, shapeStudyEntry, color = None, fit=True):
222         """
223         Display the geometrical shape whose entry is given by
224         `entry`. You should prefer use this function instead of the
225         displayShapeByName which can have an unpredictable behavior in
226         the case where several objects exist with the same name in the
227         study.
228         """
229         geomgui = salome.ImportComponentGUI("GEOM")
230         if fit:
231             geomgui.createAndDisplayFitAllGO(shapeStudyEntry)
232         else:
233             geomgui.createAndDisplayGO(shapeStudyEntry)
234         geomgui.setDisplayMode(shapeStudyEntry, DisplayMode)
235         if color is not None:
236             geomgui.setColor(shapeStudyEntry, color[0], color[1], color[2])
237         return True
238
239     ## Erase the geometrical shape whose entry is given by \em entry. 
240     #  Please note that the shape is just erased from the
241     #  viewer. The associated study object still exists in the study,
242     #  and the geom object still exists in the GEOM engine.
243     def eraseShapeByEntry(self, shapeStudyEntry):
244         """
245         Erase the geometrical shape whose entry is given by
246         `entry`. Please note that the shape is just erased from the
247         viewer. The associated study object still exists in the study,
248         and the geom object still exists in the GEOM engine.
249         """
250         geomgui = salome.ImportComponentGUI("GEOM")
251         eraseFromAllWindows=True
252         geomgui.eraseGO(shapeStudyEntry,eraseFromAllWindows)
253         return True
254
255
256     # ======================================================================
257     # Helper functions for a complete suppression of a shape from the
258     # SALOME session.
259     # ======================================================================
260     ## This completely deletes a geom shape.
261     #  \warning Please be aware that to delete a geom object, 
262     #  you have three operations to perform:
263     #    
264     #  1. erase the shape from the viewers
265     #  2. remove the entry from the study
266     #  3. destroy the underlying geom object
267     def deleteShape(self,shapeStudyEntry):
268         """
269         This completely deletes a geom shape.
270         
271         WARNING: please be aware that to delete a geom object, you have
272         three operations to perform:
273         
274         1. erase the shape from the viewers
275         2. remove the entry from the study
276         3. destroy the underlying geom object
277         """
278         self.eraseShapeByEntry(shapeStudyEntry)
279         shape = self.removeFromStudy(shapeStudyEntry)
280         shape.Destroy()
281
282     # ======================================================================
283     # Helper functions for interactivity with the object browser
284     # ======================================================================
285     ## Returns the GEOM object currently selected in the objects browser.
286     def getGeomObjectSelected(self):
287         """
288         Returns the GEOM object currently selected in the objects browser.
289         """
290         sobject, entry = guihelper.getSObjectSelected()
291         geomObject = self.getGeomObjectFromEntry(entry)
292         return geomObject
293
294     ## Returns the GEOM object associated to the specified entry,
295     #  (the entry is the identifier of an item in the active study)
296     def getGeomObjectFromEntry(self,entry):
297         """
298         Returns the GEOM object associated to the specified entry,
299         (the entry is the identifier of an item in the active study)
300         """
301         if entry is None:
302             return None
303         geomObject=IDToObject(entry, self.editor.study)
304         return geomObject._narrow(GEOM.GEOM_Object)
305
306 #
307 # ==================================================================
308 # Use cases and demo functions
309 # ==================================================================
310 #
311
312 # How to test?
313 # 1. Run a SALOME application including GEOM, and create a new study
314 # 2. In the console, enter:
315 #    >>> from salome.geom import geomtools
316 #    >>> geomtools.TEST_createBox()
317 # 3. Select the object named "box" in the browser
318 # 4. In the console, enter:
319 #    >>> geomtools.TEST_getGeomObjectSelected()
320
321 def TEST_createBox():
322     geompy = getGeompy()
323     box = geompy.MakeBoxDXDYDZ(200, 200, 200)
324     geompy.addToStudy( box, 'box' )    
325     if salome.sg.hasDesktop():
326         salome.sg.updateObjBrowser()
327
328
329 def TEST_getGeomObjectSelected():
330     tool = GeomStudyTools()
331     myGeomObject = tool.getGeomObjectSelected()
332     print(myGeomObject)
333
334 ## This test is a simple use case that illustrates how to create a
335 #  GEOM shape in a SALOME session (create the GEOM object, put in in
336 #  the study, and display the shape in a viewer) and delete a shape
337 #  from a SALOME session (erase the shape from the viewer, delete the
338 #  entry from the study, and finally destroy the underlying GEOM
339 #  object).
340 #  \ingroup geomtools
341 def TEST_createAndDeleteShape():
342     """
343     This test is a simple use case that illustrates how to create a
344     GEOM shape in a SALOME session (create the GEOM object, put in in
345     the study, and display the shape in a viewer) and delete a shape
346     from a SALOME session (erase the shape from the viewer, delete the
347     entry from the study, and finally destroy the underlying GEOM
348     object).
349     """
350     import salome
351     salome.salome_init()
352     study   = salome.myStudy
353
354     from salome.geom import geomtools
355     geompy = geomtools.getGeompy()
356     
357     from salome.kernel.studyedit import getStudyEditor
358     studyEditor = getStudyEditor()
359
360     gst = geomtools.GeomStudyTools(studyEditor)
361
362     # --------------------------------------------------
363     # Create a first shape (GEOM object)
364     radius = 5
365     length = 100
366     cylinder = geompy.MakeCylinderRH(radius, length)
367
368     # Register the shape in the study, at the root of the GEOM
369     # folder. A name must be specified. The register operation
370     # (addShapeToStudy) returns an identifier of the entry in the study.
371     cylinderName = "cyl.r%s.l%s"%(radius,length)
372     cylinderStudyEntry = gst.addShapeToStudy(cylinder, cylinderName)
373
374     # Display the registered shape in a viewer
375     gst.displayShapeByEntry(cylinderStudyEntry)
376
377     # --------------------------------------------------
378     # A second shape
379     radius = 10
380     sphere = geompy.MakeSphereR(radius)
381     sphereName = "sph.r%s"%radius
382     sphereStudyEntry = gst.addShapeToStudy(sphere, sphereName)
383     gst.displayShapeByEntry(sphereStudyEntry)
384
385     # --------------------------------------------------
386     # This new shape is stored in the study, but in a specific
387     # sub-folder, and is displayed in the viewer with a specific
388     # color.
389     length = 20
390     box = geompy.MakeBoxDXDYDZ(length,length,length)
391     boxName = "box.l%s"%length
392     folderName = "boxset" 
393     boxStudyEntry = gst.addShapeToStudy(box, boxName, folderName)
394     gst.displayShapeByEntry(boxStudyEntry,PreviewColor)
395
396     # --------------------------------------------------
397     # In this example, we illustrate how to erase a shape (the sphere)
398     # from the viewer. After this operation, the sphere is no longer
399     # displayed but still exists in the study. You can then redisplay
400     # it using the context menu of the SALOME object browser.
401     gst.eraseShapeByEntry(sphereStudyEntry)
402
403     # --------------------------------------------------
404     # In this last example, we completely delete an object from the
405     # SALOME session (erase from viewer, remove from study and finnaly
406     # destroy the object). This is done by a simple call to
407     # deleteShape().
408     gst.deleteShape(cylinderStudyEntry)
409
410     # --------------------------------------------------
411     # At the end of the execution of this test, you should have in
412     # the SALOME session:
413     # - the box, in a dedicated folder of the study, and displayed in the viewer
414     # - the sphere, in the standard place of the study, and not displayed 
415
416     # If you comment the deleteShape line, you should see the cylinder
417     # in the study and displayed in the viewer. 
418
419 if __name__ == "__main__":
420     #TEST_getGeomObjectSelected()
421     TEST_createAndDeleteShape()
422
423
424