Debug 23078: [CEA 1498] Sewing of meshes without having to set the nodes ids

This commit is contained in:
eap 2015-09-23 17:47:26 +03:00
parent 0463dee592
commit fd96feab4b
16 changed files with 455 additions and 183 deletions

BIN
doc/salome/gui/SMESH/images/sewing1.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

View File

@ -41,11 +41,9 @@ To apply this algorithm when you define your mesh, select <b>Body
This dialog allows to define
<ul>
<li>\b Name of the algorithm. </li>
<li> Minimal size of a cell truncated by the geometry boundary. If the
size of a truncated grid cell is \b Threshold times less than a
initial cell size, then a mesh element is not created. </li>
<li> <b> Implement Edges </b> check-box activates incorporation of
geometrical edges in the mesh.
@ -64,9 +62,10 @@ This dialog allows to define
System.</li>
<li> You can define the \b Spacing of a grid as an algebraic formula
<em>f(t)</em> where \a t is a position along a grid axis
normalized at [0.0,1.0]. The whole range of geometry can be
divided into sub-ranges with their own spacing formulas to apply;
\a t varies between 0.0 and 1.0 within each sub-range. \b Insert button
normalized at [0.0,1.0]. <em>f(t)</em> must be non-negative
at 0. <= \a t <= 1. The whole extent of geometry can be
divided into ranges with their own spacing formulas to apply;
\a t varies between 0.0 and 1.0 within each \b Range. \b Insert button
divides a selected range into two. \b Delete button adds the
selected sub-range to the previous one. Double click on a range in
the list enables edition of its right boundary. Double click on a

View File

@ -16,8 +16,8 @@ and hypotheses.
Mesh generation on the geometry is performed in the bottom-up
flow: nodes on vertices are created first, then edges are divided into
segments using nodes on vertices; the segments of edges are then
used to mesh faces; then the mesh of faces is used to mesh
segments using nodes on vertices; the node of segments are then
used to mesh faces; then the nodes of faces are used to mesh
solids. This automatically assures the conformity of the mesh.
It is required to choose a meshing algorithm for every dimension of

View File

@ -20,9 +20,11 @@ and from its sub-menu select the \b Sewing item.</li>
<li>Check in the dialog box one of the radio buttons corresponding to
the type of sewing operation you would like to perform.</li>
<li>Fill the other fields available in the dialog box.</li>
<li>Click the \b Apply or <b>Apply and Close</b> button to perform the operation of sewing.</li>
<li>Click the \b Apply or <b>Apply and Close</b> button to perform the
operation of sewing.</li>
</ol>
<br>
\anchor free_borders_anchor
<h2>Sew free borders</h2>
@ -31,14 +33,69 @@ This functionality allows you to unite free borders of a 2D mesh.
There are two working modes: \a Automatic and \a Manual. In the \b
Automatic mode, the program finds free borders coincident within a
certain tolerance and sew them. Optionally it is possible to adjust
the found free borders before sewing. In the \b Manual mode you are to
define borders to sew by picking three nodes of each border.
specified tolerance and sews them. Optionally it is possible to
visually check and correct is necessary the found free borders before
sewing. <br>
In the \b Manual mode you are to define borders to sew by picking
three nodes of each of two borders.
\image html sewing1.png
<center>Default mode is \a Automatic</center>
For sewing free borders you should define three points on each border:
first, second and the last node:
To use \b Automatic sewing:
<ul>
<li>Specify a mesh you want to sew by selecting it or any its part
(group or sub-mesh) in the Object Browser or in the VTK Viewer.</li>
<li>Specify the \b Tolerance within which free borders are considered
coincident. At the default zero \b Tolerance, the tolerance used by
the search algorithm is defined as one tenth of an average size of
elements adjacent to free borders being compared.</li>
<li>To visually check the coincident free borders found by the
algorithm, switch off <b>Auto Sewing</b> check-box. Then controls
to adjust groups of coincident free borders will become available in
the dialog.</li>
\image html sewing_auto.png
<center>Controls to adjust groups of coincident free borders</center>
<li>\b Detect button launches the algorithm of search of coincident
free borders.</li>
<li>The found groups of <b>Coincident Free Borders</b> are shown in a
list, a group per a line. Each group has its own color which is used
to display the borders of the group in the VTK Viewer. A free border
within a group is designated by IDs of its first and last nodes within
parenthesis. All borders present in the list will be sewn upon \b
Apply.</li>
<li>\b Remove button removes selected groups from the list.</li>
<li><b>Select All</b> check-box selects all groups in the list.</li>
<li>When a group is selected, its borders appear in <b>Edit Selected
Group</b> list that allows you to change this group.</li>
<li>
\image html sort.png
<em>Set First</em> button moves the selected border to the
first position in the group, as a result other borders will be moved
to this border during sewing.
</li><li>
\image html remove.png
<em>Remove Border</em> button removes selected borders from the
group. It is active if there are more than two borders in the group.
</li>
<li>Selection of a border in the list allows to change its first and
last nodes whose IDs appear in two fields below the list. \a Arrow
buttons near each field move the corresponding end node by
number of nodes defined by \b Step field.</li>
<li>
\image html swap.png
<em>Swap</em> button swaps the first and last nodes of a
selected border.
</li>
</ul>
For sewing free borders manually you should switch the \b Mode to \b
Manual and define three points on each border: first, second and the
last node:
\image html sewing_manual.png
<ul>
<li>the first node specifies beginning of the border;</li>
<li>the second node specifies the part of the border which should be

