From 6c4a9f32ed7b4416d79e0d0d293919609a8eb178 Mon Sep 17 00:00:00 2001 From: eap Date: Tue, 17 Mar 2015 15:06:56 +0300 Subject: [PATCH] IMP 22792: EDF 8159 SMESH: Multi-dimensional extrusion/extrusion along a path/revolution + Pre-open MED file to speed-up reading/writing (following 22349) + Clock-cursor in Display Entity dlg + In Filter dlg, do not perform filtering if it's not needed + In Group dlg, store a user-given name of a new group + Clock-cursor after hypothesis modif as mesh clearing can be long + Treat selected object right at opening of Measure dlgs + Allow removal of elements in a not shown mesh + Make filter work on a not shown mesh + Don't leave orphan nodes at RemoveGroupWithContents + Avoid crash when exporting a group + fields --- .../SMESH/images/extrusion_along_path_dlg.png | Bin 38296 -> 44946 bytes .../gui/SMESH/images/extrusionalongaline1.png | Bin 25482 -> 37137 bytes .../gui/SMESH/images/extrusionalongaline2.png | Bin 28437 -> 38678 bytes .../gui/SMESH/images/extrusionalongaline3.png | Bin 27516 -> 39501 bytes doc/salome/gui/SMESH/images/revolution1.png | Bin 19489 -> 46010 bytes doc/salome/gui/SMESH/input/extrusion.doc | 116 +- .../gui/SMESH/input/extrusion_along_path.doc | 114 +- doc/salome/gui/SMESH/input/revolution.doc | 150 +- idl/SMESH_MeshEditor.idl | 388 +--- src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx | 25 +- src/SMESH/SMESH_MeshEditor.cxx | 558 +++--- src/SMESH/SMESH_MeshEditor.hxx | 12 +- .../SMESHGUI_Add0DElemsOnAllNodesDlg.cxx | 2 +- src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx | 3 +- src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx | 29 +- .../SMESHGUI_ExtrusionAlongPathDlg.cxx | 728 +++---- src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h | 46 +- src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx | 1368 +++++++------ src/SMESHGUI/SMESHGUI_ExtrusionDlg.h | 100 +- src/SMESHGUI/SMESHGUI_FilterDlg.cxx | 15 +- src/SMESHGUI/SMESHGUI_GroupDlg.cxx | 4 +- src/SMESHGUI/SMESHGUI_Hypotheses.cxx | 6 +- src/SMESHGUI/SMESHGUI_Measurements.cxx | 10 +- src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx | 4 +- src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx | 5 + src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx | 723 ++----- src/SMESHGUI/SMESHGUI_RevolutionDlg.h | 57 +- src/SMESHGUI/SMESHGUI_ScaleDlg.cxx | 10 +- src/SMESHGUI/SMESHGUI_Utils.h | 2 +- src/SMESHGUI/SMESH_msg_en.ts | 70 +- src/SMESHUtils/SMESH_TypeDefs.hxx | 2 +- src/SMESH_I/SMESH_2smeshpy.cxx | 5 +- src/SMESH_I/SMESH_Filter_i.cxx | 1 + src/SMESH_I/SMESH_MeshEditor_i.cxx | 1730 ++++------------- src/SMESH_I/SMESH_MeshEditor_i.hxx | 338 +--- src/SMESH_I/SMESH_Mesh_i.cxx | 25 +- src/SMESH_SWIG/smeshBuilder.py | 410 ++-- 37 files changed, 2588 insertions(+), 4468 deletions(-) mode change 100755 => 100644 doc/salome/gui/SMESH/images/revolution1.png diff --git a/doc/salome/gui/SMESH/images/extrusion_along_path_dlg.png b/doc/salome/gui/SMESH/images/extrusion_along_path_dlg.png index 540bce24a2cb7a31e0f5e1491eca0a46f3009fcc..bdc1eff88c7f175904f644fd8bcd23f1d2dba8ea 100644 GIT binary patch literal 44946 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 z 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 QALb!hNhOIa#N*fh3-X!n#sB~S literal 25482 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�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 diff --git a/doc/salome/gui/SMESH/images/extrusionalongaline3.png b/doc/salome/gui/SMESH/images/extrusionalongaline3.png index beb14ec8157119fe2b49613aad8f05f22c33841b..a75601c01190526fbd04295b6d898c5925424826 100644 GIT binary patch literal 39501 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 diff --git a/doc/salome/gui/SMESH/input/extrusion.doc b/doc/salome/gui/SMESH/input/extrusion.doc index e3ea63c1e..6337e5a0e 100644 --- a/doc/salome/gui/SMESH/input/extrusion.doc +++ b/doc/salome/gui/SMESH/input/extrusion.doc @@ -3,12 +3,12 @@ \page extrusion_page Extrusion \n Extrusion is used to build mesh elements of plus one -dimension than the input ones. Boundary elements around elements of -plus one dimension are additionally created. All created elements -can be automatically grouped. Extrusion can be used to create a -\ref extrusion_struct "structured mesh from scratch". +dimension than the input ones. Boundary elements around generated +mesh of plus one dimension are additionally created. All created +elements can be automatically grouped. Extrusion can be used to create +a \ref extrusion_struct "structured mesh from scratch". -\image html extrusion_box.png "If you extruded e.g. several quadrangles, you get exactly same mesh as if you meshed a geometrical box (except that the initial quadrangles can be incorrectly oriented)" +\image html extrusion_box.png "If you extrude several quadrangles, you get exactly same mesh as if you meshed a geometrical box (except that the initial quadrangles can be incorrectly oriented): quadrangles and segments on boundary of generated mesh are created"

