Salome HOME
Colors for the structural elements (PAL #1882)
[modules/geom.git] / src / GEOM_PY / structelem / parts.py
index c4e2f8fe725dc7c4a561f58b74677d4e626fcbac..c2acc85c739133340c1d05e9becfc20d4cf24651 100644 (file)
@@ -1,22 +1,22 @@
 # -*- coding: utf-8 -*-
 #
-#  Copyright (C) 2007-2009      EDF R&D
-# 
-#    This file is part of PAL_SRC.
+# Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
 #
-#    PAL_SRC is free software; you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation; either version 2 of the License, or
-#    (at your option) any later version.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License.
 #
-#    PAL_SRC is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
 #
-#    You should have received a copy of the GNU General Public License
-#    along with PAL_SRC; if not, write to the Free Software
-#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 """
 This module defines the different structural element parts. It is used to
@@ -25,7 +25,10 @@ directly in the general case. Structural elements should be created by the
 class :class:`~salome.geom.structelem.StructuralElementManager`.
 """
 
+import math
+
 import salome
+import SALOMEDS
 
 from salome.kernel.logger import Logger
 from salome.kernel import termcolor
@@ -43,6 +46,16 @@ MIN_DIM_FOR_EXTRUDED_SHAPE = 2e-4
 MIN_LENGTH_FOR_EXTRUSION = 1e-4
 MIN_THICKNESS = 1e-5
 
+# Colors for the structural elements
+GREEN = SALOMEDS.Color(0.0, 1.0, 0.0)
+LIGHT_GREEN = SALOMEDS.Color(0.0, 1.0, 170.0/255.0)
+BLUE = SALOMEDS.Color(0.0, 0.0, 1.0)
+LIGHT_BLUE = SALOMEDS.Color(0.0, 0.5, 1.0)
+RED = SALOMEDS.Color(1.0, 0.0, 0.0)
+LIGHT_RED = SALOMEDS.Color(1.0, 0.5, 0.5)
+PURPLE = SALOMEDS.Color(170.0/255.0, 85.0/255.0, 1.0)
+ORANGE = SALOMEDS.Color(1.0, 170.0/255.0, 0.0)
+
 
 class InvalidParameterError(Exception):
     """
@@ -64,8 +77,8 @@ class InvalidParameterError(Exception):
 
 class SubShapeID:
     """
-    This class enables the use of subshapes in sets or as dictionary keys.
-    It implements __eq__ and __hash__ methods so that subshapes with the same
+    This class enables the use of sub-shapes in sets or as dictionary keys.
+    It implements __eq__ and __hash__ methods so that sub-shapes with the same
     CORBA object `mainShape` and the same `id` are considered equal.
     """
 
@@ -75,7 +88,7 @@ class SubShapeID:
 
     def getObj(self, geom):
         """
-        Return the subshape (GEOM object). `geom` is a pseudo-geompy object
+        Return the sub-shape (GEOM object). `geom` is a pseudo-geompy object
         used to find the geometrical object.
         """
         return geom.GetSubShape(self._mainShape, [self._id])
@@ -115,7 +128,7 @@ class StructuralElementPart:
     DEFAULT_NAME = "StructElemPart"
 
     def __init__(self, studyId, groupName, groupGeomObj, parameters,
-                 name = DEFAULT_NAME):
+                 name = DEFAULT_NAME, color = None):
         self._parameters = parameters
         self.groupName = groupName
         self._groupGeomObj = groupGeomObj
@@ -129,6 +142,9 @@ class StructuralElementPart:
         if mainShape is not None and listIDs is not None:
             for id in listIDs:
                 self.baseShapesSet.add(SubShapeID(mainShape, id))
+        self.color = color
+        if self.color is None:
+            self.color = self._groupGeomObj.GetColor()
 
     def _getParameter(self, nameList, default = None):
         """
@@ -189,9 +205,9 @@ class StructuralElementPart:
         """
         shape = self._buildPart()
         markers = self._buildMarkers()
-        shape.SetColor(self._groupGeomObj.GetColor())
+        shape.SetColor(self.color)
         for marker in markers:
-            marker.SetColor(self._groupGeomObj.GetColor())
+            marker.SetColor(self.color)
         return (shape, markers)
 
     def _buildPart(self):
@@ -217,7 +233,7 @@ class StructuralElementPart:
 
     def _getSubShapes(self, minDim = MIN_LENGTH_FOR_EXTRUSION):
         """
-        Find and return the base subshapes in the structural element part.
+        Find and return the base sub-shapes in the structural element part.
         """
         subShapes = []
         for subShapeID in self.baseShapesSet:
