23072: [CEA 1500] Split biquadratic elements into linear elements

This commit is contained in:
eap 2015-07-09 12:41:53 +03:00
parent 0e017d4c87
commit 38f832b912
29 changed files with 1055 additions and 131 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -51,7 +51,7 @@ The following dialog box will appear:
<center>Quadratic mesh</center>
</li>
<li>Click the \b Apply or \b OK button.</li>
<li>Click the \b Apply or <b>Apply and Close</b> button.</li>
</ol>
<br><b>See Also</b> a sample TUI Script of a \ref tui_quadratic "Convert to/from quadratic" operation.

View File

@ -43,6 +43,8 @@ transformation operations, giving the possibility to:
triangles.</li>
<li>\subpage split_to_tetra_page "Split" volumic elements into
tetrahedra or prisms.</li>
<li>\subpage split_biquad_to_linear_page "Split bi-quadratic" elements
into linear ones without creation of additional nodes.</li>
<li>\subpage smoothing_page "Smooth" elements, reducung distortions in
them by adjusting the locations of nodes.</li>
<li>Create an \subpage extrusion_page "extrusion" along a vector or by

View File

@ -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"
<em>To split bi-quadratic elements into linear:</em>
<ol>
<li>From the \b Modification menu choose the <b>Split bi-quadratic into linear</b> item or
click <em>"Split bi-quadratic into linear"</em> button in the toolbar.
\image html split_biquad_to_linear_icon.png
<center><em>"Split bi-quadratic into linear" button</em></center>
The following dialog box shall appear:
\image html split_biquad_to_linear_dlg.png
</li>
<li>Select a mesh, groups or sub-meshes in the Object Browser or in the
Viewer.</li>
<li>Click the \b Apply or <b>Apply and Close</b> button.</li>
</ol>
<br><b>See Also</b> a sample TUI Script of a \ref tui_split_biquad "Split bi-quadratic into linear" operation.
*/

View File

@ -7,7 +7,7 @@ tetrahedra or hexahedra into prisms. 2D mesh is modified accordingly.
<em>To split volumes:</em>
<ol>
<li>Display a mesh, a sub-mesh or a group in the 3D viewer.</li>
<li>Select a mesh, a sub-mesh or a group.</li>
<li>In the \b Modification menu select the <b>Split Volumes</b> item or
click <em>"Split Volumes"</em> button in the toolbar.

View File

@ -140,4 +140,9 @@
<h2>Convert mesh to/from quadratic</h2>
\tui_script{modifying_meshes_ex26.py}
<br>
\anchor tui_split_biquad
<h2>Split bi-quadratic into linear</h2>
\tui_script{split_biquad.py}
*/

View File

@ -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 };

View File

@ -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

BIN
resources/split_biquad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 945 B

View File

@ -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<const SMDS_MeshElement* > 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<const SMDS_MeshElement* > 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<const SMDS_MeshNode*> 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<const SMDS_MeshElement* > 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] );
}
}
}
//=======================================================================

View File

@ -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 };

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 <SALOMEconfig.h>
#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
#include <LightApp_UpdateFlags.h>
#include <SUIT_MessageBox.h>
#include <SUIT_OverrideCursor.h>
#include <SalomeApp_Tools.h>
#include <QStringList>
#include <QGridLayout>
//================================================================================
/*!
* \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<SUIT_SelectionFilter*> 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<SMESH::SMESH_IDSource>( 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;
}

View File

@ -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

View File

@ -599,6 +599,10 @@
<source>ICON_SPLIT_TO_TETRA</source>
<translation>split_into_tetra.png</translation>
</message>
<message>
<source>ICON_SPLIT_BIQUAD</source>
<translation>split_biquad.png</translation>
</message>
<message>
<source>ICON_MEASURE_LENGTH</source>
<translation>mesh_measure_length.png</translation>

View File

@ -1088,6 +1088,18 @@
<source>STB_SPLIT_TO_TETRA</source>
<translation>Split Volumes</translation>
</message>
<message>
<source>MEN_SPLIT_BIQUAD</source>
<translation>Split bi-quadratic into linear</translation>
</message>
<message>
<source>TOP_SPLIT_BIQUAD</source>
<translation>Split bi-quadratic into linear</translation>
</message>
<message>
<source>STB_SPLIT_BIQUAD</source>
<translation>Split bi-quadratic into linear</translation>
</message>
<message>
<source>MESHERS_FILE_CANT_OPEN</source>
<translation>Can not open resource file</translation>
@ -4900,6 +4912,33 @@ Do you want to remove all these sub-meshes?</translation>
Do you want to restore original sub-mesh priority?</translation>
</message>
</context>
<context>
<name>SMESHGUI_SplitBiQuadDlg</name>
<message>
<source>CAPTION</source>
<translation>Split bi-qiadratic into linear</translation>
</message>
<message>
<source>MESH</source>
<translation>Mesh, Group or Sub-mesh</translation>
</message>
</context>
<context>
<name>SMESHGUI_SplitBiQuadOp</name>
<message>
<source>MESH_IS_NOT_SELECTED</source>
<translation>No object to split is selected.
Please specify it and try again</translation>
</message>
<message>
<source>REF_IS_NULL</source>
<translation>No valid mesh object selected</translation>
</message>
<message>
<source>DIFFERENT_MESHES</source>
<translation>Selected objects belong to different meshes</translation>
</message>
</context>
<context>
<name>SMESHGUI_ConvToQuadDlg</name>
<message>

View File

@ -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 );

View File

@ -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 :

View File

@ -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,

View File

@ -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
#
# <a href="../tui_filters_page.html#combining_filters">Example of Criteria usage</a>
@ -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

View File

@ -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<TopoDS_Edge>& theSinuEdges,
size_t theEdgeIndPrev,
size_t theEdgeIndNext,
SMESHDS_Mesh* theMeshDS)
bool findVertexAndNode( NodePoint& theNodePnt,
const vector<TopoDS_Edge>& 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<TopoDS_Edge>& 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<TopoDS_Edge>& 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<TopoDS_Edge>& 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();