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