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.
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
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
<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>
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>
+
+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:
-For sewing free borders you should 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
Status aResult = DRS_OK;
int nbNodes, nbCells;
- //int i;
char *file2Read = (char *)myFile.c_str();
FILE* aFileId = fopen(file2Read, "w+");
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();
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);
/****************************************************************************
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());
}
/****************************************************************************
myDoGroupOfVolumes (false),
myDoGroupOf0DElems(false),
myDoGroupOfBalls(false),
- myAutoDimension(true)
+ myAutoDimension(true),
+ myAddODOnVertices(false)
{}
void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName,
//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;
}
{
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;
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 );
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
}
// find coincident
TListOfListOfElementsID equalGroups;
- FindEqualElements( segments, equalGroups );
+ if ( !segments.empty() )
+ FindEqualElements( segments, equalGroups );
if ( !equalGroups.empty() )
{
// remove from segments those that will be removed
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
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
{
ModeGroup->hide();
SewFreeBordersWidget->hide();
+ restoreDisplayMode();
}
bool isNodeSelection = true;
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();
{
myStoredEntityMode = 0;
myStoredRepresentation = -1;
- if ( myActor )
+
+ if ( myActor && AutoSewCheck->isVisible() && !AutoSewCheck->isChecked() )
{
myStoredEntityMode = myActor->GetEntityMode();
myStoredRepresentation = myActor->GetRepresentation();
myStoredEntityMode = 0;
myStoredRepresentation = -1;
}
+ for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
+ if ( myBorderDisplayers[ i ])
+ myBorderDisplayers[ i ]->Hide();
}
//=======================================================================
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();
if ( ModeButGrp->checkedId() == MODE_AUTO )
SewFreeBordersWidget->show();
+ if ( isAuto )
+ restoreDisplayMode();
+ else
+ setDisplayMode();
+ SMESH::RepaintCurrentView();
+
UpdateButtons();
updateGeometry();
void SMESHGUI_SewingDlg::onDetectClicked()
{
+ myBusy = true;
ListCoincident->clear();
if ( myMesh->_is_nil() )
item->setData( GROUP_COLOR, groupColor );
item->setData( GROUP_INDEX, i );
}
+ myBusy = false;
onSelectGroup();
void SMESHGUI_SewingDlg::onRemoveGroupClicked()
{
+ myBusy = true;
QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
for ( int i = 0; i < selItems.count(); ++i )
{
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();
}
{
if ( !item ||
item->listWidget() != ListCoincident ||
- !haveBorders() )
+ !haveBorders())
return;
int groupIndex = item->data( GROUP_INDEX ).toInt();
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 );
}
}
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();
{
DeactivateActiveDialog();
mySelector = 0;
+ myActor = 0;
for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
{
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();
}
}
}
/*!
* \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
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,
{
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 );
void Reverse()
{
std::swap( myBNode1, myBNode2 );
- myNodes[0] = myBNode1->myNode;
- myNodes[1] = myBNode2->myNode;
+ myNodes[0] = myBNode1->Node();
+ myNodes[1] = myBNode2->Node();
}
void Orient()
{
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
{
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::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;
}
- BEdge* BNode::FindCloseEdgeOfBorder( int borderID ) const
+ 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
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 ]);
{
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 );
}
}
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'
{
BEdge* ce = closeE1;
do {
- coincide = ( ce->myBNode2->FindCloseEdgeOfBorder( be.myBorderID ));
+ coincide = ( ce->myBNode2->GetCloseEdgeOfBorder( be.myBorderID ));
ce = ce->myNext;
} while ( coincide && ce && ce != closeE2 );
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] );
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 );
+ 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;
- // 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;
+ be = beRange[0];
+ 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 ));
}
- else {
- part._node1 = beRange[0]->myID;
- part._node2 = beRange[0]->myID + 1;
- part._nodeLast = beRange[1]->myID + 1;
+
+ ranges.push_back( beRange[0] );
+ ranges.push_back( beRange[1] );
+
+ be->myInGroup = groupID;
+ while ( be != beRange[1] )
+ {
+ be->myInGroup = groupID;
+ be = be->myNext;
}
+ beRange[1]->myInGroup = groupID;
+ }
+
+ 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 = true;
+ be->myInGroup = skipGroup;
while ( be != beRange[1] )
{
- be->myInGroup = true;
+ be->myInGroup = skipGroup;
be = be->myNext;
}
- beRange[1]->myInGroup = true;
+ beRange[1]->myInGroup = skipGroup;
}
- foundFreeBordes._coincidentGroups.push_back( group );
+ be = ranges[1];
} // loop on free borders
-}
+
+ return;
+
+} // SMESH_MeshAlgos::FindCoincidentFreeBorders()
+
{
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;
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 )
{
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 );
}
- //TIDSortedElemSet dummy;
+ // 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.
- ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
- for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
+ vector< const SMDS_MeshElement* > tmp0Delems;
+ 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 )
+ SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
+ for ( size_t iN = 0; iN < nodes.size(); ++iN )
{
- const SMESH::FreeBorderPart& aPART_0 = aGRP[ 0 ];
- const SMESH::FreeBorder& aBRD_0 = freeBorders.borders[ aPART_0.border ];
+ SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
+ if ( it0D->more() )
+ tmp0Delems.push_back( it0D->next() );
+ else
+ tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
+ }
+ }
- 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 ]);
+ SMESH_TRY;
- const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
- const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
+ ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
+ int i0D = 0;
+ for ( size_t i = 0; i < groups.size(); ++i )
+ {
+ bool isBordToBord = true;
+ bool groupSewed = false;
+ SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
+ for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
+ {
+ 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* 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;
}
<< 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;
}