View File

@ -38,7 +38,6 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
Status aResult = DRS_OK;
int nbNodes, nbCells;
//int i;
char *file2Read = (char *)myFile.c_str();
FILE* aFileId = fopen(file2Read, "w+");
@ -55,7 +54,7 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
nbNodes = myMesh->NbNodes();
/* Combien de mailles, faces ou aretes ? */
int /*nb_of_nodes,*/ nb_of_edges, nb_of_faces, nb_of_volumes;
int nb_of_edges, nb_of_faces, nb_of_volumes;
nb_of_edges = myMesh->NbEdges();
nb_of_faces = myMesh->NbFaces();
nb_of_volumes = myMesh->NbVolumes();
@ -64,7 +63,7 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
SCRUTE(nb_of_faces);
SCRUTE(nb_of_volumes);
fprintf(stdout, "%d %d\n", nbNodes, nbCells);
//fprintf(stdout, "%d %d\n", nbNodes, nbCells);
fprintf(aFileId, "%d %d\n", nbNodes, nbCells);
/****************************************************************************
@ -74,7 +73,7 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
SMDS_NodeIteratorPtr itNodes=myMesh->nodesIterator();
while(itNodes->more()){
const SMDS_MeshNode * node = itNodes->next();
fprintf(aFileId, "%d %e %e %e\n", node->GetID(), node->X(), node->Y(), node->Z());
fprintf(aFileId, "%d %.14e %.14e %.14e\n", node->GetID(), node->X(), node->Y(), node->Z());
}
/****************************************************************************

View File

@ -56,7 +56,8 @@ DriverMED_W_SMESHDS_Mesh::DriverMED_W_SMESHDS_Mesh():
myDoGroupOfVolumes (false),
myDoGroupOf0DElems(false),
myDoGroupOfBalls(false),
myAutoDimension(true)
myAutoDimension(true),
myAddODOnVertices(false)
{}
void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName,

View File

@ -139,8 +139,12 @@ const SMDS_MeshNode* SMDS_Mesh0DElement::GetNode(const int ind) const
//function : ChangeNode
//purpose :
//=======================================================================
bool SMDS_Mesh0DElement::ChangeNode (const SMDS_MeshNode * node)
bool SMDS_Mesh0DElement::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes)
{
myNode = node;
return true;
if ( nbNodes == 1 )
{
myNode = nodes[0];
return true;
}
return false;
}

View File

@ -34,8 +34,7 @@ class SMDS_EXPORT SMDS_Mesh0DElement: public SMDS_MeshCell
{
public:
SMDS_Mesh0DElement (const SMDS_MeshNode * node);
bool ChangeNode (const SMDS_MeshNode * node);
virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) {return false;};
virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes);
virtual void Print (std::ostream & OS) const;
virtual SMDSAbs_ElementType GetType() const;

View File

@ -7371,8 +7371,8 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
for ( ; eIt != elems.end(); eIt++ )
{
const SMDS_MeshElement* elem = *eIt;
int nbNodes = elem->NbNodes();
int aShapeId = FindShape( elem );
const int nbNodes = elem->NbNodes();
const int aShapeId = FindShape( elem );
nodeSet.clear();
curNodes.resize( nbNodes );
@ -7912,17 +7912,24 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
if ( isOk ) // the non-poly elem remains valid after sticking nodes
{
elemType.Init( elem ).SetID( elem->GetID() );
if ( nbNodes != nbUniqueNodes )
{
elemType.Init( elem ).SetID( elem->GetID() );
SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
uniqueNodes.resize(nbUniqueNodes);
SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
if ( sm && newElem )
sm->AddElement( newElem );
if ( elem != newElem )
ReplaceElemInGroups( elem, newElem, aMesh );
uniqueNodes.resize(nbUniqueNodes);
SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
if ( sm && newElem )
sm->AddElement( newElem );
if ( elem != newElem )
ReplaceElemInGroups( elem, newElem, aMesh );
}
else
{
aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes );
}
}
else {
// Remove invalid regular element or invalid polygon
@ -8749,7 +8756,8 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
}
// find coincident
TListOfListOfElementsID equalGroups;
FindEqualElements( segments, equalGroups );
if ( !segments.empty() )
FindEqualElements( segments, equalGroups );
if ( !equalGroups.empty() )
{
// remove from segments those that will be removed

View File

@ -329,14 +329,13 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
SelectAllCheck = new QCheckBox(tr("SELECT_ALL"), GroupCoincident);
aCoincidentLayout->addWidget(ListCoincident, 0, 0, 4, 2);
aCoincidentLayout->addWidget(ListCoincident, 0, 0, 5, 2);
aCoincidentLayout->addWidget(DetectButton, 1, 2);
aCoincidentLayout->addWidget(RemoveGroupButton, 3, 2);
aCoincidentLayout->addWidget(SelectAllCheck, 4, 0);
aCoincidentLayout->addWidget(SelectAllCheck, 5, 0);
aCoincidentLayout->setRowMinimumHeight(1, 10);
aCoincidentLayout->setRowStretch (1, 5);
GroupCoincidentLayout->addWidget( GroupCoincident );
aCoincidentLayout->setRowStretch (4, 5);
aCoincidentLayout->setRowStretch (5, 0);
/*****************************************/
// Controls for editing the selected group
@ -391,8 +390,13 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
GroupEditLayout->addWidget(SwapBut, 1, 7);
GroupEditLayout->addWidget(StepLabel, 1, 8);
GroupEditLayout->addWidget(StepSpin, 1, 9);
GroupEditLayout->setRowStretch( 0, 1 );
GroupCoincidentLayout->addWidget( GroupCoincident );
GroupCoincidentLayout->addWidget( GroupEdit );
GroupCoincidentLayout->setRowStretch( 0, 10 );
GroupCoincidentLayout->setRowStretch( 1, 1 );
aSewFreeBordersLayout->addWidget( GroupCoincidentWidget );
// layout
@ -579,6 +583,7 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId)
{
ModeGroup->hide();
SewFreeBordersWidget->hide();
restoreDisplayMode();
}
bool isNodeSelection = true;
@ -673,12 +678,11 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId)
LineEdit4->setValidator(new SMESHGUI_IdValidator(this, 1));
}
if ( isNodeSelection )
{
SMESH::SetPointRepresentation(true);
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
aViewWindow->SetSelectionMode(NodeSelection);
}
if ( myActor )
myActor->SetPointRepresentation( isNodeSelection );
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
aViewWindow->SetSelectionMode( isNodeSelection ? NodeSelection : ActorSelection );
UpdateButtons();
@ -700,7 +704,8 @@ void SMESHGUI_SewingDlg::setDisplayMode()
{
myStoredEntityMode = 0;
myStoredRepresentation = -1;
if ( myActor )
if ( myActor && AutoSewCheck->isVisible() && !AutoSewCheck->isChecked() )
{
myStoredEntityMode = myActor->GetEntityMode();
myStoredRepresentation = myActor->GetRepresentation();
@ -728,6 +733,9 @@ void SMESHGUI_SewingDlg::restoreDisplayMode()
myStoredEntityMode = 0;
myStoredRepresentation = -1;
}
for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
if ( myBorderDisplayers[ i ])
myBorderDisplayers[ i ]->Hide();
}
//=======================================================================
@ -751,6 +759,12 @@ void SMESHGUI_SewingDlg::onModeChange( int mode )
if ( !SewFreeBordersWidget->isVisible() )
SewFreeBordersWidget->show();
}
if ( myActor )
myActor->SetPointRepresentation( mode == MODE_MANUAL );
if ( SVTK_ViewWindow* aViewWindow = SMESH::GetCurrentVtkView() )
aViewWindow->SetSelectionMode( mode == MODE_MANUAL ? NodeSelection : ActorSelection );
onAutoSew( AutoSewCheck->isChecked() );
QApplication::instance()->processEvents();
@ -774,6 +788,12 @@ void SMESHGUI_SewingDlg::onAutoSew( int isAuto )
if ( ModeButGrp->checkedId() == MODE_AUTO )
SewFreeBordersWidget->show();
if ( isAuto )
restoreDisplayMode();
else
setDisplayMode();
SMESH::RepaintCurrentView();
UpdateButtons();
updateGeometry();
@ -847,6 +867,7 @@ QString SMESHGUI_SewingDlg::getGroupText(int groupIndex)
void SMESHGUI_SewingDlg::onDetectClicked()
{
myBusy = true;
ListCoincident->clear();
if ( myMesh->_is_nil() )
@ -881,6 +902,7 @@ void SMESHGUI_SewingDlg::onDetectClicked()
item->setData( GROUP_COLOR, groupColor );
item->setData( GROUP_INDEX, i );
}
myBusy = false;
onSelectGroup();
@ -894,6 +916,7 @@ void SMESHGUI_SewingDlg::onDetectClicked()
void SMESHGUI_SewingDlg::onRemoveGroupClicked()
{
myBusy = true;
QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
for ( int i = 0; i < selItems.count(); ++i )
{
@ -901,10 +924,14 @@ void SMESHGUI_SewingDlg::onRemoveGroupClicked()
item->setSelected( false );
int groupIndex = item->data( GROUP_INDEX ).toInt();
delete item;
myBorderDisplayers[ groupIndex ]->Hide();
if ( myBorderDisplayers[ groupIndex ])
myBorderDisplayers[ groupIndex ]->Hide();
SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
aGRP.length( 0 );
}
myBusy = false;
onSelectGroup();
UpdateButtons();
}
@ -917,7 +944,7 @@ void SMESHGUI_SewingDlg::showGroup( QListWidgetItem* item )
{
if ( !item ||
item->listWidget() != ListCoincident ||
!haveBorders() )
!haveBorders())
return;
int groupIndex = item->data( GROUP_INDEX ).toInt();
@ -925,10 +952,11 @@ void SMESHGUI_SewingDlg::showGroup( QListWidgetItem* item )
if ( groupIndex >= 0 &&
groupIndex < myBorders->coincidentGroups.length() )
{
if ( !myBorderDisplayers[ groupIndex ])
if ( !myBorderDisplayers[ groupIndex ] && SMESH::GetCurrentVtkView())
myBorderDisplayers[ groupIndex ] = new BorderGroupDisplayer( myBorders, groupIndex, groupColor, myMesh );
bool wholeBorders = setCurrentGroup();
myBorderDisplayers[ groupIndex ]->ShowGroup( wholeBorders );
if ( myBorderDisplayers[ groupIndex ])
myBorderDisplayers[ groupIndex ]->ShowGroup( wholeBorders );
}
}
@ -1111,7 +1139,8 @@ void SMESHGUI_SewingDlg::onGroupChange( bool partChange )
for ( int i = 0; i < ListEdit->count(); ++i )
ListEdit->item( i )->setText( getPartText( aGRP[ i ]));
myBorderDisplayers[ myCurGroupIndex ]->Update();
if ( myBorderDisplayers[ myCurGroupIndex ])
myBorderDisplayers[ myCurGroupIndex ]->Update();
if ( partChange )
onSelectBorderPartFromGroup();
@ -1410,6 +1439,7 @@ void SMESHGUI_SewingDlg::onCloseView()
{
DeactivateActiveDialog();
mySelector = 0;
myActor = 0;
for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
{
@ -1969,11 +1999,11 @@ void SMESHGUI_SewingDlg::BorderGroupDisplayer::Update()
myPartActors[ i ] = SMESH_Actor::New( obj, "", "", 1 );
myPartActors[ i ]->SetEdgeColor( myColor.redF(), myColor.greenF(), myColor.blueF() );
myPartActors[ i ]->SetLineWidth( 3 * SMESH::GetFloat("SMESH:element_width",1));
myPartActors[ i ]->SetPickable( false );
myPartActors[ i ]->SetNodeColor( myColor.redF(), myColor.greenF(), myColor.blueF() );
myPartActors[ i ]->SetMarkerStd( VTK::MT_POINT, 13 );
myPartActors[ i ]->SetPickable ( false );
myViewWindow->AddActor( myPartActors[ i ]);
myViewWindow->Repaint();
//myViewWindow->Repaint();
}
}
}

