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