From 38f832b912a159ca9d43b5bd031344fd7108a6d8 Mon Sep 17 00:00:00 2001 From: eap Date: Thu, 9 Jul 2015 12:41:53 +0300 Subject: [PATCH] 23072: [CEA 1500] Split biquadratic elements into linear elements --- doc/salome/examples/CMakeLists.txt | 1 + doc/salome/examples/split_biquad.py | 37 +++ .../examples/transforming_meshes_ex01.py | 11 +- .../images/split_biquad_to_linear_dlg.png | Bin 0 -> 8011 bytes .../images/split_biquad_to_linear_icon.png | Bin 0 -> 945 bytes .../images/split_biquad_to_linear_mesh.png | Bin 0 -> 25633 bytes .../input/convert_to_from_quadratic_mesh.doc | 2 +- .../gui/SMESH/input/modifying_meshes.doc | 2 + .../SMESH/input/split_biquad_to_linear.doc | 37 +++ doc/salome/gui/SMESH/input/split_to_tetra.doc | 2 +- .../gui/SMESH/input/tui_modifying_meshes.doc | 5 + idl/SMESH_MeshEditor.idl | 14 +- resources/CMakeLists.txt | 1 + resources/split_biquad.png | Bin 0 -> 945 bytes src/SMESH/SMESH_MeshEditor.cxx | 187 ++++++++++++- src/SMESH/SMESH_MeshEditor.hxx | 12 +- src/SMESHGUI/CMakeLists.txt | 2 + src/SMESHGUI/SMESHGUI.cxx | 8 + src/SMESHGUI/SMESHGUI_ConvToQuadOp.cxx | 2 + src/SMESHGUI/SMESHGUI_Operations.h | 1 + src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx | 255 ++++++++++++++++++ src/SMESHGUI/SMESHGUI_SplitBiQuad.h | 72 +++++ src/SMESHGUI/SMESH_images.ts | 4 + src/SMESHGUI/SMESH_msg_en.ts | 39 +++ src/SMESHUtils/SMESH_MAT2d.cxx | 25 +- src/SMESH_I/SMESH_MeshEditor_i.cxx | 40 ++- src/SMESH_I/SMESH_MeshEditor_i.hxx | 4 +- src/SMESH_SWIG/smeshBuilder.py | 213 +++++++++++---- .../StdMeshers_QuadFromMedialAxis_1D2D.cxx | 210 ++++++++++++--- 29 files changed, 1055 insertions(+), 131 deletions(-) create mode 100644 doc/salome/examples/split_biquad.py create mode 100644 doc/salome/gui/SMESH/images/split_biquad_to_linear_dlg.png create mode 100644 doc/salome/gui/SMESH/images/split_biquad_to_linear_icon.png create mode 100644 doc/salome/gui/SMESH/images/split_biquad_to_linear_mesh.png create mode 100644 doc/salome/gui/SMESH/input/split_biquad_to_linear.doc create mode 100644 resources/split_biquad.png create mode 100644 src/SMESHGUI/SMESHGUI_SplitBiQuad.cxx create mode 100644 src/SMESHGUI/SMESHGUI_SplitBiQuad.h 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 0000000000000000000000000000000000000000..c3df00902c56954131c3894891313ab24e2304c8 GIT binary patch literal 8011 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 WPxR3U^T8+DfV_-~H1h5Hp#K7;BdUo2 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0b9b7a038ad2198f44f1bde71a98a72d349a9fc7 GIT binary patch literal 945 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 Rc8Py?qA05-Q!Ql{_FuHU{R;p9 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0b9b7a038ad2198f44f1bde71a98a72d349a9fc7 GIT binary patch literal 945 zcmV;i15W&jP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2$> z5HtaZBapNJ00S{eL_t(I%WafRXk1kohM#+9GO^7}9YSOxbSEQ-(@J5qn_0N2D^Zt% zsQ3p#Y{W&SR&b^G(~Xd}qSE3|qayxLEiM#-kP9I+i)sfHYAdyE9NVC+Y1;FB=bn39 z%(*i+#0!^uIlR2z_de%42R1%2Fly>eztrh?;CA2^paMh%T?CZwE{$#hJg^lQkN?N4 z3{<@Yo&S=SAnZX=6c138o=gqA!aR)siL`P3`m1n6m&OT z@!1uCEX(jdD{A9%U{eDwpLqEwnaeP1tGTFVCnt}M^m;pksRGOIe}92z?%Rrr;D&}V z5XE`S1IN#xs;COnQ}<#gCa~k<)2CW3Y_+-w>;RSzefK+}0)VJsjTCpC@*t)vnR7Uo zf(Spi+xRpEV>r2O8#fjfzTO0g2$^#Mjo@6ieoWd)a#uS^P*Fs*&rg-@^Yd(aYH3OHW@t5Dm& zdl%2W^$iDJd;lYY9~yeV$9Y$xid7RvM=|v#OP$Viem)~23o!NCm#8s=4pjz`E#TsI zl0@w!!K$Ka`=Ua8U^7q=yzlR<8E{h-K6v#}=yP5Ht`!&x&N(vYn0@m}K87!VGr+&0 zx*u}u&))1CPXK%dTmsGlD+5ET%Helkr`u{U3ts`Jfo}M&9Gb zh3jIT3uawl8Mq#@dZ8c~o3Bc#TMc|iE^=ydj?=O!{ z9#7Z)2nA<=zrq9z%m7y|boDm 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(); -- 2.30.2