View File

@ -47,17 +47,20 @@ namespace
/*!
* \brief Node on a free border
*/
struct BNode
struct BNode : public SMESH_TNodeXYZ
{
const SMDS_MeshNode * myNode;
mutable std::vector< BEdge* > myLinkedEdges;
mutable std::vector< BEdge* > myCloseEdges;
mutable std::vector< std::pair < BEdge*, double > > myCloseEdges; // edge & U
BNode(const SMDS_MeshNode * node): myNode( node ) {}
BNode(const SMDS_MeshNode * node): SMESH_TNodeXYZ( node ) {}
const SMDS_MeshNode * Node() const { return _node; }
void AddLinked( BEdge* e ) const;
void AddClose ( const BEdge* e ) const;
BEdge* FindCloseEdgeOfBorder( int borderID ) const;
bool operator<(const BNode& other) const { return myNode->GetID() < other.myNode->GetID(); }
void AddClose ( const BEdge* e, double u ) const;
BEdge* GetCloseEdge( size_t i ) const { return myCloseEdges[i].first; }
double GetCloseU( size_t i ) const { return myCloseEdges[i].second; }
BEdge* GetCloseEdgeOfBorder( int borderID, double * u = 0 ) const;
bool IsCloseEdge( const BEdge* ) const;
bool operator<(const BNode& other) const { return Node()->GetID() < other.Node()->GetID(); }
};
/*!
* \brief Edge of a free border
@ -72,9 +75,9 @@ namespace
BEdge* myNext;
const SMDS_MeshElement* myFace;
std::set< int > myCloseBorders;
bool myInGroup;
int myInGroup;
BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(0) {}
BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(-1) {}
void Set( const BNode * node1,
const BNode * node2,
@ -83,11 +86,15 @@ namespace
{
myBNode1 = node1;
myBNode2 = node2;
myNodes[0] = node1->myNode;
myNodes[1] = node2->myNode;
myNodes[0] = node1->Node();
myNodes[1] = node2->Node();
myFace = face;
setId( ID ); // mesh element ID
}
bool IsInGroup() const
{
return myInGroup >= 0;
}
bool Contains( const BNode* n ) const
{
return ( n == myBNode1 || n == myBNode2 );
@ -105,8 +112,8 @@ namespace
void Reverse()
{
std::swap( myBNode1, myBNode2 );
myNodes[0] = myBNode1->myNode;
myNodes[1] = myBNode2->myNode;
myNodes[0] = myBNode1->Node();
myNodes[1] = myBNode2->Node();
}
void Orient()
{
@ -125,25 +132,95 @@ namespace
myNext->SetID( id + 1 );
}
}
void FindRangeOfSameCloseBorders(BEdge* eRange[2])
bool IsOut( const gp_XYZ& point, const double tol, double& u ) const
{
gp_XYZ me = *myBNode2 - *myBNode1;
gp_XYZ n1p = point - *myBNode1;
u = ( me * n1p ) / me.SquareModulus(); // param [0,1] on this
if ( u < 0. ) return ( n1p.SquareModulus() > tol * tol );
if ( u > 1. ) return ( ( point - *myBNode2 ).SquareModulus() > tol * tol );
gp_XYZ proj = ( 1. - u ) * *myBNode1 + u * *myBNode2; // projection of the point on this
double dist2 = ( point - proj ).SquareModulus();
return ( dist2 > tol * tol );
}
bool IsOverlappingProjection( const BEdge* toE, const double u, bool is1st ) const
{
// is1st shows which end of toE is projected on this at u
double u2;
const double eps = 0.1;
if ( toE == myBNode1->GetCloseEdgeOfBorder( toE->myBorderID, &u2 ) ||
toE == myBNode2->GetCloseEdgeOfBorder( toE->myBorderID, &u2 ))
return (( 0 < u2 && u2 < 1 ) && // u2 is proj param of myBNode's on toE
( Abs( u2 - int( !is1st )) > eps ));
const BNode* n = is1st ? toE->myBNode2 : toE->myBNode1;
if ( this == n->GetCloseEdgeOfBorder( this->myBorderID, &u2 ))
return Abs( u - u2 ) > eps;
return false;
}
bool GetRangeOfSameCloseBorders(BEdge* eRange[2], const std::set< int >& bordIDs)
{
if ( this->myCloseBorders != bordIDs )
return false;
eRange[0] = this;
while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == this->myCloseBorders )
while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == bordIDs )
{
if ( eRange[0]->myPrev == this /*|| eRange[0]->myPrev->myInGroup*/ )
break;
eRange[0] = eRange[0]->myPrev;
}
eRange[1] = this;
if ( eRange[0]->myPrev != this ) // not closed range
while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == this->myCloseBorders )
while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == bordIDs )
{
if ( eRange[1]->myNext == this /*|| eRange[1]->myNext->myInGroup*/ )
break;
eRange[1] = eRange[1]->myNext;
}
return ( eRange[0] != eRange[1] );
}
};
}; // class BEdge
void extendPart( BEdge* & e1, BEdge* & e2, const std::set< int >& bordIDs, int groupID )
{
if (( e1->myPrev == e2 ) ||
( e1 == e2 && e1->myPrev && e1->myPrev->myInGroup == groupID ))
return; // full free border already
double u;
BEdge* be;
std::set<int>::const_iterator bord;
if ( e1->myPrev )
{
for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord )
if (( *bord != e1->myBorderID ) &&
(( be = e1->myBNode1->GetCloseEdgeOfBorder( *bord, &u ))) &&
( be->myInGroup == groupID ) &&
( 0 < u && u < 1 ) &&
( be->IsOverlappingProjection( e1->myPrev, u, false )))
{
e1 = e1->myPrev;
break;
}
}
if ( e2->myNext )
{
for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord )
if (( *bord != e2->myBorderID ) &&
(( be = e2->myBNode2->GetCloseEdgeOfBorder( *bord, &u ))) &&
( be->myInGroup == groupID ) &&
( 0 < u && u < 1 ) &&
( be->IsOverlappingProjection( e2->myNext, u, true )))
{
e2 = e2->myNext;
break;
}
}
}
void BNode::AddLinked( BEdge* e ) const
{
@ -164,17 +241,32 @@ namespace
myLinkedEdges[i]->RemoveLinked( myLinkedEdges[j] );
}
}
void BNode::AddClose ( const BEdge* e ) const
void BNode::AddClose ( const BEdge* e, double u ) const
{
if ( ! e->Contains( this ))
myCloseEdges.push_back( const_cast< BEdge* >( e ));
myCloseEdges.push_back( make_pair( const_cast< BEdge* >( e ), u ));
}
BEdge* BNode::FindCloseEdgeOfBorder( int borderID ) const
BEdge* BNode::GetCloseEdgeOfBorder( int borderID, double * uPtr ) const
{
BEdge* e = 0;
double u = 0;
for ( size_t i = 0; i < myCloseEdges.size(); ++i )
if ( borderID == GetCloseEdge( i )->myBorderID )
{
if ( e && Abs( u - 0.5 ) < Abs( GetCloseU( i ) - 0.5 ))
continue;
u = GetCloseU( i );
e = GetCloseEdge ( i );
}
if ( uPtr ) *uPtr = u;
return e;
}
bool BNode::IsCloseEdge( const BEdge* e ) const
{
for ( size_t i = 0; i < myCloseEdges.size(); ++i )
if ( borderID == myCloseEdges[ i ]->myBorderID )
return myCloseEdges[ i ];
return 0;
if ( e == GetCloseEdge( i ) )
return true;
return false;
}
/// Accessor to SMDS_MeshElement* inherited by BEdge
@ -333,12 +425,11 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
std::vector< const SMDS_MeshElement* > candidateEdges;
for ( bn = bNodes.begin(); bn != bNodes.end(); ++bn )
{
gp_Pnt point = SMESH_TNodeXYZ( bn->myNode );
searcher->FindElementsByPoint( point, SMDSAbs_Edge, candidateEdges );
searcher->FindElementsByPoint( *bn, SMDSAbs_Edge, candidateEdges );
if ( candidateEdges.size() <= bn->myLinkedEdges.size() )
continue;
double nodeTol = 0;
double nodeTol = 0, u;
for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
nodeTol = Max( nodeTol, bordToler[ bn->myLinkedEdges[ i ]->myBorderID ]);
@ -346,9 +437,8 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
{
const BEdge* be = static_cast< const BEdge* >( candidateEdges[ i ]);
double tol = Max( nodeTol, bordToler[ be->myBorderID ]);
if ( maxTolerance - tol < 1e-12 ||
!SMESH_MeshAlgos::IsOut( be, point, tol ))
bn->AddClose( be );
if ( !be->IsOut( *bn, tol, u ))
bn->AddClose( be, u );
}
}
@ -366,8 +456,8 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
for ( size_t iE1 = 0; iE1 < be.myBNode1->myCloseEdges.size(); ++iE1 )
{
// find edges of the same border close to both nodes of the edge
BEdge* closeE1 = be.myBNode1->myCloseEdges[ iE1 ];
BEdge* closeE2 = be.myBNode2->FindCloseEdgeOfBorder( closeE1->myBorderID );
BEdge* closeE1 = be.myBNode1->GetCloseEdge( iE1 );
BEdge* closeE2 = be.myBNode2->GetCloseEdgeOfBorder( closeE1->myBorderID );
if ( !closeE2 )
continue;
// check that edges connecting closeE1 and closeE2 (if any) are also close to 'be'
@ -378,7 +468,7 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
{
BEdge* ce = closeE1;
do {
coincide = ( ce->myBNode2->FindCloseEdgeOfBorder( be.myBorderID ));
coincide = ( ce->myBNode2->GetCloseEdgeOfBorder( be.myBorderID ));
ce = ce->myNext;
} while ( coincide && ce && ce != closeE2 );
@ -415,9 +505,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
for ( size_t i = 0; i < borders.size(); ++i )
{
BEdge* be = borders[i];
foundFreeBordes._borders[i].push_back( be->myBNode1->myNode );
foundFreeBordes._borders[i].push_back( be->myBNode1->Node() );
do {
foundFreeBordes._borders[i].push_back( be->myBNode2->myNode );
foundFreeBordes._borders[i].push_back( be->myBNode2->Node() );
be = be->myNext;
}
while ( be && be != borders[i] );
@ -427,81 +517,158 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh,
TFreeBorderPart part;
TCoincidentGroup group;
for ( size_t i = 0; i < borders.size(); ++i )
vector< BEdge* > ranges; // couples of edges delimiting parts
BEdge* be = 0; // a current edge
int skipGroup = bEdges.size(); // a group ID used to avoid repeating treatment of edges
for ( int i = 0, nbBords = borders.size(); i < nbBords; i += bool(!be) )
{
BEdge* be = borders[i];
if ( !be )
be = borders[i];
// look for an edge close to other borders
do {
if ( !be->myInGroup && !be->myCloseBorders.empty() )
if ( !be->IsInGroup() && !be->myCloseBorders.empty() )
break;
be = be->myNext;
} while ( be && be != borders[i] );
if ( !be || be->myInGroup || be->myCloseBorders.empty() )
continue; // all edges of a border treated or are non-coincident
if ( !be || be->IsInGroup() || be->myCloseBorders.empty() )
{
be = 0;
continue; // all edges of a border are treated or non-coincident
}
group.clear();
ranges.clear();
// look for the 1st and last edge of a coincident group
BEdge* beRange[2];
be->FindRangeOfSameCloseBorders( beRange );
BEdge* be1st = beRange[0];
if ( !be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders ))
{
be->myInGroup = skipGroup;
be = be->myNext;
continue;
}
// fill in a group
part._border = i;
part._node1 = beRange[0]->myID;
part._node2 = beRange[0]->myID + 1;
part._nodeLast = beRange[1]->myID + 1;
group.push_back( part );
ranges.push_back( beRange[0] );
ranges.push_back( beRange[1] );
int groupID = foundFreeBordes._coincidentGroups.size();
be = beRange[0];
be->myInGroup = true;
be->myInGroup = groupID;
while ( be != beRange[1] )
{
be->myInGroup = true;
be->myInGroup = groupID;
be = be->myNext;
}
beRange[1]->myInGroup = true;
beRange[1]->myInGroup = groupID;
// add parts of other borders
BEdge* be1st = beRange[0];
closeEdges.clear();
std::set<int>::iterator closeBord = be1st->myCloseBorders.begin();
for ( ; closeBord != be1st->myCloseBorders.end(); ++closeBord )
closeEdges.push_back( be1st->myBNode2->GetCloseEdgeOfBorder( *closeBord ));
for ( size_t iE = 0; iE < closeEdges.size(); ++iE )
{
be = be1st->myBNode2->FindCloseEdgeOfBorder( *closeBord );
be = closeEdges[ iE ];
if ( !be ) continue;
be->FindRangeOfSameCloseBorders( beRange );
// find out mutual orientation of borders
bool reverse = ( beRange[0]->myBNode1->FindCloseEdgeOfBorder( i ) != be1st &&
beRange[0]->myBNode2->FindCloseEdgeOfBorder( i ) != be1st );
// fill in a group
part._border = beRange[0]->myBorderID;
if ( reverse ) {
part._node1 = beRange[1]->myID + 1;
part._node2 = beRange[1]->myID;
part._nodeLast = beRange[0]->myID;
}
else {
part._node1 = beRange[0]->myID;
part._node2 = beRange[0]->myID + 1;
part._nodeLast = beRange[1]->myID + 1;
}
group.push_back( part );
bool ok = be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders );
if ( !ok && be->myPrev )
ok = be->myPrev->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders );
if ( !ok && be->myNext )
ok = be->myNext->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders );
if ( !ok )
continue;
be = beRange[0];
be->myInGroup = true;
if ( be->myCloseBorders != be1st->myCloseBorders )
{
//add missing edges to closeEdges
closeBord = be->myCloseBorders.begin();
for ( ; closeBord != be->myCloseBorders.end(); ++closeBord )
if ( !be1st->myCloseBorders.count( *closeBord ))
closeEdges.push_back( be->myBNode2->GetCloseEdgeOfBorder( *closeBord ));
}
ranges.push_back( beRange[0] );
ranges.push_back( beRange[1] );
be->myInGroup = groupID;
while ( be != beRange[1] )
{
be->myInGroup = true;
be->myInGroup = groupID;
be = be->myNext;
}
beRange[1]->myInGroup = true;
beRange[1]->myInGroup = groupID;
}
foundFreeBordes._coincidentGroups.push_back( group );
if ( ranges.size() > 2 )
{
for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
// fill in a group
beRange[0] = ranges[0];
beRange[1] = ranges[1];
part._border = i;
part._node1 = beRange[0]->myID;
part._node2 = beRange[0]->myID + 1;
part._nodeLast = beRange[1]->myID + 1;
group.push_back( part );
be1st = beRange[0];
for ( size_t iR = 3; iR < ranges.size(); iR += 2 )
{
beRange[0] = ranges[iR-1];
beRange[1] = ranges[iR-0];
// find out mutual orientation of borders
double u1, u2;
be1st ->IsOut( *beRange[ 0 ]->myBNode1, maxTolerance, u1 );
beRange[ 0 ]->IsOut( *be1st->myBNode1, maxTolerance, u2 );
bool reverse = (( u1 < 0 || u1 > 1 ) && ( u2 < 0 || u2 > 1 ));
// fill in a group
part._border = beRange[0]->myBorderID;
if ( reverse ) {
part._node1 = beRange[1]->myID + 1;
part._node2 = beRange[1]->myID;
part._nodeLast = beRange[0]->myID;
}
else {
part._node1 = beRange[0]->myID;
part._node2 = beRange[0]->myID + 1;
part._nodeLast = beRange[1]->myID + 1;
}
group.push_back( part );
}
foundFreeBordes._coincidentGroups.push_back( group );
}
else
{
beRange[0] = ranges[0];
beRange[1] = ranges[1];
be = beRange[0];
be->myInGroup = skipGroup;
while ( be != beRange[1] )
{
be->myInGroup = skipGroup;
be = be->myNext;
}
beRange[1]->myInGroup = skipGroup;
}
be = ranges[1];
} // loop on free borders
}
return;
} // SMESH_MeshAlgos::FindCoincidentFreeBorders()