@@ -243,9 +259,9 @@ class Beam(StructuralElementPart):
     DEFAULT_NAME = "Beam"
 
     def __init__(self, studyId, groupName, groupGeomObj, parameters,
-                 name = DEFAULT_NAME):
+                 name = DEFAULT_NAME, color = None):
         StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
-                                       parameters, name)
+                                       parameters, name, color)
         self._orientation = orientation.Orientation1D()
 
     def _isReversed(self, path):
@@ -254,10 +270,11 @@ class Beam(StructuralElementPart):
         orientation is different than the orientation of the underlying OCC
         object.
         """
+        length = self.geom.BasicProperties(path)[0]
         p1 = self.geom.MakeVertexOnCurve(path, 0.0)
         p2 = self.geom.GetFirstVertex(path)
         dist = self.geom.MinDistance(p1, p2)
-        return dist != 0.0
+        return dist > length / 2
 
     def _getVertexAndTangentOnOrientedWire(self, path, param):
         """
@@ -295,7 +312,7 @@ class Beam(StructuralElementPart):
         """
         Build the structural element part.
         """
-        # Get all the subshapes in the group (normally only edges and wires)
+        # Get all the sub-shapes in the group (normally only edges and wires)
         paths = self._getSubShapes()
         listPipes = []
         withContact = False
@@ -346,30 +363,6 @@ class Beam(StructuralElementPart):
         return listMarkers
 
 
-class GeneralBeam(Beam):
-    """
-    This class defines a beam with a generic section. It is represented only
-    as the underlying wire. See class :class:`StructuralElementPart` for the
-    description of the parameters.
-    """
-
-    def __init__(self, studyId, groupName, groupGeomObj, parameters,
-                 name = Beam.DEFAULT_NAME):
-        Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
-                      name)
-        logger.debug(repr(self))
-
-    def _buildPart(self):
-        """
-        Create a copy of the underlying wire.
-        """
-        edges = self._getSubShapes(1e-7)
-        wire = None
-        if len(edges) > 0:
-            wire = self.geom.MakeWire(edges)
-        return wire
-
-
 class CircularBeam(Beam):
     """
     This class defines a beam with a circular section. It can be full or
@@ -389,9 +382,15 @@ class CircularBeam(Beam):
     """
 
     def __init__(self, studyId, groupName, groupGeomObj, parameters,
-                 name = Beam.DEFAULT_NAME):
+                 name = Beam.DEFAULT_NAME, color = None):
+        if color is None:
+            if parameters.has_key("R1"): # variable section
+                color = LIGHT_RED
+            else:                       # constant section
+                color = RED
+
         Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
-                      name)
+                      name, color)
 
         self.R1 = self._getParameter(["R1", "R"])
         self.R2 = self._getParameter(["R2", "R"])
@@ -472,9 +471,15 @@ class RectangularBeam(Beam):
     """
 
     def __init__(self, studyId, groupName, groupGeomObj, parameters,
-                 name = Beam.DEFAULT_NAME):
+                 name = Beam.DEFAULT_NAME, color = None):
+        if color is None:
+            if parameters.has_key("HY1") or parameters.has_key("H1"):
+                color = LIGHT_BLUE # variable section
+            else:                  # constant section
+                color = BLUE
+
         Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
-                      name)
+                      name, color)
 
         self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
         self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
@@ -530,42 +535,97 @@ class RectangularBeam(Beam):
                             "%s - 2 * %s" % (self._getParamUserName("HZ2"),
                                              self._getParamUserName("EPZ2")))
 
-    def _makeRectangle(self, HY, HZ, planeSect):
+    def _makeRectangle(self, HY, HZ, lcs):
         """
         Create a rectangle in the specified plane.
         """
         halfHY = HY / 2.0
         halfHZ = HZ / 2.0
-        sketchStr = "Sketcher:F %g" % (-halfHZ) + " %g" % (-halfHY) + ":"
-        sketchStr += "TT %g" % (halfHZ) + " %g" % (-halfHY) + ":"
-        sketchStr += "TT %g" % (halfHZ) + " %g" % (halfHY) + ":" 
-        sketchStr += "TT %g" % (-halfHZ) + " %g" % (halfHY) + ":WW"
+        sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
+        sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
+        sketchStr += "TT %g %g:" % (halfHY, halfHZ)
+        sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
         logger.debug('Drawing rectangle: "%s"' % sketchStr)
-        sketch = self.geom.MakeSketcherOnPlane(sketchStr, planeSect)
+        sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
         return sketch
 
-    def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
+    def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
         """