Any node, segment or 2D element can be extruded. Each type of elements is extruded into a corresponding type of result elements: @@ -32,7 +32,8 @@ elements is extruded into a corresponding type of result elements: "Extrusion" button -The following dialog common for node, segments and faces will appear: +The following dialog, looking different depending on selected options, +will appear: \image html extrusionalongaline1.png @@ -44,65 +45,72 @@ The following dialog common for node, segments and faces will appear:

  • In this dialog:
      -
    • Select the type of elements which will be extruded (nodes, 1D or - 2D elements).
    • -
    • Specify the IDs of the elements which will be extruded by one - following means: +
    • Specify \b Nodes, \b Edges and \b Faces, which will be extruded, by one + of following means:
      • Select the whole mesh, sub-mesh or group activating this checkbox.
      • Choose mesh elements with the mouse in the 3D Viewer. It is possible to select a whole area with a mouse frame.
      • -
      • Input the element IDs directly in ID Elements - field. The selected elements will be highlighted in the viewer.
      • +
      • Input the element IDs directly in Node IDs, Edge + IDs and Face IDs fields. The selected elements will + be highlighted in the viewer, if the mesh is shown there.
      • Apply Filters. Set filter button allows to apply a filter to the selection of elements. See more about filters in the \ref filtering_elements "Selection filters" page.
    • -
    • If the Extrusion to Distance radio button is selected
    • -
        -
      • specify the translation vector by which the elements will be extruded.
      • -
      -
    • If the Extrusion Along Vector radio button is selected
    • -
        -
      • specify the coordinates of the \b Vector along which the elements - will be extruded, or select the face (the normal to the face will - define the vector),
      • -
      • specify the \b Distance of extrusion along the vector (it can - be negative).
      • -
      +
    • If the Extrusion to Distance radio button is selected + - specify the translation vector by which the elements will be extruded. +
    • +
    • If the Extrusion Along Vector radio button is selected +
        +
      • specify the coordinates of the \b Vector along which the elements + will be extruded, either directly or by selecting the mesh face (the + normal to the face will define the vector),
      • +
      • specify the \b Distance of extrusion along the vector (it can + be negative).
      • +
      +
    • If the Extrusion By Normal radio button is selected, - which is visible in \b 2D mode only, every node of selected - elements is extruded along the \a average of the \a normal vectors to - the faces sharing the node.
    • -
        -
      • Specify the \b Distance of extrusion (it can be negative),
      • -
      • Use Along average normal check-box to specify along - what vector the distance is measured. If it is \a activated the - distance is measured along the average normal mentioned - above. If it is \a deactivated every node is extruded along the - average normal till its intersection with the virtual plane got - by translation of the face sharing the node along its own normal - by the distance.
        - The picture below shows a cross-section of a 2D mesh extruded - with Along average normal activated (to the left) and - deactivated (to the right). - - \image html extrusionbynormal_alongavgnorm.png -

      • -
      • Using Use only input elements check-box to specify what - elements to use to compute the average normal. If it is \a - activated only selected faces, among faces sharing the node, - are used to compute the average normal at the node. Else all - faces sharing the node are used.
        - The picture below shows a cross-section of a 2D mesh the upper - plane of which is extruded with Use only input elements - activated (to the left) and deactivated (to the right). - - \image html extrusionbynormal_useonly.png -

      • + every node of selected faces is extruded along the \a average + of the \a normal vectors to the faces sharing the node. (Nodes and + edges can't be extruded in this mode.) +
          +
        • Specify the \b Distance of extrusion (it can be negative),
        • +
        • Use Along average normal check-box to specify along + what vector the distance is measured. +
            +
          • If it is \a activated the distance is measured along the + average normal mentioned above.
          • +
          • If it is \a deactivated every node is extruded along the + average normal till its intersection with the virtual plane got + by translation of the face sharing the node along its own normal + by the \b Distance.
          • +
          + The picture below shows a cross-section of a 2D mesh extruded + with Along average normal activated (to the left) and + deactivated (to the right). + + \image html extrusionbynormal_alongavgnorm.png "'Along average normal' activated (to the left) and deactivated (to the right)" +

        • + +
        • Using Use only input elements check-box specify what + elements to use to compute the average normal.
            +
          • If it is \a activated only selected faces, among faces + sharing the node, are used to compute the average normal at + the node.
          • +
          • Else all faces sharing the node are used.
          + + The picture below shows a cross-section of a 2D mesh the upper + plane of which is extruded with Use only input elements + activated (to the left) and deactivated (to the right). + + \image html extrusionbynormal_useonly.png "'Use only input elements' activated (to the left) and deactivated (to the right)" +

        • +
        +
      • Specify the Number of steps.
      • If you activate Generate Groups check-box, the result elements created from selected elements contained in groups will be @@ -120,6 +128,8 @@ The following dialog common for node, segments and faces will appear:
      • Click \b Apply or Apply and Close button to confirm the operation.
      • +

        + \anchor extrusion_struct

        Example: creation of a structured mesh from scratch

        diff --git a/doc/salome/gui/SMESH/input/extrusion_along_path.doc b/doc/salome/gui/SMESH/input/extrusion_along_path.doc index 4de60e535..7151f77b8 100644 --- a/doc/salome/gui/SMESH/input/extrusion_along_path.doc +++ b/doc/salome/gui/SMESH/input/extrusion_along_path.doc @@ -3,7 +3,7 @@ \page extrusion_along_path_page Extrusion along Path \n In principle, Extrusion along Path works in the same way -as \b Extrusion, the main difference is that we define not a vector, +as \ref extrusion_page "Extrusion", the main difference is that we define not a vector, but a path of extrusion which must be a 1D mesh or 1D sub-mesh. To get an idea of how this algorithm works, examine several examples, starting from the most simple case of extrusion along a straight edge. @@ -77,75 +77,93 @@ path item or click "Extrusion along a path" button in the toolbar. \image html image101.png
        "Extrusion along a path" button
        -The following dialog common for line and planar elements will appear: +The following dialog will appear: \image html extrusion_along_path_dlg.png
      • In this dialog:
          -
        • select the type of elements which will be extruded (1D or 2D),
        • -
        • specify the IDs of the elements which will be extruded - -
            -
          • Select the whole mesh, sub-mesh or group activating the corresponding check-box; or
          • -
          • Choose mesh elements with the mouse in the 3D Viewer. It is -possible to select a whole area with a mouse frame; or
          • -
          • Input the element IDs directly in ID Elements field. The selected elements will be highlighted in the -viewer; or
          • -
          • apply Filters. Set filter button allows to apply a filter to the selection of elements. See more -about filters in the \ref selection_filter_library_page "Selection filter library" page.
          • -
          - -
        • -
        • Define the \b Path along which the elements will be extruded.
          - Path definition consists of several elements: -
            -
          • Mesh or submesh - 1D mesh or sub-mesh, along which proceeds the extrusion
          • -
          • Start node - the start node. It is used to define the direction of extrusion
          • -
          -
        • -
        • Activate Generate Groups check-box if it is necessary to copy the groups of - elements of the source mesh to the newly created one.
        • +
        • Use \a Selection button to specify what you are going to + select at a given moment, \b Nodes, \b Edges or \b Faces. +\image html image120.png +
          "Selection" button
          +
        • +
        • Specify \b Nodes, \b Edges and \b Faces, which will be extruded, by one + of following means: +
            +
          • Select the whole mesh, sub-mesh or group activating this + checkbox.
          • +
          • Choose mesh elements with the mouse in the 3D Viewer. It is + possible to select a whole area with a mouse frame.
          • +
          • Input the element IDs directly in Node IDs, Edge + IDs and Face IDs fields. The selected elements will + be highlighted in the viewer, if the mesh is shown there.
          • +
          • Apply Filters. Set filter button allows to apply a + filter to the selection of elements. See more about filters in + the \ref filtering_elements "Selection filters" page.
          • +
          +
        • +
        • Define the \b Path along which the elements will be extruded.
          + Path definition consists of several elements: +
            +
          • Mesh or submesh - 1D mesh or sub-mesh, along which + proceeds the extrusion.
          • +
          • Start node - the start node. It is used to define + the direction of extrusion.
          • +
          +
        • +
        • If you activate Generate Groups check-box, the result elements + created from selected elements contained in groups will be + included into new groups named by pattern "_extruded" and "_top". For example if a + selected quadrangle is included in \a g_Faces group (see figures + below) then result hexahedra will be included in \a + g_Faces_extruded group and a quadrangle created at the "top" of + extruded mesh will be included in \a g_Faces_top group.
          +\image html extrusion_groups.png +\image html extrusion_groups_res.png +

          This check-box is active only if there are some groups in the mesh. +

      • There are two optional parameters, which can be very useful:
        • If the path of extrusion is curvilinear, at each iteration the -extruded elements are rotated to keep its initial angularity to the -curve. By default, the Base Point around which the elements are rotated is -the mass center of the elements, however, you can specify any point as -the Base Point and the elements will be rotated with respect to this -point.
          - Note that only the displacement of the Base Point exactly equals to the - path, and all other extruded elements simply keep their position relatively to the Base Point at each iteration. -
        • -
        • The elements can also be rotated around the path to get the resulting -mesh in a helical fashion. You can set the values of angles at the -right, add them to the list of angles at the left by pressing the "Add" -button and remove them from the list by pressing the "Remove" button. - + extruded elements are rotated to keep its initial angularity to the + curve. By default, the Base Point around which the elements + are rotated is the mass center of the elements, however, you can + specify any point as the Base Point and the elements will be + rotated with respect to this point.
          + Note that only the displacement of the Base Point exactly + equals to the path, and all other extruded elements simply keep + their position relatively to the Base Point at each + iteration.
        • +
        • The elements can also be rotated around the path to get the + resulting mesh in a helical fashion. You can set the values of + angles at the right, add them to the list of angles at the left by + pressing the "Add" button and remove them from the list by + pressing the "Remove" button. \image html add.png
          "Add" button
          - \image html remove.png
          "Remove" button
          -Linear variation of the angles option allows defining the angle of gradual rotation for the whole path. -At each step the elements will be rotated by angle / nb. of steps. - +Linear variation of the angles option allows defining the angle +of gradual rotation for the whole path. At each step the elements will +be rotated by angle / nb. of steps.
      • -
      • Click \b Apply or Apply and Close button to confirm the operation. -Mesh edges will be extruded into -faces, faces into volumes. The external surface of the resulting 3d -mesh (if faces have been extruded) is covered with faces, and corners -with edges. If the path is closed, the resulting mesh can contain -duplicated nodes and faces, because no sewing is done. +
      • Click \b Apply or Apply and Close button to confirm the + operation. Mesh edges will be extruded into faces, faces into + volumes. The external surface of the resulting 3d mesh (if faces + have been extruded) is covered with faces, and corners with + edges. If the path is closed, the resulting mesh can contain + duplicated nodes and faces, because no sewing is done.
      • diff --git a/doc/salome/gui/SMESH/input/revolution.doc b/doc/salome/gui/SMESH/input/revolution.doc index 1d13bb23a..69310e34f 100644 --- a/doc/salome/gui/SMESH/input/revolution.doc +++ b/doc/salome/gui/SMESH/input/revolution.doc @@ -2,16 +2,16 @@ \page revolution_page Revolution -\n Revolution is a type of surface meshing by generation from -discretized lines. It is used to build mesh elements of plus one -dimension than the swept ones. Each swept 1D element produces one or -more quadrangles (or triangles if one node of a rotated element lays -on the revolution axis). +\n Revolution is used to build mesh elements of plus one +dimension than the input ones. Boundary elements around generated +mesh of plus one dimension are additionally created. All created +elements can be automatically grouped. Revolution can be used to create +a \ref extrusion_struct "structured mesh from scratch". To apply revolution:
          -
        1. From the \b Modification menu choose the \b Revolution item or click -"Revolution" button in the toolbar. +
        2. From the \b Modification menu choose the \b Revolution item or click + "Revolution" button in the toolbar. \image html image92.png
          "Revolution" button
          @@ -20,65 +20,91 @@ The following dialog common for line and planar elements will appear: \image html revolution1.png -
        3. - -
        4. -In this dialog you should specify: -
            -
          • the type of elements which will be extruded (1D or 2D),
          • -
          • specify the IDs of the elements which will be revolved: - - -
              -
            • Select the whole mesh, submesh or group activating this -checkbox; or
            • -
            • choose mesh elements with the mouse in the 3D Viewer. It is -possible to select a whole area with a mouse frame; or
            • -
            • input the element IDs directly in ID Elements field. The selected elements will be highlighted in the -viewer; or
            • -
            • apply Filters. Set filter button allows to apply a filter to the selection of elements. See more -about filters in the \ref selection_filter_library_page "Selection filter library" page.
            • -
            -
          • - -
          • specify the axis of revolution: -
              -
            • specify the cooordinates of the start \b Point of the vector of revolution;
            • -
            • specify the \b Vector of revolution through the coordinates of its -end point with respect to the coordinates of the start -point. Alternatively, it is possible to specify the vector through the -normal to the selected face.
            • -
            -
          • - -
          • specify the angle of revolution and the number of revolution steps,
          • -
            • Angle by Step - the elements are extruded by the specified angle at each step (i.e. for Angle=30 and Number of Steps=2, the elements will be extruded - by 30 degrees twice for a total of 30*2=60)
            • - + + +
            • In this dialog: +
                +
              • Use \a Selection button to specify what you are going to + select at a given moment, \b Nodes, \b Edges or \b Faces. +\image html image120.png +
                "Selection" button
                +
              • +
              • Specify \b Nodes, \b Edges and \b Faces, which will be revolved, by one + of following means: +
                  +
                • Select the whole mesh, sub-mesh or group activating this + checkbox.
                • +
                • Choose mesh elements with the mouse in the 3D Viewer. It is + possible to select a whole area with a mouse frame.
                • +
                • Input the element IDs directly in Node IDs, Edge + IDs and Face IDs fields. The selected elements will + be highlighted in the viewer, if the mesh is shown there.
                • +
                • Apply Filters. Set filter button allows to apply a + filter to the selection of elements. See more about filters in + the \ref filtering_elements "Selection filters" page.
                • +
                +
              • +
              • Specify the \b Axis of revolution: +
                  +
                • Specify the cooordinates of the start \b Point of the + axis of revolution; either directly or by picking a node + in the Viewer (selection of nodes is activated as you click + the \a Selection button).
                • +
                • Specify the \b Vector of the axis in either of three ways: +
                    +
                  • directly adjust vector components;
                  • +
                  • click \a Selection button, chose From Origin to + selected Point in the opened menu and pick a node + in the Viewer;
                  • +
                  • click \a Selection button, chose Normal to + selected Face in the opened menu and pick a mesh + face in the Viewer.
                  • +
                +
              • +
              • Specify the \b Angle of revolution and the Number of + steps of revolution, +
                  +
                • Angle by Step - the elements are revolved by the + specified angle at each step (i.e. for Angle=30 and Number of + Steps=2, the elements will be extruded by 30 degrees twice for a + total of 30*2=60) \image html revolutionsn2.png "Example of Revolution with Angle by Step" - -
                • Total Angle - the elements are extruded by the specified angle only once and the number of steps defines the number of iterations -(i.e.for Angle=30 and Number of Steps=2, the elements will be extruded by 30/2=15 degrees twice for a total of 30).
                • - + +
                • Total Angle - the elements are revolved by the + specified angle only once and the number of steps defines the + number of iterations (i.e. for Angle=30 and Number of Steps=2, + the elements will be revolved by 30/2=15 degrees twice for a + total of 30). \image html revolutionsn1.png "Example of Revolution with Total Angle" - -
                -
              • - -
              • specify the tolerance for the operation
              • - -
              • activate Preview checkbox to show the parameter-setting in the viewer
              • -
              • activate Generate Groups checkbox to copy the groups of -elements of the source mesh to the newly created one.
              • - -
              - -
            • Click \b Apply or Apply and Close button to confirm the -operation.
            • + +
            + +
          • Specify the \b Tolerance for the operation, which is used to + detect nodes lying on the axis of revolution. +
          • +
          • Activate Preview check-box to see the result mesh in + the viewer. +
          • +
          • If you activate Generate Groups check-box, the result elements + created from selected elements contained in groups will be + included into new groups named by pattern "_rotated" and "_top". For example if a + selected quadrangle is included in \a g_Faces group (see figures + below) then result hexahedra will be included in \a + g_Faces_rotated group and a quadrangle created at the "top" of + revolved mesh will be included in \a g_Faces_top group.
            +\image html extrusion_groups.png +\image html extrusion_groups_res.png +

            This check-box is active only if there are some groups in the mesh. +

          • +
          +
        5. + +
        6. Click \b Apply or Apply and Close button to confirm the + operation.
        - -
        See Also a sample TUI Script of a +
        See Also a sample TUI Script of a \ref tui_revolution "Revolution" operation. */ diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 7da504cb5..699f63587 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -40,20 +40,20 @@ module SMESH { /*! * Return data of mesh edition preview which is computed provided - * that the editor was obtained trough SMESH_Mesh::GetMeshEditPreviewer() + * that the editor was obtained through SMESH_Mesh::GetMeshEditPreviewer() */ MeshPreviewStruct GetPreviewData() raises (SALOME::SALOME_Exception); /*! * If during last operation of MeshEditor some nodes were - * created this method returns list of their IDs, if new nodes + * created, this method returns list of their IDs, if new nodes * not created - returns empty list */ long_array GetLastCreatedNodes() raises (SALOME::SALOME_Exception); /*! * If during last operation of MeshEditor some elements were - * created this method returns list of their IDs, if new elements + * created, this method returns list of their IDs, if new elements * not created - returns empty list */ long_array GetLastCreatedElems() raises (SALOME::SALOME_Exception); @@ -393,7 +393,7 @@ module SMESH void ConvertFromQuadraticObject(in SMESH_IDSource theObject) raises (SALOME::SALOME_Exception); - void ConvertToBiQuadratic(in boolean theForce3d, + void ConvertToBiQuadratic(in boolean theForce3d, in SMESH_IDSource theObject) raises (SALOME::SALOME_Exception); @@ -402,198 +402,73 @@ module SMESH void RenumberElements() raises (SALOME::SALOME_Exception); /*! - * \brief Genarate dim+1 elements by rotation of given elements around axis - * \param IDsOfElements - elements to ratate - * \param Axix - rotation axis - * \param AngleInRadians - rotation angle - * \param NbOfSteps - number of elements to generate from one element - */ - void RotationSweep(in long_array IDsOfElements, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but additionally create groups of elements - * generated from elements belonging to preexisting groups - */ - ListOfGroups RotationSweepMakeGroups(in long_array IDsOfElements, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Genarate dim+1 elements by rotation of the object around axis - * \param theObject - object containing elements to ratate - * \param Axix - rotation axis - * \param AngleInRadians - rotation angle - * \param NbOfSteps - number of elements to generate from one element - */ - void RotationSweepObject(in SMESH_IDSource theObject, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but additionally create groups of elements - * generated from elements belonging to preexisting groups - */ - ListOfGroups RotationSweepObjectMakeGroups(in SMESH_IDSource theObject, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Genarate dim+1 elements by rotation of the object around axis - * \param theObject - object containing elements to ratate - * \param Axix - rotation axis - * \param AngleInRadians - rotation angle - * \param NbOfSteps - number of elements to generate from one element - */ - void RotationSweepObject1D(in SMESH_IDSource theObject, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but additionally create groups of elements - * generated from elements belonging to preexisting groups - */ - ListOfGroups RotationSweepObject1DMakeGroups(in SMESH_IDSource theObject, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Genarate dim+1 elements by rotation of the object around axis - * \param theObject - object containing elements to ratate - * \param Axix - rotation axis - * \param AngleInRadians - rotation angle - * \param NbOfSteps - number of elements to generate from one element - */ - void RotationSweepObject2D(in SMESH_IDSource theObject, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but additionally create groups of elements - * generated from elements belonging to preexisting groups - */ - ListOfGroups RotationSweepObject2DMakeGroups(in SMESH_IDSource theObject, - in AxisStruct Axix, - in double AngleInRadians, - in long NbOfSteps, - in double Tolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Genarate dim+1 elements by extrusion of elements along vector - * \param IDsOfElements - elements to sweep - * \param StepVector - vector giving direction and distance of an extrusion step - * \param NbOfSteps - number of elements to generate from one element - */ - void ExtrusionSweep(in long_array IDsOfElements, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - /*! - * \brief Genarate dim+1 elements by extrusion of elements along vector - * \param IDsOfElements - elements to sweep - * \param StepVector - vector giving direction and distance of an extrusion step - * \param NbOfSteps - number of elements to generate from one element - */ - void ExtrusionSweep0D(in long_array IDsOfElements, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but additionally create groups of elements - * generated from elements belonging to preexisting groups - */ - ListOfGroups ExtrusionSweepMakeGroups(in long_array IDsOfElements, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but elements are nodes - */ - ListOfGroups ExtrusionSweepMakeGroups0D(in long_array IDsOfElements, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - /*! - * Generate new elements by extrusion of theElements - * by StepVector by NbOfSteps - * param ExtrFlags set flags for performing extrusion - * param SewTolerance - uses for comparing locations of nodes if flag - * EXTRUSION_FLAG_SEW is set - */ - void AdvancedExtrusion(in long_array IDsOfElements, - in DirStruct StepVector, - in long NbOfSteps, - in long ExtrFlags, - in double SewTolerance) - raises (SALOME::SALOME_Exception); - /*! - * \brief Same as previous but additionally create groups of elements - * generated from elements belonging to preexisting groups - */ - ListOfGroups AdvancedExtrusionMakeGroups(in long_array IDsOfElements, - in DirStruct StepVector, - in long NbOfSteps, - in long ExtrFlags, - in double SewTolerance) - raises (SALOME::SALOME_Exception); - - void ExtrusionSweepObject(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionSweepObjectMakeGroups(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - - void ExtrusionSweepObject0D(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionSweepObject0DMakeGroups(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - - void ExtrusionSweepObject1D(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionSweepObject1DMakeGroups(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - - void ExtrusionSweepObject2D(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionSweepObject2DMakeGroups(in SMESH_IDSource theObject, - in DirStruct StepVector, - in long NbOfSteps) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionByNormal(in SMESH_IDSource theObject, - in double stepSize, - in long nbOfSteps, - in boolean byAverageNormal, - in boolean useInputElemsOnly, - in boolean makeGroups, - in short dim) + * \brief Generate dim+1 elements by rotation of the object around axis + * \param Nodes - nodes to revolve: a list including groups, sub-meshes or a mesh + * \param Edges - edges to revolve: a list including groups, sub-meshes or a mesh + * \param Faces - faces to revolve: a list including groups, sub-meshes or a mesh + * \param Axis - rotation axis + * \param AngleInRadians - rotation angle + * \param NbOfSteps - number of elements to generate from one element + * \param ToMakeGroups - if true, new elements will be included into new groups + * corresponding to groups the input elements included in. + * \return ListOfGroups - new groups craeted if \a ToMakeGroups is true + */ + ListOfGroups RotationSweepObjects(in ListOfIDSources Nodes, + in ListOfIDSources Edges, + in ListOfIDSources Faces, + in AxisStruct Axis, + in double AngleInRadians, + in long NbOfSteps, + in double Tolerance, + in boolean ToMakeGroups) + raises (SALOME::SALOME_Exception); + + /*! + * \brief Generate dim+1 elements by extrusion of elements along vector + * \param nodes - nodes to extrude: a list including groups, sub-meshes or a mesh + * \param edges - edges to extrude: a list including groups, sub-meshes or a mesh + * \param faces - faces to extrude: a list including groups, sub-meshes or a mesh + * \param stepVector - vector giving direction and distance of an extrusion step + * \param nbOfSteps - number of elements to generate from one element + * \param toMakeGroups - if true, new elements will be included into new groups + * corresponding to groups the input elements included in. + * \return ListOfGroups - new groups craeted if \a toMakeGroups is true + */ + ListOfGroups ExtrusionSweepObjects(in ListOfIDSources nodes, + in ListOfIDSources edges, + in ListOfIDSources faces, + in DirStruct stepVector, + in long nbOfSteps, + in boolean toMakeGroups) + raises (SALOME::SALOME_Exception); + + /*! Generates new elements by extrusion along the normal to a discretized surface or wire + */ + ListOfGroups ExtrusionByNormal(in ListOfIDSources theObjects, + in double stepSize, + in long nbOfSteps, + in boolean byAverageNormal, + in boolean useInputElemsOnly, + in boolean makeGroups, + in short dim) + raises (SALOME::SALOME_Exception); + + /*! + * Generate new elements by extrusion of theElements + * by StepVector by NbOfSteps + * \param ExtrFlags set flags for performing extrusion + * \param SewTolerance - uses for comparing locations of nodes if flag + * EXTRUSION_FLAG_SEW is set + * \param ToMakeGroups - if true, new elements will be included into new groups + * corresponding to groups the input elements included in. + * \return ListOfGroups - new groups craeted if \a ToMakeGroups is true + */ + ListOfGroups AdvancedExtrusion(in long_array IDsOfElements, + in DirStruct StepVector, + in long NbOfSteps, + in long ExtrFlags, + in double SewTolerance, + in boolean ToMakeGroups) raises (SALOME::SALOME_Exception); enum Extrusion_Error { @@ -604,112 +479,21 @@ module SMESH EXTR_BAD_STARTING_NODE, EXTR_BAD_ANGLES_NUMBER, EXTR_CANT_GET_TANGENT - }; - - ListOfGroups ExtrusionAlongPathX(in long_array IDsOfElements, - in SMESH_IDSource Path, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean LinearVariation, - in boolean HasRefPoint, - in PointStruct RefPoint, - in boolean MakeGroups, - in ElementType ElemType, - out Extrusion_Error Error) - raises (SALOME::SALOME_Exception); - - ListOfGroups ExtrusionAlongPathObjX(in SMESH_IDSource theObject, - in SMESH_IDSource Path, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean LinearVariation, - in boolean HasRefPoint, - in PointStruct RefPoint, - in boolean MakeGroups, - in ElementType ElemType, - out Extrusion_Error Error) - raises (SALOME::SALOME_Exception); - - Extrusion_Error ExtrusionAlongPath(in long_array IDsOfElements, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionAlongPathMakeGroups(in long_array IDsOfElements, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint, - out Extrusion_Error Error) - raises (SALOME::SALOME_Exception); - - Extrusion_Error ExtrusionAlongPathObject(in SMESH_IDSource theObject, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionAlongPathObjectMakeGroups(in SMESH_IDSource theObject, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint, - out Extrusion_Error Error) - raises (SALOME::SALOME_Exception); - - Extrusion_Error ExtrusionAlongPathObject1D(in SMESH_IDSource theObject, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionAlongPathObject1DMakeGroups(in SMESH_IDSource theObject, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint, - out Extrusion_Error Error) - raises (SALOME::SALOME_Exception); - - Extrusion_Error ExtrusionAlongPathObject2D(in SMESH_IDSource theObject, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint) - raises (SALOME::SALOME_Exception); - ListOfGroups ExtrusionAlongPathObject2DMakeGroups(in SMESH_IDSource theObject, - in SMESH_Mesh PathMesh, - in GEOM::GEOM_Object PathShape, - in long NodeStart, - in boolean HasAngles, - in double_array Angles, - in boolean HasRefPoint, - in PointStruct RefPoint, - out Extrusion_Error Error) + }; + + ListOfGroups ExtrusionAlongPathObjects(in ListOfIDSources Nodes, + in ListOfIDSources Edges, + in ListOfIDSources Faces, + in SMESH_IDSource Path, + in GEOM::GEOM_Object PathShape, + in long NodeStart, + in boolean HasAngles, + in double_array Angles, + in boolean LinearVariation, + in boolean HasRefPoint, + in PointStruct RefPoint, + in boolean MakeGroups, + out Extrusion_Error Error) raises (SALOME::SALOME_Exception); /*! diff --git a/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx b/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx index 09361d0ea..b12af7850 100644 --- a/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx +++ b/src/MEDWrapper/V2_2/MED_V2_2_Wrapper.cxx @@ -163,11 +163,26 @@ namespace MED //--------------------------------------------------------------- - TVWrapper::TVWrapper(const std::string& theFileName): + TVWrapper::TVWrapper(const std::string& theFileName): myFile(new TFile(theFileName)) - {} - - + { + TErr aRet; + myFile->Open( eLECTURE_ECRITURE, &aRet ); + // if(aRet < 0) + // myFile->Close(); + // myFile->Open( eLECTURE_AJOUT, &aRet ); + // } + if(aRet < 0) { + myFile->Close(); + myFile->Open( eLECTURE, &aRet ); + } + if(aRet < 0) { + myFile->Close(); + myFile->Open( eCREATION, &aRet ); + } + } + + //---------------------------------------------------------------------------- TInt TVWrapper @@ -2871,5 +2886,5 @@ namespace MED EXCEPTION(std::runtime_error,"GetGrilleInfo - MEDmeshGridStructRd(...)"); } - } + } } diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index b3401c601..436a0ad03 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -4216,26 +4216,49 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, } -//======================================================================= -//function : isReverse -//purpose : Return true if normal of prevNodes is not co-directied with -// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). -// iNotSame is where prevNodes and nextNodes are different. -// If result is true then future volume orientation is OK -//======================================================================= - -static bool isReverse(const SMDS_MeshElement* face, - const vector& prevNodes, - const vector& nextNodes, - const int iNotSame) +namespace { + //======================================================================= + //function : isReverse + //purpose : Return true if normal of prevNodes is not co-directied with + // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). + // iNotSame is where prevNodes and nextNodes are different. + // If result is true then future volume orientation is OK + //======================================================================= + + bool isReverse(const SMDS_MeshElement* face, + const vector& prevNodes, + const vector& nextNodes, + const int iNotSame) + { - SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; - SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; - gp_XYZ extrDir( pN - pP ), faceNorm; - SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); + SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; + SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; + gp_XYZ extrDir( pN - pP ), faceNorm; + SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false ); - return faceNorm * extrDir < 0.0; + return faceNorm * extrDir < 0.0; + } + + //================================================================================ + /*! + * \brief Assure that theElemSets[0] holds elements, not nodes + */ + //================================================================================ + + void setElemsFirst( TIDSortedElemSet theElemSets[2] ) + { + if ( !theElemSets[0].empty() && + (*theElemSets[0].begin())->GetType() == SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + else if ( !theElemSets[1].empty() && + (*theElemSets[1].begin())->GetType() != SMDSAbs_Node ) + { + std::swap( theElemSets[0], theElemSets[1] ); + } + } } //======================================================================= @@ -5121,7 +5144,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, +SMESH_MeshEditor::RotationSweep(TIDSortedElemSet theElemSets[2], const gp_Ax1& theAxis, const double theAngle, const int theNbSteps, @@ -5153,84 +5176,89 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC) + myMesh->NbVolumes(ORDER_QUADRATIC) ); - // loop on theElems + // loop on theElemSets + setElemsFirst( theElemSets ); TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + // check if a node has been already sweeped + const SMDS_MeshNode* node = cast2Node( itN->next() ); - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + double coord[3]; + aXYZ.Coord( coord[0], coord[1], coord[2] ); + bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); - TNodeOfNodeListMapItr nIt = - mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - if ( listNewNodes.empty() ) - { - // check if we are to create medium nodes between corner ones - bool needMediumNodes = false; - if ( isQuadraticMesh ) + TNodeOfNodeListMapItr nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while (it->more() && !needMediumNodes ) + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) { - const SMDS_MeshElement* invElem = it->next(); - if ( invElem != elem && !theElems.count( invElem )) continue; - needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); - if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) - needMediumNodes = true; + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } } - } - // make new nodes - const SMDS_MeshNode * newNode = node; - for ( int i = 0; i < theNbSteps; i++ ) { - if ( !isOnAxis ) { - if ( needMediumNodes ) // create a medium node - { - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + // make new nodes + const SMDS_MeshNode * newNode = node; + for ( int i = 0; i < theNbSteps; i++ ) { + if ( !isOnAxis ) { + if ( needMediumNodes ) // create a medium node + { + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + } + else { + aTrsf.Transforms( coord[0], coord[1], coord[2] ); + } + // create a corner node newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); listNewNodes.push_back( newNode ); - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); } else { - aTrsf.Transforms( coord[0], coord[1], coord[2] ); + listNewNodes.push_back( newNode ); + // if ( needMediumNodes ) + // listNewNodes.push_back( newNode ); } - // create a corner node - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - else { - listNewNodes.push_back( newNode ); - // if ( needMediumNodes ) - // listNewNodes.push_back( newNode ); } } + newNodesItVec.push_back( nIt ); } - newNodesItVec.push_back( nIt ); + // make new elements + sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); } - // make new elements - sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems ); } if ( theMakeWalls ) - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems ); PGroupIDs newGroupIDs; if ( theMakeGroups ) @@ -5568,7 +5596,7 @@ makeNodesByNormal1D( SMESHDS_Mesh* mesh, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElems[2], const gp_Vec& theStep, const int theNbSteps, TTElemOfElemListMap& newElemsMap, @@ -5586,7 +5614,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, //======================================================================= SMESH_MeshEditor::PGroupIDs -SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, +SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2], ExtrusParam& theParams, TTElemOfElemListMap& newElemsMap) { @@ -5598,8 +5626,9 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, SMESHDS_Mesh* aMesh = GetMeshDS(); + setElemsFirst( theElemSets ); const int nbSteps = theParams.NbSteps(); - theParams.SetElementsToUse( theElems ); + theParams.SetElementsToUse( theElemSets[0] ); TNodeOfNodeListMap mapNewNodes; //TNodeOfNodeVecMap mapNewNodes; @@ -5611,68 +5640,72 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, myMesh->NbVolumes(ORDER_QUADRATIC) ); // loop on theElems TIDSortedElemSet::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Volume ) - continue; + TIDSortedElemSet& theElems = theElemSets[ is2ndSet ]; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + { + // check element type + const SMDS_MeshElement* elem = *itElem; + if ( !elem || elem->GetType() == SMDSAbs_Volume ) + continue; - const size_t nbNodes = elem->NbNodes(); - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( nbNodes ); + const size_t nbNodes = elem->NbNodes(); + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( nbNodes ); - // loop on elem nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - // check if a node has been already sweeped - const SMDS_MeshNode* node = cast2Node( itN->next() ); - TNodeOfNodeListMap::iterator nIt = - mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; - if ( listNewNodes.empty() ) + // loop on elem nodes + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { - // make new nodes - - // check if we are to create medium nodes between corner ones - bool needMediumNodes = false; - if ( isQuadraticMesh ) + // check if a node has been already sweeped + const SMDS_MeshNode* node = cast2Node( itN->next() ); + TNodeOfNodeListMap::iterator nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) { - SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); - while (it->more() && !needMediumNodes ) + // make new nodes + + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) { - const SMDS_MeshElement* invElem = it->next(); - if ( invElem != elem && !theElems.count( invElem )) continue; - needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); - if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) - needMediumNodes = true; + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } } - } - // create nodes for all steps - if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes )) - { - list::iterator newNodesIt = listNewNodes.begin(); - for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt ) + // create nodes for all steps + if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes )) { - myLastCreatedNodes.Append( *newNodesIt ); - srcNodes.Append( node ); + list::iterator newNodesIt = listNewNodes.begin(); + for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt ) + { + myLastCreatedNodes.Append( *newNodesIt ); + srcNodes.Append( node ); + } + } + else + { + break; // newNodesItVec will be shorter than nbNodes } } - else - { - break; // newNodesItVec will be shorter than nbNodes - } + newNodesItVec.push_back( nIt ); } - newNodesItVec.push_back( nIt ); + // make new elements + if ( newNodesItVec.size() == nbNodes ) + sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems ); } - // make new elements - if ( newNodesItVec.size() == nbNodes ) - sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems ); } if ( theParams.ToMakeBoundary() ) { - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbSteps, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems ); } PGroupIDs newGroupIDs; if ( theParams.ToMakeGroups() ) @@ -5686,7 +5719,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, //purpose : //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_subMesh* theTrack, const SMDS_MeshNode* theN1, const bool theHasAngles, @@ -5715,7 +5748,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TNodeOfNodeListMap mapNewNodes; // 1. Check data - aNbE = theElements.size(); + aNbE = theElements[0].size() + theElements[1].size(); // nothing to do if ( !aNbE ) return EXTR_NO_ELEMENTS; @@ -5858,7 +5891,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, //purpose : //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_Mesh* theTrack, const SMDS_MeshNode* theN1, const bool theHasAngles, @@ -5886,7 +5919,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, TNodeOfNodeListMap mapNewNodes; // 1. Check data - aNbE = theElements.size(); + aNbE = theElements[0].size() + theElements[1].size(); // nothing to do if ( !aNbE ) return EXTR_NO_ELEMENTS; @@ -5927,7 +5960,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, } conn = nbEdgeConnectivity(theN1); - if(conn > 2) + if( conn != 1 ) return EXTR_PATH_NOT_EDGE; aItE = theN1->GetInverseElementIterator(); @@ -6207,7 +6240,7 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, //purpose : auxilary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements, +SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2], list& fullList, const bool theHasAngles, list& theAngles, @@ -6245,15 +6278,19 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements gp_XYZ aGC( 0.,0.,0. ); TIDSortedElemSet newNodes; - itElem = theElements.begin(); - for ( ; itElem != theElements.end(); itElem++ ) { - const SMDS_MeshElement* elem = *itElem; + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + itElem = theElements.begin(); + for ( ; itElem != theElements.end(); itElem++ ) { + const SMDS_MeshElement* elem = *itElem; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshElement* node = itN->next(); - if ( newNodes.insert( node ).second ) - aGC += SMESH_TNodeXYZ( node ); + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { + const SMDS_MeshElement* node = itN->next(); + if ( newNodes.insert( node ).second ) + aGC += SMESH_TNodeXYZ( node ); + } } } aGC /= newNodes.size(); @@ -6263,144 +6300,149 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements // 4. Processing the elements SMESHDS_Mesh* aMesh = GetMeshDS(); - for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { - // check element type - const SMDS_MeshElement* elem = *itElem; - SMDSAbs_ElementType aTypeE = elem->GetType(); - if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) ) - continue; - - vector & newNodesItVec = mapElemNewNodes[ elem ]; - newNodesItVec.reserve( elem->NbNodes() ); + setElemsFirst( theElemSets ); + for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet ) + { + TIDSortedElemSet& theElements = theElemSets[ is2ndSet ]; + for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { + // check element type + const SMDS_MeshElement* elem = *itElem; + SMDSAbs_ElementType aTypeE = elem->GetType(); + if ( !elem /*|| ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge )*/ ) + continue; - // loop on elem nodes - int nodeIndex = -1; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - ++nodeIndex; - // check if a node has been already processed - const SMDS_MeshNode* node = - static_cast( itN->next() ); - TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) { - nIt = mapNewNodes.insert( make_pair( node, list() )).first; - list& listNewNodes = nIt->second; + vector & newNodesItVec = mapElemNewNodes[ elem ]; + newNodesItVec.reserve( elem->NbNodes() ); - // make new nodes - Standard_Real aAngle1x, aAngleT1T0, aTolAng; - gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; - gp_Ax1 anAx1, anAxT1T0; - gp_Dir aDT1x, aDT0x, aDT1T0; - - aTolAng=1.e-4; - - aV0x = aV0; - aPN0 = SMESH_TNodeXYZ( node ); - - const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; - aP0x = aPP0.Pnt(); - aDT0x= aPP0.Tangent(); - //cout<<"j = 0 PP: Pnt("< aTolAng) { - aDT1T0=aDT1x^aDT0x; - anAxT1T0.SetLocation( aV1x ); - anAxT1T0.SetDirection( aDT1T0 ); - aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); - - aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); - } + // loop on elem nodes + int nodeIndex = -1; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + ++nodeIndex; + // check if a node has been already processed + const SMDS_MeshNode* node = + static_cast( itN->next() ); + TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); + if ( nIt == mapNewNodes.end() ) { + nIt = mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + + // make new nodes + Standard_Real aAngle1x, aAngleT1T0, aTolAng; + gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; + gp_Ax1 anAx1, anAxT1T0; + gp_Dir aDT1x, aDT0x, aDT1T0; + + aTolAng=1.e-4; + + aV0x = aV0; + aPN0 = SMESH_TNodeXYZ( node ); + + const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; + aP0x = aPP0.Pnt(); + aDT0x= aPP0.Tangent(); + //cout<<"j = 0 PP: Pnt("< aTolAng) { + aDT1T0=aDT1x^aDT0x; + anAxT1T0.SetLocation( aV1x ); + anAxT1T0.SetDirection( aDT1T0 ); + aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); + + aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); + } - // rotation 2 - if ( theHasAngles ) { - anAx1.SetLocation( aV1x ); - anAx1.SetDirection( aDT1x ); - aTrsfRot.SetRotation( anAx1, aAngle1x ); + // rotation 2 + if ( theHasAngles ) { + anAx1.SetLocation( aV1x ); + anAx1.SetDirection( aDT1x ); + aTrsfRot.SetRotation( anAx1, aAngle1x ); - aPN1 = aPN1.Transformed( aTrsfRot ); - } + aPN1 = aPN1.Transformed( aTrsfRot ); + } - // make new node - //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node)); - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create additional node - double x = ( aPN1.X() + aPN0.X() )/2.; - double y = ( aPN1.Y() + aPN0.Y() )/2.; - double z = ( aPN1.Z() + aPN0.Z() )/2.; - const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z); + // make new node + //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node)); + if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + // create additional node + double x = ( aPN1.X() + aPN0.X() )/2.; + double y = ( aPN1.Y() + aPN0.Y() )/2.; + double z = ( aPN1.Z() + aPN0.Z() )/2.; + const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z); + myLastCreatedNodes.Append(newNode); + srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + } + const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); listNewNodes.push_back( newNode ); - } - const SMDS_MeshNode* newNode = aMesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - aPN0 = aPN1; - aP0x = aP1x; - aV0x = aV1x; - aDT0x = aDT1x; + aPN0 = aPN1; + aP0x = aP1x; + aV0x = aV1x; + aDT0x = aDT1x; + } } - } - else { - // if current elem is quadratic and current node is not medium - // we have to check - may be it is needed to insert additional nodes - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - list< const SMDS_MeshNode* > & listNewNodes = nIt->second; - if(listNewNodes.size()==aNbTP-1) { - vector aNodes(2*(aNbTP-1)); - gp_XYZ P(node->X(), node->Y(), node->Z()); - list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin(); - int i; - for(i=0; iX() + P.X() )/2.; - double y = ( N->Y() + P.Y() )/2.; - double z = ( N->Z() + P.Z() )/2.; - const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z); - srcNodes.Append( node ); - myLastCreatedNodes.Append(newN); - aNodes[2*i] = newN; - aNodes[2*i+1] = N; - P = gp_XYZ(N->X(),N->Y(),N->Z()); - } - listNewNodes.clear(); - for(i=0; i<2*(aNbTP-1); i++) { - listNewNodes.push_back(aNodes[i]); + else { + // if current elem is quadratic and current node is not medium + // we have to check - may be it is needed to insert additional nodes + if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + list< const SMDS_MeshNode* > & listNewNodes = nIt->second; + if(listNewNodes.size()==aNbTP-1) { + vector aNodes(2*(aNbTP-1)); + gp_XYZ P(node->X(), node->Y(), node->Z()); + list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin(); + int i; + for(i=0; iX() + P.X() )/2.; + double y = ( N->Y() + P.Y() )/2.; + double z = ( N->Z() + P.Z() )/2.; + const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z); + srcNodes.Append( node ); + myLastCreatedNodes.Append(newN); + aNodes[2*i] = newN; + aNodes[2*i+1] = N; + P = gp_XYZ(N->X(),N->Y(),N->Z()); + } + listNewNodes.clear(); + for(i=0; i<2*(aNbTP-1); i++) { + listNewNodes.push_back(aNodes[i]); + } } } } - } - newNodesItVec.push_back( nIt ); + newNodesItVec.push_back( nIt ); + } + // make new elements + //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], + // newNodesItVec[0]->second.size(), myLastCreatedElems ); + sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } - // make new elements - //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], - // newNodesItVec[0]->second.size(), myLastCreatedElems ); - sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems ); } - makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems ); + makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], aNbTP-1, srcElems ); if ( theMakeGroups ) generateGroups( srcNodes, srcElems, "extruded"); diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index 23f3977aa..25c01f81d 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -229,7 +229,7 @@ public: typedef std::map TElemOfVecOfNnlmiMap; typedef std::auto_ptr< std::list > PGroupIDs; - PGroupIDs RotationSweep (TIDSortedElemSet & theElements, + PGroupIDs RotationSweep (TIDSortedElemSet theElements[2], const gp_Ax1& theAxis, const double theAngle, const int theNbSteps, @@ -345,7 +345,7 @@ public: * @param theTolerance - uses for comparing locations of nodes if flag * EXTRUSION_FLAG_SEW is set */ - PGroupIDs ExtrusionSweep (TIDSortedElemSet & theElems, + PGroupIDs ExtrusionSweep (TIDSortedElemSet theElems[2], const gp_Vec& theStep, const int theNbSteps, TTElemOfElemListMap& newElemsMap, @@ -362,7 +362,7 @@ public: * EXTRUSION_FLAG_SEW is set * @param theParams - special structure for manage of extrusion */ - PGroupIDs ExtrusionSweep (TIDSortedElemSet & theElems, + PGroupIDs ExtrusionSweep (TIDSortedElemSet theElems[2], ExtrusParam& theParams, TTElemOfElemListMap& newElemsMap); @@ -380,7 +380,7 @@ public: EXTR_CANT_GET_TANGENT }; - Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet & theElements, + Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_subMesh* theTrackPattern, const SMDS_MeshNode* theNodeStart, const bool theHasAngles, @@ -389,7 +389,7 @@ public: const bool theHasRefPoint, const gp_Pnt& theRefPoint, const bool theMakeGroups); - Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet & theElements, + Extrusion_Error ExtrusionAlongTrack (TIDSortedElemSet theElements[2], SMESH_Mesh* theTrackPattern, const SMDS_MeshNode* theNodeStart, const bool theHasAngles, @@ -730,7 +730,7 @@ public: const TopoDS_Edge& aTrackEdge, bool aFirstIsStart, std::list& aLPP); - Extrusion_Error MakeExtrElements(TIDSortedElemSet& theElements, + Extrusion_Error MakeExtrElements(TIDSortedElemSet theElements[2], std::list& theFullList, const bool theHasAngles, std::list& theAngles, diff --git a/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx b/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx index a0c93fa38..3ee1841ba 100644 --- a/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_Add0DElemsOnAllNodesDlg.cxx @@ -353,7 +353,7 @@ bool SMESHGUI_Add0DElemsOnAllNodesOp::onApply() return false; // get a mesh - SMESH::SMESH_IDSource_wrap meshObject; + SMESH::IDSource_wrap meshObject; SMESH::SMESH_Mesh_var mesh; if ( !myIO.IsNull() ) { diff --git a/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx index 7c114c5d1..1c8d4dbdc 100644 --- a/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_CopyMeshDlg.cxx @@ -309,7 +309,8 @@ bool SMESHGUI_CopyMeshDlg::ClickOnApply() try { SUIT_OverrideCursor aWaitCursor; - SMESH::SMESH_IDSource_wrap aPartToCopy; + + SMESH::IDSource_wrap aPartToCopy; if ( myIdSourceCheck->isChecked()) { aPartToCopy = mySelectedObject; diff --git a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx index 2cb8f5af5..c26925804 100644 --- a/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_DisplayEntitiesDlg.cxx @@ -22,22 +22,23 @@ #include "SMESHGUI_DisplayEntitiesDlg.h" #include "SMESHGUI.h" +#include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_Utils.h" #include "SMESHGUI_VTKUtils.h" -#include "SMESHGUI_MeshUtils.h" -#include -#include -#include -#include -#include - -#include -#include -#include #include #include #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include const int MARGIN = 9; const int SPACING = 6; @@ -176,7 +177,7 @@ SMESHGUI_DisplayEntitiesDlg::~SMESHGUI_DisplayEntitiesDlg() } void SMESHGUI_DisplayEntitiesDlg::InverseEntityMode(unsigned int& theOutputMode, - unsigned int theMode) + unsigned int theMode) { bool anIsNotPresent = ~theOutputMode & theMode; if(anIsNotPresent) @@ -193,7 +194,7 @@ void SMESHGUI_DisplayEntitiesDlg::onChangeEntityMode( bool isChecked ) QCheckBox* aSender = (QCheckBox*)sender(); if ( myNbCheckedButtons == 1 && !isChecked ) { SUIT_MessageBox::warning(this, tr("SMESH_WRN_WARNING"), - tr("WRN_AT_LEAST_ONE")); + tr("WRN_AT_LEAST_ONE")); disconnect( aSender, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); aSender->setChecked( true ); connect( aSender, SIGNAL(toggled(bool)), this, SLOT(onChangeEntityMode(bool)) ); @@ -228,11 +229,13 @@ void SMESHGUI_DisplayEntitiesDlg::onHelp() */ void SMESHGUI_DisplayEntitiesDlg::onOk() { + SUIT_OverrideCursor wc; + const char* entry = myIObject->getEntry(); if ( !myActor ) { myActor = SMESH::CreateActor(SMESH::GetActiveStudyDocument(), - entry, true); + entry, true); } if( myEntityMode != myActor->GetEntityMode() ) { diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx index 9c7529761..488fddd21 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.cxx @@ -28,13 +28,14 @@ #include "SMESHGUI_ExtrusionAlongPathDlg.h" #include "SMESHGUI.h" -#include "SMESHGUI_Utils.h" -#include "SMESHGUI_VTKUtils.h" -#include "SMESHGUI_MeshUtils.h" -#include "SMESHGUI_SpinBox.h" -#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_ExtrusionDlg.h" // for SMESHGUI_3TypesSelector #include "SMESHGUI_FilterDlg.h" +#include "SMESHGUI_IdValidator.h" #include "SMESHGUI_MeshEditPreview.h" +#include "SMESHGUI_MeshUtils.h" +#include "SMESHGUI_SpinBox.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" #include #include @@ -52,10 +53,8 @@ #include #include #include - #include #include - #include // OCCT includes @@ -111,18 +110,13 @@ private: //================================================================================= SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theModule ) : SMESHGUI_PreviewDlg( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), - myFilterDlg( 0 ) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) { SUIT_ResourceMgr* mgr = SMESH::GetResourceMgr( mySMESHGUI ); - QPixmap edgeImage ( mgr->loadPixmap("SMESH", tr("ICON_DLG_EDGE"))); - QPixmap faceImage ( mgr->loadPixmap("SMESH", tr("ICON_DLG_TRIANGLE"))); QPixmap selectImage ( mgr->loadPixmap("SMESH", tr("ICON_SELECT"))); QPixmap addImage ( mgr->loadPixmap("SMESH", tr("ICON_APPEND"))); QPixmap removeImage ( mgr->loadPixmap("SMESH", tr("ICON_REMOVE"))); - myType = -1; - setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); setWindowTitle(tr("EXTRUSION_ALONG_PATH")); @@ -132,48 +126,17 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod topLayout->setSpacing(SPACING); topLayout->setMargin(MARGIN); - /***************************************************************/ - // Elements type group box (1d / 2d elements) - ConstructorsBox = new QGroupBox(tr("SMESH_EXTRUSION"), this); - GroupConstructors = new QButtonGroup(this); - QHBoxLayout* ConstructorsBoxLayout = new QHBoxLayout(ConstructorsBox); - ConstructorsBoxLayout->setSpacing(SPACING); ConstructorsBoxLayout->setMargin(MARGIN); - - Elements1dRB = new QRadioButton(ConstructorsBox); - Elements1dRB->setIcon(edgeImage); - Elements2dRB = new QRadioButton(ConstructorsBox); - Elements2dRB->setIcon(faceImage); - Elements1dRB->setChecked(true); - - // layouting - ConstructorsBoxLayout->addWidget(Elements1dRB); - ConstructorsBoxLayout->addWidget(Elements2dRB); - GroupConstructors->addButton(Elements1dRB, 0); - GroupConstructors->addButton(Elements2dRB, 1); - /***************************************************************/ // Arguments group box - GroupArguments = new QGroupBox(tr("EXTRUSION_1D"), this); + GroupArguments = new QGroupBox(tr("SMESH_EXTRUSION"), this); QGridLayout* GroupArgumentsLayout = new QGridLayout(GroupArguments); GroupArgumentsLayout->setSpacing(SPACING); GroupArgumentsLayout->setMargin(MARGIN); myIdValidator = new SMESHGUI_IdValidator(this); // Controls for elements selection - ElementsLab = new QLabel(tr("SMESH_ID_ELEMENTS"), GroupArguments); - - SelectElementsButton = new QToolButton(GroupArguments); - SelectElementsButton->setIcon(selectImage); - - ElementsLineEdit = new QLineEdit(GroupArguments); - ElementsLineEdit->setValidator(myIdValidator); - ElementsLineEdit->setMaxLength(-1); - myFilterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); - connect(myFilterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); - - // Controls for the whole mesh selection - MeshCheck = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); - + SelectorWdg = new SMESHGUI_3TypesSelector( GroupArguments ); + // Controls for path selection PathGrp = new QGroupBox(tr("SMESH_PATH"), GroupArguments); QGridLayout* PathGrpLayout = new QGridLayout(PathGrp); @@ -182,8 +145,9 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod // Controls for path mesh selection QLabel* PathMeshLab = new QLabel(tr("SMESH_PATH_MESH"), PathGrp); - SelectPathMeshButton = new QToolButton(PathGrp); + SelectPathMeshButton = new QPushButton(PathGrp); SelectPathMeshButton->setIcon(selectImage); + SelectPathMeshButton->setCheckable(true); PathMeshLineEdit = new QLineEdit(PathGrp); PathMeshLineEdit->setReadOnly(true); @@ -191,8 +155,9 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod // Controls for path starting point selection QLabel* StartPointLab = new QLabel(tr("SMESH_PATH_START"), PathGrp); - SelectStartPointButton = new QToolButton(PathGrp); + SelectStartPointButton = new QPushButton(PathGrp); SelectStartPointButton->setIcon(selectImage); + SelectStartPointButton->setCheckable(true); StartPointLineEdit = new QLineEdit(PathGrp); StartPointLineEdit->setValidator(new QIntValidator(this)); @@ -211,8 +176,13 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod QHBoxLayout* BasePointGrpLayout = new QHBoxLayout(BasePointGrp); BasePointGrpLayout->setSpacing(SPACING); BasePointGrpLayout->setMargin(MARGIN); - SelectBasePointButton = new QToolButton(BasePointGrp); + SelectBasePointButton = new QPushButton(BasePointGrp); SelectBasePointButton->setIcon(selectImage); + SelectBasePointButton->setCheckable(true); + + SelectorWdg->GetButtonGroup()->addButton( SelectPathMeshButton ); + SelectorWdg->GetButtonGroup()->addButton( SelectStartPointButton ); + SelectorWdg->GetButtonGroup()->addButton( SelectBasePointButton ); QLabel* XLab = new QLabel(tr("SMESH_X"), BasePointGrp); XSpin = new SMESHGUI_SpinBox(BasePointGrp); @@ -266,16 +236,12 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod myPreviewCheckBox = new QCheckBox(tr("PREVIEW"), GroupArguments); // layouting - GroupArgumentsLayout->addWidget(ElementsLab, 0, 0); - GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(ElementsLineEdit, 0, 2); - GroupArgumentsLayout->addWidget(myFilterBtn, 0, 3); - GroupArgumentsLayout->addWidget(MeshCheck, 1, 0, 1, 4); - GroupArgumentsLayout->addWidget(PathGrp, 2, 0, 1, 4); - GroupArgumentsLayout->addWidget(BasePointGrp, 3, 0, 1, 4); - GroupArgumentsLayout->addWidget(AnglesGrp, 4, 0, 1, 4); - GroupArgumentsLayout->addWidget(myPreviewCheckBox, 5, 0, 1, 4); - GroupArgumentsLayout->addWidget(MakeGroupsCheck, 6, 0, 1, 4); + GroupArgumentsLayout->addWidget(SelectorWdg, 0, 0); + GroupArgumentsLayout->addWidget(PathGrp, 1, 0); + GroupArgumentsLayout->addWidget(BasePointGrp, 2, 0); + GroupArgumentsLayout->addWidget(AnglesGrp, 3, 0); + GroupArgumentsLayout->addWidget(myPreviewCheckBox, 4, 0); + GroupArgumentsLayout->addWidget(MakeGroupsCheck, 5, 0); /***************************************************************/ // common buttons group box @@ -307,7 +273,6 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod /***************************************************************/ // layouting - topLayout->addWidget(ConstructorsBox); topLayout->addWidget(GroupArguments); topLayout->addWidget(GroupButtons); @@ -322,16 +287,6 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod mySMESHGUI->SetActiveDialogBox(this); - // Costruction of the logical filter for the elements: mesh/sub-mesh/group - SMESH_TypeFilter* aMeshOrSubMeshFilter = new SMESH_TypeFilter (SMESH::MESHorSUBMESH); - SMESH_TypeFilter* aSmeshGroupFilter = new SMESH_TypeFilter (SMESH::GROUP); - - QList aListOfFilters; - if (aMeshOrSubMeshFilter) aListOfFilters.append(aMeshOrSubMeshFilter); - if (aSmeshGroupFilter) aListOfFilters.append(aSmeshGroupFilter); - - myElementsFilter = new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR); - //myPathMeshFilter = new SMESH_TypeFilter (SMESH::MESH); myPathMeshFilter = new SMESH_TypeFilter(SMESH::MESHorSUBMESH); myHelpFileName = "extrusion_along_path_page.html"; @@ -348,42 +303,38 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod connect(AddAngleButton, SIGNAL(clicked()), this, SLOT(OnAngleAdded())); connect(RemoveAngleButton, SIGNAL(clicked()), this, SLOT(OnAngleRemoved())); - connect(GroupConstructors, SIGNAL(buttonClicked(int)), SLOT(ConstructorsClicked(int))); - - connect(SelectElementsButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectPathMeshButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectStartPointButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectBasePointButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(BasePointGrp, SIGNAL(toggled(bool)), this, SLOT(SetEditCurrentArgument())); - connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog())); - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); - connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), this, SLOT(reject())); + connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), SLOT(reject())); + connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), SLOT(DeactivateActiveDialog())); + connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(SelectionIntoArgument())); + connect(SelectorWdg, SIGNAL(selectionChanged()), this, SLOT(toDisplaySimulation())); + connect(SelectorWdg, SIGNAL(selectionChanged()), this, SLOT(CheckIsEnable())); - connect(ElementsLineEdit, SIGNAL(textChanged(const QString&)), - SLOT(onTextChange(const QString&))); connect(StartPointLineEdit, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&))); - connect(MeshCheck, SIGNAL(toggled(bool)), SLOT(onSelectMesh())); - connect(XSpin, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); connect(YSpin, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); connect(ZSpin, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); - connect(AddAngleButton, SIGNAL(clicked()), this, SLOT(toDisplaySimulation())); + connect(AddAngleButton, SIGNAL(clicked()), this, SLOT(toDisplaySimulation())); connect(RemoveAngleButton, SIGNAL(clicked()), this, SLOT(toDisplaySimulation())); - connect(LinearAnglesCheck, SIGNAL(toggled(bool)), SLOT(onSelectMesh())); + //connect(LinearAnglesCheck, SIGNAL(toggled(bool)), SLOT(onSelectMesh())); //To Connect preview check box connectPreviewControl(); - AnglesList->installEventFilter(this); - ElementsLineEdit->installEventFilter(this); + AnglesList ->installEventFilter(this); StartPointLineEdit->installEventFilter(this); - XSpin->editor()->installEventFilter(this); - YSpin->editor()->installEventFilter(this); - ZSpin->editor()->installEventFilter(this); + XSpin->editor() ->installEventFilter(this); + YSpin->editor() ->installEventFilter(this); + ZSpin->editor() ->installEventFilter(this); + + CheckIsEnable(); } //================================================================================= @@ -393,10 +344,6 @@ SMESHGUI_ExtrusionAlongPathDlg::SMESHGUI_ExtrusionAlongPathDlg( SMESHGUI* theMod SMESHGUI_ExtrusionAlongPathDlg::~SMESHGUI_ExtrusionAlongPathDlg() { // no need to delete child widgets, Qt does it all for us - if ( myFilterDlg != 0 ) { - myFilterDlg->setParent( 0 ); - delete myFilterDlg; - } } //================================================================================= @@ -408,12 +355,9 @@ void SMESHGUI_ExtrusionAlongPathDlg::Init (bool ResetControls) myBusy = false; myEditCurrentArgument = 0; - myMesh = SMESH::SMESH_Mesh::_nil(); - myIDSource = SMESH::SMESH_IDSource::_nil(); - myMeshActor = 0; - myPath = SMESH::SMESH_IDSource::_nil(); + myPath = SMESH::SMESH_IDSource::_nil(); - ElementsLineEdit->clear(); + SelectorWdg->Clear(); PathMeshLineEdit->clear(); StartPointLineEdit->clear(); @@ -423,9 +367,6 @@ void SMESHGUI_ExtrusionAlongPathDlg::Init (bool ResetControls) ZSpin->SetValue(0.0); AngleSpin->SetValue(45); - MeshCheck->setChecked(false); - ConstructorsClicked(0); - onSelectMesh(); myPreviewCheckBox->setChecked(false); onDisplaySimulation(false); } @@ -433,53 +374,16 @@ void SMESHGUI_ExtrusionAlongPathDlg::Init (bool ResetControls) } //================================================================================= -// function : ConstructorsClicked() -// purpose : Called when user changes type of elements (1d / 2d) +// function : CheckIsEnable() +// purpose : Check whether the Ok and Apply buttons should be enabled or not //================================================================================= -void SMESHGUI_ExtrusionAlongPathDlg::ConstructorsClicked (int type) -{ - if (myType == type) return; - - disconnect(mySelectionMgr, 0, this, 0); - hidePreview(); +void SMESHGUI_ExtrusionAlongPathDlg::CheckIsEnable() +{ + bool anIsEnable = SelectorWdg->IsAnythingSelected() && isValuesValid(); - if (type == 0) - GroupArguments->setTitle(tr("EXTRUSION_1D")); - else if (type == 1) - GroupArguments->setTitle(tr("EXTRUSION_2D")); - - // clear elements ID list - if (!MeshCheck->isChecked()) { - ElementsLineEdit->clear(); - } - // set selection mode if necessary - if (myEditCurrentArgument == ElementsLineEdit) { - mySelectionMgr->clearSelected(); - mySelectionMgr->clearFilters(); - SMESH::SetPickable(); - - SMESH::SetPointRepresentation(false); - if (MeshCheck->isChecked()) { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); - mySelectionMgr->installFilter(myElementsFilter); - } else { - if (type == 0) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - } - if (type == 1) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - } - } - } - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); - - myType = type; + OkButton->setEnabled(anIsEnable); + ApplyButton->setEnabled(anIsEnable); } //================================================================================= @@ -491,17 +395,12 @@ bool SMESHGUI_ExtrusionAlongPathDlg::ClickOnApply() if (mySMESHGUI->isActiveStudyLocked()) return false; - //if (myMesh->_is_nil() || MeshCheck->isChecked() && myIDSource->_is_nil() || - // !myMeshActor || myPathMesh->_is_nil() || myPathShape->_is_nil()) - if ( myMesh->_is_nil() || (MeshCheck->isChecked() && myIDSource->_is_nil()) || - /*!myMeshActor ||*/ myPath->_is_nil() ) + if ( !SelectorWdg->IsAnythingSelected() || myPath->_is_nil() ) return false; if (!isValid()) return false; - SMESH::long_array_var anElementsId = getSelectedElements(); - if (StartPointLineEdit->text().trimmed().isEmpty()) { return false; } @@ -517,7 +416,7 @@ bool SMESHGUI_ExtrusionAlongPathDlg::ClickOnApply() //get angles SMESH::double_array_var anAngles = getAngles(); - for (int i = 0; i < myAnglesList.count(); i++) + for (int i = 0; i < myAnglesList.count(); i++) aParameters << AnglesList->item(i)->text(); @@ -528,89 +427,108 @@ bool SMESHGUI_ExtrusionAlongPathDlg::ClickOnApply() aBasePoint.y = YSpin->GetValue(); aBasePoint.z = ZSpin->GetValue(); } - aParameters << XSpin->text(); aParameters << YSpin->text(); aParameters << ZSpin->text(); + bool meshHadNewTypeBefore = true; + int maxSelType = 0; + const bool makeGroups = ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ); + try { SUIT_OverrideCursor wc; - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); - SMESH::SMESH_MeshEditor::Extrusion_Error retVal; - - myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); - - bool NeedGroups = ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ); - SMESH::ElementType ElemType = SMESH::FACE; - if( GetConstructorId() == 0 ) - ElemType = SMESH::EDGE; - if( !MeshCheck->isChecked() ) { - SMESH::ListOfGroups_var groups = - aMeshEditor->ExtrusionAlongPathX(anElementsId, myPath, aNodeStart, AnglesGrp->isChecked(), - anAngles, LinearAnglesCheck->isChecked(), - BasePointGrp->isChecked(), aBasePoint, - NeedGroups, ElemType, retVal); - } - else { - SMESH::ListOfGroups_var groups = - aMeshEditor->ExtrusionAlongPathObjX(myIDSource, myPath, aNodeStart, AnglesGrp->isChecked(), - anAngles, LinearAnglesCheck->isChecked(), - BasePointGrp->isChecked(), aBasePoint, - NeedGroups, ElemType, retVal); - } - - - wc.suspend(); - switch (retVal) { - case SMESH::SMESH_MeshEditor::EXTR_NO_ELEMENTS: - SUIT_MessageBox::warning(this, - tr("SMESH_ERROR"), - tr("NO_ELEMENTS_SELECTED")); - return false; break; - case SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE: - SUIT_MessageBox::warning(this, - tr("SMESH_ERROR"), - tr("SELECTED_PATH_IS_NOT_EDGE")); - return false; break; - case SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE: - SUIT_MessageBox::warning(this, - tr("SMESH_ERROR"), - tr("BAD_SHAPE_TYPE")); - return false; break; - case SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE: - SUIT_MessageBox::warning(this, - tr("SMESH_ERROR"), - tr("EXTR_BAD_STARTING_NODE")); - return false; break; - case SMESH::SMESH_MeshEditor::EXTR_BAD_ANGLES_NUMBER: - SUIT_MessageBox::warning(this, - tr("SMESH_ERROR"), - tr("WRONG_ANGLES_NUMBER")); - return false; break; - case SMESH::SMESH_MeshEditor::EXTR_CANT_GET_TANGENT: - SUIT_MessageBox::warning(this, - tr("SMESH_ERROR"), - tr("CANT_GET_TANGENT")); - return false; break; - case SMESH::SMESH_MeshEditor::EXTR_OK: - break; - } + SMESH::SMESH_Mesh_var mesh = SelectorWdg->GetMesh(); + + mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + + SMESH::ListOfIDSources_var nodes = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var edges = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var faces = new SMESH::ListOfIDSources(); + maxSelType = SelectorWdg->GetSelected( nodes, edges, faces ); + + // is it necessary to switch on the next Display Mode? + SMESH::ElementType newType = (SMESH::ElementType)( maxSelType + 1 ); + SMESH::array_of_ElementType_var oldTypes = mesh->GetTypes(); + meshHadNewTypeBefore = false; + for ( size_t i = 0; i < oldTypes->length() && !meshHadNewTypeBefore; ++i ) + meshHadNewTypeBefore = ( oldTypes[i] >= newType ); + + SMESH::SMESH_MeshEditor_var aMeshEditor = mesh->GetMeshEditor(); + SMESH::SMESH_MeshEditor::Extrusion_Error retVal; + + SMESH::ListOfGroups_var groups = + aMeshEditor->ExtrusionAlongPathObjects( nodes, edges, faces, myPath, + GEOM::GEOM_Object::_nil(), + aNodeStart, AnglesGrp->isChecked(), + anAngles, LinearAnglesCheck->isChecked(), + BasePointGrp->isChecked(), aBasePoint, + makeGroups, retVal ); + + wc.suspend(); + switch (retVal) { + case SMESH::SMESH_MeshEditor::EXTR_NO_ELEMENTS: + SUIT_MessageBox::warning(this, + tr("SMESH_ERROR"), + tr("NO_ELEMENTS_SELECTED")); + return false; break; + case SMESH::SMESH_MeshEditor::EXTR_PATH_NOT_EDGE: + SUIT_MessageBox::warning(this, + tr("SMESH_ERROR"), + tr("SELECTED_PATH_IS_NOT_EDGE")); + return false; break; + case SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE: + SUIT_MessageBox::warning(this, + tr("SMESH_ERROR"), + tr("BAD_SHAPE_TYPE")); + return false; break; + case SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE: + SUIT_MessageBox::warning(this, + tr("SMESH_ERROR"), + tr("EXTR_BAD_STARTING_NODE")); + return false; break; + case SMESH::SMESH_MeshEditor::EXTR_BAD_ANGLES_NUMBER: + SUIT_MessageBox::warning(this, + tr("SMESH_ERROR"), + tr("WRONG_ANGLES_NUMBER")); + return false; break; + case SMESH::SMESH_MeshEditor::EXTR_CANT_GET_TANGENT: + SUIT_MessageBox::warning(this, + tr("SMESH_ERROR"), + tr("CANT_GET_TANGENT")); + return false; break; + case SMESH::SMESH_MeshEditor::EXTR_OK: + break; + } } catch (...) { return false; } - //mySelectionMgr->clearSelected(); - if ( myMeshActor ) - SMESH::Update( myMeshActor->getIO(), myMeshActor->GetVisibility() ); - - SMESHGUI::Modified(); - - if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ) + SMESH_Actor* actor = SelectorWdg->GetActor(); + if ( actor && !meshHadNewTypeBefore ) + { + unsigned int aMode = actor->GetEntityMode(); + switch ( maxSelType ) { + case SMESH::NODE: // extrude node -> edges + actor->SetRepresentation(SMESH_Actor::eEdge); + actor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; + case SMESH::EDGE: // edge -> faces + actor->SetRepresentation(SMESH_Actor::eSurface); + actor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; + case SMESH::FACE: // faces -> volumes + actor->SetRepresentation(SMESH_Actor::eSurface); + actor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; + } + } + if ( actor ) + SMESH::Update( actor->getIO(), actor->GetVisibility() ); + if ( makeGroups ) mySMESHGUI->updateObjBrowser(true); // new groups may appear - //SMESH::UpdateView(); Init(false); - ConstructorsClicked(GetConstructorId()); + mySelectionMgr->clearSelected(); + SelectorWdg->Clear(); + + SMESHGUI::Modified(); return true; } @@ -665,6 +583,7 @@ void SMESHGUI_ExtrusionAlongPathDlg::reject() if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySMESHGUI->ResetState(); + QDialog::reject(); } @@ -682,54 +601,13 @@ void SMESHGUI_ExtrusionAlongPathDlg::onTextChange (const QString& theNewText) // set busy flag SetBusy sb (this); - if (send != StartPointLineEdit && send != ElementsLineEdit) - send = ElementsLineEdit; - - if (send == ElementsLineEdit && myEditCurrentArgument == ElementsLineEdit) { - // hilight entered elements - SMDS_Mesh* aMesh = 0; - if (myMeshActor) - aMesh = myMeshActor->GetObject()->GetMesh(); - - if (aMesh) { - //mySelectionMgr->clearSelected(); - //mySelectionMgr->AddIObject(myMeshActor->getIO()); - SALOME_ListIO aList; - aList.Append(myMeshActor->getIO()); - mySelectionMgr->setSelectedObjects(aList, false); - - QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); - bool bOk; - const Handle(SALOME_InteractiveObject)& anIO = myMeshActor->getIO(); - TColStd_MapOfInteger newIndices; - for (int i = 0; i < aListId.count(); i++) { - long ind = aListId[ i ].toLong(&bOk); - if (bOk) { - const SMDS_MeshElement* e = aMesh->FindElement(ind); - if (e) { - // check also type of element - bool typeMatch = (Elements1dRB->isChecked() && e->GetType() == SMDSAbs_Edge) || - (Elements2dRB->isChecked() && e->GetType() == SMDSAbs_Face); - if (typeMatch) - newIndices.Add(e->GetID()); - } - } - } - mySelector->AddOrRemoveIndex(anIO, newIndices, false); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->highlight( anIO, true, true ); - } - } - else if (send == StartPointLineEdit && - myEditCurrentArgument == StartPointLineEdit) { + if (send == StartPointLineEdit && + myEditCurrentArgument == StartPointLineEdit) + { if (!myPath->_is_nil()) { SMESH_Actor* aPathActor = SMESH::FindActorByObject(myPath); - SMDS_Mesh* aMesh = 0; - if (aPathActor) - aMesh = aPathActor->GetObject()->GetMesh(); + SMDS_Mesh* aMesh = aPathActor ? aPathActor->GetObject()->GetMesh() : 0; if (aMesh) { - //mySelectionMgr->clearSelected(); - //mySelectionMgr->AddIObject(aPathActor->getIO()); SALOME_ListIO aList; aList.Append(aPathActor->getIO()); mySelectionMgr->setSelectedObjects(aList, false); @@ -739,7 +617,6 @@ void SMESHGUI_ExtrusionAlongPathDlg::onTextChange (const QString& theNewText) if (bOk) { const SMDS_MeshNode* n = aMesh->FindNode(ind); if (n) { - //if (!mySelectionMgr->IsIndexSelected(aPathActor->getIO(), n->GetID())) { TColStd_MapOfInteger newIndices; newIndices.Add(n->GetID()); mySelector->AddOrRemoveIndex( aPathActor->getIO(), newIndices, false ); @@ -750,6 +627,8 @@ void SMESHGUI_ExtrusionAlongPathDlg::onTextChange (const QString& theNewText) } } } + CheckIsEnable(); + onDisplaySimulation(true); } //================================================================================= @@ -773,67 +652,29 @@ void SMESHGUI_ExtrusionAlongPathDlg::SelectionIntoArgument() // set busy flag SetBusy sb (this); - if (myEditCurrentArgument == ElementsLineEdit) { - // we are now selecting mesh elements (or whole mesh/submesh/group) - // reset - ElementsLineEdit->clear(); - myMesh = SMESH::SMESH_Mesh::_nil(); - myIDSource = SMESH::SMESH_IDSource::_nil(); - myMeshActor = 0; + const bool isPathDef = ( SelectPathMeshButton->isChecked() || + SelectStartPointButton->isChecked() ); - // try to get mesh from selection - Handle(SALOME_InteractiveObject) IO = aList.First(); - myMesh = SMESH::GetMeshByIO(IO); - if (myMesh->_is_nil()) - return; - - // MakeGroups is available if there are groups - if ( myMesh->NbGroups() == 0 ) { - MakeGroupsCheck->setChecked(false); - MakeGroupsCheck->setEnabled(false); - } else { - MakeGroupsCheck->setEnabled(true); - } - // find actor - myMeshActor = SMESH::FindActorByObject(myMesh); - if (!myMeshActor && !MeshCheck->isChecked()) - return; - - if (MeshCheck->isChecked()) { - // If "Select whole mesh, submesh or group" check box is on -> - // get ID source and put it's name to the edit box - QString aString; - SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString); - - myIDSource = SMESH::IObjectToInterface(IO); - ElementsLineEdit->setText(aString); - } else { - // If "Select whole mesh, submesh or group" check box is off -> - // try to get selected elements IDs - QString aString; - //int aNbUnits = SMESH::GetNameOfSelectedElements(mySelectionMgr, aString); - SMESH::GetNameOfSelectedElements(mySelector, IO, aString); - ElementsLineEdit->setText(aString); - } - } - else if (myEditCurrentArgument == PathMeshLineEdit) { + if (myEditCurrentArgument == PathMeshLineEdit && isPathDef) + { // we are now selecting path mesh // reset PathMeshLineEdit->clear(); myPath = SMESH::SMESH_IDSource::_nil(); StartPointLineEdit->clear(); - + // try to get mesh from selection Handle(SALOME_InteractiveObject) IO = aList.First(); myPath = SMESH::IObjectToInterface(IO); if( myPath->_is_nil() ) return; - + QString aString; SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString); PathMeshLineEdit->setText(aString); } - else if (myEditCurrentArgument == StartPointLineEdit) { + else if (myEditCurrentArgument == StartPointLineEdit && isPathDef ) + { // we are now selecting start point of path // reset StartPointLineEdit->clear(); @@ -848,13 +689,15 @@ void SMESHGUI_ExtrusionAlongPathDlg::SelectionIntoArgument() SMESH_Actor* aPathActor = SMESH::FindActorByObject(myPath); if ( !aPathActor ) return; - + QString aString; int aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, aPathActor->getIO(), aString); if (aNbUnits == 1) StartPointLineEdit->setText(aString.trimmed()); - - } else if (myEditCurrentArgument == XSpin) { + } + else if ( myEditCurrentArgument == XSpin && + SelectBasePointButton->isChecked() ) + { // we are now selecting base point // reset is not performed here! @@ -905,7 +748,13 @@ void SMESHGUI_ExtrusionAlongPathDlg::SelectionIntoArgument() YSpin->SetValue(n->Y()); ZSpin->SetValue(n->Z()); } + else + { + return; + } + onDisplaySimulation(true); + CheckIsEnable(); } //================================================================================= @@ -914,11 +763,10 @@ void SMESHGUI_ExtrusionAlongPathDlg::SelectionIntoArgument() //================================================================================= void SMESHGUI_ExtrusionAlongPathDlg::SetEditCurrentArgument() { - QToolButton* send = (QToolButton*)sender(); + QPushButton* send = (QPushButton*)sender(); if ( sender() == BasePointGrp ) send = SelectBasePointButton; - if (send != SelectElementsButton && - send != SelectPathMeshButton && + if (send != SelectPathMeshButton && send != SelectStartPointButton && send != SelectBasePointButton) return; @@ -929,42 +777,25 @@ void SMESHGUI_ExtrusionAlongPathDlg::SetEditCurrentArgument() // function : SetEditCurrentArgument() // purpose : //================================================================================= -void SMESHGUI_ExtrusionAlongPathDlg::SetEditCurrentArgument (QToolButton* button) +void SMESHGUI_ExtrusionAlongPathDlg::SetEditCurrentArgument (QPushButton* button) { disconnect(mySelectionMgr, 0, this, 0); // mySelectionMgr->clearSelected(); mySelectionMgr->clearFilters(); SMESH::SetPickable(); - if (button == SelectElementsButton) { - myEditCurrentArgument = ElementsLineEdit; - SMESH::SetPointRepresentation(false); - if (MeshCheck->isChecked()) { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); - mySelectionMgr->installFilter(myElementsFilter); - } else { - if (Elements1dRB->isChecked()) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - } - else if (Elements2dRB->isChecked()) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - } - } - } else if (button == SelectPathMeshButton) { + myEditCurrentArgument = 0; + if (button == SelectPathMeshButton) + { myEditCurrentArgument = PathMeshLineEdit; SMESH::SetPointRepresentation(false); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(ActorSelection); mySelectionMgr->installFilter(myPathMeshFilter); } - else if (button == SelectStartPointButton) { + else if (button == SelectStartPointButton) + { myEditCurrentArgument = StartPointLineEdit; - //if (!myPathMesh->_is_nil()) { if (!myPath->_is_nil()) { SMESH_Actor* aPathActor = SMESH::FindActorByObject(myPath); if (aPathActor) { @@ -975,7 +806,8 @@ void SMESHGUI_ExtrusionAlongPathDlg::SetEditCurrentArgument (QToolButton* button } } } - else if (button == SelectBasePointButton) { + else if (button == SelectBasePointButton) + { myEditCurrentArgument = XSpin; SMESH::SetPointRepresentation(true); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) @@ -1005,10 +837,11 @@ void SMESHGUI_ExtrusionAlongPathDlg::SetEditCurrentArgument (QToolButton* button //================================================================================= void SMESHGUI_ExtrusionAlongPathDlg::DeactivateActiveDialog() { - if (ConstructorsBox->isEnabled()) { - ConstructorsBox->setEnabled(false); + if (GroupButtons->isEnabled()) + { GroupArguments->setEnabled(false); GroupButtons->setEnabled(false); + SelectorWdg->setEnabled(false); mySMESHGUI->ResetState(); mySMESHGUI->SetActiveDialogBox(0); } @@ -1022,13 +855,11 @@ void SMESHGUI_ExtrusionAlongPathDlg::ActivateThisDialog() { // Emit a signal to deactivate the active dialog mySMESHGUI->EmitSignalDeactivateDialog(); - ConstructorsBox->setEnabled(true); GroupArguments->setEnabled(true); GroupButtons->setEnabled(true); + SelectorWdg->setEnabled(true); mySMESHGUI->SetActiveDialogBox(this); - - ConstructorsClicked(GetConstructorId()); SelectionIntoArgument(); } @@ -1038,36 +869,10 @@ void SMESHGUI_ExtrusionAlongPathDlg::ActivateThisDialog() //================================================================================= void SMESHGUI_ExtrusionAlongPathDlg::enterEvent (QEvent*) { - if (!ConstructorsBox->isEnabled()) + if (!GroupButtons->isEnabled()) ActivateThisDialog(); } -//======================================================================= -// function : onSelectMesh() -// purpose : -//======================================================================= -void SMESHGUI_ExtrusionAlongPathDlg::onSelectMesh() -{ - bool toSelectMesh = MeshCheck->isChecked(); - - ElementsLineEdit->setReadOnly(toSelectMesh); - ElementsLineEdit->setValidator(toSelectMesh ? 0 : myIdValidator); - ElementsLab->setText(toSelectMesh ? tr("SMESH_NAME") : tr("SMESH_ID_ELEMENTS")); - ElementsLineEdit->clear(); - myFilterBtn->setEnabled(!toSelectMesh); - - SetEditCurrentArgument(SelectElementsButton); -} - -//================================================================================= -// function : GetConstructorId() -// purpose : -//================================================================================= -int SMESHGUI_ExtrusionAlongPathDlg::GetConstructorId() -{ - return GroupConstructors->checkedId(); -} - //======================================================================= // function : OnAngleAdded() // purpose : Called when user adds angle to the list @@ -1118,11 +923,7 @@ bool SMESHGUI_ExtrusionAlongPathDlg::eventFilter (QObject* object, QEvent* event } } else if (event->type() == QEvent::FocusIn) { - if (object == ElementsLineEdit) { - if (myEditCurrentArgument != ElementsLineEdit) - SetEditCurrentArgument(SelectElementsButton); - } - else if (object == StartPointLineEdit) { + if (object == StartPointLineEdit) { if (myEditCurrentArgument != StartPointLineEdit) SetEditCurrentArgument(SelectStartPointButton); } @@ -1150,34 +951,6 @@ void SMESHGUI_ExtrusionAlongPathDlg::keyPressEvent( QKeyEvent* e ) } } -//================================================================================= -// function : setFilters() -// purpose : SLOT. Called when "Filter" button pressed. -//================================================================================= -void SMESHGUI_ExtrusionAlongPathDlg::setFilters() -{ - if(myMesh->_is_nil()) { - SUIT_MessageBox::critical(this, - tr("SMESH_ERROR"), - tr("NO_MESH_SELECTED")); - return; - } - if ( !myFilterDlg ) - { - QList types; - types.append( SMESH::EDGE ); - types.append( SMESH::FACE ); - myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); - } - myFilterDlg->Init( Elements1dRB->isChecked() ? SMESH::EDGE : SMESH::FACE ); - - myFilterDlg->SetSelection(); - myFilterDlg->SetMesh( myMesh ); - myFilterDlg->SetSourceWg( ElementsLineEdit ); - - myFilterDlg->show(); -} - //================================================================================= // function : isValid // purpose : @@ -1224,40 +997,43 @@ void SMESHGUI_ExtrusionAlongPathDlg::updateLinearAngles() // function : isValuesValid() // purpose : Return true in case if values entered into dialog are valid //================================================================================= -bool SMESHGUI_ExtrusionAlongPathDlg::isValuesValid() { - - if ( (MeshCheck->isChecked() && myIDSource->_is_nil()) || - myMesh->_is_nil() || - myPath->_is_nil() ) + +bool SMESHGUI_ExtrusionAlongPathDlg::isValuesValid() +{ + if ( myPath->_is_nil() ) return false; - if(!MeshCheck->isChecked()) { - QStringList aListElementsId = ElementsLineEdit->text().split(" ", QString::SkipEmptyParts); - if(aListElementsId.count() <= 0) - return false; - } - bool bOk; - StartPointLineEdit->text().toLong(&bOk); - if (!bOk) { + long aNodeStart = StartPointLineEdit->text().toLong(&bOk); + if ( !bOk || aNodeStart < 1 ) + return false; + + SMESH::SMESH_Mesh_var mesh = myPath->GetMesh(); + if ( mesh->_is_nil() ) + return false; + + SMESH::ElementType type = mesh->GetElementType( aNodeStart, false ); + if ( type != SMESH::NODE ) + return false; + + SMESH::long_array_var elems = mesh->GetNodeInverseElements( aNodeStart ); + if ( elems->length() != 1 || + mesh->GetElementType( elems[0], true ) != SMESH::EDGE ) return false; - } return true; } - //================================================================================= // function : onDisplaySimulation // purpose : Show/Hide preview //================================================================================= -void SMESHGUI_ExtrusionAlongPathDlg::onDisplaySimulation( bool toDisplayPreview ) { - if (myPreviewCheckBox->isChecked() && toDisplayPreview) { - if(isValid() && isValuesValid()) { - - //Get selected elements: - SMESH::long_array_var anElementsId = getSelectedElements(); +void SMESHGUI_ExtrusionAlongPathDlg::onDisplaySimulation( bool toDisplayPreview ) +{ + if ( myPreviewCheckBox->isChecked() && toDisplayPreview ) { + if ( SelectorWdg->IsAnythingSelected() && isValid() && isValuesValid()) + { // get angles SMESH::double_array_var anAngles = getAngles(); @@ -1271,42 +1047,44 @@ void SMESHGUI_ExtrusionAlongPathDlg::onDisplaySimulation( bool toDisplayPreview bool bOk; long aNodeStart = StartPointLineEdit->text().toLong(&bOk); if (bOk) { - + try { SUIT_OverrideCursor wc; - + SMESH::SMESH_MeshEditor::Extrusion_Error retVal; - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer(); - bool NeedGroups = false; - SMESH::ElementType ElemType = ( GetConstructorId() == 0 ) ? SMESH::EDGE : SMESH::FACE; - if( !MeshCheck->isChecked() ) { - aMeshEditor->ExtrusionAlongPathX(anElementsId, myPath, aNodeStart, AnglesGrp->isChecked(), - anAngles, LinearAnglesCheck->isChecked(), - BasePointGrp->isChecked(), aBasePoint, - NeedGroups, ElemType, retVal); + SMESH::SMESH_Mesh_var mesh = SelectorWdg->GetMesh(); + SMESH::SMESH_MeshEditor_var meshEditor = mesh->GetMeshEditPreviewer(); + + SMESH::ListOfIDSources_var nodes = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var edges = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var faces = new SMESH::ListOfIDSources(); + SelectorWdg->GetSelected( nodes, edges, faces ); + const bool makeGroups = false; + + SMESH::ListOfGroups_var groups = + meshEditor->ExtrusionAlongPathObjects( nodes, edges, faces, myPath, + GEOM::GEOM_Object::_nil(), + aNodeStart, AnglesGrp->isChecked(), + anAngles, LinearAnglesCheck->isChecked(), + BasePointGrp->isChecked(), aBasePoint, + makeGroups, retVal ); + + if( retVal == SMESH::SMESH_MeshEditor::EXTR_OK ) + { + SMESH::MeshPreviewStruct_var aMeshPreviewStruct = meshEditor->GetPreviewData(); + mySimulation->SetData( aMeshPreviewStruct._retn() ); } else { - SMESH::ListOfGroups_var groups = - aMeshEditor->ExtrusionAlongPathObjX(myIDSource, myPath, aNodeStart, AnglesGrp->isChecked(), - anAngles, LinearAnglesCheck->isChecked(), - BasePointGrp->isChecked(), aBasePoint, - NeedGroups, ElemType, retVal); - } - - if( retVal == SMESH::SMESH_MeshEditor::EXTR_OK ) { - SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData(); - mySimulation->SetData(aMeshPreviewStruct._retn()); - } else { hidePreview(); } - + } catch (...) { hidePreview(); } } else { hidePreview(); } - + } else { hidePreview(); } @@ -1315,49 +1093,11 @@ void SMESHGUI_ExtrusionAlongPathDlg::onDisplaySimulation( bool toDisplayPreview } } - -//================================================================================= -// function : getSelectedElements -// purpose : return list of the selected elements -//================================================================================= -SMESH::long_array_var SMESHGUI_ExtrusionAlongPathDlg::getSelectedElements() { - - // If "Select whole mesh, submesh or group" check box is off -> - // use only elements of given type selected by user - SMESH::long_array_var anElementsId = new SMESH::long_array; - if (!MeshCheck->isChecked()) { - - SMDS_Mesh* aMesh; - if ( myMeshActor ) - aMesh = myMeshActor->GetObject()->GetMesh(); - - if (aMesh) { - QStringList aListElementsId = ElementsLineEdit->text().split(" ", QString::SkipEmptyParts); - anElementsId = new SMESH::long_array; - anElementsId->length(aListElementsId.count()); - bool bOk; - int j = 0; - for (int i = 0; i < aListElementsId.count(); i++) { - long ind = aListElementsId[ i ].toLong(&bOk); - if (bOk) { - const SMDS_MeshElement* e = aMesh->FindElement(ind); - if (e) { - bool typeMatch = (Elements1dRB->isChecked() && e->GetType() == SMDSAbs_Edge) || - (Elements2dRB->isChecked() && e->GetType() == SMDSAbs_Face); - if (typeMatch) - anElementsId[ j++ ] = ind; - } - } - } - anElementsId->length(j); - } - } - return anElementsId; -} - -SMESH::double_array_var SMESHGUI_ExtrusionAlongPathDlg::getAngles() { +SMESH::double_array_var SMESHGUI_ExtrusionAlongPathDlg::getAngles() +{ SMESH::double_array_var anAngles = new SMESH::double_array; - if (AnglesGrp->isChecked()) { + if (AnglesGrp->isChecked()) + { anAngles->length(myAnglesList.count()); int j = 0; for (int i = 0; i < myAnglesList.count(); i++) { diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h index e7c3985d2..199c8752e 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h +++ b/src/SMESHGUI/SMESHGUI_ExtrusionAlongPathDlg.h @@ -45,14 +45,15 @@ class QCheckBox; class QListWidget; class QPushButton; +class LightApp_SelectionMgr; class SMESHGUI; -class SMESH_Actor; +class SMESHGUI_3TypesSelector; +class SMESHGUI_FilterDlg; class SMESHGUI_IdValidator; class SMESHGUI_SpinBox; -class SMESHGUI_FilterDlg; -class SVTK_Selector; -class LightApp_SelectionMgr; +class SMESH_Actor; class SUIT_SelectionFilter; +class SVTK_Selector; //================================================================================= // class : SMESHGUI_ExtrusionAlongPathDlg @@ -75,13 +76,11 @@ private: void Init( bool = true ); void enterEvent( QEvent* ); /* mouse enter the QWidget */ void keyPressEvent( QKeyEvent* ); - int GetConstructorId(); - void SetEditCurrentArgument( QToolButton* ); + void SetEditCurrentArgument( QPushButton* ); bool isValid(); bool isValuesValid(); - SMESH::long_array_var getSelectedElements(); SMESH::double_array_var getAngles(); void updateLinearAngles(); @@ -89,38 +88,20 @@ private: SMESHGUI_IdValidator* myIdValidator; LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ SVTK_Selector* mySelector; - QWidget* myEditCurrentArgument; /* Current argument */ bool myBusy; - SMESH::SMESH_Mesh_var myMesh; - SMESH_Actor* myMeshActor; - SMESH::SMESH_IDSource_var myIDSource; - //SMESH::SMESH_Mesh_var myPathMesh; SMESH::SMESH_IDSource_var myPath; - //GEOM::GEOM_Object_var myPathShape; - SUIT_SelectionFilter* myElementsFilter; SUIT_SelectionFilter* myPathMeshFilter; - int myType; QList myAnglesList; // widgets - QGroupBox* ConstructorsBox; - QButtonGroup* GroupConstructors; - QRadioButton* Elements1dRB; - QRadioButton* Elements2dRB; - + SMESHGUI_3TypesSelector* SelectorWdg; QGroupBox* GroupArguments; - QLabel* ElementsLab; - QToolButton* SelectElementsButton; - QLineEdit* ElementsLineEdit; - QCheckBox* MeshCheck; QGroupBox* PathGrp; - QToolButton* SelectPathMeshButton; + QPushButton* SelectPathMeshButton; QLineEdit* PathMeshLineEdit; - //QToolButton* SelectPathShapeButton; - //QLineEdit* PathShapeLineEdit; - QToolButton* SelectStartPointButton; + QPushButton* SelectStartPointButton; QLineEdit* StartPointLineEdit; QCheckBox* LinearAnglesCheck; QGroupBox* AnglesGrp; @@ -129,7 +110,7 @@ private: QToolButton* RemoveAngleButton; SMESHGUI_SpinBox* AngleSpin; QGroupBox* BasePointGrp; - QToolButton* SelectBasePointButton; + QPushButton* SelectBasePointButton; SMESHGUI_SpinBox* XSpin; SMESHGUI_SpinBox* YSpin; SMESHGUI_SpinBox* ZSpin; @@ -143,27 +124,22 @@ private: QString myHelpFileName; - QPushButton* myFilterBtn; - SMESHGUI_FilterDlg* myFilterDlg; - protected slots: void reject(); virtual void onDisplaySimulation( bool ); private slots: - void ConstructorsClicked( int ); void ClickOnOk(); bool ClickOnApply(); void ClickOnHelp(); + void CheckIsEnable(); void SetEditCurrentArgument(); void SelectionIntoArgument(); void DeactivateActiveDialog(); void ActivateThisDialog(); void onTextChange( const QString& ); - void onSelectMesh(); void OnAngleAdded(); void OnAngleRemoved(); - void setFilters(); }; #endif // SMESHGUI_EXTRUSIONALONGPATHDLG_H diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx index b85666b55..b82b5d821 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.cxx @@ -84,21 +84,515 @@ #define SPACING 6 #define MARGIN 11 +namespace +{ + const char* getLabelText( int typeIndex, bool objSelection ) + { + const char* typeLbl[3] = { "SMESH_ID_NODES", "SMESH_ID_EDGES", "SMESH_ID_FACES" }; + const char* obj = "SMESH_OBJECTS"; + return objSelection ? obj : typeLbl[ typeIndex ]; + } +} + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +SMESHGUI_3TypesSelector::SMESHGUI_3TypesSelector( QWidget * parent ): + QWidget( parent ) +{ + SMESHGUI* gui = SMESHGUI::GetSMESHGUI(); + mySelectionMgr = SMESH::GetSelectionMgr( gui ); + mySelector = SMESH::GetViewWindow( gui )->GetSelector(); + myFilterDlg = 0; + myIdValidator = new SMESHGUI_IdValidator(this); + + QPixmap image( SMESH::GetResourceMgr( gui )->loadPixmap("SMESH", tr("ICON_SELECT"))); + + mySelectBtnGrp = new QButtonGroup( this ); + mySelectBtnGrp->setExclusive( true ); + + QVBoxLayout* mainLayout = new QVBoxLayout( this ); + mainLayout->setSpacing( SPACING ); + mainLayout->setMargin( 0 ); + + const char* groupLbl[3] = { "SMESH_NODES", "SMESH_EDGES", "SMESH_FACES" }; + + for ( int i = 0; i < 3; ++i ) + { + myGroups[i] = new QGroupBox( tr( groupLbl[i] ), this ); + mainLayout->addWidget( myGroups[i] ); + QGridLayout* layout = new QGridLayout( myGroups[i] ); + layout->setSpacing( SPACING ); + layout->setMargin( MARGIN ); + + QPushButton* selBtn = new QPushButton( myGroups[i] ); + selBtn->setIcon( image ); + selBtn->setCheckable( true ); + mySelectBtnGrp->addButton( selBtn, i ); + myLabel [i] = new QLabel( myGroups[i] ); + myLineEdit [i] = new QLineEdit( myGroups[i] ); + myMeshChk [i] = new QCheckBox( tr("SMESH_SELECT_WHOLE_MESH"), myGroups[i] ); + myFilterBtn[i] = new QPushButton( tr( "SMESH_BUT_FILTER" ), myGroups[i] ); + + myLineEdit[i]->setMaxLength(-1); + myLabel [i]->setText( tr( getLabelText( i, true ))); + + layout->addWidget(myLabel [i], 0, 0); + layout->addWidget(selBtn, 0, 1); + layout->addWidget(myLineEdit [i], 0, 2, 1, 2); + layout->addWidget(myFilterBtn[i], 0, 4); + layout->addWidget(myMeshChk [i], 1, 0, 1, 5); + layout->setColumnStretch( 2, 10 ); + + connect( myMeshChk [i], SIGNAL(toggled(bool)), SLOT(onSelectMesh(bool))); + connect( myFilterBtn[i], SIGNAL(clicked()), SLOT(setFilters())); + connect( myLineEdit [i], SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&))); + myIDSource[i] = new SMESH::ListOfIDSources; + } + connect( mySelectBtnGrp, SIGNAL(buttonClicked (int)), SLOT(onSelectType(int))); + connect(mySelectionMgr, SIGNAL( currentSelectionChanged()), SLOT(selectionIntoArgument())); + + // Costruction of the logical filter for the elements: mesh/sub-mesh/group + QList aListOfFilters; + aListOfFilters.append(new SMESH_TypeFilter (SMESH::MESH)); + aListOfFilters.append(new SMESH_TypeFilter (SMESH::SUBMESH_VERTEX)); + aListOfFilters.append(new SMESH_TypeFilter (SMESH::GROUP_NODE)); + myFilter[0] = + new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true); + aListOfFilters[0] = new SMESH_TypeFilter (SMESH::MESH); + aListOfFilters[1] = new SMESH_TypeFilter (SMESH::SUBMESH_EDGE); + aListOfFilters[2] = new SMESH_TypeFilter (SMESH::GROUP_EDGE); + myFilter[1] = + new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true); + aListOfFilters[0] = new SMESH_TypeFilter (SMESH::MESH); + aListOfFilters[1] = new SMESH_TypeFilter (SMESH::SUBMESH_FACE); + aListOfFilters[2] = new SMESH_TypeFilter (SMESH::GROUP_FACE); + myFilter[2] = + new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true); + + myBusy = false; + + myMeshChk[0]->setChecked( true ); + myMeshChk[1]->setChecked( true ); + myMeshChk[2]->setChecked( true ); + mySelectBtnGrp->button(0)->click(); +} + +//================================================================================ +/*! + * \brief Destructor + */ +//================================================================================ + +SMESHGUI_3TypesSelector::~SMESHGUI_3TypesSelector() +{ + myIDSource[0].out(); + myIDSource[1].out(); + myIDSource[2].out(); + + delete myFilter[0]; + delete myFilter[1]; + delete myFilter[2]; + + if ( myFilterDlg ) + { + myFilterDlg->setParent( 0 ); + delete myFilterDlg; + myFilterDlg = 0; + } + disconnect(mySelectionMgr, 0, this, 0); +} + +//================================================================================ +/*! + * \brief Slot called when selection changes + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::selectionIntoArgument() +{ + if (myBusy) return; + + // return if dialog box is inactive + if ( !isEnabled() ) + return; + + // get a current element type + int iType = mySelectBtnGrp->checkedId(); + if ( iType < 0 || iType > 2 ) + return; + + QString aString = ""; + int nbObjects = 0; + + // clear + myBusy = true; + myLineEdit[ iType ]->setText(aString); + myIDSource[ iType ]->length (nbObjects); + myBusy = false; + if ( !myGroups[ iType ]->isEnabled() ) + return; + + SMESH::SetPointRepresentation(false); + + SALOME_ListIO selected; + mySelectionMgr->selectedObjects( selected ); + + if ( myMeshChk[ iType ]->isChecked() ) // objects selection + myIDSource[ iType ]->length( selected.Extent() ); // reserve + myIDSource[ iType ]->length(0); + + SALOME_ListIteratorOfListIO It( selected ); + for ( ; It.More(); It.Next() ) + { + Handle(SALOME_InteractiveObject) IO = It.Value(); + + // get selected mesh + SMESH::SMESH_Mesh_var mesh = SMESH::GetMeshByIO(IO); + if ( mesh->_is_nil() ) + continue; + if ( !myMesh->_is_nil() && + IsAnythingSelected() && + myMesh->GetId() != mesh->GetId() ) + continue; // other mesh + myMesh = mesh; + myIO = IO; + myActor = SMESH::FindActorByEntry( IO->getEntry() ); + + if ( myMeshChk[ iType ]->isChecked() ) // objects selection + { + SMESH::SMESH_IDSource_var idSrc = SMESH::IObjectToInterface(IO); + if ( idSrc->_is_nil() ) + continue; + mesh = SMESH::SMESH_Mesh::_narrow( idSrc ); + if ( !mesh->_is_nil() ) // if a mesh is selected, stop iteration + { + nbObjects = 1; + myIDSource[ iType ]->length( nbObjects ); + myIDSource[ iType ][ 0 ] = idSrc; + aString = IO->getName(); + break; + } + else // several groups can be selected + { + myIDSource[ iType ]->length( nbObjects + 1 ); + myIDSource[ iType ][ nbObjects++ ] = idSrc; + aString += " " + QString( IO->getName() ) + " "; + } + } + else // get indices of selected elements + { + TColStd_IndexedMapOfInteger aMapIndex; + mySelector->GetIndex(IO,aMapIndex); + int nbElements = aMapIndex.Extent(); + if ( nbElements > 0 ) + { + SMESH::long_array_var ids = new SMESH::long_array; + ids->length( nbElements ); + for ( int i = 0; i < nbElements; ++i ) + aString += QString(" %1").arg( ids[ i ] = aMapIndex( i+1 )); + addTmpIdSource( ids, iType, nbObjects++ ); + } + break; + } + } + + myIDSource[ iType ]->length( nbObjects ); + + myBusy = true; + myLineEdit[ iType ]->setText(aString); + myBusy = false; + + emit selectionChanged(); +} + +//================================================================================ +/*! + * \brief Slot called when text changes in myLineEdit + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::onTextChange( const QString& theNewText ) +{ + // return if busy + if (myBusy) return; + + // get a current element type + int iType = 0; + QLineEdit* le = (QLineEdit*) sender(); + for ( ; iType < 3; ++iType ) + if ( myLineEdit[ iType ] == le ) + break; + if ( iType < 0 || iType > 2 ) + return; + if ( !myGroups[ iType ]->isEnabled() ) + return; + + myBusy = true; + + // hilight entered elements/nodes + + myIDSource[ iType ]->length( 0 ); + + if ( !myMesh->_is_nil() ) + { + QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); + if ( aListId.count() > 0 ) + { + SMDS_Mesh* aMesh = myActor ? myActor->GetObject()->GetMesh() : 0; + + SMESH::ElementType SMESHType = SMESH::ElementType ( iType+1 ); + SMDSAbs_ElementType SMDSType = SMDSAbs_ElementType( iType+1 ); + const bool isNode = ( SMDSType == SMDSAbs_Node ); + + SMESH::long_array_var ids = new SMESH::long_array; + ids->length( aListId.count() ); + TColStd_MapOfInteger newIndices; + for (int i = 0; i < aListId.count(); i++) { + int id = aListId[ i ].toInt(); + bool validId = false; + if ( id > 0 ) { + if ( aMesh ) { + const SMDS_MeshElement * e; + if ( isNode ) e = aMesh->FindNode( id ); + else e = aMesh->FindElement( id ); + validId = ( e && e->GetType() == SMDSType ); + } else { + validId = ( myMesh->GetElementType( id, !isNode ) == SMESHType ); + } + } + if ( validId && newIndices.Add( id )) + ids[ newIndices.Extent()-1 ] = id; + } + if ( !newIndices.IsEmpty() ) { + ids->length( newIndices.Extent() ); + addTmpIdSource( ids, iType, 0 ); + } + mySelector->AddOrRemoveIndex(myIO, newIndices, false); + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetCurrentVtkView() ) + aViewWindow->highlight( myIO, true, true ); + } + } + + emit selectionChanged(); + + myBusy = false; +} + +//================================================================================ +/*! + * \brief Creates from ids and stores a temporary IDSource + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::addTmpIdSource( SMESH::long_array_var& ids, int iType, int index ) +{ + SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); + SMESH::SMESH_IDSource_var idSrc = + aMeshEditor->MakeIDSource( ids, SMESH::ElementType( iType+1 )); + + if ( myIDSource[ iType ]->length() <= index ) + myIDSource[ iType ]->length( index + 1 ); + myIDSource[ iType ][ index ] = idSrc; + + myTmpIDSourceList.push_back( idSrc ); +} + +//================================================================================ +/*! + * \brief Slot called when myMeshChk is checked + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::onSelectMesh( bool on ) +{ + QCheckBox* send = (QCheckBox*)sender(); + for ( int iType = 0; iType < 3; ++iType ) + if ( send == myMeshChk[ iType ]) + { + myLabel[ iType ]->setText( tr( getLabelText( iType, on ))); + myFilterBtn[ iType ]->setEnabled( !on ); + myIDSource [ iType ]->length(0); + myBusy = true; + myLineEdit [ iType ]->setText(""); + myBusy = false; + myLineEdit [ iType ]->setReadOnly( on ); + myLineEdit [ iType ]->setValidator( on ? 0 : myIdValidator ); + mySelectBtnGrp->button(iType)->click(); + break; + } + else + { + + } +} + +//================================================================================ +/*! + * \brief Slot called when a selection button is clicked + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::onSelectType(int iType) +{ + if ( iType < 0 || iType > 2 ) + return; + + myIDSource[ iType ]->length(0); + myLineEdit[ iType ]->setText(""); + + disconnect(mySelectionMgr, 0, this, 0); + mySelectionMgr->clearFilters(); + + SVTK_ViewWindow* aViewWindow = SMESH::GetCurrentVtkView(); + if ( myMeshChk[ iType ]->isChecked() ) + { + if ( aViewWindow ) aViewWindow->SetSelectionMode(ActorSelection); + mySelectionMgr->installFilter( myFilter[ iType ]); + } + else if ( aViewWindow ) + { + switch ( iType+1 ) { + case SMESH::NODE: aViewWindow->SetSelectionMode(NodeSelection); break; + case SMESH::EDGE: aViewWindow->SetSelectionMode(EdgeSelection); break; + case SMESH::FACE: aViewWindow->SetSelectionMode(FaceSelection); break; + } + } + + myLineEdit[ iType ]->setFocus(); + + connect(mySelectionMgr, SIGNAL( currentSelectionChanged()), SLOT( selectionIntoArgument())); + selectionIntoArgument(); +} + +//================================================================================ +/*! + * \brief Slot called when "Set filter" is clicked + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::setFilters() +{ + if ( myMesh->_is_nil() ) { + SUIT_MessageBox::critical(this, + tr("SMESH_ERROR"), + tr("NO_MESH_SELECTED")); + return; + } + if ( !myFilterDlg ) + { + QList types; + types.append( SMESH::NODE ); + types.append( SMESH::EDGE ); + types.append( SMESH::FACE ); + myFilterDlg = new SMESHGUI_FilterDlg( SMESHGUI::GetSMESHGUI(), types ); + } + + QPushButton* send = (QPushButton*)sender(); + for ( int iType = 0; iType < 3; ++iType ) + if ( send == myFilterBtn[ iType ]) + { + mySelectBtnGrp->button(iType)->click(); + + myFilterDlg->Init( SMESH::ElementType( iType+1 ) ); + myFilterDlg->SetSelection(); + myFilterDlg->SetMesh( myMesh ); + myFilterDlg->SetSourceWg( myLineEdit[ iType ]); + myFilterDlg->show(); + break; + } +} + +//================================================================================ +/*! + * \brief Clear selection + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::Clear() +{ + myBusy = true; + for ( int iType = 0; iType < 3; ++iType ) + { + myIDSource[ iType ]->length(0); + myLineEdit[ iType ]->setText(""); + } + myBusy = false; + selectionIntoArgument(); +} + +//================================================================================ +/*! + * \brief Enable/disable controls of a type + */ +//================================================================================ + +void SMESHGUI_3TypesSelector::SetEnabled( bool enable, SMESH::ElementType type ) +{ + myBusy = true; + for ( int iType = 0; iType < 3; ++iType ) + if ( iType+1 == type || type == SMESH::ALL ) + { + myGroups[ iType ]->setEnabled( enable ); + if ( !enable ) { + myIDSource[ iType ]->length(0); + myLineEdit[ iType ]->setText(""); + } + } + myBusy = false; + selectionIntoArgument(); +} + +//================================================================================ +/*! + * \brief Checks if anything is selected + */ +//================================================================================ + +bool SMESHGUI_3TypesSelector::IsAnythingSelected( SMESH::ElementType type ) +{ + int nbSel = 0; + + for ( int iType = 0; iType < 3; ++iType ) + if ( iType+1 == type || type == SMESH::ALL ) + nbSel += myIDSource[ iType ]->length(); + + return nbSel; +} + +//================================================================================ +/*! + * \brief Returns selected elements and most complex type of selected elements + */ +//================================================================================ + +SMESH::ElementType SMESHGUI_3TypesSelector::GetSelected( SMESH::ListOfIDSources & nodes, + SMESH::ListOfIDSources & edges, + SMESH::ListOfIDSources & faces ) +{ + nodes = myIDSource[0]; + edges = myIDSource[1]; + faces = myIDSource[2]; + + if ( myIDSource[2]->length() > 0 ) return SMESH::FACE; + if ( myIDSource[1]->length() > 0 ) return SMESH::EDGE; + if ( myIDSource[0]->length() > 0 ) return SMESH::NODE; + return SMESH::ALL; +} + //================================================================================= // function : SMESHGUI_ExtrusionDlg() // purpose : constructor //================================================================================= + SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) : SMESHGUI_PreviewDlg( theModule ), - mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), - myEditCurrentArgument(0), - myFilterDlg( 0 ), - mySelectedObject(SMESH::SMESH_IDSource::_nil()) + mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ) { - QPixmap image0 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_EDGE"))); - QPixmap image1 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_TRIANGLE"))); - QPixmap image2 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT"))); - QPixmap image3 (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_DLG_NODE"))); + QPixmap image (SMESH::GetResourceMgr( mySMESHGUI )->loadPixmap("SMESH", tr("ICON_SELECT"))); setModal( false ); setAttribute( Qt::WA_DeleteOnClose, true ); @@ -110,73 +604,13 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) SMESHGUI_ExtrusionDlgLayout->setMargin(MARGIN); /***************************************************************/ - ConstructorsBox = new QGroupBox(tr("SMESH_EXTRUSION"), this); - GroupConstructors = new QButtonGroup(this); - QHBoxLayout* ConstructorsBoxLayout = new QHBoxLayout(ConstructorsBox); - ConstructorsBoxLayout->setSpacing(SPACING); - ConstructorsBoxLayout->setMargin(MARGIN); - - Contructor_RBut0= new QRadioButton(ConstructorsBox); - Contructor_RBut0->setIcon(image3); - Contructor_RBut1= new QRadioButton(ConstructorsBox); - Contructor_RBut1->setIcon(image0); - Contructor_RBut2= new QRadioButton(ConstructorsBox); - Contructor_RBut2->setIcon(image1); - - ConstructorsBoxLayout->addWidget(Contructor_RBut0); - ConstructorsBoxLayout->addWidget(Contructor_RBut1); - ConstructorsBoxLayout->addWidget(Contructor_RBut2); - - GroupConstructors->addButton(Contructor_RBut0, 0); - GroupConstructors->addButton(Contructor_RBut1, 1); - GroupConstructors->addButton(Contructor_RBut2, 2); - - /***************************************************************/ - GroupButtons = new QGroupBox(this); - QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons); - GroupButtonsLayout->setSpacing(SPACING); - GroupButtonsLayout->setMargin(MARGIN); - - buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons); - buttonOk->setAutoDefault(true); - buttonOk->setDefault(true); - buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons); - buttonApply->setAutoDefault(true); - buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons); - buttonCancel->setAutoDefault(true); - buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons); - buttonHelp->setAutoDefault(true); - - GroupButtonsLayout->addWidget(buttonOk); - GroupButtonsLayout->addSpacing(10); - GroupButtonsLayout->addWidget(buttonApply); - GroupButtonsLayout->addSpacing(10); - GroupButtonsLayout->addStretch(); - GroupButtonsLayout->addWidget(buttonCancel); - GroupButtonsLayout->addWidget(buttonHelp); - - /***************************************************************/ - GroupArguments = new QGroupBox(tr("EXTRUSION_0D"), this); + GroupArguments = new QGroupBox(tr("SMESH_EXTRUSION"), this); QGridLayout* GroupArgumentsLayout = new QGridLayout(GroupArguments); GroupArgumentsLayout->setSpacing(SPACING); GroupArgumentsLayout->setMargin(MARGIN); - myIdValidator = new SMESHGUI_IdValidator(this); - // Controls for elements selection - TextLabelElements = new QLabel(tr("SMESH_ID_ELEMENTS"), GroupArguments); - - SelectElementsButton = new QPushButton(GroupArguments); - SelectElementsButton->setIcon(image2); - - LineEditElements = new QLineEdit(GroupArguments); - LineEditElements->setValidator(myIdValidator); - LineEditElements->setMaxLength(-1); - myFilterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); - connect(myFilterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); - - // Control for the whole mesh selection - CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); + SelectorWdg = new SMESHGUI_3TypesSelector( GroupArguments ); ExtrMethod_RBut0 = new QRadioButton(GroupArguments); ExtrMethod_RBut0->setText( tr("SMESH_EXTRUSION_TO_DISTANCE") ); @@ -202,7 +636,9 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) TextLabelVector = new QLabel(tr("SMESH_VECTOR"), GroupArguments); SelectVectorButton = new QPushButton(GroupArguments); - SelectVectorButton->setIcon(image2); + SelectVectorButton->setIcon(image); + SelectVectorButton->setCheckable( true ); + SelectorWdg->GetButtonGroup()->addButton( SelectVectorButton ); TextLabelVx = new QLabel(tr("SMESH_DX"), GroupArguments); SpinBox_Vx = new SMESHGUI_SpinBox(GroupArguments); @@ -232,42 +668,60 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) //Preview check box myPreviewCheckBox = new QCheckBox(tr("PREVIEW"), GroupArguments); - GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); - GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(LineEditElements, 0, 2, 1, 5); - GroupArgumentsLayout->addWidget(myFilterBtn, 0, 7); - GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 8); - GroupArgumentsLayout->addWidget(ExtrMethod_RBut0, 2, 0, 1, 3); - GroupArgumentsLayout->addWidget(ExtrMethod_RBut1, 2, 3, 1, 3); - GroupArgumentsLayout->addWidget(ExtrMethod_RBut2, 2, 6, 1, 3); - GroupArgumentsLayout->addWidget(TextLabelDistance, 3, 0); - GroupArgumentsLayout->addWidget(TextLabelDx, 3, 2); - GroupArgumentsLayout->addWidget(SpinBox_Dx, 3, 3); - GroupArgumentsLayout->addWidget(TextLabelDy, 3, 4); - GroupArgumentsLayout->addWidget(SpinBox_Dy, 3, 5); - GroupArgumentsLayout->addWidget(TextLabelDz, 3, 6); - GroupArgumentsLayout->addWidget(SpinBox_Dz, 3, 7); - GroupArgumentsLayout->addWidget(TextLabelVector, 4, 0); - GroupArgumentsLayout->addWidget(SelectVectorButton, 4, 1); - GroupArgumentsLayout->addWidget(TextLabelVx, 4, 2); - GroupArgumentsLayout->addWidget(SpinBox_Vx, 4, 3); - GroupArgumentsLayout->addWidget(TextLabelVy, 4, 4); - GroupArgumentsLayout->addWidget(SpinBox_Vy, 4, 5); - GroupArgumentsLayout->addWidget(TextLabelVz, 4, 6); - GroupArgumentsLayout->addWidget(SpinBox_Vz, 4, 7); - GroupArgumentsLayout->addWidget(TextLabelDist, 5, 0); - GroupArgumentsLayout->addWidget(SpinBox_VDist, 5, 3); - GroupArgumentsLayout->addWidget(TextLabelNbSteps, 6, 0, 1, 3); - GroupArgumentsLayout->addWidget(SpinBox_NbSteps, 6, 3); - GroupArgumentsLayout->addWidget(ByAverageNormalCheck, 7, 0, 1, 4); - GroupArgumentsLayout->addWidget(UseInputElemsOnlyCheck, 7, 4, 1, 4); - GroupArgumentsLayout->addWidget(myPreviewCheckBox, 8, 0, 1, 8); - GroupArgumentsLayout->addWidget(MakeGroupsCheck, 9, 0, 1, 8); + GroupArgumentsLayout->addWidget(SelectorWdg, 0, 0, 1, 9); + GroupArgumentsLayout->addWidget(ExtrMethod_RBut0, 1, 0, 1, 3); + GroupArgumentsLayout->addWidget(ExtrMethod_RBut1, 1, 3, 1, 3); + GroupArgumentsLayout->addWidget(ExtrMethod_RBut2, 1, 6, 1, 3); + GroupArgumentsLayout->addWidget(TextLabelDistance, 2, 0); + GroupArgumentsLayout->addWidget(TextLabelDx, 2, 2); + GroupArgumentsLayout->addWidget(SpinBox_Dx, 2, 3); + GroupArgumentsLayout->addWidget(TextLabelDy, 2, 4); + GroupArgumentsLayout->addWidget(SpinBox_Dy, 2, 5); + GroupArgumentsLayout->addWidget(TextLabelDz, 2, 6); + GroupArgumentsLayout->addWidget(SpinBox_Dz, 2, 7); + GroupArgumentsLayout->addWidget(TextLabelVector, 3, 0); + GroupArgumentsLayout->addWidget(SelectVectorButton, 3, 1); + GroupArgumentsLayout->addWidget(TextLabelVx, 3, 2); + GroupArgumentsLayout->addWidget(SpinBox_Vx, 3, 3); + GroupArgumentsLayout->addWidget(TextLabelVy, 3, 4); + GroupArgumentsLayout->addWidget(SpinBox_Vy, 3, 5); + GroupArgumentsLayout->addWidget(TextLabelVz, 3, 6); + GroupArgumentsLayout->addWidget(SpinBox_Vz, 3, 7); + GroupArgumentsLayout->addWidget(TextLabelDist, 4, 0); + GroupArgumentsLayout->addWidget(SpinBox_VDist, 4, 3); + GroupArgumentsLayout->addWidget(TextLabelNbSteps, 5, 0, 1, 3); + GroupArgumentsLayout->addWidget(SpinBox_NbSteps, 5, 3); + GroupArgumentsLayout->addWidget(ByAverageNormalCheck, 6, 0, 1, 4); + GroupArgumentsLayout->addWidget(UseInputElemsOnlyCheck, 6, 4, 1, 4); + GroupArgumentsLayout->addWidget(myPreviewCheckBox, 7, 0, 1, 8); + GroupArgumentsLayout->addWidget(MakeGroupsCheck, 8, 0, 1, 8); GroupArgumentsLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 10, 0); + /***************************************************************/ + GroupButtons = new QGroupBox(this); + QHBoxLayout* GroupButtonsLayout = new QHBoxLayout(GroupButtons); + GroupButtonsLayout->setSpacing(SPACING); + GroupButtonsLayout->setMargin(MARGIN); + + buttonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), GroupButtons); + buttonOk->setAutoDefault(true); + buttonOk->setDefault(true); + buttonApply = new QPushButton(tr("SMESH_BUT_APPLY"), GroupButtons); + buttonApply->setAutoDefault(true); + buttonCancel = new QPushButton(tr("SMESH_BUT_CLOSE"), GroupButtons); + buttonCancel->setAutoDefault(true); + buttonHelp = new QPushButton(tr("SMESH_BUT_HELP"), GroupButtons); + buttonHelp->setAutoDefault(true); + + GroupButtonsLayout->addWidget(buttonOk); + GroupButtonsLayout->addSpacing(10); + GroupButtonsLayout->addWidget(buttonApply); + GroupButtonsLayout->addSpacing(10); + GroupButtonsLayout->addStretch(); + GroupButtonsLayout->addWidget(buttonCancel); + GroupButtonsLayout->addWidget(buttonHelp); /***************************************************************/ - SMESHGUI_ExtrusionDlgLayout->addWidget(ConstructorsBox); SMESHGUI_ExtrusionDlgLayout->addWidget(GroupArguments); SMESHGUI_ExtrusionDlgLayout->addWidget(GroupButtons); @@ -283,32 +737,13 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) SpinBox_NbSteps->setRange(1, 999999); SpinBox_VDist->RangeStepAndValidator(COORD_MIN, COORD_MAX, 10.0, "length_precision"); - Contructor_RBut0->setChecked(true); ExtrMethod_RBut0->setChecked(true); UseInputElemsOnlyCheck->setChecked(true); MakeGroupsCheck->setChecked(true); mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector(); - mySMESHGUI->SetActiveDialogBox(this); - - // Costruction of the logical filter for the elements: mesh/sub-mesh/group - QList aListOfFilters; - aListOfFilters.append(new SMESH_TypeFilter (SMESH::MESH)); - aListOfFilters.append(new SMESH_TypeFilter (SMESH::SUBMESH_VERTEX)); - aListOfFilters.append(new SMESH_TypeFilter (SMESH::GROUP_NODE)); - myMeshOrSubMeshOrGroupFilter0D = - new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true); - aListOfFilters[0] = new SMESH_TypeFilter (SMESH::MESH); - aListOfFilters[1] = new SMESH_TypeFilter (SMESH::SUBMESH_EDGE); - aListOfFilters[2] = new SMESH_TypeFilter (SMESH::GROUP_EDGE); - myMeshOrSubMeshOrGroupFilter1D = - new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true); - aListOfFilters[0] = new SMESH_TypeFilter (SMESH::MESH); - aListOfFilters[1] = new SMESH_TypeFilter (SMESH::SUBMESH_FACE); - aListOfFilters[2] = new SMESH_TypeFilter (SMESH::GROUP_FACE); - myMeshOrSubMeshOrGroupFilter2D = - new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true); + mySMESHGUI->SetActiveDialogBox(this); myHelpFileName = "extrusion_page.html"; @@ -333,15 +768,13 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) connect(SpinBox_Dy, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); connect(SpinBox_Dz, SIGNAL(valueChanged(double)), SLOT(CheckIsEnable())); - connect(GroupConstructors, SIGNAL(buttonClicked(int)), SLOT(ConstructorsClicked(int))); - connect(SelectElementsButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectVectorButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); - connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog())); - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); + connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), SLOT(DeactivateActiveDialog())); + connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(toDisplaySimulation())); + connect(SelectorWdg, SIGNAL(selectionChanged()), this, SLOT(toDisplaySimulation())); + connect(SelectorWdg, SIGNAL(selectionChanged()), this, SLOT(CheckIsEnable())); /* to close dialog if study change */ connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), this, SLOT(reject())); - connect(LineEditElements, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&))); - connect(CheckBoxMesh, SIGNAL(toggled(bool)), SLOT(onSelectMesh(bool))); connect(SpinBox_Dx, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); connect(SpinBox_Dy, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); @@ -359,9 +792,7 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) /***************************************************************/ - ConstructorsClicked(0); ClickOnRadio(); - SelectionIntoArgument(); } //================================================================================= @@ -370,13 +801,6 @@ SMESHGUI_ExtrusionDlg::SMESHGUI_ExtrusionDlg (SMESHGUI* theModule) //================================================================================= SMESHGUI_ExtrusionDlg::~SMESHGUI_ExtrusionDlg() { - if ( myFilterDlg != 0 ) { - myFilterDlg->setParent( 0 ); - delete myFilterDlg; - } - if ( myMeshOrSubMeshOrGroupFilter0D ) delete myMeshOrSubMeshOrGroupFilter0D; - if ( myMeshOrSubMeshOrGroupFilter1D ) delete myMeshOrSubMeshOrGroupFilter1D; - if ( myMeshOrSubMeshOrGroupFilter2D ) delete myMeshOrSubMeshOrGroupFilter2D; } //================================================================================= @@ -385,16 +809,8 @@ SMESHGUI_ExtrusionDlg::~SMESHGUI_ExtrusionDlg() //================================================================================= void SMESHGUI_ExtrusionDlg::Init (bool ResetControls) { - myBusy = false; - myIDs.clear(); - - LineEditElements->clear(); - myNbOkElements = 0; - - myActor = 0; - myMesh = SMESH::SMESH_Mesh::_nil(); - - if (ResetControls) { + if (ResetControls) + { SpinBox_NbSteps->setValue(1); SpinBox_VDist->setValue(10); SpinBox_Dx->SetValue(0); @@ -404,12 +820,10 @@ void SMESHGUI_ExtrusionDlg::Init (bool ResetControls) SpinBox_Vy->SetValue(0); SpinBox_Vz->SetValue(0); - CheckBoxMesh->setChecked(false); - onSelectMesh(false); myPreviewCheckBox->setChecked(false); onDisplaySimulation(false); } - + SelectorWdg->Clear(); CheckIsEnable(); } @@ -419,7 +833,7 @@ void SMESHGUI_ExtrusionDlg::Init (bool ResetControls) //================================================================================= void SMESHGUI_ExtrusionDlg::CheckIsEnable() { - bool anIsEnable = myNbOkElements > 0 && isValuesValid(); + bool anIsEnable = SelectorWdg->IsAnythingSelected() && isValuesValid(); buttonOk->setEnabled(anIsEnable); buttonApply->setEnabled(anIsEnable); @@ -429,99 +843,38 @@ void SMESHGUI_ExtrusionDlg::CheckIsEnable() // function : isValuesValid() // purpose : Return true in case if values entered into dialog are valid //================================================================================= -bool SMESHGUI_ExtrusionDlg::isValuesValid() { +bool SMESHGUI_ExtrusionDlg::isValuesValid() +{ double aX, aY, aZ, aModule = 0; - if ( ExtrMethod_RBut0->isChecked() ) { + if ( ExtrMethod_RBut0->isChecked() ) + { aX = SpinBox_Dx->GetValue(); aY = SpinBox_Dy->GetValue(); aZ = SpinBox_Dz->GetValue(); aModule = sqrt(aX*aX + aY*aY + aZ*aZ); } - else if ( ExtrMethod_RBut1->isChecked() ) { + else if ( ExtrMethod_RBut1->isChecked() ) + { aX = SpinBox_Vx->GetValue(); aY = SpinBox_Vy->GetValue(); aZ = SpinBox_Vz->GetValue(); aModule = sqrt(aX*aX + aY*aY + aZ*aZ); + double aVDist = (double)SpinBox_VDist->value(); + aModule *= aVDist; } - else if ( ExtrMethod_RBut2->isChecked() ) { - aModule = 1; + else if ( ExtrMethod_RBut2->isChecked() ) + { + aModule = (double)SpinBox_VDist->value(); } return aModule > 1.0E-38; } //================================================================================= -// function : ConstructorsClicked() +// function : ClickOnRadio() // purpose : Radio button management //================================================================================= -void SMESHGUI_ExtrusionDlg::ConstructorsClicked (int constructorId) -{ - disconnect(mySelectionMgr, 0, this, 0); - - hidePreview(); - - TextLabelElements->setText(tr( constructorId ? "SMESH_ID_ELEMENTS" : "SMESH_ID_NODES")); - - switch (constructorId) { - case 0: - { - GroupArguments->setTitle(tr("EXTRUSION_0D")); - if (!CheckBoxMesh->isChecked()) - { - LineEditElements->clear(); - myIDs.clear(); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(NodeSelection); - } - break; - } - case 1: - { - GroupArguments->setTitle(tr("EXTRUSION_1D")); - if (!CheckBoxMesh->isChecked()) - { - LineEditElements->clear(); - myIDs.clear(); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - } - break; - } - case 2: - { - GroupArguments->setTitle(tr("EXTRUSION_2D")); - if (!CheckBoxMesh->isChecked()) - { - LineEditElements->clear(); - myIDs.clear(); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - } - break; - } - } - - ExtrMethod_RBut2->setVisible( constructorId == 2 ); - if ( !ExtrMethod_RBut2->isVisible() && - ExtrMethod_RBut2->isChecked() ) - ExtrMethod_RBut0->click(); - - myEditCurrentArgument = (QWidget*)LineEditElements; - LineEditElements->setFocus(); - - if (CheckBoxMesh->isChecked()) - onSelectMesh(true); - - myEditCurrentArgument->hide(); - myEditCurrentArgument->show(); - - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); -} -//================================================================================= -// function : ConstructorsClicked() -// purpose : Radio button management -//================================================================================= void SMESHGUI_ExtrusionDlg::ClickOnRadio() { if ( ExtrMethod_RBut0->isChecked() ) @@ -547,6 +900,8 @@ void SMESHGUI_ExtrusionDlg::ClickOnRadio() ByAverageNormalCheck->hide(); UseInputElemsOnlyCheck->hide(); + + SelectorWdg->SetEnabled( true, SMESH::ALL ); } else if ( ExtrMethod_RBut1->isChecked() ) { @@ -571,6 +926,8 @@ void SMESHGUI_ExtrusionDlg::ClickOnRadio() ByAverageNormalCheck->hide(); UseInputElemsOnlyCheck->hide(); + + SelectorWdg->SetEnabled( true, SMESH::ALL ); } else if ( ExtrMethod_RBut2->isChecked() ) { @@ -596,6 +953,9 @@ void SMESHGUI_ExtrusionDlg::ClickOnRadio() ByAverageNormalCheck->show(); UseInputElemsOnlyCheck->show(); + + SelectorWdg->SetEnabled( false, SMESH::NODE ); + SelectorWdg->SetEnabled( false, SMESH::EDGE ); } CheckIsEnable(); @@ -611,6 +971,7 @@ void SMESHGUI_ExtrusionDlg::ClickOnRadio() // function : ClickOnApply() // purpose : Called when user presses button //================================================================================= + bool SMESHGUI_ExtrusionDlg::ClickOnApply() { if (mySMESHGUI->isActiveStudyLocked()) @@ -619,8 +980,8 @@ bool SMESHGUI_ExtrusionDlg::ClickOnApply() if (!isValid()) return false; - if (myNbOkElements) { - + if ( SelectorWdg->IsAnythingSelected() ) + { SMESH::DirStruct aVector; getExtrusionVector(aVector); @@ -649,100 +1010,75 @@ bool SMESHGUI_ExtrusionDlg::ClickOnApply() aParameters << SpinBox_NbSteps->text(); bool meshHadNewTypeBefore = true; + int maxSelType = 0; + const bool makeGroups = ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ); try { SUIT_OverrideCursor aWaitCursor; + SMESH::SMESH_Mesh_var mesh = SelectorWdg->GetMesh(); + + SMESH::ListOfIDSources_var nodes = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var edges = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var faces = new SMESH::ListOfIDSources(); + maxSelType = SelectorWdg->GetSelected( nodes, edges, faces ); + // is it necessary to switch on the next Display Mode? - SMESH::ElementType newType = (SMESH::ElementType)( SMESH::EDGE + GetConstructorId() ); - SMESH::array_of_ElementType_var oldTypes = myMesh->GetTypes(); + SMESH::ElementType newType = (SMESH::ElementType)( maxSelType + 1 ); + SMESH::array_of_ElementType_var oldTypes = mesh->GetTypes(); meshHadNewTypeBefore = false; for ( size_t i = 0; i < oldTypes->length() && !meshHadNewTypeBefore; ++i ) meshHadNewTypeBefore = ( oldTypes[i] >= newType ); - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); - - myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + SMESH::SMESH_MeshEditor_var meshEditor = mesh->GetMeshEditor(); + SMESH::ListOfGroups_var groups; - const bool makeGroups = MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked(); + mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); if ( ExtrMethod_RBut2->isVisible() && ExtrMethod_RBut2->isChecked() ) // Extrusion by normal { - extrusionByNormal( aMeshEditor, makeGroups ); - } - else if ( makeGroups ) // create groups - { - SMESH::ListOfGroups_var groups; - if( CheckBoxMesh->isChecked() ) - switch (GetConstructorId() ) { - case 0: - groups = aMeshEditor->ExtrusionSweepObject0DMakeGroups(mySelectedObject, aVector, - aNbSteps); break; - case 1: - groups = aMeshEditor->ExtrusionSweepObject1DMakeGroups(mySelectedObject, aVector, - aNbSteps); break; - case 2: - groups = aMeshEditor->ExtrusionSweepObject2DMakeGroups(mySelectedObject, aVector, - aNbSteps); break; - } - else - { - if (GetConstructorId() == 0) - groups = aMeshEditor->ExtrusionSweepMakeGroups0D(myElementsId.inout(), aVector, - aNbSteps); - else - groups = aMeshEditor->ExtrusionSweepMakeGroups(myElementsId.inout(), aVector, - aNbSteps); - } + double stepSize = (double) SpinBox_VDist->value(); + long nbSteps = (long) SpinBox_NbSteps->value(); + bool useInputElemsOnly = UseInputElemsOnlyCheck->isChecked(); + bool byAverageNormal = ByAverageNormalCheck->isChecked(); + int dim = (maxSelType == SMESH::FACE) ? 2 : 1; + + groups = meshEditor->ExtrusionByNormal( faces, stepSize, nbSteps, useInputElemsOnly, + byAverageNormal, makeGroups, dim ); } - else // no groups + else { - if( CheckBoxMesh->isChecked() ) - switch( GetConstructorId() ) { - case 0: - aMeshEditor->ExtrusionSweepObject0D(mySelectedObject, aVector, aNbSteps); - break; - case 1: - aMeshEditor->ExtrusionSweepObject1D(mySelectedObject, aVector, aNbSteps); - break; - case 2: - aMeshEditor->ExtrusionSweepObject2D(mySelectedObject, aVector, aNbSteps); - break; - } - else - if (GetConstructorId() == 0) - aMeshEditor->ExtrusionSweep0D(myElementsId.inout(), aVector, aNbSteps); - else - aMeshEditor->ExtrusionSweep(myElementsId.inout(), aVector, aNbSteps); + groups = meshEditor->ExtrusionSweepObjects( nodes, edges, faces, + aVector, aNbSteps, makeGroups ); } } catch (...) { } - if ( myActor && !meshHadNewTypeBefore ) + SMESH_Actor* actor = SelectorWdg->GetActor(); + if ( actor && !meshHadNewTypeBefore ) { - unsigned int aMode = myActor->GetEntityMode(); - switch ( GetConstructorId() ) { - case 0: // extrude node -> edges - myActor->SetRepresentation(SMESH_Actor::eEdge); - myActor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; - case 1: // edge -> faces - myActor->SetRepresentation(SMESH_Actor::eSurface); - myActor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; - case 2: // faces -> volumes - myActor->SetRepresentation(SMESH_Actor::eSurface); - myActor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; + unsigned int aMode = actor->GetEntityMode(); + switch ( maxSelType ) { + case SMESH::NODE: // extrude node -> edges + actor->SetRepresentation(SMESH_Actor::eEdge); + actor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; + case SMESH::EDGE: // edge -> faces + actor->SetRepresentation(SMESH_Actor::eSurface); + actor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; + case SMESH::FACE: // faces -> volumes + actor->SetRepresentation(SMESH_Actor::eSurface); + actor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; } } - SMESH::Update(myIO, SMESH::eDisplay); - if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ) + if ( actor ) + SMESH::Update( actor->getIO(), actor->GetVisibility() ); + if ( makeGroups ) mySMESHGUI->updateObjBrowser(true); // new groups may appear Init(false); mySelectionMgr->clearSelected(); - mySelectedObject = SMESH::SMESH_IDSource::_nil(); - SelectionIntoArgument(); - ConstructorsClicked(GetConstructorId()); + SelectorWdg->Clear(); SMESHGUI::Modified(); } @@ -804,185 +1140,35 @@ void SMESHGUI_ExtrusionDlg::ClickOnHelp() } } -//================================================================================= -// function : onTextChange() -// purpose : -//================================================================================= -void SMESHGUI_ExtrusionDlg::onTextChange (const QString& theNewText) -{ - QLineEdit* send = (QLineEdit*)sender(); - - // return if busy - if (myBusy) return; - - // set busy flag - myBusy = true; - - if (send == LineEditElements) - myNbOkElements = 0; - - // hilight entered elements/nodes - - if (!myIO.IsNull()) { - QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); - - if (send == LineEditElements) - { - SMDS_Mesh* aMesh = myActor ? myActor->GetObject()->GetMesh() : 0; - SMESH::ElementType SMESHType; - SMDSAbs_ElementType SMDSType; - switch (GetConstructorId()) { - case 0: - { - SMESHType = SMESH::NODE; - SMDSType = SMDSAbs_Node; - break; - } - case 1: - { - SMESHType = SMESH::EDGE; - SMDSType = SMDSAbs_Edge; - break; - } - case 2: - { - SMESHType = SMESH::FACE; - SMDSType = SMDSAbs_Face; - break; - } - } - myElementsId = new SMESH::long_array; - myElementsId->length( aListId.count() ); - TColStd_MapOfInteger newIndices; - for (int i = 0; i < aListId.count(); i++) { - int id = aListId[ i ].toInt(); - bool validId = false; - if ( id > 0 ) { - if ( aMesh ) { - const SMDS_MeshElement * e; - if (SMDSType == SMDSAbs_Node) - e = aMesh->FindNode( id ); - else - e = aMesh->FindElement( id ); - validId = ( e && e->GetType() == SMDSType ); - } else { - validId = ( myMesh->GetElementType( id, true ) == SMESHType ); - } - } - if ( validId && newIndices.Add( id )) - myElementsId[ newIndices.Extent()-1 ] = id; - } - myElementsId->length( myNbOkElements = newIndices.Extent() ); - mySelector->AddOrRemoveIndex(myIO, newIndices, false); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->highlight( myIO, true, true ); - } - } - - CheckIsEnable(); - - onDisplaySimulation(true); - - myBusy = false; -} - //================================================================================= // function : SelectionIntoArgument() -// purpose : Called when selection as changed or other case +// purpose : Called when selection has changed or other case //================================================================================= void SMESHGUI_ExtrusionDlg::SelectionIntoArgument() { - if (myBusy) return; - // return if dialog box is inactive if (!GroupButtons->isEnabled()) return; - // clear - if(myEditCurrentArgument != (QWidget*)SpinBox_Vx) { - myActor = 0; - Handle(SALOME_InteractiveObject) resIO = myIO; - myIO.Nullify(); - } - - QString aString = ""; - // set busy flag - if(myEditCurrentArgument == (QWidget*)LineEditElements) { - myBusy = true; - LineEditElements->setText(aString); - myNbOkElements = 0; - myBusy = false; - } - // get selected mesh - SALOME_ListIO aList; - mySelectionMgr->selectedObjects(aList); - int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString); - if (nbSel != 1) - return; - - Handle(SALOME_InteractiveObject) IO = aList.First(); - - if(myEditCurrentArgument != (QWidget*)SpinBox_Vx) { - myMesh = SMESH::GetMeshByIO(IO); - if (myMesh->_is_nil()) + if ( SelectVectorButton->isChecked() ) + { + SALOME_ListIO aList; + mySelectionMgr->selectedObjects(aList); + if ( aList.IsEmpty() || aList.Extent() > 1 ) return; - myIO = IO; - myActor = SMESH::FindActorByObject(myMesh); - } - - if (myEditCurrentArgument == (QWidget*)LineEditElements) { - int aNbElements = 0; - - // MakeGroups is available if there are groups - if ( myMesh->NbGroups() == 0 ) { - MakeGroupsCheck->setChecked(false); - MakeGroupsCheck->setEnabled(false); - } else { - MakeGroupsCheck->setEnabled(true); - } - - if (CheckBoxMesh->isChecked()) { - SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString); - - if (!SMESH::IObjectToInterface(IO)->_is_nil()) - mySelectedObject = SMESH::IObjectToInterface(IO); - else - return; - } else { - // get indices of selected elements - TColStd_IndexedMapOfInteger aMapIndex; - mySelector->GetIndex(IO,aMapIndex); - aNbElements = aMapIndex.Extent(); - - if (aNbElements < 1) - return; - - myElementsId = new SMESH::long_array; - myElementsId->length( aNbElements ); - aString = ""; - for ( int i = 0; i < aNbElements; ++i ) - aString += QString(" %1").arg( myElementsId[ i ] = aMapIndex( i+1 ) ); - } - - myNbOkElements = true; - myBusy = true; - ((QLineEdit*)myEditCurrentArgument)->setText(aString); - myBusy = false; - } - else if(myEditCurrentArgument == (QWidget*)SpinBox_Vx){ + Handle(SALOME_InteractiveObject) IO = aList.First(); TColStd_IndexedMapOfInteger aMapIndex; mySelector->GetIndex(IO,aMapIndex); - int aNbElements = aMapIndex.Extent(); - SMESH::SMESH_Mesh_var aMesh_var = SMESH::GetMeshByIO(IO); - SMESH_Actor* anActor = SMESH::FindActorByObject(aMesh_var); - SMDS_Mesh* aMesh = anActor ? anActor->GetObject()->GetMesh() : 0; - - if(aNbElements != 1 || !aMesh) + if ( aMapIndex.Extent() != 1 ) + return; + SMESH_Actor* anActor = SMESH::FindActorByEntry( IO->getEntry() ); + SMDS_Mesh* aMesh = anActor ? anActor->GetObject()->GetMesh() : 0; + if ( !aMesh ) return; - - const SMDS_MeshFace* face = dynamic_cast(aMesh->FindElement(aMapIndex(aNbElements))); + const SMDS_MeshFace* face = + dynamic_cast(aMesh->FindElement(aMapIndex(1))); if (!face) return; @@ -990,12 +1176,9 @@ void SMESHGUI_ExtrusionDlg::SelectionIntoArgument() SpinBox_Vx->SetValue(aNormale.X()); SpinBox_Vy->SetValue(aNormale.Y()); SpinBox_Vz->SetValue(aNormale.Z()); - } - + onDisplaySimulation(true); - - // OK CheckIsEnable(); } @@ -1011,50 +1194,12 @@ void SMESHGUI_ExtrusionDlg::SetEditCurrentArgument() mySelectionMgr->clearSelected(); mySelectionMgr->clearFilters(); - if (send == SelectElementsButton) { - myEditCurrentArgument = (QWidget*)LineEditElements; - if (CheckBoxMesh->isChecked()) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); - switch( GetConstructorId() ) { - case 0: mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter0D); break; - case 1: mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter1D); break; - case 2: mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter2D); break; - } - } - else - { - int aConstructorId = GetConstructorId(); - switch(aConstructorId) { - case 0: - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(NodeSelection); - break; - } - case 1: - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - break; - } - case 2: - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - break; - } - } - } - } - else if (send == SelectVectorButton){ - myEditCurrentArgument = (QWidget*)SpinBox_Vx; + if (send == SelectVectorButton) + { if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(FaceSelection); } - myEditCurrentArgument->setFocus(); connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); SelectionIntoArgument(); } @@ -1065,10 +1210,11 @@ void SMESHGUI_ExtrusionDlg::SetEditCurrentArgument() //================================================================================= void SMESHGUI_ExtrusionDlg::DeactivateActiveDialog() { - if (ConstructorsBox->isEnabled()) { - ConstructorsBox->setEnabled(false); + if (GroupButtons->isEnabled()) + { GroupArguments->setEnabled(false); GroupButtons->setEnabled(false); + SelectorWdg->setEnabled(false); mySMESHGUI->ResetState(); mySMESHGUI->SetActiveDialogBox(0); } @@ -1082,14 +1228,11 @@ void SMESHGUI_ExtrusionDlg::ActivateThisDialog() { // Emit a signal to deactivate the active dialog mySMESHGUI->EmitSignalDeactivateDialog(); - ConstructorsBox->setEnabled(true); GroupArguments->setEnabled(true); GroupButtons->setEnabled(true); + SelectorWdg->setEnabled(true); mySMESHGUI->SetActiveDialogBox(this); - - ConstructorsClicked(GetConstructorId()); - SelectionIntoArgument(); } //================================================================================= @@ -1098,87 +1241,10 @@ void SMESHGUI_ExtrusionDlg::ActivateThisDialog() //================================================================================= void SMESHGUI_ExtrusionDlg::enterEvent (QEvent*) { - if (!ConstructorsBox->isEnabled()) + if (!GroupButtons->isEnabled()) ActivateThisDialog(); } -//================================================================================= -// function : onSelectMesh() -// purpose : -//================================================================================= -void SMESHGUI_ExtrusionDlg::onSelectMesh (bool toSelectMesh) -{ - if (toSelectMesh) { - myIDs = LineEditElements->text(); - TextLabelElements->setText(tr("SMESH_NAME")); - } - else - TextLabelElements->setText(tr("SMESH_ID_ELEMENTS")); - - myFilterBtn->setEnabled(!toSelectMesh); - - if (myEditCurrentArgument != LineEditElements) { - LineEditElements->clear(); - return; - } - - mySelectionMgr->clearFilters(); - - if (toSelectMesh) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); - switch( GetConstructorId() ) { - case 0: mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter0D); break; - case 1: mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter1D); break; - case 2: mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter2D); break; - } - LineEditElements->setReadOnly(true); - LineEditElements->setValidator(0); - } - else - { - int aConstructorId = GetConstructorId(); - switch(aConstructorId) { - case 0: - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(NodeSelection); - break; - } - case 1: - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - break; - } - case 2: - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - break; - } - } - LineEditElements->setReadOnly(false); - LineEditElements->setValidator(myIdValidator); - onTextChange(LineEditElements->text()); - } - - SelectionIntoArgument(); - - if (!toSelectMesh) - LineEditElements->setText( myIDs ); -} - -//================================================================================= -// function : GetConstructorId() -// purpose : -//================================================================================= -int SMESHGUI_ExtrusionDlg::GetConstructorId() -{ - return GroupConstructors->checkedId(); -} - //================================================================================= // function : keyPressEvent() // purpose : @@ -1195,52 +1261,6 @@ void SMESHGUI_ExtrusionDlg::keyPressEvent( QKeyEvent* e ) } } -//================================================================================= -// function : setFilters() -// purpose : SLOT. Called when "Filter" button pressed. -//================================================================================= -void SMESHGUI_ExtrusionDlg::setFilters() -{ - if(myMesh->_is_nil()) { - SUIT_MessageBox::critical(this, - tr("SMESH_ERROR"), - tr("NO_MESH_SELECTED")); - return; - } - if ( !myFilterDlg ) - { - QList types; - types.append( SMESH::NODE ); - types.append( SMESH::EDGE ); - types.append( SMESH::FACE ); - myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); - } - switch( GetConstructorId() ){ - case 0: - { - myFilterDlg->Init( SMESH::NODE ); - break; - } - case 1: - { - myFilterDlg->Init( SMESH::EDGE ); - break; - } - case 2: - { - myFilterDlg->Init( SMESH::FACE ); - break; - } - } - - - myFilterDlg->SetSelection(); - myFilterDlg->SetMesh( myMesh ); - myFilterDlg->SetSourceWg( LineEditElements ); - - myFilterDlg->show(); -} - //================================================================================= // function : isValid // purpose : @@ -1278,7 +1298,8 @@ bool SMESHGUI_ExtrusionDlg::isValid() void SMESHGUI_ExtrusionDlg::onDisplaySimulation( bool toDisplayPreview ) { if (myPreviewCheckBox->isChecked() && toDisplayPreview) { - if (myNbOkElements && isValid() && isValuesValid()) { + if ( SelectorWdg->IsAnythingSelected() && isValid() && isValuesValid()) + { //Get input vector SMESH::DirStruct aVector; getExtrusionVector(aVector); @@ -1288,42 +1309,37 @@ void SMESHGUI_ExtrusionDlg::onDisplaySimulation( bool toDisplayPreview ) try { SUIT_OverrideCursor aWaitCursor; - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer(); + + SMESH::SMESH_Mesh_var mesh = SelectorWdg->GetMesh(); + SMESH::SMESH_MeshEditor_var meshEditor = mesh->GetMeshEditPreviewer(); + SMESH::ListOfGroups_var groups; + + SMESH::ListOfIDSources_var nodes = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var edges = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var faces = new SMESH::ListOfIDSources(); + const int maxSelType = SelectorWdg->GetSelected( nodes, edges, faces ); + const bool makeGroups = false; if ( ExtrMethod_RBut2->isVisible() && ExtrMethod_RBut2->isChecked() ) // Extrusion by normal { - extrusionByNormal( aMeshEditor ); - } - else if ( CheckBoxMesh->isChecked() ) // Extrude the whole object - { - switch (GetConstructorId()) { - case 0: - { - aMeshEditor->ExtrusionSweepObject0D(mySelectedObject, aVector, aNbSteps); - break; - } - case 1: - { - aMeshEditor->ExtrusionSweepObject1D(mySelectedObject, aVector, aNbSteps); - break; - } - case 2: - { - aMeshEditor->ExtrusionSweepObject2D(mySelectedObject, aVector, aNbSteps); - break; - } - } + double stepSize = (double) SpinBox_VDist->value(); + long nbSteps = (long) SpinBox_NbSteps->value(); + bool useInputElemsOnly = UseInputElemsOnlyCheck->isChecked(); + bool byAverageNormal = ByAverageNormalCheck->isChecked(); + int dim = (maxSelType == SMESH::FACE) ? 2 : 1; + + groups = meshEditor->ExtrusionByNormal( faces, stepSize, nbSteps, useInputElemsOnly, + byAverageNormal, makeGroups, dim ); } - else // extrude some elements + else { - if(GetConstructorId() == 0) - aMeshEditor->ExtrusionSweep0D(myElementsId.inout(), aVector, aNbSteps); - else - aMeshEditor->ExtrusionSweep(myElementsId.inout(), aVector, aNbSteps); + groups = meshEditor->ExtrusionSweepObjects( nodes, edges, faces, + aVector, aNbSteps, makeGroups ); } - SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData(); + SMESH::MeshPreviewStruct_var aMeshPreviewStruct = meshEditor->GetPreviewData(); mySimulation->SetData(aMeshPreviewStruct._retn()); + } catch (...) { hidePreview(); } @@ -1360,33 +1376,3 @@ void SMESHGUI_ExtrusionDlg::getExtrusionVector(SMESH::DirStruct& aVector) aVector.PS.z = aNormale.Z()*aVDist; } } - -//======================================================================= -//function : extrusionByNormal -//purpose : performs extrusion by normal -//======================================================================= - -void SMESHGUI_ExtrusionDlg::extrusionByNormal( SMESH::SMESH_MeshEditor_ptr meshEditor, - const bool makeGroups) -{ - SMESH::SMESH_IDSource_wrap anIDSource; - if ( CheckBoxMesh->isChecked() ) - { - anIDSource = mySelectedObject; - anIDSource->Register(); - } - else // make a temporary id source - { - anIDSource = meshEditor->MakeIDSource( myElementsId, SMESH::ALL ); - } - - double stepSize = (double) SpinBox_VDist->value(); - long nbSteps = (long)SpinBox_NbSteps->value(); - bool useInputElemsOnly = UseInputElemsOnlyCheck->isChecked(); - bool byAverageNormal = ByAverageNormalCheck->isChecked(); - int dim = GetConstructorId(); - - SMESH::ListOfGroups_var groups = - meshEditor->ExtrusionByNormal( anIDSource, stepSize, nbSteps, - useInputElemsOnly, byAverageNormal, makeGroups, dim ); -} diff --git a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h index b1334c521..80eaeacfa 100644 --- a/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h +++ b/src/SMESHGUI/SMESHGUI_ExtrusionDlg.h @@ -30,6 +30,7 @@ // SMESH includes #include "SMESH_SMESHGUI.hxx" #include "SMESHGUI_PreviewDlg.h" +#include "SMESHGUI_Utils.h" // SALOME GUI includes #include @@ -57,15 +58,80 @@ class LightApp_SelectionMgr; class SUIT_SelectionFilter; class SalomeApp_IntSpinBox; +//================================================================================= +// class : SMESHGUI_ExtrusionDlg +// purpose : A widget used to select both nodes, edges and faces for +// Extrusion and Revolution operations +//================================================================================= + +class SMESHGUI_EXPORT SMESHGUI_3TypesSelector : public QWidget +{ + Q_OBJECT + + public: + + SMESHGUI_3TypesSelector( QWidget * parent = 0 ); + ~SMESHGUI_3TypesSelector(); + + void Clear(); + void SetEnabled( bool enable, SMESH::ElementType type ); + bool IsAnythingSelected( SMESH::ElementType type = SMESH::ALL ); + SMESH::ElementType GetSelected( SMESH::ListOfIDSources & nodes, + SMESH::ListOfIDSources & edges, + SMESH::ListOfIDSources & faces ); + SMESH::SMESH_Mesh_var GetMesh() { return myMesh; } + SMESH_Actor* GetActor() { return myActor; } + Handle(SALOME_InteractiveObject) GetIO() { return myIO; } + QButtonGroup* GetButtonGroup() { return mySelectBtnGrp; } + + signals: + + void selectionChanged(); + + private slots: + + void selectionIntoArgument(); + void onTextChange( const QString& ); + void onSelectMesh( bool on ); + void setFilters(); + void onSelectType( int iType ); + + private: + + void addTmpIdSource( SMESH::long_array_var& ids, + int iType, int index); + + QGroupBox* myGroups [3]; + QLabel* myLabel [3]; + QLineEdit* myLineEdit [3]; + QCheckBox* myMeshChk [3]; + QPushButton* myFilterBtn[3]; + QButtonGroup* mySelectBtnGrp; + SMESHGUI_FilterDlg* myFilterDlg; + SUIT_SelectionFilter* myFilter [3]; + SMESHGUI_IdValidator* myIdValidator; + + bool myBusy; + SMESH::SMESH_Mesh_var myMesh; + SMESH_Actor* myActor; + Handle(SALOME_InteractiveObject) myIO; + SMESH::ListOfIDSources_var myIDSource[3]; + QList myTmpIDSourceList; + + LightApp_SelectionMgr* mySelectionMgr; + SVTK_Selector* mySelector; +}; + //================================================================================= // class : SMESHGUI_ExtrusionDlg // purpose : //================================================================================= + class SMESHGUI_EXPORT SMESHGUI_ExtrusionDlg : public SMESHGUI_PreviewDlg { Q_OBJECT -public: + public: SMESHGUI_ExtrusionDlg( SMESHGUI* ); ~SMESHGUI_ExtrusionDlg(); @@ -81,39 +147,16 @@ private: bool isValid(); bool isValuesValid(); - SMESHGUI_IdValidator* myIdValidator; LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ - QWidget* myEditCurrentArgument; /* Current argument editor */ - int myNbOkElements; /* to check when elements are defined */ SVTK_Selector* mySelector; - SMESH::SMESH_IDSource_var mySelectedObject; - - bool myBusy; - SMESH::SMESH_Mesh_var myMesh; - SMESH::long_array_var myElementsId; - SMESH_Actor* myActor; - Handle(SALOME_InteractiveObject) myIO; - SUIT_SelectionFilter* myMeshOrSubMeshOrGroupFilter0D; - SUIT_SelectionFilter* myMeshOrSubMeshOrGroupFilter1D; - SUIT_SelectionFilter* myMeshOrSubMeshOrGroupFilter2D; - // widgets - QGroupBox* ConstructorsBox; - QButtonGroup* GroupConstructors; - QRadioButton* Contructor_RBut0; - QRadioButton* Contructor_RBut1; - QRadioButton* Contructor_RBut2; + SMESHGUI_3TypesSelector* SelectorWdg; QRadioButton* ExtrMethod_RBut0; QRadioButton* ExtrMethod_RBut1; QRadioButton* ExtrMethod_RBut2; QGroupBox* GroupArguments; - QGroupBox* GroupDimensions; - QLabel* TextLabelElements; - QPushButton* SelectElementsButton; - QLineEdit* LineEditElements; - QCheckBox* CheckBoxMesh; QLabel* TextLabelVector; QLabel* TextLabelDistance; QPushButton* SelectVectorButton; @@ -146,15 +189,11 @@ private: QString myHelpFileName; QString myIDs; - QPushButton* myFilterBtn; - SMESHGUI_FilterDlg* myFilterDlg; - protected slots: virtual void onDisplaySimulation( bool ); virtual void reject(); private slots: - void ConstructorsClicked( int ); void CheckIsEnable(); void ClickOnOk(); bool ClickOnApply(); @@ -164,9 +203,6 @@ private slots: void SelectionIntoArgument(); void DeactivateActiveDialog(); void ActivateThisDialog(); - void onTextChange( const QString& ); - void onSelectMesh( bool ); - void setFilters(); }; #endif // SMESHGUI_EXTRUSIONDLG_H diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index f75ccd7b3..891b41ca5 100755 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -3299,13 +3299,18 @@ bool SMESHGUI_FilterDlg::onApply() insertFilterInViewer(); if (!myFilter[ aCurrType ]->GetPredicate()->_is_nil()) { - QList aResultIds; - filterSource(aCurrType, aResultIds); - // select in viewer - selectInViewer(aCurrType, aResultIds); + // + bool toFilter = (( SMESH::FindActorByObject( myMesh )) || + ( myInitSourceWgOnApply && mySourceWg ) || + ( mySourceGrp->checkedId() == Dialog && mySourceWg )); + if ( toFilter ) { + QList aResultIds; + filterSource(aCurrType, aResultIds); + // select in viewer + selectInViewer(aCurrType, aResultIds); + } } - myInsertState[ aCurrType ] = mySetInViewer->isChecked(); myApplyToState[ aCurrType ] = mySourceGrp->checkedId(); } diff --git a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx index 9e4a17941..fdae2f562 100644 --- a/src/SMESHGUI/SMESHGUI_GroupDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_GroupDlg.cxx @@ -1135,6 +1135,8 @@ bool SMESHGUI_GroupDlg::onApply() if( aMeshGroupSO ) anEntryList.append( aMeshGroupSO->GetID().c_str() ); + resultGroup->SetName(SMESH::toUtf8(myName->text().trimmed())); + if ( isCreation ) { SMESH::setFileType ( aMeshGroupSO, "COULEURGROUP" ); @@ -1151,8 +1153,6 @@ bool SMESHGUI_GroupDlg::onApply() } else { - resultGroup->SetName(SMESH::toUtf8(myName->text())); - if ( aMeshGroupSO ) { if ( SMESH_Actor *anActor = SMESH::FindActorByEntry(aMeshGroupSO->GetID().c_str())) diff --git a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx index ac8e4194d..ee55c5023 100644 --- a/src/SMESHGUI/SMESHGUI_Hypotheses.cxx +++ b/src/SMESHGUI/SMESHGUI_Hypotheses.cxx @@ -35,10 +35,11 @@ #include // SALOME GUI includes -#include +#include #include +#include #include -#include +#include #include // Qt includes @@ -264,6 +265,7 @@ void SMESHGUI_GenericHypothesisCreator::onDialogFinished( int result ) bool res = result==QDialog::Accepted; if( res ) { + SUIT_OverrideCursor wc; /*QString paramValues = */storeParams(); // No longer needed since NoteBook appears and "Value" OB field shows names of variable // if ( !paramValues.isEmpty() ) { diff --git a/src/SMESHGUI/SMESHGUI_Measurements.cxx b/src/SMESHGUI/SMESHGUI_Measurements.cxx index aa1ad13a8..e2d3b5b01 100644 --- a/src/SMESHGUI/SMESHGUI_Measurements.cxx +++ b/src/SMESHGUI/SMESHGUI_Measurements.cxx @@ -519,8 +519,8 @@ void SMESHGUI_MinDistance::secondEdited() void SMESHGUI_MinDistance::compute() { SUIT_OverrideCursor wc; - SMESH::SMESH_IDSource_wrap s1; - SMESH::SMESH_IDSource_wrap s2; + SMESH::IDSource_wrap s1; + SMESH::IDSource_wrap s2; bool isOrigin = mySecond->checkedId() == OriginTgt; // process first target @@ -760,7 +760,8 @@ void SMESHGUI_BoundingBox::updateSelection() sourceEdited(); - //selectionChanged(); + if ( mySource->text().isEmpty() ) + selectionChanged(); } /*! @@ -1206,6 +1207,9 @@ void SMESHGUI_BasicProperties::updateSelection() selMgr->installFilter( myFilter ); connect( selMgr, SIGNAL( currentSelectionChanged() ), this, SLOT( selectionChanged() ) ); + + if ( mySource->text().isEmpty() ) + selectionChanged(); } /*! diff --git a/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx b/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx index 0f0346684..6c05668ae 100755 --- a/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MultiEditDlg.cxx @@ -1283,7 +1283,7 @@ bool SMESHGUI_CuttingOfQuadsDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor, { if ( hasObj ) return theEditor->QuadTo4Tri( obj ), true; - SMESH::SMESH_IDSource_wrap elems = theEditor->MakeIDSource( theIds, SMESH::FACE ); + SMESH::IDSource_wrap elems = theEditor->MakeIDSource( theIds, SMESH::FACE ); theEditor->QuadTo4Tri( elems ); return true; } @@ -1619,7 +1619,7 @@ bool SMESHGUI_SplitVolumesDlg::process (SMESH::SMESH_MeshEditor_ptr theEditor, const SMESH::long_array& theIds, SMESH::SMESH_IDSource_ptr theObj) { - SMESH::SMESH_IDSource_wrap obj = theObj; + SMESH::IDSource_wrap obj = theObj; if ( CORBA::is_nil( obj )) obj = theEditor->MakeIDSource( theIds, SMESH::VOLUME ); else diff --git a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx index 675d29458..9164ac57b 100644 --- a/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RemoveElementsDlg.cxx @@ -332,6 +332,11 @@ void SMESHGUI_RemoveElementsDlg::onTextChange(const QString& theNewText) aViewWindow->highlight(anIO,true,true); } } + else + { + QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); + myNbOkElements = aListId.count(); + } myBusy = false; updateButtons(); diff --git a/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx b/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx index 3c0f04bbb..a62c7bfc8 100644 --- a/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_RevolutionDlg.cxx @@ -35,6 +35,7 @@ #include "SMESHGUI_IdValidator.h" #include "SMESHGUI_MeshEditPreview.h" #include "SMESHGUI_FilterDlg.h" +#include "SMESHGUI_ExtrusionDlg.h" #include #include @@ -91,66 +92,28 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) : SMESHGUI_PreviewDlg( theModule ), mySelectionMgr( SMESH::GetSelectionMgr( theModule ) ), - myVectorDefinition(NONE_SELECT), - myFilterDlg( 0 ), - mySelectedObject(SMESH::SMESH_IDSource::_nil()), - myActor(0) + myVectorDefinition(NONE_SELECT) { - mySimulation = new SMESHGUI_MeshEditPreview(SMESH::GetViewWindow( mySMESHGUI )); - SUIT_ResourceMgr* mgr = SMESH::GetResourceMgr( mySMESHGUI ); - QPixmap image0 ( mgr->loadPixmap("SMESH", tr("ICON_DLG_EDGE"))); - QPixmap image1 ( mgr->loadPixmap("SMESH", tr("ICON_DLG_TRIANGLE"))); - QPixmap image2 ( mgr->loadPixmap("SMESH", tr("ICON_SELECT"))); + QPixmap image ( mgr->loadPixmap("SMESH", tr("ICON_SELECT"))); setModal(false); setAttribute(Qt::WA_DeleteOnClose, true); setWindowTitle(tr("REVOLUTION_AROUND_AXIS")); setSizeGripEnabled(true); - + QVBoxLayout* SMESHGUI_RevolutionDlgLayout = new QVBoxLayout(this); SMESHGUI_RevolutionDlgLayout->setSpacing(SPACING); SMESHGUI_RevolutionDlgLayout->setMargin(MARGIN); /***************************************************************/ - ConstructorsBox = new QGroupBox(tr("SMESH_REVOLUTION"), this); - GroupConstructors = new QButtonGroup(this); - QHBoxLayout* ConstructorsBoxLayout = new QHBoxLayout(ConstructorsBox); - ConstructorsBoxLayout->setSpacing(SPACING); - ConstructorsBoxLayout->setMargin(MARGIN); - - RadioButton1 = new QRadioButton(ConstructorsBox); - RadioButton1->setIcon(image0); - RadioButton2 = new QRadioButton(ConstructorsBox); - RadioButton2->setIcon(image1); - - ConstructorsBoxLayout->addWidget(RadioButton1); - ConstructorsBoxLayout->addWidget(RadioButton2); - GroupConstructors->addButton(RadioButton1, 0); - GroupConstructors->addButton(RadioButton2, 1); - - /***************************************************************/ - GroupArguments = new QGroupBox(tr("REVOLUTION_1D"), this); + GroupArguments = new QGroupBox(tr("REVOLUTION"), this); QGridLayout* GroupArgumentsLayout = new QGridLayout(GroupArguments); GroupArgumentsLayout->setSpacing(SPACING); GroupArgumentsLayout->setMargin(MARGIN); - myIdValidator = new SMESHGUI_IdValidator(this); - // Controls for elements selection - TextLabelElements = new QLabel(tr("SMESH_ID_ELEMENTS"), GroupArguments); - - SelectElementsButton = new QPushButton(GroupArguments); - SelectElementsButton->setIcon(image2); - - LineEditElements = new QLineEdit(GroupArguments); - LineEditElements->setValidator(myIdValidator); - LineEditElements->setMaxLength(-1); - myFilterBtn = new QPushButton( tr( "SMESH_BUT_FILTER" ), GroupArguments ); - connect(myFilterBtn, SIGNAL(clicked()), this, SLOT(setFilters())); - - // Control for the whole mesh selection - CheckBoxMesh = new QCheckBox(tr("SMESH_SELECT_WHOLE_MESH"), GroupArguments); + SelectorWdg = new SMESHGUI_3TypesSelector( GroupArguments ); // Controls for axis defining GroupAxis = new QGroupBox(tr("SMESH_AXIS"), GroupArguments); @@ -160,7 +123,8 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) TextLabelPoint = new QLabel(tr("SMESH_POINT"), GroupAxis); SelectPointButton = new QPushButton(GroupAxis); - SelectPointButton->setIcon(image2); + SelectPointButton->setIcon(image); + SelectPointButton->setCheckable(true); TextLabelX = new QLabel(tr("SMESH_X"), GroupAxis); SpinBox_X = new SMESHGUI_SpinBox(GroupAxis); @@ -173,7 +137,8 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) TextLabelVector = new QLabel(tr("SMESH_VECTOR"), GroupAxis); SelectVectorButton = new QPushButton(GroupAxis); - SelectVectorButton->setIcon(image2); + SelectVectorButton->setIcon(image); + SelectVectorButton->setCheckable(true); TextLabelDX = new QLabel(tr("SMESH_DX"), GroupAxis); SpinBox_DX = new SMESHGUI_SpinBox(GroupAxis); @@ -237,17 +202,16 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) MakeGroupsCheck = new QCheckBox(tr("SMESH_MAKE_GROUPS"), GroupArguments); MakeGroupsCheck->setChecked(true); - GroupArgumentsLayout->addWidget(TextLabelElements, 0, 0); - GroupArgumentsLayout->addWidget(SelectElementsButton, 0, 1); - GroupArgumentsLayout->addWidget(LineEditElements, 0, 2); - GroupArgumentsLayout->addWidget(myFilterBtn, 0, 3); - GroupArgumentsLayout->addWidget(CheckBoxMesh, 1, 0, 1, 4); - GroupArgumentsLayout->addWidget(GroupAxis, 2, 0, 1, 4); - GroupArgumentsLayout->addWidget(GroupAngleBox, 3, 0, 1, 4); - GroupArgumentsLayout->addWidget(TextLabelTolerance, 4, 0, 1, 2); - GroupArgumentsLayout->addWidget(SpinBox_Tolerance, 4, 2, 1, 2); - GroupArgumentsLayout->addWidget(myPreviewCheckBox, 5, 0, 1, 4); - GroupArgumentsLayout->addWidget(MakeGroupsCheck, 6, 0, 1, 4); + GroupArgumentsLayout->addWidget(SelectorWdg, 0, 0, 1, 4); + GroupArgumentsLayout->addWidget(GroupAxis, 1, 0, 1, 4); + GroupArgumentsLayout->addWidget(GroupAngleBox, 2, 0, 1, 4); + GroupArgumentsLayout->addWidget(TextLabelTolerance, 3, 0, 1, 2); + GroupArgumentsLayout->addWidget(SpinBox_Tolerance, 3, 2, 1, 2); + GroupArgumentsLayout->addWidget(myPreviewCheckBox, 4, 0, 1, 4); + GroupArgumentsLayout->addWidget(MakeGroupsCheck, 5, 0, 1, 4); + + SelectorWdg->GetButtonGroup()->addButton( SelectVectorButton ); + SelectorWdg->GetButtonGroup()->addButton( SelectPointButton ); /***************************************************************/ GroupButtons = new QGroupBox(this); @@ -274,7 +238,6 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) GroupButtonsLayout->addWidget(buttonHelp); /***************************************************************/ - SMESHGUI_RevolutionDlgLayout->addWidget(ConstructorsBox); SMESHGUI_RevolutionDlgLayout->addWidget(GroupArguments); SMESHGUI_RevolutionDlgLayout->addWidget(GroupButtons); @@ -294,23 +257,10 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) SpinBox_Tolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision"); - RadioButton1->setChecked(true); - mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector(); mySMESHGUI->SetActiveDialogBox((QDialog*)this); - // Costruction of the logical filter - SMESH_TypeFilter* aMeshOrSubMeshFilter = new SMESH_TypeFilter (SMESH::MESHorSUBMESH); - SMESH_TypeFilter* aSmeshGroupFilter = new SMESH_TypeFilter (SMESH::GROUP); - - QList aListOfFilters; - if (aMeshOrSubMeshFilter) aListOfFilters.append(aMeshOrSubMeshFilter); - if (aSmeshGroupFilter) aListOfFilters.append(aSmeshGroupFilter); - - myMeshOrSubMeshOrGroupFilter = - new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR); - myHelpFileName = "revolution_page.html"; Init(); @@ -326,9 +276,7 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); connect(buttonApply, SIGNAL(clicked()), this, SLOT(ClickOnApply())); connect(buttonHelp, SIGNAL(clicked()), this, SLOT(ClickOnHelp())); - connect(GroupConstructors, SIGNAL(buttonClicked(int)), SLOT(ConstructorsClicked(int))); - connect(SelectElementsButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectPointButton, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); connect(SelectVectorButton, SIGNAL(clicked()), this, SLOT(onSelectVectorButton())); @@ -336,16 +284,19 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) connect(SpinBox_Y, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); connect(SpinBox_Z, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); - connect(SpinBox_DX, SIGNAL(valueChanged(double)), this, SLOT(onVectorChanged())); - connect(SpinBox_DY, SIGNAL(valueChanged(double)), this, SLOT(onVectorChanged())); - connect(SpinBox_DZ, SIGNAL(valueChanged(double)), this, SLOT(onVectorChanged())); - - connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog())); - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); + connect(SpinBox_DX, SIGNAL(valueChanged(double)), this, SLOT(CheckIsEnable())); + connect(SpinBox_DY, SIGNAL(valueChanged(double)), this, SLOT(CheckIsEnable())); + connect(SpinBox_DZ, SIGNAL(valueChanged(double)), this, SLOT(CheckIsEnable())); + connect(SpinBox_DX, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); + connect(SpinBox_DY, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); + connect(SpinBox_DZ, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); + + connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), SLOT(DeactivateActiveDialog())); + connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(SelectionIntoArgument())); + connect(SelectorWdg, SIGNAL(selectionChanged()), this, SLOT(toDisplaySimulation())); + connect(SelectorWdg, SIGNAL(selectionChanged()), this, SLOT(CheckIsEnable())); /* to close dialog if study change */ connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), this, SLOT(reject())); - connect(LineEditElements, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&))); - connect(CheckBoxMesh, SIGNAL(toggled(bool)), SLOT(onSelectMesh(bool))); connect(GroupAngle, SIGNAL(buttonClicked(int)), this, SLOT(toDisplaySimulation())); connect(SpinBox_Angle, SIGNAL(valueChanged(double)), this, SLOT(toDisplaySimulation())); @@ -357,8 +308,7 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) connect(SpinBox_Angle, SIGNAL(textChanged(const QString&)), this, SLOT(onAngleTextChange(const QString&))); - ConstructorsClicked(0); - SelectionIntoArgument(); + CheckIsEnable(); } //================================================================================= @@ -367,12 +317,6 @@ SMESHGUI_RevolutionDlg::SMESHGUI_RevolutionDlg( SMESHGUI* theModule ) //================================================================================= SMESHGUI_RevolutionDlg::~SMESHGUI_RevolutionDlg() { - delete mySimulation; - if ( myFilterDlg ) { - myFilterDlg->setParent( 0 ); - delete myFilterDlg; - myFilterDlg = 0; - } } //================================================================================= @@ -381,17 +325,6 @@ SMESHGUI_RevolutionDlg::~SMESHGUI_RevolutionDlg() //================================================================================= void SMESHGUI_RevolutionDlg::Init (bool ResetControls) { - myBusy = false; - - myEditCurrentArgument = 0; - LineEditElements->clear(); - myElementsId = ""; - myNbOkElements = 0; - myIDs.clear(); - - myActor = 0; - myMesh = SMESH::SMESH_Mesh::_nil(); - if (ResetControls) { SpinBox_X->SetValue(0.0); SpinBox_Y->SetValue(0.0); @@ -404,68 +337,51 @@ void SMESHGUI_RevolutionDlg::Init (bool ResetControls) SpinBox_NbSteps->setValue(1); SpinBox_Tolerance->SetValue(1e-05); - CheckBoxMesh->setChecked(false); - onSelectMesh(false); myPreviewCheckBox->setChecked(false); onDisplaySimulation(false); } + SelectorWdg->Clear(); } //================================================================================= -// function : ConstructorsClicked() -// purpose : Radio button management +// function : CheckIsEnable() +// purpose : Check whether the Ok and Apply buttons should be enabled or not //================================================================================= -void SMESHGUI_RevolutionDlg::ConstructorsClicked (int constructorId) -{ - disconnect(mySelectionMgr, 0, this, 0); - - /* SALOME_ListIO io; - mySelectionMgr->selectedObjects( io ); - SALOME_ListIO aList; - mySelectionMgr->setSelectedObjects( aList );*/ - buttonApply->setEnabled(false); - buttonOk->setEnabled(false); - mySimulation->SetVisibility(false); +void SMESHGUI_RevolutionDlg::CheckIsEnable() +{ + bool anIsEnable = SelectorWdg->IsAnythingSelected() && IsAxisOk(); - Selection_Mode aSelMode = ActorSelection; + buttonOk->setEnabled(anIsEnable); + buttonApply->setEnabled(anIsEnable); +} - switch (constructorId) { - case 0: - { - GroupArguments->setTitle(tr("REVOLUTION_1D")); - aSelMode = EdgeSelection; - break; - } - case 1: - { - GroupArguments->setTitle(tr("REVOLUTION_2D")); - aSelMode = FaceSelection; - break; - } - } +//================================================================================= +// function : isValid +// purpose : Return true in case if values entered into dialog are valid +//================================================================================= +bool SMESHGUI_RevolutionDlg::isValid() +{ + QString msg; + bool ok = true; + ok = SpinBox_X->isValid( msg, true ) && ok; + ok = SpinBox_Y->isValid( msg, true ) && ok; + ok = SpinBox_Z->isValid( msg, true ) && ok; + ok = SpinBox_DX->isValid( msg, true ) && ok; + ok = SpinBox_DY->isValid( msg, true ) && ok; + ok = SpinBox_DZ->isValid( msg, true ) && ok; + ok = SpinBox_Angle->isValid( msg, true ) && ok; + ok = SpinBox_NbSteps->isValid( msg, true ) && ok; + ok = SpinBox_Tolerance->isValid( msg, true ) && ok; - if (myEditCurrentArgument != (QWidget*)LineEditElements) { - SMESH::SetPointRepresentation(false); + if( !ok ) { + QString str( tr( "SMESH_INCORRECT_INPUT" ) ); + if ( !msg.isEmpty() ) + str += "\n" + msg; + SUIT_MessageBox::critical( this, tr( "SMESH_ERROR" ), str ); + return false; } - - if (!CheckBoxMesh->isChecked()) - { - LineEditElements->clear(); - myIDs.clear(); - myNbOkElements = 0; - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(aSelMode); - } - - myEditCurrentArgument = (QWidget*)LineEditElements; - LineEditElements->setFocus(); - - if (CheckBoxMesh->isChecked()) - onSelectMesh(true); - - connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); - // mySelectionMgr->setSelectedObjects( io ); + return true; } //================================================================================= @@ -480,14 +396,7 @@ bool SMESHGUI_RevolutionDlg::ClickOnApply() if (!isValid()) return false; - if (myNbOkElements && IsAxisOk()) { - QStringList aListElementsId = myElementsId.split(" ", QString::SkipEmptyParts); - - SMESH::long_array_var anElementsId = new SMESH::long_array; - - anElementsId->length(aListElementsId.count()); - for (int i = 0; i < aListElementsId.count(); i++) - anElementsId[i] = aListElementsId[i].toInt(); + if ( SelectorWdg->IsAnythingSelected() && IsAxisOk() ) { SMESH::AxisStruct anAxis; @@ -498,8 +407,8 @@ bool SMESHGUI_RevolutionDlg::ClickOnApply() anAxis.vy = SpinBox_DY->GetValue(); anAxis.vz = SpinBox_DZ->GetValue(); - double anAngle = (SpinBox_Angle->GetValue())*M_PI/180.; - long aNbSteps = (long)SpinBox_NbSteps->value(); + double anAngle = (SpinBox_Angle->GetValue())*M_PI/180.; + long aNbSteps = (long)SpinBox_NbSteps->value(); double aTolerance = SpinBox_Tolerance->GetValue(); if ( GroupAngle->checkedId() == 1 ) @@ -517,75 +426,60 @@ bool SMESHGUI_RevolutionDlg::ClickOnApply() aParameters << SpinBox_Tolerance->text(); bool meshHadNewTypeBefore = true; + int maxSelType = 0; + const bool makeGroups = ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ); try { SUIT_OverrideCursor aWaitCursor; + SMESH::SMESH_Mesh_var mesh = SelectorWdg->GetMesh(); + + mesh->SetParameters( aParameters.join(":").toLatin1().constData() ); + + SMESH::ListOfIDSources_var nodes = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var edges = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var faces = new SMESH::ListOfIDSources(); + maxSelType = SelectorWdg->GetSelected( nodes, edges, faces ); + // is it necessary to switch on the next Display Mode? - SMESH::ElementType newType = (SMESH::ElementType)( SMESH::FACE + GetConstructorId() ); - SMESH::array_of_ElementType_var oldTypes = myMesh->GetTypes(); + SMESH::ElementType newType = (SMESH::ElementType)( maxSelType + 1 ); + SMESH::array_of_ElementType_var oldTypes = mesh->GetTypes(); meshHadNewTypeBefore = false; for ( size_t i = 0; i < oldTypes->length() && !meshHadNewTypeBefore; ++i ) meshHadNewTypeBefore = ( oldTypes[i] >= newType ); - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); - - myMesh->SetParameters( aParameters.join(":").toLatin1().constData() ); - - if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ) { - if( CheckBoxMesh->isChecked() ) { - if( GetConstructorId() == 0 ) - SMESH::ListOfGroups_var groups = - aMeshEditor->RotationSweepObject1DMakeGroups(mySelectedObject, anAxis, - anAngle, aNbSteps, aTolerance); - else - SMESH::ListOfGroups_var groups = - aMeshEditor->RotationSweepObject2DMakeGroups(mySelectedObject, anAxis, - anAngle, aNbSteps, aTolerance); - } - else - SMESH::ListOfGroups_var groups = - aMeshEditor->RotationSweepMakeGroups(anElementsId.inout(), anAxis, - anAngle, aNbSteps, aTolerance); - } - else { - if( CheckBoxMesh->isChecked() ) { - if( GetConstructorId() == 0 ) - aMeshEditor->RotationSweepObject1D(mySelectedObject, anAxis, anAngle, aNbSteps, aTolerance); - else - aMeshEditor->RotationSweepObject2D(mySelectedObject, anAxis, anAngle, aNbSteps, aTolerance); - } - else - aMeshEditor->RotationSweep(anElementsId.inout(), anAxis, anAngle, aNbSteps, aTolerance); - } + SMESH::SMESH_MeshEditor_var aMeshEditor = mesh->GetMeshEditor(); + + SMESH::ListOfGroups_var groups = + aMeshEditor->RotationSweepObjects( nodes, edges, faces, anAxis, + anAngle, aNbSteps, aTolerance, makeGroups); } catch (...) { } - if ( myActor && !meshHadNewTypeBefore ) + SMESH_Actor* actor = SelectorWdg->GetActor(); + if ( actor && !meshHadNewTypeBefore ) { - unsigned int aMode = myActor->GetEntityMode(); - switch ( GetConstructorId() ) { - case 0-1: // extrude node -> edges - myActor->SetRepresentation(SMESH_Actor::eEdge); - myActor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; - case 1-1: // edge -> faces - myActor->SetRepresentation(SMESH_Actor::eSurface); - myActor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; - case 2-1: // faces -> volumes - myActor->SetRepresentation(SMESH_Actor::eSurface); - myActor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; + unsigned int aMode = actor->GetEntityMode(); + switch ( maxSelType ) { + case SMESH::NODE: // extrude node -> edges + actor->SetRepresentation(SMESH_Actor::eEdge); + actor->SetEntityMode( aMode |= SMESH_Actor::eEdges ); break; + case SMESH::EDGE: // edge -> faces + actor->SetRepresentation(SMESH_Actor::eSurface); + actor->SetEntityMode( aMode |= SMESH_Actor::eFaces ); break; + case SMESH::FACE: // faces -> volumes + actor->SetRepresentation(SMESH_Actor::eSurface); + actor->SetEntityMode( aMode |= SMESH_Actor::eVolumes ); break; } } - SMESH::UpdateView(); - SMESH::Update(myIO, SMESH::eDisplay); - if ( MakeGroupsCheck->isEnabled() && MakeGroupsCheck->isChecked() ) + if ( actor ) + SMESH::Update( actor->getIO(), actor->GetVisibility() ); + if ( makeGroups ) mySMESHGUI->updateObjBrowser(true); // new groups may appear Init(false); mySelectionMgr->clearSelected(); - mySelectedObject = SMESH::SMESH_IDSource::_nil(); - SelectionIntoArgument(); - ConstructorsClicked(GetConstructorId()); + SelectorWdg->Clear(); SMESHGUI::Modified(); } @@ -660,159 +554,50 @@ void SMESHGUI_RevolutionDlg::onAngleTextChange (const QString& theNewText) RadioButton4->setEnabled( isNumber ); } -//======================================================================= -// function : onTextChange() -// purpose : -//======================================================================= -void SMESHGUI_RevolutionDlg::onTextChange (const QString& theNewText) -{ - QLineEdit* send = (QLineEdit*)sender(); - - if (myBusy) return; - myBusy = true; - - if (send == LineEditElements) - myNbOkElements = 0; - - buttonOk->setEnabled(false); - buttonApply->setEnabled(false); - - // hilight entered elements - SMDS_Mesh* aMesh = 0; - if (myActor) - aMesh = myActor->GetObject()->GetMesh(); - - if (aMesh) { - if (send == LineEditElements) { - Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); - - TColStd_MapOfInteger newIndices; - - QStringList aListId = theNewText.split(" ", QString::SkipEmptyParts); - - for (int i = 0; i < aListId.count(); i++) { - const SMDS_MeshElement * e = aMesh->FindElement(aListId[ i ].toInt()); - if (e) - newIndices.Add(e->GetID()); - myNbOkElements++; - } - - mySelector->AddOrRemoveIndex(myActor->getIO(), newIndices, false); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->highlight( myActor->getIO(), true, true ); - - myElementsId = theNewText; - } - } - - if (myNbOkElements && IsAxisOk()) { - buttonOk->setEnabled(true); - buttonApply->setEnabled(true); - } - onDisplaySimulation(true); - - myBusy = false; -} - //================================================================================= // function : SelectionIntoArgument() // purpose : Called when selection as changed or other case //================================================================================= void SMESHGUI_RevolutionDlg::SelectionIntoArgument() { - if (myBusy) return; - - // clear - QString aString = ""; - - myBusy = true; - if (myEditCurrentArgument == (QWidget*)LineEditElements) { - LineEditElements->setText(aString); - myNbOkElements = 0; - buttonOk->setEnabled(false); - buttonApply->setEnabled(false); - } - myBusy = false; - if (!GroupButtons->isEnabled()) // inactive return; + + if ( SelectVectorButton->isChecked() || + SelectPointButton->isChecked() ) + { + // get selected mesh + SALOME_ListIO aList; + mySelectionMgr->selectedObjects(aList); + int nbSel = aList.Extent(); + if (nbSel != 1) + return; - // get selected mesh - SALOME_ListIO aList; - mySelectionMgr->selectedObjects(aList); - int nbSel = aList.Extent(); - if (nbSel != 1) - return; - - Handle(SALOME_InteractiveObject) IO = aList.First(); - SMESH::SMESH_Mesh_var aMeshVar = SMESH::GetMeshByIO(IO); - if (aMeshVar->_is_nil()) - return; - - SMESH_Actor* anActor = SMESH::FindActorByObject(aMeshVar); - if (!anActor) - anActor = SMESH::FindActorByEntry(IO->getEntry()); - if (!anActor && !CheckBoxMesh->isChecked()) - return; - - int aNbUnits = 0; - - if (myEditCurrentArgument == (QWidget*)LineEditElements) { - myElementsId = ""; - myMesh = aMeshVar; - myActor = anActor; - myIO = IO; - - // MakeGroups is available if there are groups - if ( myMesh->NbGroups() == 0 ) { - MakeGroupsCheck->setChecked(false); - MakeGroupsCheck->setEnabled(false); - } else { - MakeGroupsCheck->setEnabled(true); - } - - if (CheckBoxMesh->isChecked()) { - SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString); - - if (!SMESH::IObjectToInterface(IO)->_is_nil()) - mySelectedObject = SMESH::IObjectToInterface(IO); - else - return; - } else { - aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString); - myElementsId = aString; - if (aNbUnits < 1) - return; - } - myNbOkElements = true; - } else { + Handle(SALOME_InteractiveObject) IO = aList.First(); + TColStd_IndexedMapOfInteger aMapIndex; + mySelector->GetIndex(IO,aMapIndex); + if ( aMapIndex.Extent() != 1 ) + return; - SMDS_Mesh* aMesh = anActor->GetObject()->GetMesh(); - if (!aMesh) + SMESH_Actor* anActor = SMESH::FindActorByEntry( IO->getEntry() ); + SMDS_Mesh* aMesh = anActor ? anActor->GetObject()->GetMesh() : 0; + if ( !aMesh ) return; + int aNbUnits = 0; + bool isNodeSelected = (myEditCurrentArgument == (QWidget*)SpinBox_X || - (myEditCurrentArgument == (QWidget*)SpinBox_DX && + (myEditCurrentArgument == (QWidget*)SpinBox_DX && myVectorDefinition==POINT_SELECT)); - bool isFaceSelected = (myEditCurrentArgument == (QWidget*)SpinBox_DX && + bool isFaceSelected = (myEditCurrentArgument == (QWidget*)SpinBox_DX && myVectorDefinition==FACE_SELECT); - if(isNodeSelected) { - aNbUnits = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString); - } - else if(isFaceSelected){ - aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString); - } - - if (aNbUnits != 1) - return; - - if(isNodeSelected) { - const SMDS_MeshNode * n = aMesh->FindNode(aString.toInt()); + if ( isNodeSelected ) + { + const SMDS_MeshNode * n = aMesh->FindNode( aMapIndex(1) ); if (!n) return; - double x = n->X(); double y = n->Y(); double z = n->Z(); @@ -827,30 +612,21 @@ void SMESHGUI_RevolutionDlg::SelectionIntoArgument() SpinBox_DZ->SetValue(z - SpinBox_Z->GetValue()); } } - else if(isFaceSelected){ - const SMDS_MeshFace* face = dynamic_cast(aMesh->FindElement(aString.toInt())); + else if ( isFaceSelected ) + { + const SMDS_MeshFace* face = + dynamic_cast(aMesh->FindElement(aMapIndex(1))); if (!face) return; - gp_XYZ aNormale = SMESH::getNormale(face); SpinBox_DX->SetValue(aNormale.X()); SpinBox_DY->SetValue(aNormale.Y()); SpinBox_DZ->SetValue(aNormale.Z()); - - } - } - - myBusy = true; - if (myEditCurrentArgument == (QWidget*)LineEditElements) - LineEditElements->setText(aString); - myBusy = false; - // OK - if (myNbOkElements && IsAxisOk()) { - buttonOk->setEnabled(true); - buttonApply->setEnabled(true); + } } + CheckIsEnable(); onDisplaySimulation(true); } @@ -866,35 +642,13 @@ void SMESHGUI_RevolutionDlg::SetEditCurrentArgument() mySelectionMgr->clearSelected(); mySelectionMgr->clearFilters(); - if (send == SelectElementsButton) { - mySimulation->SetVisibility(false); - myEditCurrentArgument = (QWidget*)LineEditElements; - SMESH::SetPointRepresentation(false); - if (CheckBoxMesh->isChecked()) { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); - mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter); - } else { - int aConstructorId = GetConstructorId(); - if (aConstructorId == 0) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - } - else if (aConstructorId == 1) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - } - } - } else if (send == SelectPointButton) { + if (send == SelectPointButton) { myEditCurrentArgument = (QWidget*)SpinBox_X; + myEditCurrentArgument->setFocus(); SMESH::SetPointRepresentation(true); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(NodeSelection); } - - myEditCurrentArgument->setFocus(); connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); SelectionIntoArgument(); } @@ -905,10 +659,11 @@ void SMESHGUI_RevolutionDlg::SetEditCurrentArgument() //================================================================================= void SMESHGUI_RevolutionDlg::DeactivateActiveDialog() { - if (ConstructorsBox->isEnabled()) { - ConstructorsBox->setEnabled(false); + if (GroupButtons->isEnabled()) + { GroupArguments->setEnabled(false); GroupButtons->setEnabled(false); + SelectorWdg->setEnabled(false); mySMESHGUI->ResetState(); mySMESHGUI->SetActiveDialogBox(0); } @@ -922,14 +677,11 @@ void SMESHGUI_RevolutionDlg::ActivateThisDialog() { /* Emit a signal to deactivate the active dialog */ mySMESHGUI->EmitSignalDeactivateDialog(); - ConstructorsBox->setEnabled(true); GroupArguments->setEnabled(true); GroupButtons->setEnabled(true); + SelectorWdg->setEnabled(true); mySMESHGUI->SetActiveDialogBox((QDialog*)this); - - ConstructorsClicked(GetConstructorId()); - SelectionIntoArgument(); } //================================================================================= @@ -938,73 +690,10 @@ void SMESHGUI_RevolutionDlg::ActivateThisDialog() //================================================================================= void SMESHGUI_RevolutionDlg::enterEvent (QEvent*) { - if (!ConstructorsBox->isEnabled()) + if (!GroupButtons->isEnabled()) ActivateThisDialog(); } -//======================================================================= -//function : onSelectMesh -//purpose : -//======================================================================= -void SMESHGUI_RevolutionDlg::onSelectMesh (bool toSelectMesh) -{ - if (toSelectMesh) { - myIDs = LineEditElements->text(); - TextLabelElements->setText(tr("SMESH_NAME")); - } - else - TextLabelElements->setText(tr("SMESH_ID_ELEMENTS")); - myFilterBtn->setEnabled(!toSelectMesh); - - if (myEditCurrentArgument != LineEditElements) { - LineEditElements->clear(); - mySimulation->SetVisibility(false); - return; - } - - mySelectionMgr->clearFilters(); - SMESH::SetPointRepresentation(false); - - if (toSelectMesh) { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(ActorSelection); - mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter); - LineEditElements->setReadOnly(true); - LineEditElements->setValidator(0); - } else { - int aConstructorId = GetConstructorId(); - if (aConstructorId == 0) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(EdgeSelection); - } - else if (aConstructorId == 1) - { - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(FaceSelection); - } - - LineEditElements->setReadOnly(false); - LineEditElements->setValidator(myIdValidator); - onTextChange(LineEditElements->text()); - mySimulation->SetVisibility(false); - } - - SelectionIntoArgument(); - - if (!toSelectMesh) - LineEditElements->setText( myIDs ); -} - -//================================================================================= -// function : GetConstructorId() -// purpose : -//================================================================================= -int SMESHGUI_RevolutionDlg::GetConstructorId() -{ - return GroupConstructors->checkedId(); -} - //================================================================================= // function : IsAxisOk() // purpose : @@ -1016,22 +705,6 @@ bool SMESHGUI_RevolutionDlg::IsAxisOk() SpinBox_DZ->GetValue() != 0); } -//================================================================================= -// function : onVectorChanged() -// purpose : -//================================================================================= -void SMESHGUI_RevolutionDlg::onVectorChanged() -{ - if (IsAxisOk()) { - buttonOk->setEnabled(true); - buttonApply->setEnabled(true); - } else { - buttonOk->setEnabled(false); - buttonApply->setEnabled(false); - } - onDisplaySimulation(true); -} - //================================================================================= // function : keyPressEvent() // purpose : @@ -1056,17 +729,8 @@ void SMESHGUI_RevolutionDlg::onDisplaySimulation(bool toDisplayPreview) { if (myPreviewCheckBox->isChecked() && toDisplayPreview) { - //display preview - if (myNbOkElements && IsAxisOk()) + if (SelectorWdg->IsAnythingSelected() && IsAxisOk()) { - QStringList aListElementsId = myElementsId.split(" ", QString::SkipEmptyParts); - - SMESH::long_array_var anElementsId = new SMESH::long_array; - - anElementsId->length(aListElementsId.count()); - for (int i = 0; i < aListElementsId.count(); i++) - anElementsId[i] = aListElementsId[i].toInt(); - SMESH::AxisStruct anAxis; anAxis.x = SpinBox_X->GetValue(); @@ -1076,33 +740,34 @@ void SMESHGUI_RevolutionDlg::onDisplaySimulation(bool toDisplayPreview) anAxis.vy = SpinBox_DY->GetValue(); anAxis.vz = SpinBox_DZ->GetValue(); - double anAngle = (SpinBox_Angle->GetValue())*M_PI/180.; - long aNbSteps = (long)SpinBox_NbSteps->value(); + double anAngle = (SpinBox_Angle->GetValue())*M_PI/180.; + long aNbSteps = (long)SpinBox_NbSteps->value(); double aTolerance = SpinBox_Tolerance->GetValue(); if (GroupAngle->checkedId() == 1) anAngle = anAngle/aNbSteps; - try { + try + { SUIT_OverrideCursor aWaitCursor; - SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditPreviewer(); - if( CheckBoxMesh->isChecked() ) { - if( GetConstructorId() == 0 ) - aMeshEditor->RotationSweepObject1D(mySelectedObject, anAxis, - anAngle, aNbSteps, aTolerance); - else - aMeshEditor->RotationSweepObject2D(mySelectedObject, anAxis, - anAngle, aNbSteps, aTolerance); - } - else - aMeshEditor->RotationSweep(anElementsId.inout(), - anAxis, - anAngle, - aNbSteps, - aTolerance); - SMESH::MeshPreviewStruct_var aMeshPreviewStruct = aMeshEditor->GetPreviewData(); - mySimulation->SetData(aMeshPreviewStruct._retn()); - } catch (...) {} + + SMESH::SMESH_Mesh_var mesh = SelectorWdg->GetMesh(); + SMESH::SMESH_MeshEditor_var meshEditor = mesh->GetMeshEditPreviewer(); + SMESH::ListOfGroups_var groups; + + SMESH::ListOfIDSources_var nodes = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var edges = new SMESH::ListOfIDSources(); + SMESH::ListOfIDSources_var faces = new SMESH::ListOfIDSources(); + SelectorWdg->GetSelected( nodes, edges, faces ); + const bool makeGroups = false; + + meshEditor->RotationSweepObjects(nodes, edges, faces, + anAxis, anAngle, aNbSteps, aTolerance, makeGroups ); + + SMESH::MeshPreviewStruct_var aMeshPreviewStruct = meshEditor->GetPreviewData(); + mySimulation->SetData( aMeshPreviewStruct._retn() ); + } + catch (...) {} } else { @@ -1120,7 +785,8 @@ void SMESHGUI_RevolutionDlg::onDisplaySimulation(bool toDisplayPreview) // function : onSelectVectorButton() // purpose : [slot] //================================================================================= -void SMESHGUI_RevolutionDlg::onSelectVectorButton(){ +void SMESHGUI_RevolutionDlg::onSelectVectorButton() +{ if(SelectVectorMenu) { SelectVectorMenu->exec( QCursor::pos() ); } @@ -1130,7 +796,8 @@ void SMESHGUI_RevolutionDlg::onSelectVectorButton(){ // function : onSelectVectorMenu() // purpose : [slot] //================================================================================= -void SMESHGUI_RevolutionDlg::onSelectVectorMenu( QAction* action){ +void SMESHGUI_RevolutionDlg::onSelectVectorMenu( QAction* action) +{ if(!action) return; @@ -1157,58 +824,4 @@ void SMESHGUI_RevolutionDlg::onSelectVectorMenu( QAction* action){ SelectionIntoArgument(); } -//================================================================================= -// function : setFilters() -// purpose : SLOT. Called when "Filter" button pressed. -//================================================================================= -void SMESHGUI_RevolutionDlg::setFilters() -{ - if(myMesh->_is_nil()) { - SUIT_MessageBox::critical(this, - tr("SMESH_ERROR"), - tr("NO_MESH_SELECTED")); - return; - } - if ( !myFilterDlg ) - { - QList types; - types.append( SMESH::EDGE ); - types.append( SMESH::FACE ); - myFilterDlg = new SMESHGUI_FilterDlg( mySMESHGUI, types ); - } - myFilterDlg->Init( GetConstructorId() ? SMESH::FACE : SMESH::EDGE ); - - myFilterDlg->SetSelection(); - myFilterDlg->SetMesh( myMesh ); - myFilterDlg->SetSourceWg( LineEditElements ); - - myFilterDlg->show(); -} -//================================================================================= -// function : isValid -// purpose : -//================================================================================= -bool SMESHGUI_RevolutionDlg::isValid() -{ - QString msg; - bool ok = true; - ok = SpinBox_X->isValid( msg, true ) && ok; - ok = SpinBox_Y->isValid( msg, true ) && ok; - ok = SpinBox_Z->isValid( msg, true ) && ok; - ok = SpinBox_DX->isValid( msg, true ) && ok; - ok = SpinBox_DY->isValid( msg, true ) && ok; - ok = SpinBox_DZ->isValid( msg, true ) && ok; - ok = SpinBox_Angle->isValid( msg, true ) && ok; - ok = SpinBox_NbSteps->isValid( msg, true ) && ok; - ok = SpinBox_Tolerance->isValid( msg, true ) && ok; - - if( !ok ) { - QString str( tr( "SMESH_INCORRECT_INPUT" ) ); - if ( !msg.isEmpty() ) - str += "\n" + msg; - SUIT_MessageBox::critical( this, tr( "SMESH_ERROR" ), str ); - return false; - } - return true; -} diff --git a/src/SMESHGUI/SMESHGUI_RevolutionDlg.h b/src/SMESHGUI/SMESHGUI_RevolutionDlg.h index db65d7c92..3f85e932c 100644 --- a/src/SMESHGUI/SMESHGUI_RevolutionDlg.h +++ b/src/SMESHGUI/SMESHGUI_RevolutionDlg.h @@ -41,26 +41,27 @@ #include #include CORBA_SERVER_HEADER(SMESH_Mesh) +class LightApp_SelectionMgr; +class QAction; class QButtonGroup; +class QCheckBox; class QGroupBox; class QLabel; class QLineEdit; +class QMenu; class QPushButton; class QRadioButton; -class QCheckBox; -class SalomeApp_IntSpinBox; -class SMESHGUI_IdValidator; -class SMESHGUI_SpinBox; +class SALOME_Actor; class SMESHGUI; +class SMESHGUI_3TypesSelector; class SMESHGUI_FilterDlg; +class SMESHGUI_IdValidator; +class SMESHGUI_MeshEditPreview; +class SMESHGUI_SpinBox; class SMESH_Actor; -class SVTK_Selector; -class LightApp_SelectionMgr; class SMESH_LogicalFilter; -class SALOME_Actor; -class SMESHGUI_MeshEditPreview; -class QMenu; -class QAction; +class SVTK_Selector; +class SalomeApp_IntSpinBox; //================================================================================= // class : SMESHGUI_RevolutionDlg @@ -85,27 +86,11 @@ private: bool isValid(); - SMESHGUI_IdValidator* myIdValidator; LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ - int myNbOkElements; /* to check when elements are defined */ - QString myElementsId; - QWidget* myEditCurrentArgument; /* Current argument */ SVTK_Selector* mySelector; - Handle(SALOME_InteractiveObject) myIO; - - SMESH::SMESH_IDSource_var mySelectedObject; - - bool myBusy; - SMESH::SMESH_Mesh_var myMesh; - SMESH_Actor* myActor; - SMESH_LogicalFilter* myMeshOrSubMeshOrGroupFilter; - SMESHGUI_MeshEditPreview* mySimulation; - SALOME_Actor* myPreviewActor; + QWidget* myEditCurrentArgument; /* Current argument */ - QGroupBox* ConstructorsBox; - QButtonGroup* GroupConstructors; - QRadioButton* RadioButton1; - QRadioButton* RadioButton2; + SMESHGUI_3TypesSelector* SelectorWdg; QGroupBox* GroupButtons; QPushButton* buttonOk; QPushButton* buttonCancel; @@ -113,10 +98,6 @@ private: QPushButton* buttonHelp; QGroupBox* GroupArguments; QGroupBox* GroupAxis; - QLabel* TextLabelElements; - QPushButton* SelectElementsButton; - QLineEdit* LineEditElements; - QCheckBox* CheckBoxMesh; QCheckBox* MakeGroupsCheck; QGroupBox* GroupAngleBox; QButtonGroup* GroupAngle; @@ -153,17 +134,13 @@ private: QString myHelpFileName; - QString myIDs; - - QPushButton* myFilterBtn; - SMESHGUI_FilterDlg* myFilterDlg; protected slots: virtual void onDisplaySimulation( bool ); - virtual void reject(); + virtual void reject(); private slots: - void ConstructorsClicked( int ); + void CheckIsEnable(); void ClickOnOk(); bool ClickOnApply(); void ClickOnHelp(); @@ -171,13 +148,9 @@ private slots: void SelectionIntoArgument(); void DeactivateActiveDialog(); void ActivateThisDialog(); - void onTextChange( const QString& ); void onAngleTextChange( const QString& ); - void onSelectMesh( bool ); - void onVectorChanged(); void onSelectVectorMenu( QAction* ); void onSelectVectorButton(); - void setFilters(); }; #endif // SMESHGUI_REVOLUTIONDLG_H diff --git a/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx b/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx index 023056a95..df0989317 100644 --- a/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_ScaleDlg.cxx @@ -486,7 +486,7 @@ bool SMESHGUI_ScaleDlg::ClickOnApply() } else { SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor(); - SMESH::SMESH_IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); + SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); myMeshes[0]->SetParameters( aParameters.join( ":" ).toLatin1().constData() ); aMeshEditor->Scale( src, aPoint, aScaleFact, false); } @@ -503,7 +503,7 @@ bool SMESHGUI_ScaleDlg::ClickOnApply() } else { SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor(); - SMESH::SMESH_IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); + SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); myMeshes[0]->SetParameters(aParameters.join( ":" ).toLatin1().constData()); groups = aMeshEditor->ScaleMakeGroups( src, aPoint, aScaleFact); } @@ -518,7 +518,7 @@ bool SMESHGUI_ScaleDlg::ClickOnApply() } else { SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor(); - SMESH::SMESH_IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); + SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); myMeshes[0]->SetParameters(aParameters.join( ":" ).toLatin1().constData()); aMeshEditor->Scale( src, aPoint, aScaleFact, true); } @@ -541,7 +541,7 @@ bool SMESHGUI_ScaleDlg::ClickOnApply() else { SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditor(); myMeshes[0]->SetParameters(aParameters.join( ":" ).toLatin1().constData()); - SMESH::SMESH_IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); + SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); mesh = aMeshEditor->ScaleMakeMesh( src, aPoint, aScaleFact, makeGroups, LineEditNewMesh->text().toLatin1().data()); if( _PTR(SObject) aSObject = SMESH::ObjectToSObject( mesh ) ) @@ -1147,7 +1147,7 @@ void SMESHGUI_ScaleDlg::onDisplaySimulation( bool toDisplayPreview ) { } else { SMESH::SMESH_MeshEditor_var aMeshEditor = myMeshes[0]->GetMeshEditPreviewer(); - SMESH::SMESH_IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); + SMESH::IDSource_wrap src = aMeshEditor->MakeIDSource(anElementsId, SMESH::ALL); aMeshEditor->Scale( src, aPoint, aScaleFact, copy); aMeshPreviewStruct << aMeshEditor->GetPreviewData(); } diff --git a/src/SMESHGUI/SMESHGUI_Utils.h b/src/SMESHGUI/SMESHGUI_Utils.h index c1aa3ad4d..a15fada9f 100644 --- a/src/SMESHGUI/SMESHGUI_Utils.h +++ b/src/SMESHGUI/SMESHGUI_Utils.h @@ -182,7 +182,7 @@ SMESHGUI_EXPORT // type to use instead of SMESH_IDSource_var for automatic UnRegister() - typedef SALOME::GenericObj_wrap SMESH_IDSource_wrap; + typedef SALOME::GenericObj_wrap IDSource_wrap; /*! * \brief Class usefull to convert a string returned from a CORBA call diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index a33acb178..baf5fb8bc 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -286,7 +286,7 @@ MEN_MESH_ORDER - Change submesh priority + Change sub-mesh priority MEN_CREATE_GROUP @@ -1287,7 +1287,7 @@ Please enter correct values and try again SMESH_ADD_SUBMESH - SubMesh Construction + Sub-mesh Construction SMESH_ADD_TETRAS @@ -1805,7 +1805,7 @@ add the exported data to its contents? SMESH_HYP_10 - Hypothesis and submesh dimensions mismatch + Hypothesis and sub-mesh dimensions mismatch SMESH_HYP_11 @@ -1830,7 +1830,7 @@ Check algorithm documentation for supported geometry SMESH_HYP_4 - Submesh is ignored as there is another algorithm of upper dimension generating %1D elements + Sub-mesh is ignored as there is another algorithm of upper dimension generating %1D elements SMESH_HYP_5 @@ -1853,20 +1853,20 @@ Check algorithm documentation for supported geometry Such dimention hypothesis is already assigned to the shape - SMESH_ID_DIAGONAL - Id Edges + SMESH_ID_EDGES + Edge IDs SMESH_ID_ELEMENTS - Id Elements + Element IDs SMESH_ID_FACES - Id Faces + Face IDs SMESH_ID_NODES - Id Nodes + Node IDs SMESH_INCORRECT_INPUT @@ -1938,23 +1938,23 @@ Check algorithm documentation for supported geometry SMESH_MEN_SubMeshesOnCompound - SubMeshes On Compound + Sub-meshes On Compound SMESH_MEN_SubMeshesOnEdge - SubMeshes On Edge + Sub-meshes On Edge SMESH_MEN_SubMeshesOnFace - SubMeshes On Face + Sub-meshes On Face SMESH_MEN_SubMeshesOnSolid - SubMeshes On Solid + Sub-meshes On Solid SMESH_MEN_SubMeshesOnVertex - SubMeshes On Vertex + Sub-meshes On Vertex SMESH_AUTOMATIC @@ -2168,9 +2168,13 @@ Check algorithm documentation for supported geometry SMESH_OBJECT_MESH Mesh + + SMESH_OBJECTS + Objects + SMESH_OBJECT_MESHorSUBMESH - Mesh or SubMesh + Mesh or Sub-mesh SMESH_OPERATION_FAILED @@ -2587,11 +2591,11 @@ Check algorithm documentation for supported geometry SMESH_SUBMESH - SubMesh + Sub-mesh SMESH_SUBMESH_SELECTED - %1 SubMeshes + %1 Sub-meshes SMESH_SYMMETRY @@ -2914,7 +2918,7 @@ Use Display Entity menu command to show them. STB_MESH_ORDER - Change submesh priority + Change sub-mesh priority STB_CREATE_GROUP @@ -3574,7 +3578,7 @@ Use Display Entity menu command to show them. TOP_MESH_ORDER - Change submesh priority + Change sub-mesh priority TOP_CREATE_GROUP @@ -4833,9 +4837,9 @@ Please, create VTK viewer and try again SMESHGUI_PrecomputeOp CLEAR_SUBMESH_QUESTION - Temporary submeshes on the selected geometry + Temporary sub-meshes on the selected geometry were created during preview operation. -Do you want to remove all these submeshes? +Do you want to remove all these sub-meshes? SMESH_WRN_NOTHING_PREVIEW @@ -4843,8 +4847,8 @@ Do you want to remove all these submeshes? SMESH_REJECT_MESH_ORDER - The submesh priority changed during preview operation. -Do you want to restore original submesh priority? + The sub-mesh priority changed during preview operation. +Do you want to restore original sub-mesh priority? @@ -4940,7 +4944,7 @@ Please verify validity of entered information MESH_OR_SUBMESH - Mesh or SubMesh + Mesh or Sub-mesh PATTERN @@ -5104,7 +5108,7 @@ Please select a group and try again SMESH_PATH_MESH - Mesh or submesh + Mesh or sub-mesh SMESH_PATH_SHAPE @@ -6034,12 +6038,12 @@ Please specify them and try again EDIT_SUBMESH_QUESTION - A submesh on the selected geometry already exists. - Do you want to edit this submesh? + A sub-mesh on the selected geometry already exists. + Do you want to edit this sub-mesh? SUBMESH_NOT_ALLOWED - No sense in creating a submesh ignored by global algorithm "%1" + No sense in creating a sub-mesh ignored by global algorithm "%1" GEOMETRY_OBJECT_IS_NOT_DEFINED_MESH @@ -6108,7 +6112,7 @@ Please enter valid name and try again NAME_OF_SUBMESH_IS_EMPTY - Name of submesh is empty + Name of sub-mesh is empty Please enter valid name and try again @@ -6415,8 +6419,8 @@ It is impossible to read point coordinates from file Preview - REVOLUTION_1D - Revolution of 1D elements + REVOLUTION + Revolution REVOLUTION_2D @@ -6650,14 +6654,14 @@ It is impossible to read point coordinates from file SMESHGUI_MeshOrderDlg SMESH_MESHORDER_TITLE - Order of submesh in meshing process + Order of sub-mesh in meshing process SMESHGUI_MeshOrderOp SMESH_NO_CONCURENT_MESH - No concurent submeshes detected + No concurent sub-meshes detected diff --git a/src/SMESHUtils/SMESH_TypeDefs.hxx b/src/SMESHUtils/SMESH_TypeDefs.hxx index 532805027..f5c44e79a 100644 --- a/src/SMESHUtils/SMESH_TypeDefs.hxx +++ b/src/SMESHUtils/SMESH_TypeDefs.hxx @@ -80,7 +80,7 @@ namespace SMESHUtils struct Deleter { TOBJ* _obj; - Deleter( TOBJ* obj ): _obj( obj ) {} + Deleter( TOBJ* obj = (TOBJ*)NULL ): _obj( obj ) {} ~Deleter() { delete _obj; _obj = 0; } private: Deleter( const Deleter& ); diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index c680de4e6..03c514aab 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -384,6 +384,7 @@ namespace { "ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D", "ExtrusionSweepObject1D","ExtrusionSweepObject1DMakeGroups", "ExtrusionSweepObject2D","ExtrusionSweepObject2DMakeGroups", + "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects", "Translate","TranslateMakeGroups","TranslateMakeMesh", "TranslateObject","TranslateObjectMakeGroups", "TranslateObjectMakeMesh", "ExtrusionAlongPathX","ExtrusionAlongPathObjX","SplitHexahedraIntoPrisms" @@ -431,7 +432,8 @@ namespace { "ExportCGNS","ExportGMF", "Create0DElementsOnAllNodes","Reorient2D","QuadTo4Tri", "ScaleMakeGroups","Scale","ScaleMakeMesh", - "FindCoincidentNodesOnPartBut","DoubleElements" + "FindCoincidentNodesOnPartBut","DoubleElements", + "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects" ,"" }; // <- mark of the end methodsAcceptingList.Insert( methodNames ); } @@ -2404,6 +2406,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) "ExtrusionSweep","AdvancedExtrusion","ExtrusionSweepObject","ExtrusionSweepObject1D", "ExtrusionSweepObject2D","ExtrusionAlongPath","ExtrusionAlongPathObject", "ExtrusionAlongPathX","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D", + "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects", "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject", "FindCoincidentNodes","MergeNodes","FindEqualElements", "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders", diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index a0d3c0a15..fa32444eb 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -2413,6 +2413,7 @@ GetElementsId( SMESH_Mesh_ptr theMesh ) { SMESH::long_array_var anArray = new SMESH::long_array; if(!CORBA::is_nil(theMesh) && myPredicate){ + theMesh->Load(); Controls::Filter::TIdSequence aSequence; GetElementsId(myPredicate,theMesh,aSequence); long i = 0, iEnd = aSequence.size(); diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index ba4962656..600c5e7a3 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -302,65 +302,7 @@ namespace MeshEditor_I { aMap.insert( aMap.end(), elem ); } } - //================================================================================ - /*! - * \brief Retrieve elements of given type from SMESH_IDSource - */ - //================================================================================ - - enum IDSource_Error { IDSource_OK, IDSource_INVALID, IDSource_EMPTY }; - - bool idSourceToSet(SMESH::SMESH_IDSource_ptr theIDSource, - const SMESHDS_Mesh* theMeshDS, - TIDSortedElemSet& theElemSet, - const SMDSAbs_ElementType theType, - const bool emptyIfIsMesh = false, - IDSource_Error* error = 0) - - { - if ( error ) *error = IDSource_OK; - if ( CORBA::is_nil( theIDSource ) ) - { - if ( error ) *error = IDSource_INVALID; - return false; - } - if ( emptyIfIsMesh && SMESH::DownCast( theIDSource )) - { - if ( error && theMeshDS->GetMeshInfo().NbElements( theType ) == 0 ) - *error = IDSource_EMPTY; - return true; - } - SMESH::long_array_var anIDs = theIDSource->GetIDs(); - if ( anIDs->length() == 0 ) - { - if ( error ) *error = IDSource_EMPTY; - return false; - } - SMESH::array_of_ElementType_var types = theIDSource->GetTypes(); - if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes - { - if ( theType == SMDSAbs_All || theType == SMDSAbs_Node ) - { - arrayToSet( anIDs, theMeshDS, theElemSet, SMDSAbs_Node ); - } - else - { - if ( error ) *error = IDSource_INVALID; - return false; - } - } - else - { - arrayToSet( anIDs, theMeshDS, theElemSet, theType); - if ( bool(anIDs->length()) != bool(theElemSet.size())) - { - if ( error ) *error = IDSource_INVALID; - return false; - } - } - return true; - } //================================================================================ /*! * \brief Retrieve nodes from SMESH_IDSource @@ -1285,7 +1227,6 @@ SMESH_MeshEditor_i::Create0DElementsOnAllNodes(SMESH::SMESH_IDSource_ptr theObje TPythonDump pyDump; TIDSortedElemSet elements, elems0D; - prepareIdSource( theObject ); if ( idSourceToSet( theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) getEditor().Create0DElementsOnAllNodes( elements, elems0D ); @@ -1670,7 +1611,6 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2D(SMESH::SMESH_IDSource_ptr the2Dgroup, initData(/*deleteSearchers=*/false); TIDSortedElemSet elements; - prepareIdSource( the2Dgroup ); IDSource_Error error; idSourceToSet( the2Dgroup, getMeshDS(), elements, SMDSAbs_Face, /*emptyIfIsMesh=*/1, &error ); if ( error == IDSource_EMPTY ) @@ -1755,7 +1695,6 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& fac initData(); TIDSortedElemSet volumes; - prepareIdSource( volumeGroup ); IDSource_Error volsError; idSourceToSet( volumeGroup, getMeshDS(), volumes, SMDSAbs_Volume, /*emptyIfMesh=*/1, &volsError); @@ -1763,7 +1702,6 @@ CORBA::Long SMESH_MeshEditor_i::Reorient2DBy3D(const SMESH::ListOfIDSources& fac for ( size_t i = 0; i < faceGroups.length(); ++i ) { SMESH::SMESH_IDSource_ptr faceGrp = faceGroups[i].in(); - prepareIdSource( faceGrp ); TIDSortedElemSet faces; IDSource_Error error; @@ -1961,7 +1899,6 @@ void SMESH_MeshEditor_i::QuadTo4Tri (SMESH::SMESH_IDSource_ptr theObject) initData(); TIDSortedElemSet faces; - prepareIdSource( theObject ); if ( !idSourceToSet( theObject, getMeshDS(), faces, SMDSAbs_Face, /*emptyIfIsMesh=*/true ) && faces.empty() ) THROW_SALOME_CORBA_EXCEPTION("No faces given", SALOME::BAD_PARAM); @@ -2082,7 +2019,6 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems, { SMESH_TRY; initData(); - prepareIdSource( elems ); ::SMESH_MeshEditor::TFacetOfElem elemSet; const int noneFacet = -1; @@ -2385,309 +2321,77 @@ SMESH::ListOfGroups* SMESH_MeshEditor_i::getGroups(const std::list* groupID } //======================================================================= -//function : rotationSweep +//function : RotationSweepObjects //purpose : //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::rotationSweep(const SMESH::long_array & theIDsOfElements, - const SMESH::AxisStruct & theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance, - const bool theMakeGroups, - const SMDSAbs_ElementType theElementType) +SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes, + const SMESH::ListOfIDSources & theEdges, + const SMESH::ListOfIDSources & theFaces, + const SMESH::AxisStruct & theAxis, + CORBA::Double theAngleInRadians, + CORBA::Long theNbOfSteps, + CORBA::Double theTolerance, + const bool theMakeGroups) throw (SALOME::SALOME_Exception) { SMESH_TRY; initData(); - TIDSortedElemSet inElements, copyElements; - arrayToSet(theIDsOfElements, getMeshDS(), inElements, theElementType); + TIDSortedElemSet elemsNodes[2]; + for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) { + SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ); + while ( nIt->more() ) elemsNodes[1].insert( nIt->next() ); + } + for ( int i = 0, nb = theEdges.length(); i < nb; ++i ) + idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge ); + for ( int i = 0, nb = theFaces.length(); i < nb; ++i ) + idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face ); - TIDSortedElemSet* workElements = & inElements; + TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2]; bool makeWalls=true; if ( myIsPreviewMode ) { SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume; - getPreviewMesh( SMDSAbs_Face )->Copy( inElements, copyElements, select, avoid ); - workElements = & copyElements; - //makeWalls = false; + TPreviewMesh * tmpMesh = getPreviewMesh(); + tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid ); + tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid ); + workElements = & copyElements[0]; + //makeWalls = false; -- faces are needed for preview } + TPythonDump aPythonDump; // it is here to prevent dump of getGroups() + gp_Ax1 Ax1 (gp_Pnt( theAxis.x, theAxis.y, theAxis.z ), gp_Vec( theAxis.vx, theAxis.vy, theAxis.vz )); ::SMESH_MeshEditor::PGroupIDs groupIds = - getEditor().RotationSweep (*workElements, Ax1, theAngleInRadians, + getEditor().RotationSweep (workElements, Ax1, theAngleInRadians, theNbOfSteps, theTolerance, theMakeGroups, makeWalls); - declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute() - - return theMakeGroups ? getGroups(groupIds.get()) : 0; - - SMESH_CATCH( SMESH::throwCorbaException ); - return 0; -} - -//======================================================================= -//function : RotationSweep -//purpose : -//======================================================================= - -void SMESH_MeshEditor_i::RotationSweep(const SMESH::long_array & theIDsOfElements, - const SMESH::AxisStruct & theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".RotationSweep( " - << theIDsOfElements << ", " - << theAxis << ", " - << TVar( theAngleInRadians ) << ", " - << TVar( theNbOfSteps ) << ", " - << TVar( theTolerance ) << " )"; - } - rotationSweep(theIDsOfElements, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - false); -} - -//======================================================================= -//function : RotationSweepMakeGroups -//purpose : -//======================================================================= + SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0; -SMESH::ListOfGroups* -SMESH_MeshEditor_i::RotationSweepMakeGroups(const SMESH::long_array& theIDsOfElements, - const SMESH::AxisStruct& theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() + declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute() - SMESH::ListOfGroups *aGroups = rotationSweep(theIDsOfElements, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - true); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".RotationSweepMakeGroups( " - << theIDsOfElements << ", " + if ( !myIsPreviewMode ) + { + dumpGroupsList( aPythonDump, aGroups ); + aPythonDump << this<< ".RotationSweepObjects( " + << theNodes << ", " + << theEdges << ", " + << theFaces << ", " << theAxis << ", " << TVar( theAngleInRadians ) << ", " << TVar( theNbOfSteps ) << ", " - << TVar( theTolerance ) << " )"; - } - return aGroups; -} - -//======================================================================= -//function : RotationSweepObject -//purpose : -//======================================================================= - -void SMESH_MeshEditor_i::RotationSweepObject(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct & theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".RotationSweepObject( " - << theObject << ", " - << theAxis << ", " - << theAngleInRadians << ", " - << theNbOfSteps << ", " - << theTolerance << " )"; - } - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - rotationSweep(anElementsId, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - false); -} - -//======================================================================= -//function : RotationSweepObject1D -//purpose : -//======================================================================= - -void SMESH_MeshEditor_i::RotationSweepObject1D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct & theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".RotationSweepObject1D( " - << theObject << ", " - << theAxis << ", " - << TVar( theAngleInRadians ) << ", " - << TVar( theNbOfSteps ) << ", " - << TVar( theTolerance ) << " )"; - } - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - rotationSweep(anElementsId, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - false, - SMDSAbs_Edge); -} - -//======================================================================= -//function : RotationSweepObject2D -//purpose : -//======================================================================= - -void SMESH_MeshEditor_i::RotationSweepObject2D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct & theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".RotationSweepObject2D( " - << theObject << ", " - << theAxis << ", " - << TVar( theAngleInRadians ) << ", " - << TVar( theNbOfSteps ) << ", " - << TVar( theTolerance ) << " )"; - } - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - rotationSweep(anElementsId, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - false, - SMDSAbs_Face); -} - -//======================================================================= -//function : RotationSweepObjectMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::RotationSweepObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct& theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups *aGroups = rotationSweep(anElementsId, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - true); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".RotationSweepObjectMakeGroups( " - << theObject << ", " - << theAxis << ", " - << theAngleInRadians << ", " - << theNbOfSteps << ", " - << theTolerance << " )"; - } - return aGroups; -} - -//======================================================================= -//function : RotationSweepObject1DMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::RotationSweepObject1DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct& theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups *aGroups = rotationSweep(anElementsId, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - true, - SMDSAbs_Edge); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".RotationSweepObject1DMakeGroups( " - << theObject << ", " - << theAxis << ", " - << TVar( theAngleInRadians ) << ", " - << TVar( theNbOfSteps ) << ", " - << TVar( theTolerance ) << " )"; + << TVar( theTolerance ) << ", " + << theMakeGroups << " )"; } - return aGroups; -} - -//======================================================================= -//function : RotationSweepObject2DMakeGroups -//purpose : -//======================================================================= -SMESH::ListOfGroups* -SMESH_MeshEditor_i::RotationSweepObject2DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct& theAxis, - CORBA::Double theAngleInRadians, - CORBA::Long theNbOfSteps, - CORBA::Double theTolerance) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() + return aGroups ? aGroups : new SMESH::ListOfGroups; - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups *aGroups = rotationSweep(anElementsId, - theAxis, - theAngleInRadians, - theNbOfSteps, - theTolerance, - true, - SMDSAbs_Face); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".RotationSweepObject2DMakeGroups( " - << theObject << ", " - << theAxis << ", " - << TVar( theAngleInRadians ) << ", " - << TVar( theNbOfSteps ) << ", " - << TVar( theTolerance ) << " )"; - } - return aGroups; + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; } namespace MeshEditor_I @@ -2763,498 +2467,308 @@ namespace MeshEditor_I } //======================================================================= -//function : extrusionSweep -//purpose : +/*! + * \brief Generate dim+1 elements by extrusion of elements along vector + * \param [in] edges - edges to extrude: a list including groups, sub-meshes or a mesh + * \param [in] faces - faces to extrude: a list including groups, sub-meshes or a mesh + * \param [in] nodes - nodes to extrude: a list including groups, sub-meshes or a mesh + * \param [in] stepVector - vector giving direction and distance of an extrusion step + * \param [in] nbOfSteps - number of elements to generate from one element + * \param [in] toMakeGroups - if true, new elements will be included into new groups + * corresponding to groups the input elements included in. + * \return ListOfGroups - new groups craeted if \a toMakeGroups is true + */ //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::extrusionSweep(const SMESH::long_array & theIDsOfElements, - MeshEditor_I::ExtrusionParams& theParams, - const SMDSAbs_ElementType theElementType) +SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNodes, + const SMESH::ListOfIDSources & theEdges, + const SMESH::ListOfIDSources & theFaces, + const SMESH::DirStruct & theStepVector, + CORBA::Long theNbOfSteps, + CORBA::Boolean theToMakeGroups) throw (SALOME::SALOME_Exception) { SMESH_TRY; initData(); - TIDSortedElemSet elements, copyElements; - arrayToSet( theIDsOfElements, getMeshDS(), elements, theElementType ); + ExtrusionParams params( theStepVector, theNbOfSteps, theToMakeGroups ); - TIDSortedElemSet* workElements = & elements; + TIDSortedElemSet elemsNodes[2]; + for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) { + SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ); + while ( nIt->more() ) elemsNodes[1].insert( nIt->next() ); + } + for ( int i = 0, nb = theEdges.length(); i < nb; ++i ) + idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge ); + for ( int i = 0, nb = theFaces.length(); i < nb; ++i ) + idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face ); + TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2]; if ( myIsPreviewMode ) { - SMDSAbs_ElementType previewType = SMDSAbs_Face; - if (theElementType == SMDSAbs_Node) - previewType = SMDSAbs_Edge; + SMDSAbs_ElementType previewType = SMDSAbs_All; //SMDSAbs_Face; + // if ( (*elemsNodes.begin())->GetType() == SMDSAbs_Node ) + // previewType = SMDSAbs_Edge; SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume; - getPreviewMesh( previewType )->Copy( elements, copyElements, select, avoid ); - workElements = & copyElements; - theParams.SetNoGroups(); + TPreviewMesh * tmpMesh = getPreviewMesh(); + tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid ); + tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid ); + workElements = & copyElements[0]; - if ( theParams.myIsExtrusionByNormal && !theParams.ToUseInpElemsOnly() ) - { - TIDSortedElemSet elemsAround, elemsAroundCopy; - getElementsAround( elements, getMeshDS(), elemsAround ); - getPreviewMesh( previewType )->Copy( elemsAround, elemsAroundCopy, select, avoid ); - } + params.SetNoGroups(); } + TPythonDump aPythonDump; // it is here to prevent dump of getGroups() - ::SMESH_MeshEditor::TTElemOfElemListMap aHystory; + ::SMESH_MeshEditor::TTElemOfElemListMap aHistory; ::SMESH_MeshEditor::PGroupIDs groupIds = - getEditor().ExtrusionSweep (*workElements, theParams, aHystory ); + getEditor().ExtrusionSweep( workElements, params, aHistory ); + + SMESH::ListOfGroups * aGroups = theToMakeGroups ? getGroups( groupIds.get()) : 0; declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute() - return theParams.ToMakeGroups() ? getGroups(groupIds.get()) : 0; + if ( !myIsPreviewMode ) + { + dumpGroupsList( aPythonDump, aGroups ); + aPythonDump << this<< ".ExtrusionSweepObjects( " + << theNodes << ", " + << theEdges << ", " + << theFaces << ", " + << theStepVector << ", " + << TVar( theNbOfSteps ) << ", " + << theToMakeGroups << " )"; + } + + return aGroups ? aGroups : new SMESH::ListOfGroups; SMESH_CATCH( SMESH::throwCorbaException ); return 0; } //======================================================================= -//function : ExtrusionSweep +//function : ExtrusionByNormal //purpose : //======================================================================= -void SMESH_MeshEditor_i::ExtrusionSweep(const SMESH::long_array & theIDsOfElements, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps) +SMESH::ListOfGroups* +SMESH_MeshEditor_i::ExtrusionByNormal(const SMESH::ListOfIDSources& objects, + CORBA::Double stepSize, + CORBA::Long nbOfSteps, + CORBA::Boolean byAverageNormal, + CORBA::Boolean useInputElemsOnly, + CORBA::Boolean makeGroups, + CORBA::Short dim) throw (SALOME::SALOME_Exception) { - ExtrusionParams params( theStepVector, theNbOfSteps, false ); - extrusionSweep( theIDsOfElements, params ); - if (!myIsPreviewMode) { - TPythonDump() << this << ".ExtrusionSweep( " - << theIDsOfElements << ", " << theStepVector <<", " << TVar(theNbOfSteps) << " )"; + SMESH_TRY; + initData(); + + TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() + + ExtrusionParams params( stepSize, nbOfSteps, dim, + byAverageNormal, useInputElemsOnly, makeGroups ); + + SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face ); + if ( objects.length() > 0 && !SMESH::DownCast( objects[0] )) + { + SMESH::array_of_ElementType_var elemTypes = objects[0]->GetTypes(); + if (( elemTypes->length() == 1 ) && + ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE )) + elemType = ( SMDSAbs_ElementType ) elemTypes[0]; } -} -//======================================================================= -//function : ExtrusionSweep0D -//purpose : -//======================================================================= + TIDSortedElemSet elemsNodes[2]; + for ( int i = 0, nb = objects.length(); i < nb; ++i ) + idSourceToSet( objects[i], getMeshDS(), elemsNodes[0], elemType ); -void SMESH_MeshEditor_i::ExtrusionSweep0D(const SMESH::long_array & theIDsOfElements, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - ExtrusionParams params( theStepVector, theNbOfSteps, false ); - extrusionSweep( theIDsOfElements, params, SMDSAbs_Node ); - if (!myIsPreviewMode) { - TPythonDump() << this << ".ExtrusionSweep0D( " - << theIDsOfElements << ", " << theStepVector <<", " << TVar(theNbOfSteps)<< " )"; + TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2]; + if ( myIsPreviewMode ) + { + SMDSAbs_ElementType previewType = SMDSAbs_Face; + SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume; + TPreviewMesh * tmpMesh = getPreviewMesh( previewType ); + tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid ); + workElements = & copyElements[0]; + + params.SetNoGroups(); } -} -//======================================================================= -//function : ExtrusionSweepObject -//purpose : -//======================================================================= + ::SMESH_MeshEditor::TTElemOfElemListMap aHistory; + ::SMESH_MeshEditor::PGroupIDs groupIds = + getEditor().ExtrusionSweep( workElements, params, aHistory ); + + SMESH::ListOfGroups * aGroups = makeGroups ? getGroups( groupIds.get()) : 0; -void SMESH_MeshEditor_i::ExtrusionSweepObject(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, false ); - extrusionSweep( anElementsId, params ); if (!myIsPreviewMode) { - TPythonDump() << this << ".ExtrusionSweepObject( " - << theObject << ", " << theStepVector << ", " << theNbOfSteps << " )"; + dumpGroupsList(aPythonDump, aGroups); + aPythonDump << this << ".ExtrusionByNormal( " << objects + << ", " << TVar( stepSize ) + << ", " << TVar( nbOfSteps ) + << ", " << byAverageNormal + << ", " << makeGroups + << ", " << dim + << " )"; } -} -//======================================================================= -//function : ExtrusionSweepObject0D -//purpose : -//======================================================================= + declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute() -void SMESH_MeshEditor_i::ExtrusionSweepObject0D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - if ( anElementsId->length() == 0 ) - if ( SMESH_Mesh_i* mesh = SMESH::DownCast( theObject )) - anElementsId = mesh->GetNodesId(); + return aGroups ? aGroups : new SMESH::ListOfGroups; - ExtrusionParams params( theStepVector, theNbOfSteps, false ); - extrusionSweep( anElementsId, params, SMDSAbs_Node ); - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".ExtrusionSweepObject0D( " - << theObject << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )"; - } + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; } //======================================================================= -//function : ExtrusionSweepObject1D +//function : AdvancedExtrusion //purpose : //======================================================================= -void SMESH_MeshEditor_i::ExtrusionSweepObject1D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps) +SMESH::ListOfGroups* +SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements, + const SMESH::DirStruct & theStepVector, + CORBA::Long theNbOfSteps, + CORBA::Long theExtrFlags, + CORBA::Double theSewTolerance, + CORBA::Boolean theMakeGroups) throw (SALOME::SALOME_Exception) { - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, false ); - extrusionSweep( anElementsId, params, SMDSAbs_Edge ); - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".ExtrusionSweepObject1D( " - << theObject << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )"; - } -} + SMESH_TRY; + initData(); -//======================================================================= -//function : ExtrusionSweepObject2D -//purpose : -//======================================================================= + TPythonDump aPythonDump; // it is here to prevent dump of getGroups() -void SMESH_MeshEditor_i::ExtrusionSweepObject2D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, false ); - extrusionSweep( anElementsId, params, SMDSAbs_Face ); - if ( !myIsPreviewMode ) { - TPythonDump() << this << ".ExtrusionSweepObject2D( " - << theObject << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )"; - } -} - -//======================================================================= -//function : ExtrusionSweepMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionSweepMakeGroups(const SMESH::long_array& theIDsOfElements, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - ExtrusionParams params( theStepVector, theNbOfSteps, true ); - SMESH::ListOfGroups* aGroups = extrusionSweep( theIDsOfElements, params ); - - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionSweepMakeGroups( " << theIDsOfElements - << ", " << theStepVector <<", " << TVar( theNbOfSteps ) << " )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionSweepMakeGroups0D -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionSweepMakeGroups0D(const SMESH::long_array& theIDsOfElements, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - ExtrusionParams params( theStepVector, theNbOfSteps, true ); - SMESH::ListOfGroups* aGroups = extrusionSweep( theIDsOfElements, params, SMDSAbs_Node ); - - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionSweepMakeGroups0D( " << theIDsOfElements - << ", " << theStepVector <<", " << TVar( theNbOfSteps ) << " )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionSweepObjectMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionSweepObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, true ); - SMESH::ListOfGroups* aGroups = extrusionSweep( anElementsId, params ); - - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionSweepObjectMakeGroups( " << theObject - << ", " << theStepVector << ", " << theNbOfSteps << " )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionSweepObject0DMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionSweepObject0DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, true ); - SMESH::ListOfGroups* aGroups = extrusionSweep( anElementsId, params, SMDSAbs_Node ); - - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionSweepObject0DMakeGroups( " << theObject - << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionSweepObject1DMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionSweepObject1DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, true ); - SMESH::ListOfGroups* aGroups = extrusionSweep( anElementsId, params, SMDSAbs_Edge ); + ExtrusionParams params( theStepVector, theNbOfSteps, theMakeGroups, + theExtrFlags, theSewTolerance ); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionSweepObject1DMakeGroups( " << theObject - << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )"; - } - return aGroups; -} + TIDSortedElemSet elemsNodes[2]; + arrayToSet( theIDsOfElements, getMeshDS(), elemsNodes[0] ); -//======================================================================= -//function : ExtrusionSweepObject2DMakeGroups -//purpose : -//======================================================================= + ::SMESH_MeshEditor::TTElemOfElemListMap aHistory; + ::SMESH_MeshEditor::PGroupIDs groupIds = + getEditor().ExtrusionSweep( elemsNodes, params, aHistory ); -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionSweepObject2DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() + SMESH::ListOfGroups * aGroups = theMakeGroups ? getGroups( groupIds.get()) : 0; - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - ExtrusionParams params( theStepVector, theNbOfSteps, true ); - SMESH::ListOfGroups* aGroups = extrusionSweep( anElementsId, params, SMDSAbs_Face ); + declareMeshModified( /*isReComputeSafe=*/true ); // does not influence Compute() - if (!myIsPreviewMode) { + if ( !myIsPreviewMode ) { dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionSweepObject2DMakeGroups( " << theObject - << ", " << theStepVector << ", " << TVar( theNbOfSteps ) << " )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionByNormal -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionByNormal(SMESH::SMESH_IDSource_ptr object, - CORBA::Double stepSize, - CORBA::Long nbOfSteps, - CORBA::Boolean byAverageNormal, - CORBA::Boolean useInputElemsOnly, - CORBA::Boolean makeGroups, - CORBA::Short dim) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - ExtrusionParams params( stepSize, nbOfSteps, dim, - byAverageNormal, useInputElemsOnly, makeGroups ); - - SMDSAbs_ElementType elemType = ( dim == 1 ? SMDSAbs_Edge : SMDSAbs_Face ); - if ( !SMESH::DownCast( object )) - { - SMESH::array_of_ElementType_var elemTypes = object->GetTypes(); - if (( elemTypes->length() == 1 ) && - ( elemTypes[0] == SMESH::EDGE || elemTypes[0] == SMESH::FACE )) - elemType = ( SMDSAbs_ElementType ) elemTypes[0]; + aPythonDump << this << ".AdvancedExtrusion( " + << theIDsOfElements << ", " + << theStepVector << ", " + << theNbOfSteps << ", " + << theExtrFlags << ", " + << theSewTolerance << ", " + << theMakeGroups << " )"; } - prepareIdSource( object ); - SMESH::long_array_var anElementsId = object->GetIDs(); - SMESH::ListOfGroups* aGroups = extrusionSweep( anElementsId, params, elemType ); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".ExtrusionByNormal( " << object - << ", " << TVar( stepSize ) - << ", " << TVar( nbOfSteps ) - << ", " << byAverageNormal - << ", " << makeGroups - << ", " << dim - << " )"; - } return aGroups ? aGroups : new SMESH::ListOfGroups; -} - -//======================================================================= -//function : AdvancedExtrusion -//purpose : -//======================================================================= - -void SMESH_MeshEditor_i::AdvancedExtrusion(const SMESH::long_array & theIDsOfElements, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps, - CORBA::Long theExtrFlags, - CORBA::Double theSewTolerance) - throw (SALOME::SALOME_Exception) -{ - ExtrusionParams params( theStepVector, theNbOfSteps, false, theExtrFlags, theSewTolerance); - extrusionSweep( theIDsOfElements, params ); - - if ( !myIsPreviewMode ) { - TPythonDump() << "stepVector = " << theStepVector; - TPythonDump() << this << ".AdvancedExtrusion(" - << theIDsOfElements - << ", stepVector, " - << theNbOfSteps << "," - << theExtrFlags << ", " - << theSewTolerance << " )"; - } -} - -//======================================================================= -//function : AdvancedExtrusionMakeGroups -//purpose : -//======================================================================= -SMESH::ListOfGroups* -SMESH_MeshEditor_i::AdvancedExtrusionMakeGroups(const SMESH::long_array& theIDsOfElements, - const SMESH::DirStruct& theStepVector, - CORBA::Long theNbOfSteps, - CORBA::Long theExtrFlags, - CORBA::Double theSewTolerance) - throw (SALOME::SALOME_Exception) -{ - if (!myIsPreviewMode) { - TPythonDump() << "stepVector = " << theStepVector; - } - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - ExtrusionParams params( theStepVector, theNbOfSteps, true, theExtrFlags, theSewTolerance); - SMESH::ListOfGroups * aGroups = extrusionSweep( theIDsOfElements, params ); - if (!myIsPreviewMode) { - dumpGroupsList(aPythonDump, aGroups); - aPythonDump << this << ".AdvancedExtrusionMakeGroups(" - << theIDsOfElements - << ", stepVector, " - << theNbOfSteps << "," - << theExtrFlags << ", " - << theSewTolerance << " )"; - } - return aGroups; + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; } - //================================================================================ /*! * \brief Convert extrusion error to IDL enum */ //================================================================================ +namespace +{ #define RETCASE(enm) case ::SMESH_MeshEditor::enm: return SMESH::SMESH_MeshEditor::enm; -static SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( const::SMESH_MeshEditor::Extrusion_Error e ) -{ - switch ( e ) { - RETCASE( EXTR_OK ); - RETCASE( EXTR_NO_ELEMENTS ); - RETCASE( EXTR_PATH_NOT_EDGE ); - RETCASE( EXTR_BAD_PATH_SHAPE ); - RETCASE( EXTR_BAD_STARTING_NODE ); - RETCASE( EXTR_BAD_ANGLES_NUMBER ); - RETCASE( EXTR_CANT_GET_TANGENT ); + SMESH::SMESH_MeshEditor::Extrusion_Error convExtrError( ::SMESH_MeshEditor::Extrusion_Error e ) + { + switch ( e ) { + RETCASE( EXTR_OK ); + RETCASE( EXTR_NO_ELEMENTS ); + RETCASE( EXTR_PATH_NOT_EDGE ); + RETCASE( EXTR_BAD_PATH_SHAPE ); + RETCASE( EXTR_BAD_STARTING_NODE ); + RETCASE( EXTR_BAD_ANGLES_NUMBER ); + RETCASE( EXTR_CANT_GET_TANGENT ); + } + return SMESH::SMESH_MeshEditor::EXTR_OK; } - return SMESH::SMESH_MeshEditor::EXTR_OK; } - //======================================================================= //function : extrusionAlongPath //purpose : //======================================================================= SMESH::ListOfGroups* -SMESH_MeshEditor_i::extrusionAlongPath(const SMESH::long_array & theIDsOfElements, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array & theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct & theRefPoint, - const bool theMakeGroups, - SMESH::SMESH_MeshEditor::Extrusion_Error & theError, - const SMDSAbs_ElementType theElementType) +SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & theNodes, + const SMESH::ListOfIDSources & theEdges, + const SMESH::ListOfIDSources & theFaces, + SMESH::SMESH_IDSource_ptr thePathMesh, + GEOM::GEOM_Object_ptr thePathShape, + CORBA::Long theNodeStart, + CORBA::Boolean theHasAngles, + const SMESH::double_array & theAngles, + CORBA::Boolean theLinearVariation, + CORBA::Boolean theHasRefPoint, + const SMESH::PointStruct & theRefPoint, + bool theMakeGroups, + SMESH::SMESH_MeshEditor::Extrusion_Error& theError) throw (SALOME::SALOME_Exception) { SMESH_TRY; - MESSAGE("extrusionAlongPath"); initData(); - if ( thePathMesh->_is_nil() || thePathShape->_is_nil() ) { - theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE; - return 0; - } - SMESH_Mesh_i* aMeshImp = SMESH::DownCast( thePathMesh ); + SMESH::ListOfGroups_var aGroups = new SMESH::ListOfGroups; - TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape ); - SMESH_subMesh* aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape ); + theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE; + if ( thePathMesh->_is_nil() ) + return aGroups._retn(); - if ( !aSubMesh || !aSubMesh->GetSubMeshDS()) { - theError = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE; - return 0; + // get a sub-mesh + SMESH_subMesh* aSubMesh = 0; + SMESH_Mesh_i* aMeshImp = SMESH::DownCast( thePathMesh ); + if ( thePathShape->_is_nil() ) + { + // thePathMesh should be either a sub-mesh or a mesh with 1D elements only + if ( SMESH_subMesh_i* sm = SMESH::DownCast( thePathMesh )) + { + SMESH::SMESH_Mesh_var mesh = thePathMesh->GetMesh(); + aMeshImp = SMESH::DownCast( mesh ); + if ( !aMeshImp ) return aGroups._retn(); + aSubMesh = aMeshImp->GetImpl().GetSubMeshContaining( sm->GetId() ); + if ( !aSubMesh ) return aGroups._retn(); + } + else if ( !aMeshImp || + aMeshImp->NbEdges() != aMeshImp->NbElements() ) + { + return aGroups._retn(); + } + } + else + { + if ( !aMeshImp ) return aGroups._retn(); + TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape ); + aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape ); + if ( !aSubMesh || !aSubMesh->GetSubMeshDS() ) + return aGroups._retn(); } - SMDS_MeshNode* nodeStart = (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart); + SMDS_MeshNode* nodeStart = + (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(theNodeStart); if ( !nodeStart ) { theError = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE; - return 0; + return aGroups._retn(); } - TIDSortedElemSet elements; - arrayToSet(theIDsOfElements, getMeshDS(), elements, theElementType); + TIDSortedElemSet elemsNodes[2]; + for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) { + SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ); + while ( nIt->more() ) elemsNodes[1].insert( nIt->next() ); + } + for ( int i = 0, nb = theEdges.length(); i < nb; ++i ) + idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge ); + for ( int i = 0, nb = theFaces.length(); i < nb; ++i ) + idSourceToSet( theFaces[i], getMeshDS(), elemsNodes[0], SMDSAbs_Face ); list angles; for (int i = 0; i < theAngles.length(); i++) { @@ -3265,658 +2779,63 @@ SMESH_MeshEditor_i::extrusionAlongPath(const SMESH::long_array & theIDsOfEleme int nbOldGroups = myMesh->NbGroup(); - ::SMESH_MeshEditor::Extrusion_Error error = - getEditor().ExtrusionAlongTrack( elements, aSubMesh, nodeStart, - theHasAngles, angles, false, - theHasRefPoint, refPnt, theMakeGroups ); - - declareMeshModified( /*isReComputeSafe=*/true ); - theError = convExtrError( error ); - - if ( theMakeGroups ) { - list groupIDs = myMesh->GetGroupIds(); - list::iterator newBegin = groupIDs.begin(); - std::advance( newBegin, nbOldGroups ); // skip old groups - groupIDs.erase( groupIDs.begin(), newBegin ); - return getGroups( & groupIDs ); - } - return 0; - - SMESH_CATCH( SMESH::throwCorbaException ); - return 0; -} - -//======================================================================= -//function : extrusionAlongPathX -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array & IDsOfElements, - SMESH::SMESH_IDSource_ptr Path, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean LinearVariation, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - bool MakeGroups, - const SMDSAbs_ElementType ElementType, - SMESH::SMESH_MeshEditor::Extrusion_Error & Error) - throw (SALOME::SALOME_Exception) -{ - SMESH_TRY; - SMESH::ListOfGroups* EmptyGr = new SMESH::ListOfGroups; - - initData(); - - list angles; - for (int i = 0; i < Angles.length(); i++) { - angles.push_back( Angles[i] ); - } - gp_Pnt refPnt( RefPoint.x, RefPoint.y, RefPoint.z ); - int nbOldGroups = myMesh->NbGroup(); - - if ( Path->_is_nil() ) { - Error = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE; - return EmptyGr; - } - - TIDSortedElemSet elements, copyElements; - arrayToSet(IDsOfElements, getMeshDS(), elements, ElementType); - - TIDSortedElemSet* workElements = &elements; - + TIDSortedElemSet* workElements = & elemsNodes[0], copyElements[2]; if ( myIsPreviewMode ) { SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume; - getPreviewMesh( SMDSAbs_Face )->Copy( elements, copyElements, select, avoid ); - workElements = & copyElements; - MakeGroups = false; + TPreviewMesh * tmpMesh = getPreviewMesh(); + tmpMesh->Copy( elemsNodes[0], copyElements[0], select, avoid ); + tmpMesh->Copy( elemsNodes[1], copyElements[1], select, avoid ); + workElements = & copyElements[0]; + theMakeGroups = false; } ::SMESH_MeshEditor::Extrusion_Error error; - - if ( SMESH_Mesh_i* aMeshImp = SMESH::DownCast( Path )) - { - // path as mesh - SMDS_MeshNode* aNodeStart = - (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart); - if ( !aNodeStart ) { - Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE; - return EmptyGr; - } - error = getEditor().ExtrusionAlongTrack( *workElements, &(aMeshImp->GetImpl()), aNodeStart, - HasAngles, angles, LinearVariation, - HasRefPoint, refPnt, MakeGroups ); - declareMeshModified( /*isReComputeSafe=*/true ); - } - else if ( SMESH_subMesh_i* aSubMeshImp = SMESH::DownCast( Path )) - { - // path as submesh - SMESH::SMESH_Mesh_ptr aPathMesh = aSubMeshImp->GetFather(); - aMeshImp = SMESH::DownCast( aPathMesh ); - SMDS_MeshNode* aNodeStart = - (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart); - if ( !aNodeStart ) { - Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE; - return EmptyGr; - } - SMESH_subMesh* aSubMesh = - aMeshImp->GetImpl().GetSubMeshContaining(aSubMeshImp->GetId()); - error = getEditor().ExtrusionAlongTrack( *workElements, aSubMesh, aNodeStart, - HasAngles, angles, LinearVariation, - HasRefPoint, refPnt, MakeGroups ); - declareMeshModified( /*isReComputeSafe=*/true ); - } - else if ( SMESH::DownCast( Path )) - { - // path as group of 1D elements - // ???????? - } + if ( !aSubMesh ) + error = getEditor().ExtrusionAlongTrack( workElements, &(aMeshImp->GetImpl()), nodeStart, + theHasAngles, angles, theLinearVariation, + theHasRefPoint, refPnt, theMakeGroups ); else - { - // invalid path - Error = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE; - return EmptyGr; - } + error = getEditor().ExtrusionAlongTrack( workElements, aSubMesh, nodeStart, + theHasAngles, angles, theLinearVariation, + theHasRefPoint, refPnt, theMakeGroups ); - Error = convExtrError( error ); + declareMeshModified( /*isReComputeSafe=*/true ); + theError = convExtrError( error ); - if ( MakeGroups ) { + TPythonDump aPythonDump; // it is here to prevent dump of getGroups() + if ( theMakeGroups ) { list groupIDs = myMesh->GetGroupIds(); list::iterator newBegin = groupIDs.begin(); std::advance( newBegin, nbOldGroups ); // skip old groups groupIDs.erase( groupIDs.begin(), newBegin ); - return getGroups( & groupIDs ); + aGroups = getGroups( & groupIDs ); + if ( ! &aGroups.in() ) aGroups = new SMESH::ListOfGroups; } - return EmptyGr; - - SMESH_CATCH( SMESH::throwCorbaException ); - return 0; -} - -//======================================================================= -//function : ExtrusionAlongPath -//purpose : -//======================================================================= - -SMESH::SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor_i::ExtrusionAlongPath(const SMESH::long_array & theIDsOfElements, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array & theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct & theRefPoint) - throw (SALOME::SALOME_Exception) -{ - MESSAGE("ExtrusionAlongPath"); - if ( !myIsPreviewMode ) { - TPythonDump() << "error = " << this << ".ExtrusionAlongPath( " - << theIDsOfElements << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - SMESH::SMESH_MeshEditor::Extrusion_Error anError; - extrusionAlongPath( theIDsOfElements, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - false, - anError); - return anError; -} - -//======================================================================= -//function : ExtrusionAlongPathObject -//purpose : -//======================================================================= - -SMESH::SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor_i::ExtrusionAlongPathObject(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array & theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct & theRefPoint) - throw (SALOME::SALOME_Exception) -{ - if ( !myIsPreviewMode ) { - TPythonDump() << "error = " << this << ".ExtrusionAlongPathObject( " - << theObject << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - SMESH::SMESH_MeshEditor::Extrusion_Error anError; - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - extrusionAlongPath( anElementsId, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - false, - anError); - return anError; -} - -//======================================================================= -//function : ExtrusionAlongPathObject1D -//purpose : -//======================================================================= - -SMESH::SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor_i::ExtrusionAlongPathObject1D(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array & theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct & theRefPoint) - throw (SALOME::SALOME_Exception) -{ - if ( !myIsPreviewMode ) { - TPythonDump() << "error = " << this << ".ExtrusionAlongPathObject1D( " - << theObject << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - SMESH::SMESH_MeshEditor::Extrusion_Error anError; - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - extrusionAlongPath( anElementsId, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - false, - anError, - SMDSAbs_Edge); - return anError; -} -//======================================================================= -//function : ExtrusionAlongPathObject2D -//purpose : -//======================================================================= - -SMESH::SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor_i::ExtrusionAlongPathObject2D(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array & theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct & theRefPoint) - throw (SALOME::SALOME_Exception) -{ if ( !myIsPreviewMode ) { - TPythonDump() << "error = " << this << ".ExtrusionAlongPathObject2D( " - << theObject << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - SMESH::SMESH_MeshEditor::Extrusion_Error anError; - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - extrusionAlongPath( anElementsId, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - false, - anError, - SMDSAbs_Face); - return anError; -} - - -//======================================================================= -//function : ExtrusionAlongPathMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* -SMESH_MeshEditor_i::ExtrusionAlongPathMakeGroups(const SMESH::long_array& theIDsOfElements, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array& theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct& theRefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - SMESH::ListOfGroups * aGroups = extrusionAlongPath( theIDsOfElements, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - true, - Error); - if (!myIsPreviewMode) { - bool isDumpGroups = aGroups && aGroups->length() > 0; - if (isDumpGroups) - aPythonDump << "(" << aGroups << ", error)"; - else - aPythonDump <<"error"; - - aPythonDump<<" = "<< this << ".ExtrusionAlongPathMakeGroups( " - << theIDsOfElements << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionAlongPathObjectMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* SMESH_MeshEditor_i:: -ExtrusionAlongPathObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array& theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct& theRefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = extrusionAlongPath( anElementsId, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - true, - Error); - - if (!myIsPreviewMode) { - bool isDumpGroups = aGroups && aGroups->length() > 0; - if (isDumpGroups) - aPythonDump << "(" << aGroups << ", error)"; - else - aPythonDump <<"error"; - - aPythonDump << " = " << this << ".ExtrusionAlongPathObjectMakeGroups( " - << theObject << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionAlongPathObject1DMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* SMESH_MeshEditor_i:: -ExtrusionAlongPathObject1DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array& theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct& theRefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = extrusionAlongPath( anElementsId, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - true, - Error, - SMDSAbs_Edge); - - if (!myIsPreviewMode) { - bool isDumpGroups = aGroups && aGroups->length() > 0; - if (isDumpGroups) - aPythonDump << "(" << aGroups << ", error)"; - else - aPythonDump << "error"; - - aPythonDump << " = " << this << ".ExtrusionAlongPathObject1DMakeGroups( " - << theObject << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " - << "SMESH.PointStruct( " - << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionAlongPathObject2DMakeGroups -//purpose : -//======================================================================= - -SMESH::ListOfGroups* SMESH_MeshEditor_i:: -ExtrusionAlongPathObject2DMakeGroups(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr thePathMesh, - GEOM::GEOM_Object_ptr thePathShape, - CORBA::Long theNodeStart, - CORBA::Boolean theHasAngles, - const SMESH::double_array& theAngles, - CORBA::Boolean theHasRefPoint, - const SMESH::PointStruct& theRefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( theObject ); - SMESH::long_array_var anElementsId = theObject->GetIDs(); - SMESH::ListOfGroups * aGroups = extrusionAlongPath( anElementsId, - thePathMesh, - thePathShape, - theNodeStart, - theHasAngles, - theAngles, - theHasRefPoint, - theRefPoint, - true, - Error, - SMDSAbs_Face); - - if (!myIsPreviewMode) { - bool isDumpGroups = aGroups && aGroups->length() > 0; - if (isDumpGroups) - aPythonDump << "(" << aGroups << ", error)"; - else - aPythonDump << "error"; - - aPythonDump << " = " << this << ".ExtrusionAlongPathObject2DMakeGroups( " - << theObject << ", " - << thePathMesh << ", " - << thePathShape << ", " - << theNodeStart << ", " - << theHasAngles << ", " - << theAngles << ", " - << theHasRefPoint << ", " + aPythonDump << "(" << aGroups << ", error) = " + << this << ".ExtrusionAlongPathObjects( " + << theNodes << ", " + << theEdges << ", " + << theFaces << ", " + << thePathMesh << ", " + << thePathShape << ", " + << theNodeStart << ", " + << theHasAngles << ", " + << theAngles << ", " + << theLinearVariation << ", " + << theHasRefPoint << ", " << "SMESH.PointStruct( " << ( theHasRefPoint ? theRefPoint.x : 0 ) << ", " << ( theHasRefPoint ? theRefPoint.y : 0 ) << ", " - << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ) )"; - } - return aGroups; -} - -//======================================================================= -//function : ExtrusionAlongPathObjX -//purpose : -//======================================================================= - -SMESH::ListOfGroups* SMESH_MeshEditor_i:: -ExtrusionAlongPathObjX(SMESH::SMESH_IDSource_ptr Object, - SMESH::SMESH_IDSource_ptr Path, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean LinearVariation, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - CORBA::Boolean MakeGroups, - SMESH::ElementType ElemType, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - - prepareIdSource( Object ); - SMESH::long_array_var anElementsId = Object->GetIDs(); - SMESH::ListOfGroups * aGroups = extrusionAlongPathX(anElementsId, - Path, - NodeStart, - HasAngles, - Angles, - LinearVariation, - HasRefPoint, - RefPoint, - MakeGroups, - (SMDSAbs_ElementType)ElemType, - Error); - - if (!myIsPreviewMode) { - bool isDumpGroups = aGroups && aGroups->length() > 0; - if (isDumpGroups) - aPythonDump << "(" << *aGroups << ", error)"; - else - aPythonDump << "error"; - - aPythonDump << " = " << this << ".ExtrusionAlongPathObjX( " - << Object << ", " - << Path << ", " - << NodeStart << ", " - << HasAngles << ", " - << TVar( Angles ) << ", " - << LinearVariation << ", " - << HasRefPoint << ", " - << "SMESH.PointStruct( " - << TVar( HasRefPoint ? RefPoint.x : 0 ) << ", " - << TVar( HasRefPoint ? RefPoint.y : 0 ) << ", " - << TVar( HasRefPoint ? RefPoint.z : 0 ) << " ), " - << MakeGroups << ", " - << ElemType << " )"; + << ( theHasRefPoint ? theRefPoint.z : 0 ) << " ))"; } - return aGroups; -} - -//======================================================================= -//function : ExtrusionAlongPathX -//purpose : -//======================================================================= - -SMESH::ListOfGroups* SMESH_MeshEditor_i:: -ExtrusionAlongPathX(const SMESH::long_array& IDsOfElements, - SMESH::SMESH_IDSource_ptr Path, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean LinearVariation, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - CORBA::Boolean MakeGroups, - SMESH::ElementType ElemType, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception) -{ - TPythonDump aPythonDump; // it is here to prevent dump of GetGroups() - SMESH::ListOfGroups * aGroups = extrusionAlongPathX(IDsOfElements, - Path, - NodeStart, - HasAngles, - Angles, - LinearVariation, - HasRefPoint, - RefPoint, - MakeGroups, - (SMDSAbs_ElementType)ElemType, - Error); + return aGroups._retn(); - if (!myIsPreviewMode) { - bool isDumpGroups = aGroups && aGroups->length() > 0; - if (isDumpGroups) - aPythonDump << "(" << *aGroups << ", error)"; - else - aPythonDump <<"error"; - - aPythonDump << " = " << this << ".ExtrusionAlongPathX( " - << IDsOfElements << ", " - << Path << ", " - << NodeStart << ", " - << HasAngles << ", " - << TVar( Angles ) << ", " - << LinearVariation << ", " - << HasRefPoint << ", " - << "SMESH.PointStruct( " - << TVar( HasRefPoint ? RefPoint.x : 0 ) << ", " - << TVar( HasRefPoint ? RefPoint.y : 0 ) << ", " - << TVar( HasRefPoint ? RefPoint.z : 0 ) << " ), " - << MakeGroups << ", " - << ElemType << " )"; - } - return aGroups; + SMESH_CATCH( SMESH::throwCorbaException ); + return 0; } //================================================================================ @@ -4111,7 +3030,6 @@ void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr theObj bool emptyIfIsMesh = myIsPreviewMode ? false : true; - prepareIdSource( theObject ); if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh)) mirror(elements, theAxis, theMirrorType, theCopy, false); } @@ -4161,7 +3079,6 @@ SMESH_MeshEditor_i::MirrorObjectMakeGroups(SMESH::SMESH_IDSource_ptr t SMESH::ListOfGroups * aGroups = 0; TIDSortedElemSet elements; - prepareIdSource( theObject ); if ( idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) aGroups = mirror(elements, theMirror, theMirrorType, true, true); @@ -4247,7 +3164,6 @@ SMESH_MeshEditor_i::MirrorObjectMakeMesh(SMESH::SMESH_IDSource_ptr the mesh = makeMesh( theMeshName ); mesh_i = SMESH::DownCast( mesh ); TIDSortedElemSet elements; - prepareIdSource( theObject ); if ( mesh_i && idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) { @@ -4375,8 +3291,7 @@ void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject, TIDSortedElemSet elements; bool emptyIfIsMesh = myIsPreviewMode ? false : true; - - prepareIdSource( theObject ); + if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh)) translate(elements, theVector, theCopy, false); } @@ -4422,7 +3337,6 @@ SMESH_MeshEditor_i::TranslateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObjec SMESH::ListOfGroups * aGroups = 0; TIDSortedElemSet elements; - prepareIdSource( theObject ); if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) aGroups = translate(elements, theVector, true, true); @@ -4505,9 +3419,8 @@ SMESH_MeshEditor_i::TranslateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, mesh_i = SMESH::DownCast( mesh ); TIDSortedElemSet elements; - prepareIdSource( theObject ); if ( mesh_i && - idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) + idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) { translate(elements, theVector,false, theCopyGroups, & mesh_i->GetImpl()); mesh_i->CreateGroupServants(); @@ -4633,7 +3546,6 @@ void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject, } TIDSortedElemSet elements; bool emptyIfIsMesh = myIsPreviewMode ? false : true; - prepareIdSource( theObject ); if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh)) rotate(elements,theAxis,theAngle,theCopy,false); } @@ -4683,7 +3595,6 @@ SMESH_MeshEditor_i::RotateObjectMakeGroups(SMESH::SMESH_IDSource_ptr theObject, SMESH::ListOfGroups * aGroups = 0; TIDSortedElemSet elements; - prepareIdSource( theObject ); if (idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) aGroups = rotate(elements, theAxis, theAngle, true, true); @@ -4775,7 +3686,6 @@ SMESH_MeshEditor_i::RotateObjectMakeMesh(SMESH::SMESH_IDSource_ptr theObject, mesh_i = SMESH::DownCast( mesh ); TIDSortedElemSet elements; - prepareIdSource( theObject ); if (mesh_i && idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1)) { @@ -4828,7 +3738,6 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr theObject, theCopy = false; TIDSortedElemSet elements; - prepareIdSource( theObject ); bool emptyIfIsMesh = myIsPreviewMode ? false : true; if ( !idSourceToSet(theObject, getMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh)) return 0; @@ -5026,7 +3935,6 @@ void SMESH_MeshEditor_i::FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr initData(); TIDSortedNodeSet nodes; - prepareIdSource( theObject ); idSourceToNodeSet( theObject, getMeshDS(), nodes ); ::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes; @@ -5070,7 +3978,6 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr theObject, initData(); TIDSortedNodeSet nodes; - prepareIdSource( theObject ); idSourceToNodeSet( theObject, getMeshDS(), nodes ); for ( int i = 0; i < theExceptSubMeshOrGroups.length(); ++i ) @@ -5164,7 +4071,6 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr theObj if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) ) { TIDSortedElemSet elems; - prepareIdSource( theObject ); idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true); ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID; @@ -5858,7 +4764,6 @@ void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean theForce3d bool elemsOK; if ( !( elemsOK = CORBA::is_nil( theObject ))) { - prepareIdSource( theObject ); elemsOK = idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true ); } @@ -5944,7 +4849,6 @@ void SMESH_MeshEditor_i::ConvertFromQuadraticObject(SMESH::SMESH_IDSource_ptr th TPythonDump pyDump; TIDSortedElemSet elems; - prepareIdSource( theObject ); if ( idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true )) { if ( elems.empty() ) @@ -6044,10 +4948,68 @@ void SMESH_MeshEditor_i::prepareIdSource(SMESH::SMESH_IDSource_ptr theObject) filter->SetMesh( mesh ); } } +//================================================================================ +/*! + * \brief Retrieve elements of given type from SMESH_IDSource + */ +//================================================================================ + +bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr theIDSource, + const SMESHDS_Mesh* theMeshDS, + TIDSortedElemSet& theElemSet, + const SMDSAbs_ElementType theType, + const bool emptyIfIsMesh, + IDSource_Error* error) + +{ + if ( error ) *error = IDSource_OK; + + if ( CORBA::is_nil( theIDSource ) ) + { + if ( error ) *error = IDSource_INVALID; + return false; + } + if ( emptyIfIsMesh && SMESH::DownCast( theIDSource )) + { + if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 ) + *error = IDSource_EMPTY; + return true; + } + prepareIdSource( theIDSource ); + SMESH::long_array_var anIDs = theIDSource->GetIDs(); + if ( anIDs->length() == 0 ) + { + if ( error ) *error = IDSource_EMPTY; + return false; + } + SMESH::array_of_ElementType_var types = theIDSource->GetTypes(); + if ( types->length() == 1 && types[0] == SMESH::NODE ) // group of nodes + { + if ( theType == SMDSAbs_All || theType == SMDSAbs_Node ) + { + arrayToSet( anIDs, getMeshDS(), theElemSet, SMDSAbs_Node ); + } + else + { + if ( error ) *error = IDSource_INVALID; + return false; + } + } + else + { + arrayToSet( anIDs, getMeshDS(), theElemSet, theType); + if ( bool(anIDs->length()) != bool(theElemSet.size())) + { + if ( error ) *error = IDSource_INVALID; + return false; + } + } + return true; +} //================================================================================ /*! - * \brief Duplicates given elements, i.e. creates new elements based on the + * \brief Duplicates given elements, i.e. creates new elements based on the * same nodes as the given ones. * \param theElements - container of elements to duplicate. * \param theGroupName - a name of group to contain the generated elements. @@ -6073,7 +5035,6 @@ SMESH_MeshEditor_i::DoubleElements(SMESH::SMESH_IDSource_ptr theElements, TPythonDump pyDump; TIDSortedElemSet elems; - prepareIdSource( theElements ); if ( idSourceToSet( theElements, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true)) { getEditor().DoubleElements( elems ); @@ -7270,7 +6231,6 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource, TIDSortedElemSet elements; SMDSAbs_ElementType elemType = (dim == SMESH::BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume; - prepareIdSource( idSource ); if ( idSourceToSet( idSource, aMeshDS, elements, elemType,/*emptyIfIsMesh=*/true )) { // mesh to fill in diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 721a1a741..bd914f3c3 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -308,117 +308,59 @@ public: void RenumberNodes() throw (SALOME::SALOME_Exception); void RenumberElements() throw (SALOME::SALOME_Exception); - void RotationSweep(const SMESH::long_array & IDsOfElements, - const SMESH::AxisStruct & Axis, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - void RotationSweepObject(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct & Axis, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - void RotationSweepObject1D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct & Axis, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - void RotationSweepObject2D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::AxisStruct & Axis, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - - void ExtrusionSweep(const SMESH::long_array & IDsOfElements, - const SMESH::DirStruct & StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - void ExtrusionSweep0D(const SMESH::long_array & IDsOfElements, - const SMESH::DirStruct & StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - - void ExtrusionSweepObject(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - - void ExtrusionSweepObject0D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - void ExtrusionSweepObject1D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - void ExtrusionSweepObject2D(SMESH::SMESH_IDSource_ptr theObject, - const SMESH::DirStruct & StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionByNormal(SMESH::SMESH_IDSource_ptr object, - CORBA::Double stepSize, - CORBA::Long nbOfSteps, - CORBA::Boolean byAverageNormal, - CORBA::Boolean useInputElemsOnly, - CORBA::Boolean makeGroups, - CORBA::Short dim) - throw (SALOME::SALOME_Exception); - void AdvancedExtrusion(const SMESH::long_array & theIDsOfElements, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps, - CORBA::Long theExtrFlags, - CORBA::Double theSewTolerance) - throw (SALOME::SALOME_Exception); - - SMESH::SMESH_MeshEditor::Extrusion_Error - ExtrusionAlongPath(const SMESH::long_array & IDsOfElements, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array & Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct & RefPoint) - throw (SALOME::SALOME_Exception); - - SMESH::SMESH_MeshEditor::Extrusion_Error - ExtrusionAlongPathObject(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array & Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct & RefPoint) - throw (SALOME::SALOME_Exception); - SMESH::SMESH_MeshEditor::Extrusion_Error - ExtrusionAlongPathObject1D(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array & Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct & RefPoint) - throw (SALOME::SALOME_Exception); - SMESH::SMESH_MeshEditor::Extrusion_Error - ExtrusionAlongPathObject2D(SMESH::SMESH_IDSource_ptr theObject, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array & Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct & RefPoint) + SMESH::ListOfGroups* RotationSweepObjects(const SMESH::ListOfIDSources & nodes, + const SMESH::ListOfIDSources & edges, + const SMESH::ListOfIDSources & faces, + const SMESH::AxisStruct & Axis, + CORBA::Double AngleInRadians, + CORBA::Long NbOfSteps, + CORBA::Double Tolerance, + CORBA::Boolean toMakeGroups) + throw (SALOME::SALOME_Exception); + + SMESH::ListOfGroups* ExtrusionSweepObjects(const SMESH::ListOfIDSources & nodes, + const SMESH::ListOfIDSources & edges, + const SMESH::ListOfIDSources & faces, + const SMESH::DirStruct & stepVector, + CORBA::Long nbOfSteps, + CORBA::Boolean toMakeGroups) + throw (SALOME::SALOME_Exception); + + SMESH::ListOfGroups* ExtrusionByNormal(const SMESH::ListOfIDSources& objects, + CORBA::Double stepSize, + CORBA::Long nbOfSteps, + CORBA::Boolean byAverageNormal, + CORBA::Boolean useInputElemsOnly, + CORBA::Boolean makeGroups, + CORBA::Short dim) + throw (SALOME::SALOME_Exception); + SMESH::ListOfGroups* AdvancedExtrusion(const SMESH::long_array & theIDsOfElements, + const SMESH::DirStruct & theStepVector, + CORBA::Long theNbOfSteps, + CORBA::Long theExtrFlags, + CORBA::Double theSewTolerance, + CORBA::Boolean theMakeGroups) + throw (SALOME::SALOME_Exception); + + SMESH::ListOfGroups* + ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & nodes, + const SMESH::ListOfIDSources & edges, + const SMESH::ListOfIDSources & faces, + SMESH::SMESH_IDSource_ptr PathMesh, + GEOM::GEOM_Object_ptr PathShape, + CORBA::Long NodeStart, + CORBA::Boolean HasAngles, + const SMESH::double_array & Angles, + CORBA::Boolean LinearVariation, + CORBA::Boolean HasRefPoint, + const SMESH::PointStruct & RefPoint, + bool MakeGroups, + SMESH::SMESH_MeshEditor::Extrusion_Error& Error) throw (SALOME::SALOME_Exception); SMESH::double_array* LinearAnglesVariation(SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - const SMESH::double_array & Angles); + GEOM::GEOM_Object_ptr PathShape, + const SMESH::double_array & Angles); void Mirror(const SMESH::long_array & IDsOfElements, const SMESH::AxisStruct & Axis, @@ -449,128 +391,6 @@ public: CORBA::Boolean Copy) throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* RotationSweepMakeGroups(const SMESH::long_array& IDsOfElements, - const SMESH::AxisStruct& Axix, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* RotationSweepObjectMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::AxisStruct& Axix, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* RotationSweepObject1DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::AxisStruct& Axix, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* RotationSweepObject2DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::AxisStruct& Axix, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionSweepMakeGroups(const SMESH::long_array& IDsOfElements, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionSweepMakeGroups0D(const SMESH::long_array& IDsOfElements, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - - SMESH::ListOfGroups* AdvancedExtrusionMakeGroups(const SMESH::long_array& IDsOfElements, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps, - CORBA::Long ExtrFlags, - CORBA::Double SewTolerance) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionSweepObjectMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionSweepObject0DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionSweepObject1DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionSweepObject2DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - const SMESH::DirStruct& StepVector, - CORBA::Long NbOfSteps) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionAlongPathMakeGroups(const SMESH::long_array& IDsOfElements, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionAlongPathObjectMakeGroups(SMESH::SMESH_IDSource_ptr Object, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionAlongPathObject1DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionAlongPathObject2DMakeGroups(SMESH::SMESH_IDSource_ptr Object, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception); - - // skl 04.06.2009 - SMESH::ListOfGroups* ExtrusionAlongPathObjX(SMESH::SMESH_IDSource_ptr Object, - SMESH::SMESH_IDSource_ptr Path, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean LinearVariation, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - CORBA::Boolean MakeGroups, - SMESH::ElementType ElemType, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* ExtrusionAlongPathX(const SMESH::long_array& IDsOfElements, - SMESH::SMESH_IDSource_ptr Path, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean LinearVariation, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - CORBA::Boolean MakeGroups, - SMESH::ElementType ElemType, - SMESH::SMESH_MeshEditor::Extrusion_Error& Error) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* MirrorMakeGroups(const SMESH::long_array& IDsOfElements, const SMESH::AxisStruct& Mirror, SMESH::SMESH_MeshEditor::MirrorType MirrorType) @@ -1026,49 +846,6 @@ private: //!< private methods SMESH::ListOfGroups* getGroups(const std::list* groupIDs) throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* rotationSweep(const SMESH::long_array & IDsOfElements, - const SMESH::AxisStruct & Axis, - CORBA::Double AngleInRadians, - CORBA::Long NbOfSteps, - CORBA::Double Tolerance, - const bool MakeGroups, - const SMDSAbs_ElementType ElementType=SMDSAbs_All) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* extrusionSweep(const SMESH::long_array & IDsOfElements, - MeshEditor_I::ExtrusionParams& params, - const SMDSAbs_ElementType ElementType=SMDSAbs_All) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* advancedExtrusion(const SMESH::long_array & theIDsOfElements, - const SMESH::DirStruct & theStepVector, - CORBA::Long theNbOfSteps, - CORBA::Long theExtrFlags, - CORBA::Double theSewTolerance, - const bool MakeGroups) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* extrusionAlongPath(const SMESH::long_array & IDsOfElements, - SMESH::SMESH_Mesh_ptr PathMesh, - GEOM::GEOM_Object_ptr PathShape, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array & Angles, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct & RefPoint, - const bool MakeGroups, - SMESH::SMESH_MeshEditor::Extrusion_Error & Error, - const SMDSAbs_ElementType ElementType=SMDSAbs_All) - throw (SALOME::SALOME_Exception); - SMESH::ListOfGroups* extrusionAlongPathX(const SMESH::long_array & IDsOfElements, - SMESH::SMESH_IDSource_ptr Path, - CORBA::Long NodeStart, - CORBA::Boolean HasAngles, - const SMESH::double_array& Angles, - CORBA::Boolean LinearVariation, - CORBA::Boolean HasRefPoint, - const SMESH::PointStruct& RefPoint, - bool MakeGroups, - const SMDSAbs_ElementType ElementType, - SMESH::SMESH_MeshEditor::Extrusion_Error & theError) - throw (SALOME::SALOME_Exception); SMESH::ListOfGroups* mirror(TIDSortedElemSet & IDsOfElements, const SMESH::AxisStruct & Axis, SMESH::SMESH_MeshEditor::MirrorType MirrorType, @@ -1105,14 +882,25 @@ private: //!< private methods SMESH::SMESH_Mesh_ptr makeMesh(const char* theMeshName); - void dumpGroupsList(SMESH::TPythonDump & theDumpPython, + void dumpGroupsList(SMESH::TPythonDump & theDumpPython, const SMESH::ListOfGroups * theGroupList); string generateGroupName(const string& thePrefix); void prepareIdSource(SMESH::SMESH_IDSource_ptr theObject); -private: //!< fields + + enum IDSource_Error { IDSource_OK, IDSource_INVALID, IDSource_EMPTY }; + + bool idSourceToSet(SMESH::SMESH_IDSource_ptr theIDSource, + const SMESHDS_Mesh* theMeshDS, + TIDSortedElemSet& theElemSet, + const SMDSAbs_ElementType theType, + const bool emptyIfIsMesh = false, + IDSource_Error* error = 0); + + + private: //!< fields SMESH_Mesh_i* myMesh_i; SMESH_Mesh * myMesh; diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index 0e1a130f1..815c1cf23 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -1077,14 +1077,35 @@ void SMESH_Mesh_i::RemoveGroupWithContents( SMESH::SMESH_GroupBase_ptr theGroup if ( _preMeshInfo ) _preMeshInfo->FullLoadFromFile(); - if ( theGroup->_is_nil() ) + if ( theGroup->_is_nil() || theGroup->IsEmpty() ) return; + vector nodeIds; // to remove nodes becoming free + CORBA::Long elemID = theGroup->GetID( 1 ); + int nbElemNodes = GetElemNbNodes( elemID ); + if ( nbElemNodes > 0 ) + nodeIds.reserve( theGroup->Size() * nbElemNodes ); + // Remove contents SMESH::SMESH_IDSource_var idSrc = SMESH::SMESH_IDSource::_narrow( theGroup ); SMDS_ElemIteratorPtr elemIt = GetElements( idSrc, theGroup->GetType() ); while ( elemIt->more() ) + { + const SMDS_MeshElement* e = elemIt->next(); + + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + while ( nIt->more() ) + nodeIds.push_back( nIt->next()->GetID() ); + _impl->GetMeshDS()->RemoveElement( elemIt->next() ); + } + + // Remove free nodes + if ( theGroup->GetType() != SMESH::NODE ) + for ( size_t i = 0 ; i < nodeIds.size(); ++i ) + if ( const SMDS_MeshNode* n = _impl->GetMeshDS()->FindNode( nodeIds[i] )) + if ( n->NbInverseElements() == 0 ) + _impl->GetMeshDS()->RemoveFreeNode( n, /*sm=*/0 ); TPythonDump pyDump; // Supress dump from RemoveGroup() @@ -6022,6 +6043,8 @@ SMESH_MeshPartDS::SMESH_MeshPartDS(SMESH::SMESH_IDSource_ptr meshPart): } myInfo = tmpInfo; + ShapeToMesh( _meshDS->ShapeToMesh() ); + _meshDS = 0; // to enforce iteration on _elements and _nodes } } diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 9e4386da5..9bcac48d7 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -161,6 +161,9 @@ SMESH.PointStruct.__init__ = __initPointStruct # Substitute AxisStruct.__init__() to create SMESH.AxisStruct using notebook variables. # Parameters are stored in AxisStruct.parameters attribute def __initAxisStruct(ax,*args): + if len( args ) != 6: + raise RuntimeError,\ + "Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args )) ax.x, ax.y, ax.z, ax.vx, ax.vy, ax.vz, ax.parameters,hasVars = ParseParameters(*args) pass SMESH.AxisStruct.__init__ = __initAxisStruct @@ -3515,6 +3518,56 @@ class Mesh: def RenumberElements(self): self.editor.RenumberElements() + ## Private method converting \a arg into a list of SMESH_IdSource's + def _getIdSourceList(self, arg, idType, unRegister): + if arg and isinstance( arg, list ): + if isinstance( arg[0], int ): + arg = self.GetIDSource( arg, idType ) + unRegister.set( arg ) + elif isinstance( arg[0], Mesh ): + arg[0] = arg[0].GetMesh() + elif isinstance( arg, Mesh ): + arg = arg.GetMesh() + if arg and isinstance( arg, SMESH._objref_SMESH_IDSource ): + arg = [arg] + return arg + + ## Generates new elements by rotation of the given elements and nodes around the axis + # @param nodes - nodes to revolve: a list including ids, groups, sub-meshes or a mesh + # @param edges - edges to revolve: a list including ids, groups, sub-meshes or a mesh + # @param faces - faces to revolve: a list including ids, groups, sub-meshes or a mesh + # @param Axis the axis of rotation: AxisStruct, line (geom object) or [x,y,z,dx,dy,dz] + # @param AngleInRadians the angle of Rotation (in radians) or a name of variable + # which defines angle in degrees + # @param NbOfSteps the number of steps + # @param Tolerance tolerance + # @param MakeGroups forces the generation of new groups from existing ones + # @param TotalAngle gives meaning of AngleInRadians: if True then it is an angular size + # of all steps, else - size of each step + # @return the list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise + # @ingroup l2_modif_extrurev + def RotationSweepObjects(self, nodes, edges, faces, Axis, AngleInRadians, NbOfSteps, Tolerance, + MakeGroups=False, TotalAngle=False): + unRegister = genObjUnRegister() + nodes = self._getIdSourceList( nodes, SMESH.NODE, unRegister ) + edges = self._getIdSourceList( edges, SMESH.EDGE, unRegister ) + faces = self._getIdSourceList( faces, SMESH.FACE, unRegister ) + + if isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object): + Axis = self.smeshpyD.GetDirStruct( Axis ) + if isinstance( Axis, list ): + Axis = SMESH.AxisStruct( *Axis ) + + AngleInRadians,AngleParameters,hasVars = ParseAngles(AngleInRadians) + NbOfSteps,Tolerance,Parameters,hasVars = ParseParameters(NbOfSteps,Tolerance) + Parameters = Axis.parameters + var_separator + AngleParameters + var_separator + Parameters + self.mesh.SetParameters(Parameters) + if TotalAngle and NbOfSteps: + AngleInRadians /= NbOfSteps + return self.editor.RotationSweepObjects( nodes, edges, faces, + Axis, AngleInRadians, + NbOfSteps, Tolerance, MakeGroups) + ## Generates new elements by rotation of the elements around the axis # @param IDsOfElements the list of ids of elements to sweep # @param Axis the axis of rotation, AxisStruct or line(geom object) @@ -3528,9 +3581,15 @@ class Mesh: # @ingroup l2_modif_extrurev def RotationSweep(self, IDsOfElements, Axis, AngleInRadians, NbOfSteps, Tolerance, MakeGroups=False, TotalAngle=False): + unRegister = genObjUnRegister() if IDsOfElements == []: - IDsOfElements = self.GetElementsId() - if ( isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object)): + IDsOfElements = self.mesh + if IDsOfElements and \ + isinstance( IDsOfElements, list ) and \ + isinstance( IDsOfElements[0], int ): + IDsOfElements = self.GetIDSource( IDsOfElements, SMESH.ALL ) + unRegister.set( IDsOfElements ) + if isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object): Axis = self.smeshpyD.GetAxisStruct(Axis) AngleInRadians,AngleParameters,hasVars = ParseAngles(AngleInRadians) NbOfSteps,Tolerance,Parameters,hasVars = ParseParameters(NbOfSteps,Tolerance) @@ -3538,11 +3597,8 @@ class Mesh: self.mesh.SetParameters(Parameters) if TotalAngle and NbOfSteps: AngleInRadians /= NbOfSteps - if MakeGroups: - return self.editor.RotationSweepMakeGroups(IDsOfElements, Axis, - AngleInRadians, NbOfSteps, Tolerance) - self.editor.RotationSweep(IDsOfElements, Axis, AngleInRadians, NbOfSteps, Tolerance) - return [] + return self.editor.RotationSweepObjects([],[IDsOfElements],[IDsOfElements], Axis, + AngleInRadians, NbOfSteps, Tolerance, MakeGroups) ## Generates new elements by rotation of the elements of object around the axis # @param theObject object which elements should be sweeped. @@ -3558,9 +3614,9 @@ class Mesh: # @ingroup l2_modif_extrurev def RotationSweepObject(self, theObject, Axis, AngleInRadians, NbOfSteps, Tolerance, MakeGroups=False, TotalAngle=False): - if ( isinstance( theObject, Mesh )): + if isinstance( theObject, Mesh ): theObject = theObject.GetMesh() - if ( isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object): Axis = self.smeshpyD.GetAxisStruct(Axis) AngleInRadians,AngleParameters,hasVars = ParseAngles(AngleInRadians) NbOfSteps,Tolerance,Parameters,hasVars = ParseParameters(NbOfSteps,Tolerance) @@ -3568,11 +3624,8 @@ class Mesh: self.mesh.SetParameters(Parameters) if TotalAngle and NbOfSteps: AngleInRadians /= NbOfSteps - if MakeGroups: - return self.editor.RotationSweepObjectMakeGroups(theObject, Axis, AngleInRadians, - NbOfSteps, Tolerance) - self.editor.RotationSweepObject(theObject, Axis, AngleInRadians, NbOfSteps, Tolerance) - return [] + return self.editor.RotationSweepObjects([],[theObject],[theObject], Axis, + AngleInRadians, NbOfSteps, Tolerance ) ## Generates new elements by rotation of the elements of object around the axis # @param theObject object which elements should be sweeped. @@ -3588,9 +3641,9 @@ class Mesh: # @ingroup l2_modif_extrurev def RotationSweepObject1D(self, theObject, Axis, AngleInRadians, NbOfSteps, Tolerance, MakeGroups=False, TotalAngle=False): - if ( isinstance( theObject, Mesh )): + if isinstance( theObject, Mesh ): theObject = theObject.GetMesh() - if ( isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object): Axis = self.smeshpyD.GetAxisStruct(Axis) AngleInRadians,AngleParameters,hasVars = ParseAngles(AngleInRadians) NbOfSteps,Tolerance,Parameters,hasVars = ParseParameters(NbOfSteps,Tolerance) @@ -3598,11 +3651,8 @@ class Mesh: self.mesh.SetParameters(Parameters) if TotalAngle and NbOfSteps: AngleInRadians /= NbOfSteps - if MakeGroups: - return self.editor.RotationSweepObject1DMakeGroups(theObject, Axis, AngleInRadians, - NbOfSteps, Tolerance) - self.editor.RotationSweepObject1D(theObject, Axis, AngleInRadians, NbOfSteps, Tolerance) - return [] + return self.editor.RotationSweepObjects([],[theObject],[], Axis, + AngleInRadians, NbOfSteps, Tolerance) ## Generates new elements by rotation of the elements of object around the axis # @param theObject object which elements should be sweeped. @@ -3618,9 +3668,9 @@ class Mesh: # @ingroup l2_modif_extrurev def RotationSweepObject2D(self, theObject, Axis, AngleInRadians, NbOfSteps, Tolerance, MakeGroups=False, TotalAngle=False): - if ( isinstance( theObject, Mesh )): + if isinstance( theObject, Mesh ): theObject = theObject.GetMesh() - if ( isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( Axis, geomBuilder.GEOM._objref_GEOM_Object): Axis = self.smeshpyD.GetAxisStruct(Axis) AngleInRadians,AngleParameters,hasVars = ParseAngles(AngleInRadians) NbOfSteps,Tolerance,Parameters,hasVars = ParseParameters(NbOfSteps,Tolerance) @@ -3628,72 +3678,72 @@ class Mesh: self.mesh.SetParameters(Parameters) if TotalAngle and NbOfSteps: AngleInRadians /= NbOfSteps - if MakeGroups: - return self.editor.RotationSweepObject2DMakeGroups(theObject, Axis, AngleInRadians, - NbOfSteps, Tolerance) - self.editor.RotationSweepObject2D(theObject, Axis, AngleInRadians, NbOfSteps, Tolerance) - return [] + return self.editor.RotationSweepObjects([],[],[theObject], Axis, AngleInRadians, + NbOfSteps, Tolerance) - ## Generates new elements by extrusion of the elements with given ids - # @param IDsOfElements the list of elements ids for extrusion + ## Generates new elements by extrusion of the given elements and nodes + # @param nodes - nodes to extrude: a list including ids, groups, sub-meshes or a mesh + # @param edges - edges to extrude: a list including ids, groups, sub-meshes or a mesh + # @param faces - faces to extrude: a list including ids, groups, sub-meshes or a mesh # @param StepVector vector or DirStruct or 3 vector components, defining # the direction and value of extrusion for one step (the total extrusion # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param MakeGroups forces the generation of new groups from existing ones - # @param IsNodes is True if elements with given ids are nodes # @return the list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev - def ExtrusionSweep(self, IDsOfElements, StepVector, NbOfSteps, MakeGroups=False, IsNodes = False): - if IDsOfElements == []: - IDsOfElements = self.GetElementsId() + def ExtrusionSweepObjects(self, nodes, edges, faces, StepVector, NbOfSteps, MakeGroups=False): + unRegister = genObjUnRegister() + nodes = self._getIdSourceList( nodes, SMESH.NODE, unRegister ) + edges = self._getIdSourceList( edges, SMESH.EDGE, unRegister ) + faces = self._getIdSourceList( faces, SMESH.FACE, unRegister ) + if isinstance( StepVector, geomBuilder.GEOM._objref_GEOM_Object): StepVector = self.smeshpyD.GetDirStruct(StepVector) if isinstance( StepVector, list ): StepVector = self.smeshpyD.MakeDirStruct(*StepVector) + NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) - if MakeGroups: - if(IsNodes): - return self.editor.ExtrusionSweepMakeGroups0D(IDsOfElements, StepVector, NbOfSteps) - else: - return self.editor.ExtrusionSweepMakeGroups(IDsOfElements, StepVector, NbOfSteps) - if(IsNodes): - self.editor.ExtrusionSweep0D(IDsOfElements, StepVector, NbOfSteps) - else: - self.editor.ExtrusionSweep(IDsOfElements, StepVector, NbOfSteps) - return [] + + return self.editor.ExtrusionSweepObjects( nodes, edges, faces, StepVector, NbOfSteps, MakeGroups) + ## Generates new elements by extrusion of the elements with given ids - # @param IDsOfElements is ids of elements + # @param IDsOfElements the list of elements ids for extrusion # @param StepVector vector or DirStruct or 3 vector components, defining # the direction and value of extrusion for one step (the total extrusion # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps - # @param ExtrFlags sets flags for extrusion - # @param SewTolerance uses for comparing locations of nodes if flag - # EXTRUSION_FLAG_SEW is set # @param MakeGroups forces the generation of new groups from existing ones - # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise + # @param IsNodes is True if elements with given ids are nodes + # @return the list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev - def AdvancedExtrusion(self, IDsOfElements, StepVector, NbOfSteps, - ExtrFlags, SewTolerance, MakeGroups=False): - if ( isinstance( StepVector, geomBuilder.GEOM._objref_GEOM_Object)): + def ExtrusionSweep(self, IDsOfElements, StepVector, NbOfSteps, MakeGroups=False, IsNodes = False): + if IDsOfElements == []: + IDsOfElements = self.mesh + unRegister = genObjUnRegister() + if IDsOfElements and \ + isinstance( IDsOfElements, list ) and \ + isinstance( IDsOfElements[0], int ): + IDsOfElements = self.GetIDSource( IDsOfElements, SMESH.ALL ) + unRegister.set( IDsOfElements ) + if isinstance( StepVector, geomBuilder.GEOM._objref_GEOM_Object): StepVector = self.smeshpyD.GetDirStruct(StepVector) if isinstance( StepVector, list ): StepVector = self.smeshpyD.MakeDirStruct(*StepVector) - if MakeGroups: - return self.editor.AdvancedExtrusionMakeGroups(IDsOfElements, StepVector, NbOfSteps, - ExtrFlags, SewTolerance) - self.editor.AdvancedExtrusion(IDsOfElements, StepVector, NbOfSteps, - ExtrFlags, SewTolerance) - return [] + NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) + Parameters = StepVector.PS.parameters + var_separator + Parameters + self.mesh.SetParameters(Parameters) + n,e,f = [],[],[] + if IsNodes: n = [IDsOfElements] + else : e,f, = [IDsOfElements],[IDsOfElements] + return self.editor.ExtrusionSweepObjects(n,e,f, StepVector, NbOfSteps, MakeGroups) ## Generates new elements by extrusion along the normal to a discretized surface or wire - # @param Elements container of elements to extrude; - # it can be Mesh, Group, Sub-mesh, Filter or list of IDs; - # Only faces can be extruded so far. Sub-mesh sould be a sub-mesh on geom faces. + # @param Elements elements to extrude - a list including ids, groups, sub-meshes or a mesh + # Only faces can be extruded so far. Sub-mesh should be a sub-mesh on geom faces. # @param StepSize length of one extrusion step (the total extrusion # length will be \a NbOfSteps * \a StepSize ). # @param NbOfSteps number of extrusion steps. @@ -3715,14 +3765,15 @@ class Mesh: ByAverageNormal=False, UseInputElemsOnly=True, MakeGroups=False, Dim = 2): unRegister = genObjUnRegister() if isinstance( Elements, Mesh ): - Elements = Elements.GetMesh() + Elements = [ Elements.GetMesh() ] if isinstance( Elements, list ): if not Elements: - raise RuntimeError, "List of element IDs is empty!" - if not isinstance( Elements[0], int ): - raise RuntimeError, "List must contain element IDs and not %s"% Elements[0] - Elements = self.GetIDSource( Elements, SMESH.ALL ) - unRegister.set( Elements ) + raise RuntimeError, "Elements empty!" + if isinstance( Elements[0], int ): + Elements = self.GetIDSource( Elements, SMESH.ALL ) + unRegister.set( Elements ) + else: + Elements = [ Elements ] StepSize,NbOfSteps,Parameters,hasVars = ParseParameters(StepSize,NbOfSteps) self.mesh.SetParameters(Parameters) return self.editor.ExtrusionByNormal(Elements, StepSize, NbOfSteps, @@ -3736,29 +3787,23 @@ class Mesh: # length will be NbOfSteps * ||StepVector||) # @param NbOfSteps the number of steps # @param MakeGroups forces the generation of new groups from existing ones - # @param IsNodes is True if elements which belong to the object are nodes + # @param IsNodes is True if elements to extrude are nodes # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev def ExtrusionSweepObject(self, theObject, StepVector, NbOfSteps, MakeGroups=False, IsNodes=False): - if ( isinstance( theObject, Mesh )): + if isinstance( theObject, Mesh ): theObject = theObject.GetMesh() - if ( isinstance( StepVector, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( StepVector, geomBuilder.GEOM._objref_GEOM_Object): StepVector = self.smeshpyD.GetDirStruct(StepVector) if isinstance( StepVector, list ): StepVector = self.smeshpyD.MakeDirStruct(*StepVector) NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) - if MakeGroups: - if(IsNodes): - return self.editor.ExtrusionSweepObject0DMakeGroups(theObject, StepVector, NbOfSteps) - else: - return self.editor.ExtrusionSweepObjectMakeGroups(theObject, StepVector, NbOfSteps) - if(IsNodes): - self.editor.ExtrusionSweepObject0D(theObject, StepVector, NbOfSteps) - else: - self.editor.ExtrusionSweepObject(theObject, StepVector, NbOfSteps) - return [] + n,e,f = [],[],[] + if IsNodes: n = [theObject] + else : e,f, = [theObject],[theObject] + return self.editor.ExtrusionSweepObjects(n,e,f, StepVector, NbOfSteps, MakeGroups) ## Generates new elements by extrusion of the elements which belong to the object # @param theObject object which elements should be processed. @@ -3780,10 +3825,8 @@ class Mesh: NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) - if MakeGroups: - return self.editor.ExtrusionSweepObject1DMakeGroups(theObject, StepVector, NbOfSteps) - self.editor.ExtrusionSweepObject1D(theObject, StepVector, NbOfSteps) - return [] + return self.editor.ExtrusionSweepObjects([],[theObject],[], + StepVector, NbOfSteps, MakeGroups) ## Generates new elements by extrusion of the elements which belong to the object # @param theObject object which elements should be processed. @@ -3805,12 +3848,72 @@ class Mesh: NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) Parameters = StepVector.PS.parameters + var_separator + Parameters self.mesh.SetParameters(Parameters) - if MakeGroups: - return self.editor.ExtrusionSweepObject2DMakeGroups(theObject, StepVector, NbOfSteps) - self.editor.ExtrusionSweepObject2D(theObject, StepVector, NbOfSteps) - return [] + return self.editor.ExtrusionSweepObjects([],[],[theObject], + StepVector, NbOfSteps, MakeGroups) + ## Generates new elements by extrusion of the elements with given ids + # @param IDsOfElements is ids of elements + # @param StepVector vector or DirStruct or 3 vector components, defining + # the direction and value of extrusion for one step (the total extrusion + # length will be NbOfSteps * ||StepVector||) + # @param NbOfSteps the number of steps + # @param ExtrFlags sets flags for extrusion + # @param SewTolerance uses for comparing locations of nodes if flag + # EXTRUSION_FLAG_SEW is set + # @param MakeGroups forces the generation of new groups from existing ones + # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise + # @ingroup l2_modif_extrurev + def AdvancedExtrusion(self, IDsOfElements, StepVector, NbOfSteps, + ExtrFlags, SewTolerance, MakeGroups=False): + if isinstance( StepVector, geomBuilder.GEOM._objref_GEOM_Object): + StepVector = self.smeshpyD.GetDirStruct(StepVector) + if isinstance( StepVector, list ): + StepVector = self.smeshpyD.MakeDirStruct(*StepVector) + return self.editor.AdvancedExtrusion(IDsOfElements, StepVector, NbOfSteps, + ExtrFlags, SewTolerance, MakeGroups) + + ## Generates new elements by extrusion of the given elements and nodes along the path. + # The path of extrusion must be a meshed edge. + # @param Nodes nodes to extrude: a list including ids, groups, sub-meshes or a mesh + # @param Edges edges to extrude: a list including ids, groups, sub-meshes or a mesh + # @param Faces faces to extrude: a list including ids, groups, sub-meshes or a mesh + # @param PathMesh 1D mesh or 1D sub-mesh, along which proceeds the extrusion + # @param PathShape shape (edge) defines the sub-mesh of PathMesh if PathMesh + # contains not only path segments, else it can be None + # @param NodeStart the first or the last node on the path. Defines the direction of extrusion + # @param HasAngles allows the shape to be rotated around the path + # to get the resulting mesh in a helical fashion + # @param Angles list of angles + # @param HasRefPoint allows using the reference point + # @param RefPoint the point around which the shape is rotated (the mass center of the + # shape by default). The User can specify any point as the Reference Point. + # @param MakeGroups forces the generation of new groups from existing ones + # @param LinearVariation forces the computation of rotation angles as linear + # variation of the given Angles along path steps + # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error + # @ingroup l2_modif_extrurev + def ExtrusionAlongPathObjects(self, Nodes, Edges, Faces, PathMesh, PathShape=None, + NodeStart=1, HasAngles=False, Angles=[], + HasRefPoint=False, RefPoint=[0,0,0], + MakeGroups=False, LinearVariation=False): + unRegister = genObjUnRegister() + Nodes = self._getIdSourceList( Nodes, SMESH.NODE, unRegister ) + Edges = self._getIdSourceList( Edges, SMESH.EDGE, unRegister ) + Faces = self._getIdSourceList( Faces, SMESH.FACE, unRegister ) + if isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object): + RefPoint = self.smeshpyD.GetPointStruct(RefPoint) + if isinstance( RefPoint, list ): + RefPoint = SMESH.PointStruct( *RefPoint ) + if isinstance( PathMesh, Mesh ): + PathMesh = PathMesh.GetMesh() + Angles,AnglesParameters,hasVars = ParseAngles(Angles) + Parameters = AnglesParameters + var_separator + RefPoint.parameters + self.mesh.SetParameters(Parameters) + return self.editor.ExtrusionAlongPathObjects(Nodes, Edges, Faces, + PathMesh, PathShape, NodeStart, + HasAngles, Angles, LinearVariation, + HasRefPoint, RefPoint, MakeGroups) ## Generates new elements by extrusion of the given elements # The path of extrusion must be a meshed edge. @@ -3845,23 +3948,30 @@ class Mesh: Parameters = AnglesParameters + var_separator + RefPoint.parameters self.mesh.SetParameters(Parameters) - if (isinstance(Path, Mesh)): Path = Path.GetMesh() + if isinstance(Path, Mesh): Path = Path.GetMesh() + unRegister = genObjUnRegister() if isinstance(Base, list): - IDsOfElements = [] - if Base == []: IDsOfElements = self.GetElementsId() - else: IDsOfElements = Base - return self.editor.ExtrusionAlongPathX(IDsOfElements, Path, NodeStart, - HasAngles, Angles, LinearVariation, - HasRefPoint, RefPoint, MakeGroups, ElemType) + if Base: + Base = self.GetIDSource( Base, ElemType ) + unRegister.set( Base ) + else: + Base = self.mesh else: - if isinstance(Base, Mesh): Base = Base.GetMesh() - if isinstance(Base, SMESH._objref_SMESH_Mesh) or isinstance(Base, SMESH._objref_SMESH_Group) or isinstance(Base, SMESH._objref_SMESH_subMesh): - return self.editor.ExtrusionAlongPathObjX(Base, Path, NodeStart, + if isinstance(Base, Mesh): + Base = Base.GetMesh() + if isinstance(Base, SMESH._objref_SMESH_IDSource): + n,e,f = [],[],[] + if ElemType == SMESH.NODE: n = [Base] + if ElemType == SMESH.EDGE: e = [Base] + if ElemType == SMESH.FACE: f = [Base] + gr,er = self.editor.ExtrusionAlongPathObjects(n,e,f, Path, None, NodeStart, HasAngles, Angles, LinearVariation, - HasRefPoint, RefPoint, MakeGroups, ElemType) - else: - raise RuntimeError, "Invalid Base for ExtrusionAlongPathX" + HasRefPoint, RefPoint, MakeGroups) + if MakeGroups: return gr,er + return er + else: + raise RuntimeError, "Invalid Base for ExtrusionAlongPathX" ## Generates new elements by extrusion of the given elements @@ -3887,28 +3997,26 @@ class Mesh: MakeGroups=False, LinearVariation=False): if IDsOfElements == []: IDsOfElements = self.GetElementsId() - if ( isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object): RefPoint = self.smeshpyD.GetPointStruct(RefPoint) pass - if ( isinstance( PathMesh, Mesh )): + if isinstance( PathMesh, Mesh ): PathMesh = PathMesh.GetMesh() Angles,AnglesParameters,hasVars = ParseAngles(Angles) Parameters = AnglesParameters + var_separator + RefPoint.parameters self.mesh.SetParameters(Parameters) - if HasAngles and Angles and LinearVariation: - Angles = self.editor.LinearAnglesVariation( PathMesh, PathShape, Angles ) - pass - if MakeGroups: - return self.editor.ExtrusionAlongPathMakeGroups(IDsOfElements, PathMesh, - PathShape, NodeStart, HasAngles, - Angles, HasRefPoint, RefPoint) - return self.editor.ExtrusionAlongPath(IDsOfElements, PathMesh, PathShape, - NodeStart, HasAngles, Angles, HasRefPoint, RefPoint) + n,e,f = [],[IDsOfElements],[IDsOfElements] + gr,er = self.editor.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, + NodeStart, HasAngles, Angles, + LinearVariation, + HasRefPoint, RefPoint, MakeGroups) + if MakeGroups: return gr,er + return er ## Generates new elements by extrusion of the elements which belong to the object # The path of extrusion must be a meshed edge. # @param theObject the object which elements should be processed. - # It can be a mesh, a sub mesh or a group. + # It can be a mesh, a sub-mesh or a group. # @param PathMesh mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds # @param PathShape shape(edge) defines the sub-mesh for the path # @param NodeStart the first or the last node on the edge. Defines the direction of extrusion @@ -3927,25 +4035,21 @@ class Mesh: def ExtrusionAlongPathObject(self, theObject, PathMesh, PathShape, NodeStart, HasAngles, Angles, HasRefPoint, RefPoint, MakeGroups=False, LinearVariation=False): - if ( isinstance( theObject, Mesh )): + if isinstance( theObject, Mesh ): theObject = theObject.GetMesh() - if ( isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object): RefPoint = self.smeshpyD.GetPointStruct(RefPoint) - if ( isinstance( PathMesh, Mesh )): + if isinstance( PathMesh, Mesh ): PathMesh = PathMesh.GetMesh() Angles,AnglesParameters,hasVars = ParseAngles(Angles) Parameters = AnglesParameters + var_separator + RefPoint.parameters self.mesh.SetParameters(Parameters) - if HasAngles and Angles and LinearVariation: - Angles = self.editor.LinearAnglesVariation( PathMesh, PathShape, Angles ) - pass - if MakeGroups: - return self.editor.ExtrusionAlongPathObjectMakeGroups(theObject, PathMesh, - PathShape, NodeStart, HasAngles, - Angles, HasRefPoint, RefPoint) - return self.editor.ExtrusionAlongPathObject(theObject, PathMesh, PathShape, - NodeStart, HasAngles, Angles, HasRefPoint, - RefPoint) + n,e,f = [],[theObject],[theObject] + gr,er = self.editor.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart, + HasAngles, Angles, LinearVariation, + HasRefPoint, RefPoint, MakeGroups) + if MakeGroups: return gr,er + return er ## Generates new elements by extrusion of the elements which belong to the object # The path of extrusion must be a meshed edge. @@ -3969,25 +4073,21 @@ class Mesh: def ExtrusionAlongPathObject1D(self, theObject, PathMesh, PathShape, NodeStart, HasAngles, Angles, HasRefPoint, RefPoint, MakeGroups=False, LinearVariation=False): - if ( isinstance( theObject, Mesh )): + if isinstance( theObject, Mesh ): theObject = theObject.GetMesh() - if ( isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object)): + if isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object): RefPoint = self.smeshpyD.GetPointStruct(RefPoint) - if ( isinstance( PathMesh, Mesh )): + if isinstance( PathMesh, Mesh ): PathMesh = PathMesh.GetMesh() Angles,AnglesParameters,hasVars = ParseAngles(Angles) Parameters = AnglesParameters + var_separator + RefPoint.parameters self.mesh.SetParameters(Parameters) - if HasAngles and Angles and LinearVariation: - Angles = self.editor.LinearAnglesVariation( PathMesh, PathShape, Angles ) - pass - if MakeGroups: - return self.editor.ExtrusionAlongPathObject1DMakeGroups(theObject, PathMesh, - PathShape, NodeStart, HasAngles, - Angles, HasRefPoint, RefPoint) - return self.editor.ExtrusionAlongPathObject1D(theObject, PathMesh, PathShape, - NodeStart, HasAngles, Angles, HasRefPoint, - RefPoint) + n,e,f = [],[theObject],[] + gr,er = self.editor.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart, + HasAngles, Angles, LinearVariation, + HasRefPoint, RefPoint, MakeGroups) + if MakeGroups: return gr,er + return er ## Generates new elements by extrusion of the elements which belong to the object # The path of extrusion must be a meshed edge. @@ -4020,16 +4120,12 @@ class Mesh: Angles,AnglesParameters,hasVars = ParseAngles(Angles) Parameters = AnglesParameters + var_separator + RefPoint.parameters self.mesh.SetParameters(Parameters) - if HasAngles and Angles and LinearVariation: - Angles = self.editor.LinearAnglesVariation( PathMesh, PathShape, Angles ) - pass - if MakeGroups: - return self.editor.ExtrusionAlongPathObject2DMakeGroups(theObject, PathMesh, - PathShape, NodeStart, HasAngles, - Angles, HasRefPoint, RefPoint) - return self.editor.ExtrusionAlongPathObject2D(theObject, PathMesh, PathShape, - NodeStart, HasAngles, Angles, HasRefPoint, - RefPoint) + n,e,f = [],[],[theObject] + gr,er = self.editor.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart, + HasAngles, Angles, LinearVariation, + HasRefPoint, RefPoint, MakeGroups) + if MakeGroups: return gr,er + return er ## Creates a symmetrical copy of mesh elements # @param IDsOfElements list of elements ids @@ -4360,7 +4456,9 @@ class Mesh: return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,exceptNodes) ## Merges nodes - # @param GroupsOfNodes a list of pairs of nodes IDs for merging (e.g. [[1,12],[25,4]]) + # @param GroupsOfNodes a list of pairs of nodes IDs for merging + # (e.g. [[1,12],[25,4]], then nodes 12 and 4 will be removed and replaced + # by nodes 1 and 25 correspondingly in all elements and groups # @ingroup l2_modif_trsf def MergeNodes (self, GroupsOfNodes): self.editor.MergeNodes(GroupsOfNodes) @@ -4369,13 +4467,17 @@ class Mesh: # @param MeshOrSubMeshOrGroup Mesh or SubMesh, or Group of elements for searching # @return the list of pairs of equal elements IDs (e.g. [[1,12],[25,4]]) # @ingroup l2_modif_trsf - def FindEqualElements (self, MeshOrSubMeshOrGroup): - if ( isinstance( MeshOrSubMeshOrGroup, Mesh )): + def FindEqualElements (self, MeshOrSubMeshOrGroup=None): + if not MeshOrSubMeshOrGroup: + MeshOrSubMeshOrGroup=self.mesh + elif isinstance( MeshOrSubMeshOrGroup, Mesh ): MeshOrSubMeshOrGroup = MeshOrSubMeshOrGroup.GetMesh() - return self.editor.FindEqualElements(MeshOrSubMeshOrGroup) + return self.editor.FindEqualElements( MeshOrSubMeshOrGroup ) ## Merges elements in each given group. - # @param GroupsOfElementsID a list of pairs of elements IDs for merging (e.g. [[1,12],[25,4]]) + # @param GroupsOfElementsID a list of pairs of elements IDs for merging + # (e.g. [[1,12],[25,4]], then elements 12 and 4 will be removed and + # replaced by elements 1 and 25 in all groups) # @ingroup l2_modif_trsf def MergeElements(self, GroupsOfElementsID): self.editor.MergeElements(GroupsOfElementsID) -- 2.30.2