View File

@ -1210,19 +1210,13 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
{
gp_Vec edge( xyz[i-1], xyz[i] );
gp_Vec n1p ( xyz[i-1], point );
// double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
// if ( dist > tol )
// continue;
// gp_Vec n2p( xyz[i], point );
// if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
// continue;
double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
if ( u < 0. ) {
if ( u <= 0. ) {
if ( n1p.SquareMagnitude() < tol * tol )
return false;
continue;
}
if ( u > 1. ) {
if ( u >= 1. ) {
if ( point.SquareDistance( xyz[i] ) < tol * tol )
return false;
continue;

View File

@ -4641,11 +4641,12 @@ SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
CORBA::Short nbSewed = 0;
SMESH_MeshAlgos::TFreeBorderVec groups;
SMESH_MeshAlgos::TFreeBorder borderNodes; // triples on nodes for every FreeBorderPart
SMESH_MeshAlgos::TFreeBorder borderNodes; // triples of nodes for every FreeBorderPart
// check the input
// check the input and collect nodes
for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
{
borderNodes.clear();
const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
{
@ -4672,71 +4673,70 @@ SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
if ( !n3 )
THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
borderNodes.push_back( n1 );
borderNodes.push_back( n2 );
borderNodes.push_back( n3 );
}
groups.push_back( borderNodes );
}
// SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
// to get nodes that replace other nodes during merge we create 0D elements
// on each node and MergeNodes() will replace underlying nodes of 0D elements by
// new ones.
vector< const SMDS_MeshElement* > tmp0Delems;
for ( size_t i = 0; i < groups.size(); ++i )
{
SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
for ( size_t iN = 0; iN < nodes.size(); ++iN )
{
SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
if ( it0D->more() )
tmp0Delems.push_back( it0D->next() );
else
tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
}
}
//TIDSortedElemSet dummy;
SMESH_TRY;
::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
int i0D = 0;
for ( size_t i = 0; i < groups.size(); ++i )
{
const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
if ( aGRP.length() < 2 )
continue;
//int n1bord2, n2bord2;
bool groupSewed = false;
for ( CORBA::ULong iP = 1; iP < aGRP.length(); ++iP )
bool isBordToBord = true;
bool groupSewed = false;
SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
{
const SMESH::FreeBorderPart& aPART_0 = aGRP[ 0 ];
const SMESH::FreeBorder& aBRD_0 = freeBorders.borders[ aPART_0.border ];
const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
const SMDS_MeshNode* n0 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.node1 ]);
const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.node2 ]);
const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.nodeLast ]);
const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1 ]);
const SMDS_MeshNode* n4 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2 ]);
const SMDS_MeshNode* n5 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
continue;
// if ( iP == 1 )
// {
// n1bord2 = aBRD.nodeIDs[ aPART.node1 ];
// n2bord2 = aBRD.nodeIDs[ aPART.node2 ];
// }
// else if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, dummy, dummy ))
// {
// // a face including n0 and n1 was split;
// // find a new face starting at n0 in order to get a new n1
// const SMDS_MeshNode* n1test = getMeshDS()->FindNode( n1bord2 );
// const SMDS_MeshNode* n2test = getMeshDS()->FindNode( n2bord2 );
// if ( n1test && SMESH_MeshAlgos::FindFaceInSet( n0, n1test, dummy, dummy ))
// n1 = n1test;
// else if ( n2test && SMESH_MeshAlgos::FindFaceInSet( n0, n2test, dummy, dummy ))
// n1 = n2test;
// // else continue; ??????
// }
if ( iP > 1 )
if ( !isBordToBord )
{
n1 = n2; // at border-to-side sewing only last side node (n1) is needed
n2 = 0; // and n2 is not used
}
// 1st border moves to 2nd
res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
n0 ,n1 ,n2 ,// 2nd
/*2ndIsFreeBorder=*/ iP == 1,
/*2ndIsFreeBorder=*/ isBordToBord,
createPolygons, createPolyhedra);
groupSewed = ( res == ok );
isBordToBord = false;
}
i0D += nodes.size();
nbSewed += groupSewed;
}
@ -4745,6 +4745,20 @@ SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
<< createPolygons << ", "
<< createPolyhedra << " )";
SMESH_CATCH( SMESH::doNothing );
declareMeshModified( /*isReComputeSafe=*/false );
// remove tmp 0D elements
SMESH_TRY;
set< const SMDS_MeshElement* > removed0D;
for ( size_t i = 0; i < tmp0Delems.size(); ++i )
{
if ( removed0D.insert( tmp0Delems[i] ).second )
getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
}
SMESH_CATCH( SMESH::throwCorbaException );
return nbSewed;
}