-        Create the rectangular sections used to build the pipe.
+        Create one side of the rectangular sections used to build the pipe.
         """
-        planeSect1 = self.geom.MakePlane(fPoint, fNormal, 1.0)
-        outerRect1 = self._makeRectangle(self.HY1, self.HZ1, planeSect1)
-        planeSect2 = self.geom.MakePlane(lPoint, lNormal, 1.0)
-        outerRect2 = self._makeRectangle(self.HY2, self.HZ2, planeSect2)
+        (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
+        lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
+        outerRect = self._makeRectangle(HY, HZ, lcs)
         if self.filling == HOLLOW:
-            innerRect1 = self._makeRectangle(self.HY1 - 2 * self.EPY1,
-                                             self.HZ1 - 2 * self.EPZ1,
-                                             planeSect1)
-            innerRect2 = self._makeRectangle(self.HY2 - 2 * self.EPY2,
-                                             self.HZ2 - 2 * self.EPZ2,
-                                             planeSect2)
+            innerRect = self._makeRectangle(HY - 2.0 * EPY,
+                                            HZ - 2.0 * EPZ,
+                                            lcs)
         else:
-            innerRect1 = None
-            innerRect2 = None
+            innerRect = None
+        return (outerRect, innerRect)
 
+    def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
+        """
+        Create the rectangular sections used to build the pipe.
+        """
+        (outerRect1, innerRect1) = \
+            self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
+                                        self.EPY1, self.EPZ1)
+        (outerRect2, innerRect2) = \
+            self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
+                                        self.EPY2, self.EPZ2)
         return (outerRect1, innerRect1, outerRect2, innerRect2)
 
 
+def getParameterInDict(nameList, parametersDict, default = None):
+    """
+    This method finds the value of a parameter in the parameters
+    dictionary. The argument is a list because some parameters can have
+    several different names.
+    """
+    for name in nameList:
+        if parametersDict.has_key(name):
+            return parametersDict[name]
+    return default
+
+
+class GeneralBeam(RectangularBeam):
+    """
+    This class defines a beam with a generic section. It is represented as a
+    full rectangular beam with the following parameters:
+    
+    * HY1 = sqrt(12 * IZ1 / A1)
+    * HZ1 = sqrt(12 * IY1 / A1)
+    * HY2 = sqrt(12 * IZ2 / A2)
+    * HZ2 = sqrt(12 * IY2 / A2)
+    
+    See class :class:`StructuralElementPart` for the description of the other
+    parameters.
+    """
+
+    def __init__(self, studyId, groupName, groupGeomObj, parameters,
+                 name = Beam.DEFAULT_NAME, color = None):
+        self.IY1 = getParameterInDict(["IY1", "IY"], parameters)
+        self.IZ1 = getParameterInDict(["IZ1", "IZ"], parameters)
+        self.IY2 = getParameterInDict(["IY2", "IY"], parameters)
+        self.IZ2 = getParameterInDict(["IZ2", "IZ"], parameters)
+        self.A1 = getParameterInDict(["A1", "A"], parameters)
+        self.A2 = getParameterInDict(["A2", "A"], parameters)
+        parameters["HY1"] = math.sqrt(12 * self.IZ1 / self.A1)
+        parameters["HZ1"] = math.sqrt(12 * self.IY1 / self.A1)
+        parameters["HY2"] = math.sqrt(12 * self.IZ2 / self.A2)
+        parameters["HZ2"] = math.sqrt(12 * self.IY2 / self.A2)
+
+        if color is None:
+            if parameters.has_key("IY1"): # variable section
+                color = LIGHT_GREEN
+            else:                         # constant section
+                color = GREEN
+
+        RectangularBeam.__init__(self, studyId, groupName, groupGeomObj, parameters,
+                                 name, color)
+
+
 class StructuralElementPart2D(StructuralElementPart):
     """
     This class is an "abstract" class for all 2D structural element parts. It
@@ -910,27 +970,31 @@ def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
     """
     Alias for class :class:`GeneralBeam`.
     """
-    return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
+    return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name,
+                       color = ORANGE)
       
 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
                        name = "BARRE"):
     """
     Alias for class :class:`RectangularBeam`.
     """
-    return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
+    return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name,
+                           color = ORANGE)
 
 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
                     name = "BARRE"):
     """
     Alias for class :class:`CircularBeam`.
     """
-    return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
+    return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
+                        color = ORANGE)
 
 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
     """
     Alias for class :class:`CircularBeam`.
     """
-    return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
+    return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
+                        color = PURPLE)
 
 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
     """