From: eap Date: Thu, 9 Jul 2015 09:41:53 +0000 (+0300) Subject: 23072: [CEA 1500] Split biquadratic elements into linear elements X-Git-Tag: V7_7_0a1~26 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=38f832b912a159ca9d43b5bd031344fd7108a6d8;p=modules%2Fsmesh.git 23072: [CEA 1500] Split biquadratic elements into linear elements --- diff --git a/doc/salome/examples/CMakeLists.txt b/doc/salome/examples/CMakeLists.txt index 7ee8ff5fd..65d8e52e2 100644 --- a/doc/salome/examples/CMakeLists.txt +++ b/doc/salome/examples/CMakeLists.txt @@ -165,6 +165,7 @@ SET(GOOD_TESTS transforming_meshes_ex13.py use_existing_faces.py viewing_meshes_ex02.py + split_biquad.py ) SET(EXAMPLES_TESTS ${BAD_TESTS} ${GOOD_TESTS} testme.py) diff --git a/doc/salome/examples/split_biquad.py b/doc/salome/examples/split_biquad.py new file mode 100644 index 000000000..e53e7b0b1 --- /dev/null +++ b/doc/salome/examples/split_biquad.py @@ -0,0 +1,37 @@ +# Split bi-quadratic to linear + +import salome +salome.salome_init() + +from salome.geom import geomBuilder +geompy = geomBuilder.New(salome.myStudy) + +from salome.smesh import smeshBuilder +smesh = smeshBuilder.New(salome.myStudy) + +# make a shape consisting of two quadranges +OY = geompy.MakeVectorDXDYDZ(0, 1, 0) +OY1 = geompy.MakeTranslation( OY, 1, 0, 0 ) +OY2 = geompy.MakeTranslation( OY, 2, 0, 0 ) +q1 = geompy.MakeQuad2Edges( OY, OY1 ) +q2 = geompy.MakeQuad2Edges( OY1, OY2 ) + +shape = geompy.Partition( [q1,q2], theName='shape' ) +ff = geompy.SubShapeAll( shape, geompy.ShapeType["FACE"], theName="quad" ) + +# mesh one quadrange with quadrangless and the other with triangles +mesh = smesh.Mesh( shape ) +mesh.Segment().NumberOfSegments(1) +mesh.Quadrangle() +mesh.Triangle( ff[1] ) +mesh.Compute() + +# make group of quadrangles and extrude them into a hexahedron +quadGroup = mesh.Group( ff[0], "quads") +mesh.ExtrusionSweepObject2D( quadGroup, [0,0,1], 1 ) + +# make the mesh bi-quadratic +mesh.ConvertToQuadratic( theToBiQuad=True ) + +# split all elements into linear ones +mesh.SplitBiQuadraticIntoLinear() diff --git a/doc/salome/examples/transforming_meshes_ex01.py b/doc/salome/examples/transforming_meshes_ex01.py index dc61324ec..93f5196c0 100644 --- a/doc/salome/examples/transforming_meshes_ex01.py +++ b/doc/salome/examples/transforming_meshes_ex01.py @@ -1,16 +1,11 @@ # Translation import SMESH_mechanic -import SMESH -smesh = SMESH_mechanic.smesh mesh = SMESH_mechanic.mesh # define translation vector -point = SMESH.PointStruct(-150., -150., 0.) -vector =SMESH.DirStruct(point) +vector = [-150., -150., 0.] -# translate a mesh -doCopy = 1 - -mesh.Translate([], vector, doCopy) +# make a translated copy of all elements of the mesh +mesh.TranslateObject(mesh, vector, Copy=True) diff --git a/doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png b/doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png new file mode 100644 index 000000000..c3df00902 Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png differ diff --git a/doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png b/doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png new file mode 100644 index 000000000..0b9b7a038 Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png differ diff --git a/doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png b/doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png new file mode 100644 index 000000000..4a25e8f32 Binary files /dev/null and b/doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png differ diff --git a/doc/salome/gui/SMESH/input/convert_to_from_quadratic_mesh.doc b/doc/salome/gui/SMESH/input/convert_to_from_quadratic_mesh.doc index a8ad620b5..a253c0523 100644 --- a/doc/salome/gui/SMESH/input/convert_to_from_quadratic_mesh.doc +++ b/doc/salome/gui/SMESH/input/convert_to_from_quadratic_mesh.doc @@ -51,7 +51,7 @@ The following dialog box will appear:
Quadratic mesh
-
  • Click the \b Apply or \b OK button.
  • +
  • Click the \b Apply or Apply and Close button.

  • See Also a sample TUI Script of a \ref tui_quadratic "Convert to/from quadratic" operation. diff --git a/doc/salome/gui/SMESH/input/modifying_meshes.doc b/doc/salome/gui/SMESH/input/modifying_meshes.doc index 94002fad5..3490916bc 100644 --- a/doc/salome/gui/SMESH/input/modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/modifying_meshes.doc @@ -43,6 +43,8 @@ transformation operations, giving the possibility to: triangles.
  • \subpage split_to_tetra_page "Split" volumic elements into tetrahedra or prisms.
  • +
  • \subpage split_biquad_to_linear_page "Split bi-quadratic" elements + into linear ones without creation of additional nodes.
  • \subpage smoothing_page "Smooth" elements, reducung distortions in them by adjusting the locations of nodes.
  • Create an \subpage extrusion_page "extrusion" along a vector or by diff --git a/doc/salome/gui/SMESH/input/split_biquad_to_linear.doc b/doc/salome/gui/SMESH/input/split_biquad_to_linear.doc new file mode 100644 index 000000000..85002f949 --- /dev/null +++ b/doc/salome/gui/SMESH/input/split_biquad_to_linear.doc @@ -0,0 +1,37 @@ +/*! + +\page split_biquad_to_linear_page Split bi-quadratic into linear + +\n This functionality allows to split bi-quadratic elements into +linear ones without creation of additional nodes. + +So that +- bi-quadratic triangle will be split into 3 linear quadrangles; +- bi-quadratic quadrangle will be split into 4 linear quadrangles; +- tri-quadratic hexahedron will be split into 8 linear hexahedra; +- quadratic segments adjacent to the split bi-quadratic element will + be split into 2 liner segment. + +\image html split_biquad_to_linear_mesh.png "Mesh before and after splitting" + +To split bi-quadratic elements into linear: +
      +
    1. From the \b Modification menu choose the Split bi-quadratic into linear item or +click "Split bi-quadratic into linear" button in the toolbar. + +\image html split_biquad_to_linear_icon.png +
      "Split bi-quadratic into linear" button
      + +The following dialog box shall appear: + +\image html split_biquad_to_linear_dlg.png + +
    2. +
    3. Select a mesh, groups or sub-meshes in the Object Browser or in the + Viewer.
    4. +
    5. Click the \b Apply or Apply and Close button.
    6. +
    + +
    See Also a sample TUI Script of a \ref tui_split_biquad "Split bi-quadratic into linear" operation. + +*/ diff --git a/doc/salome/gui/SMESH/input/split_to_tetra.doc b/doc/salome/gui/SMESH/input/split_to_tetra.doc index fb5c4e165..b6ee36e93 100644 --- a/doc/salome/gui/SMESH/input/split_to_tetra.doc +++ b/doc/salome/gui/SMESH/input/split_to_tetra.doc @@ -7,7 +7,7 @@ tetrahedra or hexahedra into prisms. 2D mesh is modified accordingly. To split volumes:
      -
    1. Display a mesh, a sub-mesh or a group in the 3D viewer.
    2. +
    3. Select a mesh, a sub-mesh or a group.
    4. In the \b Modification menu select the Split Volumes item or click "Split Volumes" button in the toolbar. diff --git a/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc b/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc index 7ceb5ebf7..107306547 100644 --- a/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc +++ b/doc/salome/gui/SMESH/input/tui_modifying_meshes.doc @@ -140,4 +140,9 @@

      Convert mesh to/from quadratic

      \tui_script{modifying_meshes_ex26.py} +
      +\anchor tui_split_biquad +

      Split bi-quadratic into linear

      +\tui_script{split_biquad.py} + */ diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 0b4321172..509e9ed8c 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -360,13 +360,25 @@ module SMESH * to \a facetToSplitNormal location are split, else \a facetToSplitNormal * is used to find the facet to split in all domains present in \a elems. */ - void SplitHexahedraIntoPrisms(in SMESH_IDSource elems, + void SplitHexahedraIntoPrisms(in SMESH_IDSource elems, in SMESH::PointStruct startHexPoint, in SMESH::DirStruct facetToSplitNormal, in short methodFlags, in boolean allDomains) raises (SALOME::SALOME_Exception); + /*! + * \brief Split bi-quadratic elements into linear ones without creation of additional nodes. + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ + void SplitBiQuadraticIntoLinear(in ListOfIDSources elems) + raises (SALOME::SALOME_Exception); + enum Smooth_Method { LAPLACIAN_SMOOTH, CENTROIDAL_SMOOTH }; diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 421d99888..66f426f00 100755 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -203,6 +203,7 @@ SET(SMESH_RESOURCES_FILES scale.png scale_along_axes.png split_into_tetra.png + split_biquad.png mesh_duplicate_nodes.png mesh_duplicate_nodes_with_elem.png mesh_duplicate_elem_only.png diff --git a/resources/split_biquad.png b/resources/split_biquad.png new file mode 100644 index 000000000..0b9b7a038 Binary files /dev/null and b/resources/split_biquad.png differ diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index fc945c44e..54233ac96 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -2239,6 +2239,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, // map face of volume to it's baricenrtic node map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; double bc[3]; + vector splitVols; TFacetOfElem::const_iterator elem2facet = theElems.begin(); for ( ; elem2facet != theElems.end(); ++elem2facet ) @@ -2314,7 +2315,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, } // make new volumes - vector splitVols( splitMethod._nbSplits ); // splits of a volume + splitVols.resize( splitMethod._nbSplits ); // splits of a volume const int* volConn = splitMethod._connectivity; if ( splitMethod._nbCorners == 4 ) // tetra for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners ) @@ -2619,7 +2620,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, startHex = curHex; - // find a facet of startHex to split + // find a facet of startHex to split set lateralNodes; vTool.GetFaceNodes( lateralFacet, lateralNodes ); @@ -2649,6 +2650,188 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found"); } } // while ( startHex ) + + return; +} + +namespace +{ + //================================================================================ + /*! + * \brief Selects nodes of several elements according to a given interlace + * \param [in] srcNodes - nodes to select from + * \param [out] tgtNodesVec - array of nodes of several elements to fill in + * \param [in] interlace - indices of nodes for all elements + * \param [in] nbElems - nb of elements + * \param [in] nbNodes - nb of nodes in each element + * \param [in] mesh - the mesh + * \param [out] elemQueue - a list to push elements found by the selected nodes + * \param [in] type - type of elements to look for + */ + //================================================================================ + + void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes, + vector< const SMDS_MeshNode* >* tgtNodesVec, + const int* interlace, + const int nbElems, + const int nbNodes, + SMESHDS_Mesh* mesh = 0, + list< const SMDS_MeshElement* >* elemQueue=0, + SMDSAbs_ElementType type=SMDSAbs_All) + { + for ( int iE = 0; iE < nbElems; ++iE ) + { + vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE]; + const int* select = & interlace[iE*nbNodes]; + elemNodes.resize( nbNodes ); + for ( int iN = 0; iN < nbNodes; ++iN ) + elemNodes[iN] = srcNodes[ select[ iN ]]; + } + const SMDS_MeshElement* e; + if ( elemQueue ) + for ( int iE = 0; iE < nbElems; ++iE ) + if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false))) + elemQueue->push_back( e ); + } +} + +//======================================================================= +/* + * Split bi-quadratic elements into linear ones without creation of additional nodes + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ +//======================================================================= + +void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems) +{ + vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8]; + vector splitElems; + list< const SMDS_MeshElement* > elemQueue; + list< const SMDS_MeshElement* >::iterator elemIt; + + SMESHDS_Mesh * mesh = GetMeshDS(); + ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge); + int nbElems, nbNodes; + + TIDSortedElemSet::iterator elemSetIt = theElems.begin(); + for ( ; elemSetIt != theElems.end(); ++elemSetIt ) + { + elemQueue.clear(); + elemQueue.push_back( *elemSetIt ); + for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt ) + { + const SMDS_MeshElement* elem = *elemIt; + switch( elem->GetEntityType() ) + { + case SMDSEntity_TriQuad_Hexa: // HEX27 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = nbNodes = 8; + elemType = & hexaType; + + // get nodes for new elements + static int vInd[8][8] = {{ 0,8,20,11, 16,21,26,24 }, + { 1,9,20,8, 17,22,26,21 }, + { 2,10,20,9, 18,23,26,22 }, + { 3,11,20,10, 19,24,26,23 }, + { 16,21,26,24, 4,12,25,15 }, + { 17,22,26,21, 5,13,25,12 }, + { 18,23,26,22, 6,14,25,13 }, + { 19,24,26,23, 7,15,25,14 }}; + selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes ); + + // add boundary faces to elemQueue + static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11, 20 }, + { 4,5,6,7, 12,13,14,15, 25 }, + { 0,1,5,4, 8,17,12,16, 21 }, + { 1,2,6,5, 9,18,13,17, 22 }, + { 2,3,7,6, 10,19,14,18, 23 }, + { 3,0,4,7, 11,16,15,19, 24 }}; + selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face ); + + // add boundary segments to elemQueue + static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 }, + { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 }, + { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Triangle: // TRIA7 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 3; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_BiQuad_Quadrangle: // QUAD9 + { + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 4; + nbNodes = 4; + elemType = & quadType; + + // get nodes for new elements + static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }}; + selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes ); + + // add boundary segments to elemQueue + static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }}; + selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge ); + break; + } + case SMDSEntity_Quad_Edge: + { + if ( elemIt == elemQueue.begin() ) + continue; // an elem is in theElems + elemNodes.assign( elem->begin_nodes(), elem->end_nodes() ); + nbElems = 2; + nbNodes = 2; + elemType = & segType; + + // get nodes for new elements + static int eInd[2][2] = {{ 0,2 }, { 2,1 }}; + selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes ); + break; + } + default: continue; + } // switch( elem->GetEntityType() ) + + // Create new elements + + SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() ); + + splitElems.clear(); + + //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one + mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false ); + //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType )); + //elemType->SetID( -1 ); + + for ( int iE = 0; iE < nbElems; ++iE ) + splitElems.push_back( AddElement( splitNodes[ iE ], *elemType )); + + + ReplaceElemInGroups( elem, splitElems, mesh ); + + if ( subMesh ) + for ( size_t i = 0; i < splitElems.size(); ++i ) + subMesh->AddElement( splitElems[i] ); + } + } } //======================================================================= diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index 1dbed7d99..6f75318e6 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -221,7 +221,7 @@ public: /*! * \brief For hexahedra that will be split into prisms, finds facets to - * split into triangles + * split into triangles * \param [in,out] theHexas - the hexahedra * \param [in] theFacetNormal - facet normal * \param [out] theFacets - the hexahedra and found facet IDs @@ -230,6 +230,16 @@ public: const gp_Ax1& theFacetNormal, TFacetOfElem & theFacets); + /*! + * \brief Split bi-quadratic elements into linear ones without creation of additional nodes + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra; + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ + void SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems); enum SmoothMethod { LAPLACIAN = 0, CENTROIDAL }; diff --git a/src/SMESHGUI/CMakeLists.txt b/src/SMESHGUI/CMakeLists.txt index ed8b7836e..b334baa56 100644 --- a/src/SMESHGUI/CMakeLists.txt +++ b/src/SMESHGUI/CMakeLists.txt @@ -141,6 +141,7 @@ SET(_moc_HEADERS SMESHGUI_Add0DElemsOnAllNodesDlg.h SMESHGUI_FieldSelectorWdg.h SMESHGUI_DisplayEntitiesDlg.h + SMESHGUI_SplitBiQuad.h ) # header files / no moc processing @@ -249,6 +250,7 @@ SET(_other_SOURCES SMESHGUI_FileValidator.cxx SMESHGUI_FieldSelectorWdg.cxx SMESHGUI_DisplayEntitiesDlg.cxx + SMESHGUI_SplitBiQuad.cxx ) # sources / to compile diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index 1214bf191..6271fe857 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -82,6 +82,7 @@ #include "SMESHGUI_TranslationDlg.h" #include "SMESHGUI_TransparencyDlg.h" #include "SMESHGUI_DisplayEntitiesDlg.h" +#include "SMESHGUI_SplitBiQuad.h" #include "SMESHGUI_FilterUtils.h" #include "SMESHGUI_GEOMGenUtils.h" @@ -2853,6 +2854,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) } break; } + case SMESHOp::OpSplitBiQuadratic: case SMESHOp::OpConvertMeshToQuadratic: case SMESHOp::OpCreateBoundaryElements: // create 2D mesh from 3D case SMESHOp::OpReorientFaces: @@ -3942,6 +3944,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( SMESHOp::OpUnionOfTriangles, "UNION", "ICON_UNIONTRI" ); createSMESHAction( SMESHOp::OpCuttingOfQuadrangles, "CUT", "ICON_CUTQUAD" ); createSMESHAction( SMESHOp::OpSplitVolumes, "SPLIT_TO_TETRA", "ICON_SPLIT_TO_TETRA" ); + createSMESHAction( SMESHOp::OpSplitBiQuadratic, "SPLIT_BIQUAD", "ICON_SPLIT_BIQUAD" ); createSMESHAction( SMESHOp::OpSmoothing, "SMOOTH", "ICON_DLG_SMOOTHING" ); createSMESHAction( SMESHOp::OpExtrusion, "EXTRUSION", "ICON_EXTRUSION" ); createSMESHAction( SMESHOp::OpExtrusionAlongAPath, "EXTRUSION_ALONG", "ICON_EXTRUSION_ALONG" ); @@ -4177,6 +4180,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpUnionOfTriangles, modifyId, -1 ); createMenu( SMESHOp::OpCuttingOfQuadrangles, modifyId, -1 ); createMenu( SMESHOp::OpSplitVolumes, modifyId, -1 ); + createMenu( SMESHOp::OpSplitBiQuadratic, modifyId, -1 ); createMenu( SMESHOp::OpSmoothing, modifyId, -1 ); createMenu( SMESHOp::OpExtrusion, modifyId, -1 ); createMenu( SMESHOp::OpExtrusionAlongAPath , modifyId, -1 ); @@ -4312,6 +4316,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createTool( SMESHOp::OpUnionOfTriangles, modifyTb ); createTool( SMESHOp::OpCuttingOfQuadrangles, modifyTb ); createTool( SMESHOp::OpSplitVolumes, modifyTb ); + createTool( SMESHOp::OpSplitBiQuadratic, modifyTb ); createTool( SMESHOp::OpSmoothing, modifyTb ); createTool( SMESHOp::OpExtrusion, modifyTb ); createTool( SMESHOp::OpExtrusionAlongAPath, modifyTb ); @@ -5480,6 +5485,9 @@ LightApp_Operation* SMESHGUI::createOperation( const int id ) const // to do : create operation here switch( id ) { + case SMESHOp::OpSplitBiQuadratic: + op = new SMESHGUI_SplitBiQuadOp(); + break; case SMESHOp::OpConvertMeshToQuadratic: op = new SMESHGUI_ConvToQuadOp(); break; diff --git a/src/SMESHGUI/SMESHGUI_ConvToQuadOp.cxx b/src/SMESHGUI/SMESHGUI_ConvToQuadOp.cxx index bc2629a21..cc60fc471 100644 --- a/src/SMESHGUI/SMESHGUI_ConvToQuadOp.cxx +++ b/src/SMESHGUI/SMESHGUI_ConvToQuadOp.cxx @@ -346,6 +346,7 @@ SMESHGUI_ConvToQuadOp::DestinationMesh( const SMESH::SMESH_IDSource_var& idSourc nbElemOfType[SMDSEntity_Quad_Tetra ] || nbElemOfType[SMDSEntity_Quad_Hexa ] || nbElemOfType[SMDSEntity_Quad_Pyramid ] || + nbElemOfType[SMDSEntity_Quad_Polygon ] || nbElemOfType[SMDSEntity_Quad_Penta ] ); bool hasLin = ( nbElemOfType[SMDSEntity_Edge ] || @@ -354,6 +355,7 @@ SMESHGUI_ConvToQuadOp::DestinationMesh( const SMESH::SMESH_IDSource_var& idSourc nbElemOfType[SMDSEntity_Tetra ] || nbElemOfType[SMDSEntity_Hexa ] || nbElemOfType[SMDSEntity_Pyramid ] || + nbElemOfType[SMDSEntity_Polygon ] || nbElemOfType[SMDSEntity_Penta ] ); int tgtType = 0; diff --git a/src/SMESHGUI/SMESHGUI_Operations.h b/src/SMESHGUI/SMESHGUI_Operations.h index cd28f8bd5..9f492bf17 100644 --- a/src/SMESHGUI/SMESHGUI_Operations.h +++ b/src/SMESHGUI/SMESHGUI_Operations.h @@ -176,6 +176,7 @@ namespace SMESHOp { OpPatternMapping = 4512, // MENU MODIFICATION - PATTERN MAPPING OpConvertMeshToQuadratic = 4513, // MENU MODIFICATION - CONVERT TO/FROM QUADRATIC OpCreateBoundaryElements = 4514, // MENU MODIFICATION - CREATE BOUNDARY ELEMENTS + OpSplitBiQuadratic = 4515, // MENU MODIFICATION - SPLIT BI-QUADRATIC TO LINEAR // Measurements -------------------//-------------------------------- OpPropertiesLength = 5000, // MENU MEASUREMENTS - BASIC PROPERTIES - LENGTH OpPropertiesArea = 5001, // MENU MEASUREMENTS - BASIC PROPERTIES - AREA diff --git a/src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx b/src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx new file mode 100644 index 000000000..a35f7525a --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx @@ -0,0 +1,255 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_SplitBiQuad.h +// Author : Open CASCADE S.A.S. +// + +#include "SMESHGUI_SplitBiQuad.h" + +#include "SMESHGUI.h" +#include "SMESHGUI_Utils.h" +#include "SMESH_LogicalFilter.hxx" +#include "SMESH_TypeFilter.hxx" + +#include +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) + +#include +#include +#include +#include + +#include +#include + +//================================================================================ +/*! + * \brief Dialog constructor + */ +//================================================================================ + +SMESHGUI_SplitBiQuadDlg::SMESHGUI_SplitBiQuadDlg() + : SMESHGUI_Dialog( 0, /*modal=*/false, /*allowResize=*/true ) +{ + setWindowTitle( tr( "CAPTION" ) ); + setObjectPixmap( "SMESH", tr( "ICON_SELECT" ) ); + createObject( tr( "MESH" ), mainFrame(), 0 ); + + QGridLayout* aLay = new QGridLayout( mainFrame() ); + aLay->setMargin( 5 ); + aLay->setSpacing( 5 ); + + aLay->addWidget( objectWg( 0, Label ), 0, 0 ); + //aLay->addWidget( objectWg( 0, Btn ), 0, 1 ); + aLay->addWidget( objectWg( 0, Control ), 0, 1 ); + objectWg( 0, Btn )->hide(); +} + +//================================================================================ +/*! + * \brief Dialog destructor + */ +//================================================================================ + +SMESHGUI_SplitBiQuadDlg::~SMESHGUI_SplitBiQuadDlg() +{ +} + +//================================================================================ +/*! + * \brief SMESHGUI_SplitBiQuadOp constructor + */ +//================================================================================ + +SMESHGUI_SplitBiQuadOp::SMESHGUI_SplitBiQuadOp() + : SMESHGUI_SelectionOp(), myDlg( 0 ) +{ +} + +//================================================================================ +/*! + * \brief SMESHGUI_SplitBiQuadOp destructor + */ +//================================================================================ + +SMESHGUI_SplitBiQuadOp::~SMESHGUI_SplitBiQuadOp() +{ + if ( myDlg ) delete myDlg; +} + +//================================================================================ +/*! + * \brief Gets dialog of this operation + * \retval LightApp_Dialog* - pointer to dialog of this operation +*/ +//================================================================================ + +LightApp_Dialog* SMESHGUI_SplitBiQuadOp::dlg() const +{ + return myDlg; +} + +//================================================================================ +/*! + * \brief Creates dialog if necessary and shows it + * + * Virtual method redefined from base class called when operation is started creates + * dialog if necessary and shows it, activates selection + */ +//================================================================================ + +void SMESHGUI_SplitBiQuadOp::startOperation() +{ + if( !myDlg ) + { + myDlg = new SMESHGUI_SplitBiQuadDlg(); + } + myHelpFileName = "split_biquad_to_linear_page.html"; + + SMESHGUI_SelectionOp::startOperation(); + + myDlg->activateObject( 0 ); + myDlg->show(); + + selectionDone(); +} + +//================================================================================ +/*! + * \brief Updates dialog's look and feel + * + * Virtual method redefined from the base class updates dialog's look and feel + */ +//================================================================================ + +// void SMESHGUI_SplitBiQuadOp::selectionDone() +// { +// if ( !dlg()->isVisible() ) +// return; + +// SMESHGUI_SelectionOp::selectionDone(); +// } + +//================================================================================ +/*! + * \brief Creates selection filter + * \param theId - identifier of current selection widget + * \retval SUIT_SelectionFilter* - pointer to the created filter or null + * + * Creates selection filter in accordance with identifier of current selection widget + */ +//================================================================================ + +SUIT_SelectionFilter* SMESHGUI_SplitBiQuadOp::createFilter( const int theId ) const +{ + if ( theId != 0 ) + return 0; + + QList filters; + filters << new SMESH_TypeFilter( SMESH::IDSOURCE_FACE ); + filters << new SMESH_TypeFilter( SMESH::IDSOURCE_VOLUME ); + return new SMESH_LogicalFilter( filters, + SMESH_LogicalFilter::LO_OR, + /*takeOwnership=*/true ); +} + +//================================================================================ +/*! + * \brief Edits mesh + * + * Virtual slot redefined from the base class called when "Apply" button is clicked + */ +//================================================================================ + +bool SMESHGUI_SplitBiQuadOp::onApply() +{ + SUIT_OverrideCursor aWaitCursor; + + LightApp_Dialog::SelectedObjects selection; + myDlg->objectSelection( selection ); + if ( selection.empty() || selection[0].empty() ) + { + SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("MESH_IS_NOT_SELECTED") ); + return false; + } + QStringList& entries = selection[0]; + + SMESH::SMESH_Mesh_var mesh; + SMESH::ListOfIDSources_var idSource = new SMESH::ListOfIDSources(); + idSource->length( entries.count() ); + + int nbObj = 0; + for ( int i = 0; i < entries.count() ; ++i ) + { + _PTR(SObject) pObj = studyDS()->FindObjectID( entries[i].toLatin1().data() ); + SMESH::SMESH_IDSource_var obj = SMESH::SObjectToInterface( pObj ); + if( !CORBA::is_nil( obj )) + { + idSource[ nbObj++ ] = obj; + SMESH::SMESH_Mesh_var m = obj->GetMesh(); + if ( !mesh->_is_nil() && mesh->GetId() != m->GetId() ) + { + SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("DIFFERENT_MESHES") ); + return false; + } + mesh = m; + } + } + if ( CORBA::is_nil( mesh )) + { + SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("REF_IS_NULL") ); + return false; + } + if ( nbObj == 0 ) + { + SUIT_MessageBox::warning( myDlg, tr( "SMESH_WRN_WARNING" ), tr("MESH_IS_NOT_SELECTED") ); + return false; + } + idSource->length( nbObj ); + + bool aResult = false; + + try + { + SMESH::SMESH_MeshEditor_var aEditor = mesh->GetMeshEditor(); + aResult = true; + aEditor->SplitBiQuadraticIntoLinear( idSource ); + } + catch ( const SALOME::SALOME_Exception& S_ex ) + { + SalomeApp_Tools::QtCatchCorbaException( S_ex ); + aResult = false; + } + catch ( ... ) + { + aResult = false; + } + if( aResult ) + { + SMESHGUI::Modified(); + update( UF_ObjBrowser | UF_Model | UF_Viewer ); + selectionDone(); + } + return aResult; +} diff --git a/src/SMESHGUI/SMESHGUI_SplitBiQuad.h b/src/SMESHGUI/SMESHGUI_SplitBiQuad.h new file mode 100644 index 000000000..13cbd7172 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_SplitBiQuad.h @@ -0,0 +1,72 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// SMESH SMESHGUI : GUI for SMESH component +// File : SMESHGUI_SplitBiQuad.h +// Author : Open CASCADE S.A.S. +// +#ifndef SMESHGUI_SplitBiQuad_H +#define SMESHGUI_SplitBiQuad_H + +#include "SMESH_SMESHGUI.hxx" +#include "SMESHGUI_Dialog.h" +#include "SMESHGUI_SelectionOp.h" + +class SMESHGUI_SplitBiQuadOp; + +/*! + * \brief Dialog performing SMESH_MeshEditor::SplitBiQuadraticIntoLinear() + */ +class SMESHGUI_EXPORT SMESHGUI_SplitBiQuadDlg : public SMESHGUI_Dialog +{ + Q_OBJECT + + public: + SMESHGUI_SplitBiQuadDlg(); + virtual ~SMESHGUI_SplitBiQuadDlg(); + + friend class SMESHGUI_SplitBiQuadOp; +}; + +class SMESHGUI_EXPORT SMESHGUI_SplitBiQuadOp : public SMESHGUI_SelectionOp +{ + Q_OBJECT + +public: + SMESHGUI_SplitBiQuadOp(); + virtual ~SMESHGUI_SplitBiQuadOp(); + + virtual LightApp_Dialog* dlg() const; + +protected: + virtual void startOperation(); + //virtual void selectionDone(); + virtual SUIT_SelectionFilter* createFilter( const int ) const; + +protected slots: + virtual bool onApply(); + +private: + SMESHGUI_SplitBiQuadDlg* myDlg; +}; + +#endif // SMESHGUI_SplitBiQuad_H diff --git a/src/SMESHGUI/SMESH_images.ts b/src/SMESHGUI/SMESH_images.ts index c13a65eb6..a0c988e6c 100644 --- a/src/SMESHGUI/SMESH_images.ts +++ b/src/SMESHGUI/SMESH_images.ts @@ -599,6 +599,10 @@ ICON_SPLIT_TO_TETRA split_into_tetra.png + + ICON_SPLIT_BIQUAD + split_biquad.png + ICON_MEASURE_LENGTH mesh_measure_length.png diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 45fef3733..3bdd72e93 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -1088,6 +1088,18 @@ STB_SPLIT_TO_TETRA Split Volumes + + MEN_SPLIT_BIQUAD + Split bi-quadratic into linear + + + TOP_SPLIT_BIQUAD + Split bi-quadratic into linear + + + STB_SPLIT_BIQUAD + Split bi-quadratic into linear + MESHERS_FILE_CANT_OPEN Can not open resource file @@ -4900,6 +4912,33 @@ Do you want to remove all these sub-meshes? Do you want to restore original sub-mesh priority? + + SMESHGUI_SplitBiQuadDlg + + CAPTION + Split bi-qiadratic into linear + + + MESH + Mesh, Group or Sub-mesh + + + + SMESHGUI_SplitBiQuadOp + + MESH_IS_NOT_SELECTED + No object to split is selected. +Please specify it and try again + + + REF_IS_NULL + No valid mesh object selected + + + DIFFERENT_MESHES + Selected objects belong to different meshes + + SMESHGUI_ConvToQuadDlg diff --git a/src/SMESHUtils/SMESH_MAT2d.cxx b/src/SMESHUtils/SMESH_MAT2d.cxx index f0f4d52a6..a64c4ba9d 100644 --- a/src/SMESHUtils/SMESH_MAT2d.cxx +++ b/src/SMESHUtils/SMESH_MAT2d.cxx @@ -66,8 +66,8 @@ namespace struct InPoint { - int _a, _b; - double _param; + int _a, _b; // coordinates + double _param; // param on EDGE InPoint(int x, int y, double param) : _a(x), _b(y), _param(param) {} InPoint() : _a(0), _b(0), _param(0) {} @@ -773,7 +773,7 @@ namespace inPoints[0]._edges.clear(); } - // Divide InSegment's into BndSeg's + // Divide InSegment's into BndSeg's (each BndSeg corresponds to one MA edge) vector< BndSeg > bndSegs; bndSegs.reserve( inSegments.size() * 3 ); @@ -791,25 +791,26 @@ namespace inPntChecked[ ip0 ] = false; // segments of InSegment's - size_t nbMaEdges = inSeg._edges.size(); + const size_t nbMaEdges = inSeg._edges.size(); switch ( nbMaEdges ) { case 0: // "around" circle center bndSegs.push_back( BndSeg( &inSeg, 0, inSeg._p1->_param )); break; case 1: bndSegs.push_back( BndSeg( &inSeg, inSeg._edges.back(), inSeg._p1->_param )); break; default: - vector< double > len; - len.push_back(0); - for ( e = inSeg._edges.rbegin(); e != inSeg._edges.rend(); ++e ) - len.push_back( len.back() + length( *e )); - + gp_XY inSegDir( inSeg._p1->_a - inSeg._p0->_a, + inSeg._p1->_b - inSeg._p0->_b ); + const double inSegLen2 = inSegDir.SquareModulus(); e = inSeg._edges.rbegin(); - for ( size_t l = 1; l < len.size(); ++e, ++l ) + for ( size_t iE = 1; iE < nbMaEdges; ++e, ++iE ) { - double dl = len[l] / len.back(); - double u = dl * inSeg._p1->_param + ( 1. - dl ) * inSeg._p0->_param; + gp_XY toMA( (*e)->vertex0()->x() - inSeg._p0->_a, + (*e)->vertex0()->y() - inSeg._p0->_b ); + double r = toMA * inSegDir / inSegLen2; + double u = r * inSeg._p1->_param + ( 1. - r ) * inSeg._p0->_param; bndSegs.push_back( BndSeg( &inSeg, *e, u )); } + bndSegs.push_back( BndSeg( &inSeg, *e, inSeg._p1->_param )); } // segments around 2nd concave point size_t ip1 = inSeg._p1->index( inPoints ); diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 157983e3c..c0e4963cc 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -2086,7 +2086,7 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems, */ //================================================================================ -void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr elems, +void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr elems, const SMESH::PointStruct & startHexPoint, const SMESH::DirStruct& facetToSplitNormal, CORBA::Short methodFlags, @@ -2138,6 +2138,44 @@ void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms (SMESH::SMESH_IDSource_ptr el SMESH_CATCH( SMESH::throwCorbaException ); } +//================================================================================ +/*! + * \brief Split bi-quadratic elements into linear ones without creation of additional nodes: + * - bi-quadratic triangle will be split into 3 linear quadrangles; + * - bi-quadratic quadrangle will be split into 4 linear quadrangles; + * - tri-quadratic hexahedron will be split into 8 linear hexahedra. + * Quadratic elements of lower dimension adjacent to the split bi-quadratic element + * will be split in order to keep the mesh conformal. + * \param elems - elements to split + */ +//================================================================================ + +void SMESH_MeshEditor_i::SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& theElems) + throw (SALOME::SALOME_Exception) +{ + SMESH_TRY; + initData(); + + TIDSortedElemSet elemSet; + for ( size_t i = 0; i < theElems.length(); ++i ) + { + SMESH::SMESH_IDSource_ptr elems = theElems[i].in(); + SMESH::SMESH_Mesh_var mesh = elems->GetMesh(); + if ( mesh->GetId() != myMesh_i->GetId() ) + THROW_SALOME_CORBA_EXCEPTION("Wrong mesh of IDSource", SALOME::BAD_PARAM); + + idSourceToSet( elems, getMeshDS(), elemSet, SMDSAbs_All ); + } + getEditor().SplitBiQuadraticIntoLinear( elemSet ); + + declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute() + + TPythonDump() << this << ".SplitBiQuadraticIntoLinear( " + << theElems << " )"; + + SMESH_CATCH( SMESH::throwCorbaException ); +} + //======================================================================= //function : Smooth //purpose : diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 6d25784d5..560afae05 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -221,7 +221,7 @@ public: CORBA::Boolean outsideNormal) throw (SALOME::SALOME_Exception); - // Split/Join faces + // Split/Join CORBA::Boolean TriToQuad (const SMESH::long_array & IDsOfElements, SMESH::NumericalFunctor_ptr Criterion, CORBA::Double MaxAngle) @@ -256,6 +256,8 @@ public: CORBA::Short methodFlags, CORBA::Boolean allDomains) throw (SALOME::SALOME_Exception); + void SplitBiQuadraticIntoLinear(const SMESH::ListOfIDSources& elems) + throw (SALOME::SALOME_Exception); CORBA::Boolean Smooth(const SMESH::long_array & IDsOfElements, const SMESH::long_array & IDsOfFixedNodes, diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 430b1fb35..3e3b6750d 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -689,15 +689,17 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): ## Creates a criterion by the given parameters # \n Criterion structures allow to define complex filters by combining them with logical operations (AND / OR) (see example below) - # @param elementType the type of elements(NODE, EDGE, FACE, VOLUME) - # @param CritType the type of criterion (FT_Taper, FT_Area, FT_RangeOfIds, FT_LyingOnGeom etc.) - # @param Compare belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo} + # @param elementType the type of elements(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) + # @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.) + # Type SMESH.FunctorType._items in the Python Console to see all values. + # Note that the items starting from FT_LessThan are not suitable for CritType. + # @param Compare belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo} # @param Threshold the threshold value (range of ids as string, shape, numeric) - # @param UnaryOp FT_LogicalNOT or FT_Undefined - # @param BinaryOp a binary logical operation FT_LogicalAND, FT_LogicalOR or - # FT_Undefined (must be for the last criterion of all criteria) - # @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface, - # FT_LyingOnGeom, FT_CoplanarFaces criteria + # @param UnaryOp SMESH.FT_LogicalNOT or SMESH.FT_Undefined + # @param BinaryOp a binary logical operation SMESH.FT_LogicalAND, SMESH.FT_LogicalOR or + # SMESH.FT_Undefined + # @param Tolerance the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface, + # SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces criteria # @return SMESH.Filter.Criterion # # Example of Criteria usage @@ -874,13 +876,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return aCriterion ## Creates a filter with the given parameters - # @param elementType the type of elements in the group - # @param CritType the type of criterion ( FT_Taper, FT_Area, FT_RangeOfIds, FT_LyingOnGeom etc. ) - # @param Compare belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo} - # @param Threshold the threshold value (range of id ids as string, shape, numeric) - # @param UnaryOp FT_LogicalNOT or FT_Undefined - # @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface, - # FT_LyingOnGeom, FT_CoplanarFaces and FT_EqualNodes criteria + # @param elementType the type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) + # @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.) + # Type SMESH.FunctorType._items in the Python Console to see all values. + # Note that the items starting from FT_LessThan are not suitable for CritType. + # @param Compare belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo} + # @param Threshold the threshold value (range of ids as string, shape, numeric) + # @param UnaryOp SMESH.FT_LogicalNOT or SMESH.FT_Undefined + # @param Tolerance the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface, + # SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces and SMESH.FT_EqualNodes criteria # @param mesh the mesh to initialize the filter with # @return SMESH_Filter # @@ -923,7 +927,9 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return aFilter ## Creates a numerical functor by its type - # @param theCriterion FT_...; functor type + # @param theCriterion functor type - an item of SMESH.FunctorType enumeration. + # Type SMESH.FunctorType._items in the Python Console to see all items. + # Note that not all items corresponds to numerical functors. # @return SMESH_NumericalFunctor # @ingroup l1_controls def GetFunctor(self,theCriterion): @@ -1828,7 +1834,8 @@ class Mesh: # ---------------------- ## Creates an empty mesh group - # @param elementType the type of elements in the group + # @param elementType the type of elements in the group; either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) # @param name the name of the mesh group # @return SMESH_Group # @ingroup l2_grps_create @@ -1851,8 +1858,9 @@ class Mesh: # the name is the same as the geometrical group name # @param grp a geometrical group, a vertex, an edge, a face or a solid # @param name the name of the mesh group - # @param typ the type of elements in the group. If not set, it is - # automatically detected by the type of the geometry + # @param typ the type of elements in the group; either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). If not set, it is + # automatically detected by the type of the geometry # @return SMESH_GroupOnGeom # @ingroup l2_grps_create def GroupOnGeom(self, grp, name="", typ=None): @@ -1887,7 +1895,8 @@ class Mesh: ## Creates a mesh group with given \a name based on the \a filter which ## is a special type of group dynamically updating it's contents during ## mesh modification - # @param typ the type of elements in the group + # @param typ the type of elements in the group; either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). # @param name the name of the mesh group # @param filter the filter defining group contents # @return SMESH_GroupOnFilter @@ -1897,7 +1906,8 @@ class Mesh: ## Creates a mesh group by the given ids of elements # @param groupName the name of the mesh group - # @param elementType the type of elements in the group + # @param elementType the type of elements in the group; either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). # @param elemIDs the list of ids # @return SMESH_Group # @ingroup l2_grps_create @@ -1913,13 +1923,15 @@ class Mesh: ## Creates a mesh group by the given conditions # @param groupName the name of the mesh group - # @param elementType the type of elements in the group - # @param CritType the type of criterion( FT_Taper, FT_Area, FT_RangeOfIds, FT_LyingOnGeom etc. ) - # @param Compare belongs to {FT_LessThan, FT_MoreThan, FT_EqualTo} - # @param Threshold the threshold value (range of id ids as string, shape, numeric) - # @param UnaryOp FT_LogicalNOT or FT_Undefined - # @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface, - # FT_LyingOnGeom, FT_CoplanarFaces criteria + # @param elementType the type of elements(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) + # @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.) + # Type SMESH.FunctorType._items in the Python Console to see all values. + # Note that the items starting from FT_LessThan are not suitable for CritType. + # @param Compare belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo} + # @param Threshold the threshold value (range of ids as string, shape, numeric) + # @param UnaryOp SMESH.FT_LogicalNOT or SMESH.FT_Undefined + # @param Tolerance the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface, + # SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces criteria # @return SMESH_GroupOnFilter # @ingroup l2_grps_create def MakeGroup(self, @@ -1977,10 +1989,22 @@ class Mesh: ## Gets the list of groups existing in the mesh in the order # of creation (starting from the oldest one) + # @param elemType type of elements the groups contain; either of + # (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); + # by default groups of elements of all types are returned # @return a sequence of SMESH_GroupBase # @ingroup l2_grps_create - def GetGroups(self): - return self.mesh.GetGroups() + def GetGroups(self, elemType = SMESH.ALL): + groups = self.mesh.GetGroups() + if elemType == SMESH.ALL: + return groups + typedGroups = [] + for g in groups: + if g.GetType() == elemType: + typedGroups.append( g ) + pass + pass + return typedGroups ## Gets the number of groups existing in the mesh # @return the quantity of groups as an integer value @@ -1998,6 +2022,25 @@ class Mesh: names.append(group.GetName()) return names + ## Finds groups by name and type + # @param name name of the group of interest + # @param elemType type of elements the groups contain; either of + # (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); + # by default one group of any type of elements is returned + # if elemType == SMESH.ALL then all groups of any type are returned + # @return a list of SMESH_GroupBase's + # @ingroup l2_grps_create + def GetGroupByName(self, name, elemType = None): + groups = [] + for group in self.GetGroups(): + if group.GetName() == name: + if elemType is None: + return [group] + if ( elemType == SMESH.ALL or + group.GetType() == elemType ): + groups.append( group ) + return groups + ## Produces a union of two groups. # A new group is created. All mesh elements that are # present in the initial groups are added to the new one @@ -2049,7 +2092,8 @@ class Mesh: ## # Create a standalone group of entities basing on nodes of other groups. # \param groups - list of groups, sub-meshes or filters, of any type. - # \param elemType - a type of elements to include to the new group. + # \param elemType - a type of elements to include to the new group; either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). # \param name - a name of the new group. # \param nbCommonNodes - a criterion of inclusion of an element to the new group # basing on number of element nodes common with reference \a groups. @@ -2134,9 +2178,17 @@ class Mesh: ## Wrap a list of IDs of elements or nodes into SMESH_IDSource which # can be passed as argument to a method accepting mesh, group or sub-mesh + # @param ids list of IDs + # @param elemType type of elements; this parameter is used to distinguish + # IDs of nodes from IDs of elements; by default ids are treated as + # IDs of elements; use SMESH.NODE if ids are IDs of nodes. # @return an instance of SMESH_IDSource + # @warning call UnRegister() for the returned object as soon as it is no more useful: + # idSrc = mesh.GetIDSource( [1,3,5], SMESH.NODE ) + # mesh.DoSomething( idSrc ) + # idSrc.UnRegister() # @ingroup l1_auxiliary - def GetIDSource(self, ids, elemType): + def GetIDSource(self, ids, elemType = SMESH.ALL): return self.editor.MakeIDSource(ids, elemType) @@ -2182,7 +2234,7 @@ class Mesh: ## Returns the number of edges with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbEdgesOfOrder(self, elementOrder): @@ -2196,7 +2248,7 @@ class Mesh: ## Returns the number of faces with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbFacesOfOrder(self, elementOrder): @@ -2210,7 +2262,7 @@ class Mesh: ## Returns the number of triangles with the given order in the mesh # @param elementOrder is the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbTrianglesOfOrder(self, elementOrder): @@ -2230,7 +2282,7 @@ class Mesh: ## Returns the number of quadrangles with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbQuadranglesOfOrder(self, elementOrder): @@ -2243,6 +2295,8 @@ class Mesh: return self.mesh.NbBiQuadQuadrangles() ## Returns the number of polygons of given order in the mesh + # @param elementOrder the order of elements: + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbPolygons(self, elementOrder = SMESH.ORDER_ANY): @@ -2256,7 +2310,7 @@ class Mesh: ## Returns the number of volumes with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbVolumesOfOrder(self, elementOrder): @@ -2270,7 +2324,7 @@ class Mesh: ## Returns the number of tetrahedrons with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbTetrasOfOrder(self, elementOrder): @@ -2284,7 +2338,7 @@ class Mesh: ## Returns the number of hexahedrons with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbHexasOfOrder(self, elementOrder): @@ -2304,7 +2358,7 @@ class Mesh: ## Returns the number of pyramids with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbPyramidsOfOrder(self, elementOrder): @@ -2318,7 +2372,7 @@ class Mesh: ## Returns the number of prisms with the given order in the mesh # @param elementOrder the order of elements: - # ORDER_ANY, ORDER_LINEAR or ORDER_QUADRATIC + # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value # @ingroup l1_meshinfo def NbPrismsOfOrder(self, elementOrder): @@ -2349,7 +2403,8 @@ class Mesh: return self.mesh.GetElementsId() ## Returns the list of IDs of mesh elements with the given type - # @param elementType the required type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) + # @param elementType the required type of elements, either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) # @return list of integer values # @ingroup l1_meshinfo def GetElementsByType(self, elementType): @@ -2366,18 +2421,21 @@ class Mesh: ## Returns the type of mesh element # @return the value from SMESH::ElementType enumeration + # Type SMESH.ElementType._items in the Python Console to see all possible values. # @ingroup l1_meshinfo def GetElementType(self, id, iselem=True): return self.mesh.GetElementType(id, iselem) ## Returns the geometric type of mesh element # @return the value from SMESH::EntityType enumeration + # Type SMESH.EntityType._items in the Python Console to see all possible values. # @ingroup l1_meshinfo def GetElementGeomType(self, id): return self.mesh.GetElementGeomType(id) ## Returns the shape type of mesh element - # @return the value from SMESH::GeometryType enumeration + # @return the value from SMESH::GeometryType enumeration. + # Type SMESH.GeometryType._items in the Python Console to see all possible values. # @ingroup l1_meshinfo def GetElementShape(self, id): return self.mesh.GetElementShape(id) @@ -2495,6 +2553,9 @@ class Mesh: return self.mesh.IsMediumNode(elementID, nodeID) ## Returns true if the given node is the medium node in one of quadratic elements + # @param nodeID ID of the node + # @param elementType the type of elements to check a state of the node, either of + # (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) # @ingroup l1_meshinfo def IsMediumNodeOfAnyElem(self, nodeID, elementType = SMESH.ALL ): return self.mesh.IsMediumNodeOfAnyElem(nodeID, elementType) @@ -2918,8 +2979,9 @@ class Mesh: # @param x the X coordinate of a point # @param y the Y coordinate of a point # @param z the Z coordinate of a point - # @param elementType type of elements to find (SMESH.ALL type - # means elements of any type excluding nodes, discrete and 0D elements) + # @param elementType type of elements to find; either of + # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); SMESH.ALL type + # means elements of any type excluding nodes, discrete and 0D elements. # @param meshPart a part of mesh (group, sub-mesh) to search within # @return list of IDs of found elements # @ingroup l2_modif_throughp @@ -2929,10 +2991,9 @@ class Mesh: else: return self.editor.FindElementsByPoint(x, y, z, elementType) - # Return point state in a closed 2D mesh in terms of TopAbs_State enumeration: - # 0-IN, 1-OUT, 2-ON, 3-UNKNOWN - # TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails. - + ## Return point state in a closed 2D mesh in terms of TopAbs_State enumeration: + # 0-IN, 1-OUT, 2-ON, 3-UNKNOWN + # UNKNOWN state means that either mesh is wrong or the analysis fails. def GetPointState(self, x, y, z): return self.editor.GetPointState(x, y, z) @@ -3050,12 +3111,14 @@ class Mesh: return self.editor.Reorient2DBy3D( the2DObject, the3DObject, theOutsideNormal ) ## Fuses the neighbouring triangles into quadrangles. - # @param IDsOfElements The triangles to be fused, - # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to - # choose a neighbour to fuse with. + # @param IDsOfElements The triangles to be fused. + # @param theCriterion a numerical functor, in terms of enum SMESH.FunctorType, used to + # choose a neighbour to fuse with. + # Type SMESH.FunctorType._items in the Python Console to see all items. + # Note that not all items corresponds to numerical functors. # @param MaxAngle is the maximum angle between element normals at which the fusion - # is still performed; theMaxAngle is mesured in radians. - # Also it could be a name of variable which defines angle in degrees. + # is still performed; theMaxAngle is mesured in radians. + # Also it could be a name of variable which defines angle in degrees. # @return TRUE in case of success, FALSE otherwise. # @ingroup l2_modif_unitetri def TriToQuad(self, IDsOfElements, theCriterion, MaxAngle): @@ -3069,9 +3132,11 @@ class Mesh: ## Fuses the neighbouring triangles of the object into quadrangles # @param theObject is mesh, submesh or group # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to - # choose a neighbour to fuse with. + # choose a neighbour to fuse with. + # Type SMESH.FunctorType._items in the Python Console to see all items. + # Note that not all items corresponds to numerical functors. # @param MaxAngle a max angle between element normals at which the fusion - # is still performed; theMaxAngle is mesured in radians. + # is still performed; theMaxAngle is mesured in radians. # @return TRUE in case of success, FALSE otherwise. # @ingroup l2_modif_unitetri def TriToQuadObject (self, theObject, theCriterion, MaxAngle): @@ -3087,6 +3152,8 @@ class Mesh: # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to # choose a diagonal for splitting. If @a theCriterion is None, which is a default # value, then quadrangles will be split by the smallest diagonal. + # Type SMESH.FunctorType._items in the Python Console to see all items. + # Note that not all items corresponds to numerical functors. # @return TRUE in case of success, FALSE otherwise. # @ingroup l2_modif_cutquadr def QuadToTri (self, IDsOfElements, theCriterion = None): @@ -3103,6 +3170,8 @@ class Mesh: # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to # choose a diagonal for splitting. If @a theCriterion is None, which is a default # value, then quadrangles will be split by the smallest diagonal. + # Type SMESH.FunctorType._items in the Python Console to see all items. + # Note that not all items corresponds to numerical functors. # @return TRUE in case of success, FALSE otherwise. # @ingroup l2_modif_cutquadr def QuadToTriObject (self, theObject, theCriterion = None): @@ -3154,6 +3223,8 @@ class Mesh: # @param IDOfQuad the ID of the quadrangle to be splitted. # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to # choose a diagonal for splitting. + # Type SMESH.FunctorType._items in the Python Console to see all items. + # Note that not all items corresponds to numerical functors. # @return 1 if 1-3 diagonal is better, 2 if 2-4 # diagonal is better, 0 if error occurs. # @ingroup l2_modif_cutquadr @@ -3174,6 +3245,29 @@ class Mesh: elems = self.editor.MakeIDSource(elems, SMESH.VOLUME) unRegister.set( elems ) self.editor.SplitVolumesIntoTetra(elems, method) + return + + ## Split bi-quadratic elements into linear ones without creation of additional nodes: + # - bi-quadratic triangle will be split into 3 linear quadrangles; + # - bi-quadratic quadrangle will be split into 4 linear quadrangles; + # - tri-quadratic hexahedron will be split into 8 linear hexahedra. + # Quadratic elements of lower dimension adjacent to the split bi-quadratic element + # will be split in order to keep the mesh conformal. + # @param elems - elements to split: sub-meshes, groups, filters or element IDs; + # if None (default), all bi-quadratic elements will be split + # @ingroup l2_modif_cutquadr + def SplitBiQuadraticIntoLinear(self, elems=None): + unRegister = genObjUnRegister() + if elems and isinstance( elems, list ) and isinstance( elems[0], int ): + elems = self.editor.MakeIDSource(elems, SMESH.ALL) + unRegister.set( elems ) + if elems is None: + elems = [ self.GetMesh() ] + if isinstance( elems, Mesh ): + elems = [ elems.GetMesh() ] + if not isinstance( elems, list ): + elems = [elems] + self.editor.SplitBiQuadraticIntoLinear( elems ) ## Splits hexahedra into prisms # @param elems either a list of elements or a mesh or a group or a submesh or a filter @@ -3473,8 +3567,8 @@ class Mesh: # @param elements - elements whose boundary is to be checked: # mesh, group, sub-mesh or list of elements # if elements is mesh, it must be the mesh whose MakeBoundaryMesh() is called - # @param dimension - defines type of boundary elements to create: - # SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D + # @param dimension - defines type of boundary elements to create, either of + # { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D } # SMESH.BND_1DFROM3D creates mesh edges on all borders of free facets of 3D cells # @param groupName - a name of group to store created boundary elements in, # "" means not to create the group @@ -3504,7 +3598,8 @@ class Mesh: ## # @brief Creates missing boundary elements around either the whole mesh or # groups of elements - # @param dimension - defines type of boundary elements to create + # @param dimension - defines type of boundary elements to create, either of + # { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D } # @param groupName - a name of group to store all boundary elements in, # "" means not to create the group # @param meshName - a name of a new mesh, which is a copy of the initial diff --git a/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx b/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx index ea8fdc936..534860754 100644 --- a/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx +++ b/src/StdMeshers/StdMeshers_QuadFromMedialAxis_1D2D.cxx @@ -134,13 +134,14 @@ namespace */ struct SinuousFace { - FaceQuadStruct::Ptr _quad; - vector< TopoDS_Edge > _edges; - vector< TopoDS_Edge > _sinuSide[2], _shortSide[2]; - vector< TopoDS_Edge > _sinuEdges; - int _nbWires; - list< int > _nbEdgesInWire; - TMergeMap _nodesToMerge; + FaceQuadStruct::Ptr _quad; + vector< TopoDS_Edge > _edges; + vector< TopoDS_Edge > _sinuSide[2], _shortSide[2]; + vector< TopoDS_Edge > _sinuEdges; + vector< Handle(Geom_Curve) > _sinuCurves; + int _nbWires; + list< int > _nbEdgesInWire; + TMergeMap _nodesToMerge; SinuousFace( const TopoDS_Face& f ): _quad( new FaceQuadStruct ) { @@ -830,11 +831,11 @@ namespace */ //================================================================================ - bool findVertex( NodePoint& theNodePnt, - const vector& theSinuEdges, - size_t theEdgeIndPrev, - size_t theEdgeIndNext, - SMESHDS_Mesh* theMeshDS) + bool findVertexAndNode( NodePoint& theNodePnt, + const vector& theSinuEdges, + SMESHDS_Mesh* theMeshDS = 0, + size_t theEdgeIndPrev = 0, + size_t theEdgeIndNext = 0) { if ( theNodePnt._edgeInd >= theSinuEdges.size() ) return false; @@ -851,7 +852,7 @@ namespace else if ( theEdgeIndPrev != theEdgeIndNext ) TopExp::CommonVertex( theSinuEdges[theEdgeIndPrev], theSinuEdges[theEdgeIndNext], V ); - if ( !V.IsNull() ) + if ( !V.IsNull() && theMeshDS ) { theNodePnt._node = SMESH_Algo::VertexNode( V, theMeshDS ); if ( !theNodePnt._node ) @@ -860,9 +861,8 @@ namespace theNodePnt._node = theMeshDS->AddNode( p.X(), p.Y(), p.Z() ); theMeshDS->SetNodeOnVertex( theNodePnt._node, V ); } - return true; } - return false; + return !V.IsNull(); } //================================================================================ @@ -881,41 +881,44 @@ namespace //================================================================================ bool projectVertices( SMESH_MesherHelper& theHelper, - //const double theMinSegLen, const SMESH_MAT2d::MedialAxis& theMA, const vector< SMESH_MAT2d::BranchPoint >& theDivPoints, const vector< std::size_t > & theEdgeIDs1, const vector< std::size_t > & theEdgeIDs2, - const vector& theSinuEdges, - const vector< Handle(Geom_Curve) >& theCurves, const vector< bool >& theIsEdgeComputed, map< double, pair< NodePoint, NodePoint > > & thePointsOnE, - TMergeMap& theNodes2Merge) + SinuousFace& theSinuFace) { - if ( theDivPoints.empty() ) - return true; - SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + const vector& theSinuEdges = theSinuFace._sinuEdges; + const vector< Handle(Geom_Curve) >& theCurves = theSinuFace._sinuCurves; double uMA; SMESH_MAT2d::BoundaryPoint bp[2]; const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0); - // fill a map holding NodePoint's of ends of theSinuEdges - map< double, pair< NodePoint, NodePoint > > extremaNP; - map< double, pair< NodePoint, NodePoint > >::iterator u2NP0, u2NP1; + // add to thePointsOnE NodePoint's of ends of theSinuEdges if ( !branch.getBoundaryPoints( 0., bp[0], bp[1] ) || !theMA.getBoundary().moveToClosestEdgeEnd( bp[0] ) || !theMA.getBoundary().moveToClosestEdgeEnd( bp[1] )) return false; - u2NP0 = extremaNP.insert - ( make_pair( 0., make_pair( NodePoint( bp[0]), NodePoint( bp[1])))).first; + NodePoint np0( bp[0]), np1( bp[1] ); + findVertexAndNode( np0, theSinuEdges, meshDS ); + findVertexAndNode( np1, theSinuEdges, meshDS ); + thePointsOnE.insert( make_pair( -0.1, make_pair( np0, np1 ))); + if ( !branch.getBoundaryPoints( 1., bp[0], bp[1] ) || !theMA.getBoundary().moveToClosestEdgeEnd( bp[0] ) || !theMA.getBoundary().moveToClosestEdgeEnd( bp[1] )) return false; - u2NP1 = extremaNP.insert - ( make_pair( 1., make_pair( NodePoint( bp[0]), NodePoint( bp[1])))).first; + np0 = bp[0]; np1 = bp[1]; + findVertexAndNode( np0, theSinuEdges, meshDS ); + findVertexAndNode( np1, theSinuEdges, meshDS ); + thePointsOnE.insert( make_pair( 1.1, make_pair( np0, np1))); // project theDivPoints + + if ( theDivPoints.empty() ) + return true; + for ( size_t i = 0; i < theDivPoints.size(); ++i ) { if ( !branch.getParameter( theDivPoints[i], uMA )) @@ -928,8 +931,8 @@ namespace NodePoint( bp[1] ) }; bool isVertex[2] = { - findVertex( np[0], theSinuEdges, theEdgeIDs1[i], theEdgeIDs1[i+1], meshDS ), - findVertex( np[1], theSinuEdges, theEdgeIDs2[i], theEdgeIDs2[i+1], meshDS ) + findVertexAndNode( np[0], theSinuEdges, meshDS, theEdgeIDs1[i], theEdgeIDs1[i+1] ), + findVertexAndNode( np[1], theSinuEdges, meshDS, theEdgeIDs2[i], theEdgeIDs2[i+1] ) }; map< double, pair< NodePoint, NodePoint > >::iterator u2NP = @@ -957,10 +960,10 @@ namespace bool isShortPrev[2], isShortNext[2]; map< double, pair< NodePoint, NodePoint > >::iterator u2NPPrev = u2NP, u2NPNext = u2NP; --u2NPPrev; ++u2NPNext; - bool hasPrev = ( u2NP != thePointsOnE.begin() ); - bool hasNext = ( u2NPNext != thePointsOnE.end() ); - if ( !hasPrev ) u2NPPrev = u2NP0; - if ( !hasNext ) u2NPNext = u2NP1; + // bool hasPrev = ( u2NP != thePointsOnE.begin() ); + // bool hasNext = ( u2NPNext != thePointsOnE.end() ); + // if ( !hasPrev ) u2NPPrev = u2NP0; + // if ( !hasNext ) u2NPNext = u2NP1; for ( int iS = 0; iS < 2; ++iS ) // side with Vertex and side with Nodes { NodePoint np = get( u2NP->second, iS ); @@ -1003,19 +1006,134 @@ namespace u2NPClose = isShortPrev[ iNode ] ? u2NPPrev : u2NPNext; NodePoint& npProj = get( u2NP->second, iNode ); // NP of VERTEX projection NodePoint& npCloseN = get( u2NPClose->second, iNode ); // NP close to npProj - // npProj._edgeInd = npCloseN._edgeInd; + npProj = npCloseN; + npProj._node = 0; + //npProj._edgeInd = npCloseN._edgeInd; // npProj._u = npCloseN._u + 1e-3 * Abs( get( u2NPPrev->second, iNode )._u - // get( u2NPNext->second, iNode )._u ); - gp_Pnt p = npProj.Point( theCurves ); - npProj._node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); - meshDS->SetNodeOnEdge( npProj._node, theSinuEdges[ npProj._edgeInd ], npProj._u ); + // gp_Pnt p = npProj.Point( theCurves ); + // npProj._node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + // meshDS->SetNodeOnEdge( npProj._node, theSinuEdges[ npProj._edgeInd ], npProj._u ); - theNodes2Merge[ npCloseN._node ].push_back( npProj._node ); + //theNodes2Merge[ npCloseN._node ].push_back( npProj._node ); } } return true; } + //================================================================================ + /*! + * \brief Move coincident nodes to make node params on EDGE unique + * \param [in] theHelper - the helper + * \param [in] thePointsOnE - nodes on two opposite river sides + * \param [in] theSinuFace - the sinuous FACE + * \param [out] theNodes2Merge - the map of nodes to merge + */ + //================================================================================ + + void separateNodes( SMESH_MesherHelper& theHelper, + map< double, pair< NodePoint, NodePoint > > & thePointsOnE, + SinuousFace& theSinuFace ) + { + if ( thePointsOnE.size() < 2 ) + return; + + SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); + const vector& theSinuEdges = theSinuFace._sinuEdges; + + typedef map< double, pair< NodePoint, NodePoint > >::iterator TIterator; + + for ( int iSide = 0; iSide < 2; ++iSide ) + { + TIterator u2NP0, u2NP1, u2NP = thePointsOnE.begin(); + while ( u2NP != thePointsOnE.end() ) + { + while ( u2NP != thePointsOnE.end() && + get( u2NP->second, iSide )._node ) + ++u2NP; // skip NP with an existing node (VERTEXes must be meshed) + if ( u2NP == thePointsOnE.end() ) + break; + + // find a range of not meshed NP on one EDGE + u2NP0 = u2NP; + if ( !findVertexAndNode( get( u2NP0->second, iSide ), theSinuEdges )) + --u2NP0; + int iCurEdge = get( u2NP->second, iSide )._edgeInd; + int nbNP = 1; + while ( get( u2NP->second, iSide )._edgeInd == iCurEdge && + get( u2NP->second, iSide )._node == 0 ) + ++u2NP, ++nbNP; + u2NP1 = u2NP; // end of not meshed NP on iCurEdge + + // fix parameters of extremity NP of the range + NodePoint* np0 = & get( u2NP0->second, iSide ); + NodePoint* np1 = & get( u2NP1->second, iSide ); + const TopoDS_Edge& edge = TopoDS::Edge( theSinuFace._sinuEdges[ iCurEdge ]); + if ( np0->_node && np0->_edgeInd != iCurEdge ) + { + np0->_u = theHelper.GetNodeU( edge, np0->_node ); + np0->_edgeInd = iCurEdge; + } + if ( np1->_node && np1->_edgeInd != iCurEdge ) + { + np1->_u = theHelper.GetNodeU( edge, np1->_node ); + np1->_edgeInd = iCurEdge; + } + + // find coincident NPs + double f,l; + BRep_Tool::Range( edge, f,l ); + double tol = 1e-2* (l-f) / nbNP; + TIterator u2NPEq = thePointsOnE.end(); + u2NP = u2NP0; + for ( ++u2NP; u2NP0 != u2NP1; ++u2NP, ++u2NP0 ) + { + np0 = & get( u2NP0->second, iSide ); + np1 = & get( u2NP->second, iSide ); + bool coincides = ( Abs( np0->_u - np1->_u ) < tol ); + if ( coincides && u2NPEq == thePointsOnE.end() ) + u2NPEq = u2NP0; + + if (( u2NPEq != thePointsOnE.end() ) && + ( u2NP == u2NP1 || !coincides )) + { + if ( !get( u2NPEq->second, iSide )._node ) + --u2NPEq; + if ( coincides && !get( u2NP->second, iSide )._node && u2NP0 != u2NP1 ) + ++u2NP; + + // distribute nodes between u2NPEq and u2NP + size_t nbSeg = std::distance( u2NPEq, u2NP ); + double du = 1. / nbSeg * ( get( u2NP->second, iSide )._u - + get( u2NPEq->second, iSide )._u ); + double u = get( u2NPEq->second, iSide )._u + du; + + const SMDS_MeshNode* closeNode = + get(( coincides ? u2NP : u2NPEq )->second, iSide )._node; + list< const SMDS_MeshNode* >& eqNodes = theSinuFace._nodesToMerge[ closeNode ]; + + for ( ++u2NPEq; u2NPEq != u2NP; ++u2NPEq, u += du ) + { + np0 = & get( u2NPEq->second, iSide ); + np0->_u = u; + gp_Pnt p = np0->Point( theSinuFace._sinuCurves ); + np0->_node = meshDS->AddNode( p.X(), p.Y(), p.Z() ); + meshDS->SetNodeOnEdge( np0->_node, theSinuEdges[ np0->_edgeInd ], np0->_u ); + if ( !closeNode ) + eqNodes = theSinuFace._nodesToMerge[ closeNode = np0->_node ]; + else + eqNodes.push_back( np0->_node ); + } + } + } + u2NP = u2NP1; + while ( get( u2NP->second, iSide )._edgeInd != iCurEdge ) + --u2NP; + u2NP++; + } + } + } + //================================================================================ /*! * \brief Divide the sinuous EDGEs by projecting the division point of Medial @@ -1048,11 +1166,12 @@ namespace SMESHDS_Mesh* meshDS = theHelper.GetMeshDS(); double f,l; + // get data of sinuous EDGEs and remove unnecessary nodes const vector< TopoDS_Edge >& theSinuEdges = theSinuFace._sinuEdges; - vector< Handle(Geom_Curve) > curves ( theSinuEdges.size() ); + vector< Handle(Geom_Curve) >& curves = theSinuFace._sinuCurves; vector< int > edgeIDs( theSinuEdges.size() ); vector< bool > isComputed( theSinuEdges.size() ); - //bool hasComputed = false; + curves.resize( theSinuEdges.size(), 0 ); for ( size_t i = 0; i < theSinuEdges.size(); ++i ) { curves[i] = BRep_Tool::Curve( theSinuEdges[i], f,l ); @@ -1172,10 +1291,12 @@ namespace ++iEdgePair; } - if ( !projectVertices( theHelper, theMA, divPoints, edgeIDs1, edgeIDs2, theSinuEdges, - curves, isComputed, pointsOnE, theSinuFace._nodesToMerge )) + if ( !projectVertices( theHelper, theMA, divPoints, edgeIDs1, edgeIDs2, + isComputed, pointsOnE, theSinuFace )) return false; + separateNodes( theHelper, pointsOnE, theSinuFace ); + // create nodes TMAPar2NPoints::iterator u2np = pointsOnE.begin(); for ( ; u2np != pointsOnE.end(); ++u2np ) @@ -1353,6 +1474,7 @@ namespace TMergeMap::iterator n2nn = theSinuFace._nodesToMerge.begin(); for ( ; n2nn != theSinuFace._nodesToMerge.end(); ++n2nn ) { + if ( !n2nn->first ) continue; nodesGroups.push_back( list< const SMDS_MeshNode* >() ); list< const SMDS_MeshNode* > & group = nodesGroups.back();