Salome HOME
Integration of a patch from Renaud Barate which fixes some issues at install step...
[modules/geom.git] / src / GEOM_PY / geomtools.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2007-2013  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.
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 This module provides tools to facilitate the use of geom engine and geom
23 objects in Salome.
24 """
25 import salome
26 GEOM = None    # GEOM module is loaded only when needed
27
28 from salome.kernel.logger import Logger
29 from salome.kernel import termcolor
30 logger = Logger("salome.geom.geomtools", color = termcolor.RED)
31
32 from salome.kernel.studyedit import getActiveStudyId, getStudyEditor
33 from salome.kernel.services import IDToObject, IDToSObject
34 from salome.kernel.deprecation import is_called_by_sphinx
35 if not is_called_by_sphinx():
36     from salome.gui import helper as guihelper
37
38 _geompys = {}
39
40 def getGeompy(studyId = None):
41     """
42     Return an object behaving exactly like geompy module, except that it is
43     associated with the study `studyId`. If `studyId` is :const:`None`, return
44     a pseudo geompy object for the current study.
45     """
46     # We can't use geompy module because it initializes GEOM with
47     # salome.myStudy, which may not exist. So we use this trick to create
48     # a pseudo geompy module. 
49     salome.salome_init()
50     if studyId is None:
51         studyId = getActiveStudyId()
52     if not _geompys.has_key(studyId):
53         from salome.geom import geomBuilder
54         study = salome.myStudyManager.GetStudyByID(studyId)
55         _geompys[studyId] = geomBuilder.New(study)
56     return _geompys[studyId]
57
58
59 ModeWireFrame = 0
60 ModeShading = 1
61 DisplayMode=ModeShading
62 PreviewColor=[236,163,255]
63
64 class GeomStudyTools:
65     """
66     This class provides several methods to manipulate geom objects in Salome
67     study. The parameter `studyEditor` defines a
68     :class:`~salome.kernel.studyedit.StudyEditor` object used to access the study. If
69     :const:`None`, the method returns a :class:`~salome.kernel.studyedit.StudyEditor`
70     object on the current study.
71
72     .. attribute:: editor
73     
74        This instance attribute contains the underlying
75        :class:`~salome.kernel.studyedit.StudyEditor` object. It can be used to access
76        the study but the attribute itself should not be modified.
77
78     """
79
80     def __init__(self, studyEditor = None):
81         global GEOM
82         if GEOM is None:
83             GEOM = __import__("GEOM")
84         if studyEditor is None:
85             studyEditor = getStudyEditor()
86         self.editor = studyEditor
87
88     # ======================================================================
89     # Helper functions to add/remove a geometrical shape in/from the study
90     # ======================================================================
91     def addShapeToStudy(self, shape,shapeName,folderName=None):
92         """
93         Add a GEOM shape in the study. It returns the associated entry
94         that corresponds to the identifier of the entry in the study. This
95         entry can be used to retrieve an object in the study. A folderName
96         can be specified. In this case, a folder with this name is first
97         created in the Geometry part of the study, and the shape study
98         object is stored in this folder of the study. 
99
100         :type   shape: GEOM object
101         :param  shape: the GEOM object defining the shape
102
103         :type   shapeName: string
104         :param  shapeName: the name for this shape in the study 
105
106         :type   folderName: string
107         :param  folderName: the name of a folder in the GEOM part of the study
108         """
109         study   = self.editor.study
110         studyId = study._get_StudyId()
111         geompy  = getGeompy(studyId)
112
113         if folderName is None:
114             # Insert the shape in the study by the standard way
115             entry = geompy.addToStudy( shape, shapeName )
116         else:
117             # A folder name has been specified to embed this shape. Find
118             # or create a folder with this name in the Geometry study, and
119             # then store the shape in this folder.
120             geomStudyFolder = self.editor.findOrCreateComponent("GEOM")
121             shapeStudyFolder = self.editor.findOrCreateItem(geomStudyFolder,folderName)
122             
123             shapeIor = salome.orb.object_to_string(shape)
124             geomgui = salome.ImportComponentGUI("GEOM")
125             shapeIcon = geomgui.getShapeTypeIcon(shapeIor)
126             
127             shapeStudyObject = self.editor.createItem(shapeStudyFolder,
128                                                       name=shapeName,
129                                                       IOR=shapeIor,
130                                                       icon=shapeIcon)
131             entry = shapeStudyObject.GetID()
132
133         return entry
134
135     def removeFromStudy(self, shapeStudyEntry):
136         """
137         This removes the specified entry from the study. Note that this
138         operation does not destroy the underlying GEOM object, neither
139         erase the drawing in the viewer.
140         The underlying GEOM object is returned (so that it can be destroyed)
141         """
142         study = self.editor.study
143         studyId = study._get_StudyId()
144         shape = self.getGeomObjectFromEntry(shapeStudyEntry)    
145         studyObject = IDToSObject(shapeStudyEntry)
146         self.editor.removeItem(studyObject,True)
147         return shape
148
149     # ======================================================================
150     # Helper functions to display/erase a shape in/from the viewer. The
151     # shape must be previously put in the study and the study entry must
152     # be known. Note also that these function works implicitly on the
153     # active study (WARN: it does not ensure consistency with the
154     # study associated to the studyEditor used to initiate this
155     # object. It's up to you to be self-consistent (or to improve this
156     # python source code). 
157     # ======================================================================
158
159     def displayShapeByName(self, shapeName, color = None, fit=True):
160         """
161         Display the geometrical shape whose name in the study is `shapeName`.
162         
163         :type   shapeName: string
164         :param  shapeName: name of the geometrical shape
165         
166         :type   color: tuple (triplet)
167         :param  color: RGB components of the color of the shape
168         
169         :return: True if the shape was found, False otherwise
170         """
171         logger.debug("displayShapeByName in PAL: %s with color %s" %
172                      (shapeName, color))
173         listSO = self.editor.study.FindObjectByName(shapeName, "GEOM")
174         for sObj in listSO:
175             entry = sObj.GetID()
176             geomObj = self.editor.getOrLoadObject(sObj)
177             if geomObj:
178                 shape = geomObj._narrow(GEOM.GEOM_Object)
179                 if shape:
180                     return self.displayShapeByEntry(entry,color,fit)
181         return False
182
183     def displayShapeByEntry(self, shapeStudyEntry, color = None, fit=True):
184         """
185         Display the geometrical shape whose entry is given by
186         `entry`. You should prefer use this function instead of the
187         displayShapeByName which can have an unpredictible behavior in
188         the case where several objects exist with the same name in the
189         study.
190         """
191         geomgui = salome.ImportComponentGUI("GEOM")
192         if fit:
193             geomgui.createAndDisplayFitAllGO(shapeStudyEntry)
194         else:
195             geomgui.createAndDisplayGO(shapeStudyEntry)
196         geomgui.setDisplayMode(shapeStudyEntry, DisplayMode)
197         if color is not None:
198             geomgui.setColor(shapeStudyEntry, color[0], color[1], color[2])
199         return True
200
201     def eraseShapeByEntry(self, shapeStudyEntry):
202         """
203         Erase the geometrical shape whose entry is given by
204         `entry`. Please note that the shape is just erased from the
205         viewer. The associated study object still exists in the study,
206         and the geom object still exists in the GEOM engine.
207         """
208         geomgui = salome.ImportComponentGUI("GEOM")
209         eraseFromAllWindows=True
210         geomgui.eraseGO(shapeStudyEntry,eraseFromAllWindows)
211         return True
212
213
214     # ======================================================================
215     # Helper functions for a complete suppression of a shape from the
216     # SALOME session.
217     # ======================================================================
218     def deleteShape(self,shapeStudyEntry):
219         """
220         This completly deletes a geom shape.
221         
222         WARNING: please be aware that to delete a geom object, you have
223         three operations to perform:
224         
225         1. erase the shape from the viewers
226         2. remove the entry from the study
227         3. destroy the underlying geom object
228         """
229         self.eraseShapeByEntry(shapeStudyEntry)
230         shape = self.removeFromStudy(shapeStudyEntry)
231         shape.Destroy()
232
233     # ======================================================================
234     # Helper functions for interactivity with the object browser
235     # ======================================================================
236     def getGeomObjectSelected(self):
237         '''
238         Returns the GEOM object currently selected in the objects browser.
239         '''
240         sobject, entry = guihelper.getSObjectSelected()
241         geomObject = self.getGeomObjectFromEntry(entry)
242         return geomObject
243
244     def getGeomObjectFromEntry(self,entry):
245         '''
246         Returns the GEOM object associated to the specified entry,
247         (the entry is the identifier of an item in the active study)
248         '''
249         if entry is None:
250             return None
251         geomObject=IDToObject(entry, self.editor.study)
252         return geomObject._narrow(GEOM.GEOM_Object)
253
254 #
255 # ==================================================================
256 # Use cases and demo functions
257 # ==================================================================
258 #
259
260 # How to test?
261 # 1. Run a SALOME application including GEOM, and create a new study
262 # 2. In the console, enter:
263 #    >>> from salome.geom import geomtools
264 #    >>> geomtools.TEST_createBox()
265 # 3. Select the object named "box" in the browser
266 # 4. In the console, enter:
267 #    >>> geomtools.TEST_getGeomObjectSelected()
268
269 def TEST_createBox():
270     geompy = getGeompy()
271     box = geompy.MakeBoxDXDYDZ(200, 200, 200)
272     geompy.addToStudy( box, 'box' )    
273     if salome.sg.hasDesktop():
274         salome.sg.updateObjBrowser(1)
275
276
277 def TEST_getGeomObjectSelected():
278     tool = GeomStudyTools()
279     myGeomObject = tool.getGeomObjectSelected()
280     print myGeomObject
281
282 def TEST_createAndDeleteShape():
283     """
284     This test is a simple use case that illustrates how to create a
285     GEOM shape in a SALOME session (create the GEOM object, put in in
286     the study, and display the shape in a viewer) and delete a shape
287     from a SALOME session (erase the shape from the viewer, delete the
288     entry from the study, and finally destroy the underlying GEOM
289     object).
290     """
291     import salome
292     salome.salome_init()
293     study   = salome.myStudy
294     studyId = salome.myStudyId
295
296     from salome.geom import geomtools
297     geompy = geomtools.getGeompy(studyId)
298     
299     from salome.kernel.studyedit import getStudyEditor
300     studyEditor = getStudyEditor(studyId)
301
302     gst = geomtools.GeomStudyTools(studyEditor)
303
304     # --------------------------------------------------
305     # Create a first shape (GEOM object)
306     radius = 5
307     length = 100
308     cylinder = geompy.MakeCylinderRH(radius, length)
309
310     # Register the shape in the study, at the root of the GEOM
311     # folder. A name must be specified. The register operation
312     # (addShapeToStudy) returns an identifier of the entry in the study.
313     cylinderName = "cyl.r%s.l%s"%(radius,length)
314     cylinderStudyEntry = gst.addShapeToStudy(cylinder, cylinderName)
315
316     # Display the registered shape in a viewer
317     gst.displayShapeByEntry(cylinderStudyEntry)
318
319     # --------------------------------------------------
320     # A second shape
321     radius = 10
322     sphere = geompy.MakeSphereR(radius)
323     sphereName = "sph.r%s"%radius
324     sphereStudyEntry = gst.addShapeToStudy(sphere, sphereName)
325     gst.displayShapeByEntry(sphereStudyEntry)
326
327     # --------------------------------------------------
328     # This new shape is stored in the study, but in a specific
329     # sub-folder, and is displayed in the viewer with a specific
330     # color.
331     length = 20
332     box = geompy.MakeBoxDXDYDZ(length,length,length)
333     boxName = "box.l%s"%length
334     folderName = "boxset" 
335     boxStudyEntry = gst.addShapeToStudy(box, boxName, folderName)
336     gst.displayShapeByEntry(boxStudyEntry,PreviewColor)
337
338     # --------------------------------------------------
339     # In this example, we illustrate how to erase a shape (the sphere)
340     # from the viewer. After this operation, the sphere is no longer
341     # displayed but still exists in the study. You can then redisplay
342     # it using the context menu of the SALOME object browser.
343     gst.eraseShapeByEntry(sphereStudyEntry)
344
345     # --------------------------------------------------
346     # In this last example, we completly delete an object from the
347     # SALOME session (erase from viewer, remove from study and finnaly
348     # destroy the object). This is done by a simple call to
349     # deleteShape().
350     gst.deleteShape(cylinderStudyEntry)
351
352     # --------------------------------------------------
353     # At the end of the executioon of this test, you should have in
354     # the SALOME session:
355     # - the box, in a dedicated folder of the study, and displayed in the viewer
356     # - the sphere, in the standard place of the study, and not displayed 
357
358     # If you comment the deleteShape line, you should see the cylinder
359     # in the study and displayed in the viewer. 
360
361 if __name__ == "__main__":
362     #TEST_getGeomObjectSelected()
363     TEST_createAndDeleteShape()
364
365
366