#include <algorithm>
#include <sstream>
+#include <boost/tuple/tuple.hpp>
+
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
{
}
+//================================================================================
+/*!
+ * \brief Clears myLastCreatedNodes and myLastCreatedElems
+ */
+//================================================================================
+
+void SMESH_MeshEditor::CrearLastCreated()
+{
+ myLastCreatedNodes.Clear();
+ myLastCreatedElems.Clear();
+}
+
+
//=======================================================================
/*!
* \brief Add element
return removed;
}
+//================================================================================
+/*!
+ * \brief Create 0D elements on all nodes of the given object except those
+ * nodes on which a 0D element already exists.
+ * \param elements - Elements on whose nodes to create 0D elements; if empty,
+ * the all mesh is treated
+ * \param all0DElems - returns all 0D elements found or created on nodes of \a elements
+ */
+//================================================================================
+
+void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
+ TIDSortedElemSet& all0DElems )
+{
+ typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator> TSetIterator;
+ SMDS_ElemIteratorPtr elemIt;
+ if ( elements.empty() )
+ elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
+ else
+ elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* e = elemIt->next();
+ SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+ while ( nodeIt->more() )
+ {
+ const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+ SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
+ if ( it0D->more() )
+ all0DElems.insert( it0D->next() );
+ else {
+ myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
+ all0DElems.insert( myLastCreatedElems.Last() );
+ }
+ }
+ }
+}
+
//=======================================================================
//function : FindShape
//purpose : Return an index of the shape theElem is on
* \brief Reorient faces.
* \param theFaces - the faces to reorient. If empty the whole mesh is meant
* \param theDirection - desired direction of normal of \a theFace
- * \param theFace - one of \a theFaces that sould be orientated according to
+ * \param theFace - one of \a theFaces that sould be oriented according to
* \a theDirection and whose orientation defines orientation of other faces
* \return number of reoriented faces.
*/
// Orient other faces
- set< const SMDS_MeshElement* > startFaces;
+ set< const SMDS_MeshElement* > startFaces, visitedFaces;
TIDSortedElemSet avoidSet;
set< SMESH_TLink > checkedLinks;
pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
theFaces.erase( theFace );
startFaces.insert( theFace );
+ int nodeInd1, nodeInd2;
+ const SMDS_MeshElement* otherFace;
+ vector< const SMDS_MeshElement* > facesNearLink;
+ vector< std::pair< int, int > > nodeIndsOfFace;
+
set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
- while ( startFace != startFaces.end() )
+ while ( !startFaces.empty() )
{
+ startFace = startFaces.begin();
theFace = *startFace;
- const int nbNodes = theFace->NbCornerNodes();
+ startFaces.erase( startFace );
+ if ( !visitedFaces.insert( theFace ).second )
+ continue;
avoidSet.clear();
avoidSet.insert(theFace);
NLink link( theFace->GetNode( 0 ), 0 );
+
+ const int nbNodes = theFace->NbCornerNodes();
for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
{
link.second = theFace->GetNode(( i+1 ) % nbNodes );
{
// link has already been checked and won't be encountered more
// if the group (theFaces) is manifold
- checkedLinks.erase( linkIt_isNew.first );
+ //checkedLinks.erase( linkIt_isNew.first );
}
else
{
- int nodeInd1, nodeInd2;
- const SMDS_MeshElement* otherFace = FindFaceInSet( link.first, link.second,
- theFaces, avoidSet,
- & nodeInd1, & nodeInd2);
+ facesNearLink.clear();
+ nodeIndsOfFace.clear();
+ while (( otherFace = FindFaceInSet( link.first, link.second,
+ theFaces, avoidSet, &nodeInd1, &nodeInd2 )))
+ if ( otherFace != theFace)
+ {
+ facesNearLink.push_back( otherFace );
+ nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
+ avoidSet.insert( otherFace );
+ }
+ if ( facesNearLink.size() > 1 )
+ {
+ // NON-MANIFOLD mesh shell !
+ // select a face most co-directed with theFace,
+ // other faces won't be visited this time
+ gp_XYZ NF, NOF;
+ SMESH_Algo::FaceNormal( theFace, NF, /*normalized=*/false );
+ double proj, maxProj = -1;
+ for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
+ SMESH_Algo::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
+ if (( proj = Abs( NF * NOF )) > maxProj ) {
+ maxProj = proj;
+ otherFace = facesNearLink[i];
+ nodeInd1 = nodeIndsOfFace[i].first;
+ nodeInd2 = nodeIndsOfFace[i].second;
+ }
+ }
+ // not to visit rejected faces
+ for ( size_t i = 0; i < facesNearLink.size(); ++i )
+ if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
+ visitedFaces.insert( facesNearLink[i] );
+ }
+ else if ( facesNearLink.size() == 1 )
+ {
+ otherFace = facesNearLink[0];
+ nodeInd1 = nodeIndsOfFace.back().first;
+ nodeInd2 = nodeIndsOfFace.back().second;
+ }
if ( otherFace && otherFace != theFace)
{
- // link must be reversed in otherFace if orientation ot otherFace
+ // link must be reverse in otherFace if orientation ot otherFace
// is same as that of theFace
if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
{
- // cout << "Reorient " << otherFace->GetID() << " near theFace=" <<theFace->GetID()
- // << " \tlink( " << link.first->GetID() << " " << link.second->GetID() << endl;
nbReori += Reorient( otherFace );
}
startFaces.insert( otherFace );
- if ( theFaces.size() > 1 ) // leave 1 face to prevent finding not selected faces
- theFaces.erase( otherFace );
}
}
- std::swap( link.first, link.second );
+ std::swap( link.first, link.second ); // reverse the link
}
- startFaces.erase( startFace );
- startFace = startFaces.begin();
}
return nbReori;
}
if( !elem->IsQuadratic() ) {
// split liner quadrangle
-
+ // for MaxElementLength2D functor we return minimum diagonal for splitting,
+ // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
if ( aBadRate1 <= aBadRate2 ) {
// tr1 + tr2 is better
newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
-
+ // for MaxElementLength2D functor we return minimum diagonal for splitting,
+ // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
return 1; // diagonal 1-3
SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
while ( fIt->more() ) {
const SMDS_MeshElement* face = fIt->next();
- theElems.insert( face );
+ theElems.insert( theElems.end(), face );
}
}
// get all face ids theElems are on
vecNewNodes[ 1 ]->second.back())) {
myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
vecNewNodes[ 1 ]->second.back()));
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
}
else {
myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
vecNewNodes[ 1 ]->second.back(),
vecNewNodes[ 2 ]->second.back()));
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
}
}
int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
- // check if a link is free
+ // check if a link n1-n2 is free
if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
hasFreeLinks = true;
- // make an edge and a ceiling for a new edge
- if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
+ // make a new edge and a ceiling for a new edge
+ const SMDS_MeshElement* edge;
+ if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
+ myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
srcElements.Append( myLastCreatedElems.Last() );
}
n1 = vecNewNodes[ iNode ]->second.back();
n2 = vecNewNodes[ iNext ]->second.back();
if ( !aMesh->FindEdge( n1, n2 )) {
- myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
- srcElements.Append( myLastCreatedElems.Last() );
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
+ srcElements.Append( edge );
}
}
}
// find medium node
if ( !aMesh->FindEdge( n1, n2, n3 )) {
myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
n1 = vecNewNodes[ iNode ]->second.back();
n2 = vecNewNodes[ iNext ]->second.back();
n3 = vecNewNodes[ iNode+nbn ]->second.back();
if ( !aMesh->FindEdge( n1, n2, n3 )) {
myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
}
}
}
while ( srcElements.Length() < myLastCreatedElems.Length() )
- srcElements.Append( myLastCreatedElems.Last() );
+ srcElements.Append( elem );
}
} // loop on swept elements
}
if ( BRep_Tool::Degenerated( aTrackEdge ) )
return EXTR_BAD_PATH_SHAPE;
TopExp::Vertices( aTrackEdge, aV1, aV2 );
- aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN1 = aItN->next();
- aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN2 = aItN->next();
+ const SMDS_MeshNode* aN1 = 0;
+ const SMDS_MeshNode* aN2 = 0;
+ if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
+ aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+ aN1 = aItN->next();
+ }
+ if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
+ aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+ aN2 = aItN->next();
+ }
// starting node must be aN1 or aN2
if ( !( aN1 == theN1 || aN2 == theN1 ) )
return EXTR_BAD_STARTING_NODE;
}
}
list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
- int startNid = theN1->GetID();
+ TopoDS_Vertex aVprev;
TColStd_MapOfInteger UsedNums;
int NbEdges = Edges.Length();
int i = 1;
SMESH_subMesh* locTrack = *itLSM;
SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
TopExp::Vertices( aTrackEdge, aV1, aV2 );
- aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN1 = aItN->next();
- aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN2 = aItN->next();
- // starting node must be aN1 or aN2
- if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+ bool aN1isOK = false, aN2isOK = false;
+ if ( aVprev.IsNull() ) {
+ // if previous vertex is not yet defined, it means that we in the beginning of wire
+ // and we have to find initial vertex corresponding to starting node theN1
+ const SMDS_MeshNode* aN1 = 0;
+ const SMDS_MeshNode* aN2 = 0;
+
+ if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
+ aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+ aN1 = aItN->next();
+ }
+ if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
+ aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+ aN2 = aItN->next();
+ }
+ // starting node must be aN1 or aN2
+ aN1isOK = ( aN1 && aN1 == theN1 );
+ aN2isOK = ( aN2 && aN2 == theN1 );
+ }
+ else {
+ // we have specified ending vertex of the previous edge on the previous iteration
+ // and we have just to check that it corresponds to any vertex in current segment
+ aN1isOK = aVprev.IsSame( aV1 );
+ aN2isOK = aVprev.IsSame( aV2 );
+ }
+ if ( !aN1isOK && !aN2isOK ) continue;
// 2. Collect parameters on the track edge
aPrms.clear();
aItN = locMeshDS->GetNodes();
while ( aItN->more() ) {
- const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_MeshNode* pNode = aItN->next();
const SMDS_EdgePosition* pEPos =
static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
double aT = pEPos->GetUParameter();
}
list<SMESH_MeshEditor_PathPoint> LPP;
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
LLPPs.push_back(LPP);
UsedNums.Add(k);
// update startN for search following egde
- if( aN1->GetID() == startNid ) startNid = aN2->GetID();
- else startNid = aN1->GetID();
+ if ( aN1isOK ) aVprev = aV2;
+ else aVprev = aV1;
break;
}
}
SMESH_MeshEditor_PathPoint PP2 = currList.front();
gp_Dir D1 = PP1.Tangent();
gp_Dir D2 = PP2.Tangent();
- gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
- (D1.Z()+D2.Z())/2 ) );
+ gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
PP1.SetTangent(Dnew);
fullList.push_back(PP1);
itPP++;
// Sort existing groups by types and collect their names
- // to store an old group and a generated new one
- typedef pair< SMESHDS_GroupBase*, SMESHDS_Group* > TOldNewGroup;
+ // to store an old group and a generated new ones
+ using boost::tuple;
+ using boost::make_tuple;
+ typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
// group names
if ( !group ) continue;
SMESHDS_GroupBase* groupDS = group->GetGroupDS();
if ( !groupDS || groupDS->IsEmpty() ) continue;
- groupNames.insert( group->GetName() );
+ groupNames.insert ( group->GetName() );
groupDS->SetStoreName( group->GetName() );
- SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(),
- groupDS->GetType() );
- groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, newGroup ));
+ const SMDSAbs_ElementType type = groupDS->GetType();
+ SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
+ SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
+ groupsByType[ groupDS->GetType() ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
orderedOldNewGroups.push_back( & groupsByType[ groupDS->GetType() ].back() );
}
const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
if ( gens.Length() != elems.Length() )
- throw SALOME_Exception(LOCALIZED("invalid args"));
+ throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
// loop on created elements
for (int iElem = 1; iElem <= elems.Length(); ++iElem )
++iElem; // skip all elements made by sourceElem
continue;
}
- // collect all elements made by sourceElem
+ // collect all elements made by the iElem-th sourceElem
list< const SMDS_MeshElement* > resultElems;
if ( const SMDS_MeshElement* resElem = elems( iElem ))
if ( resElem != sourceElem )
list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
{
- SMESHDS_GroupBase* oldGroup = gOldNew->first;
+ SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
{
// fill in a new group
- SMDS_MeshGroup & newGroup = gOldNew->second->SMDSGroup();
+ SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
+ list< const SMDS_MeshElement* > rejectedElems; // elements of other type
list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
- newGroup.Add( *resElemIt );
+ if ( !newGroup.Add( *resElemIt ))
+ rejectedElems.push_back( *resElemIt );
+
+ // fill "top" group
+ if ( !rejectedElems.empty() )
+ {
+ SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
+ resLast = rejectedElems.end();
+ for ( resElemIt = rejectedElems.begin(); resElemIt != resLast; ++resElemIt )
+ !newTopGroup.Add( *resElemIt );
+ }
}
}
} // loop on created elements
// Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
+ list<int> topGrouIds;
for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
{
- SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->first;
- SMESHDS_Group* newGroupDS = orderedOldNewGroups[i]->second;
- if ( newGroupDS->IsEmpty() )
- {
- mesh->GetMeshDS()->RemoveGroup( newGroupDS );
- }
- else
- {
- // make a name
- string name = oldGroupDS->GetStoreName();
- if ( !targetMesh ) {
- name += "_";
- name += postfix;
- int nb = 1;
- while ( !groupNames.insert( name ).second ) // name exists
- name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << postfix << "_" << nb++;
+ SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->get<0>();
+ SMESHDS_Group* newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
+ orderedOldNewGroups[i]->get<2>() };
+ const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
+ if ( newGroupDS->IsEmpty() )
+ {
+ mesh->GetMeshDS()->RemoveGroup( newGroupDS );
+ }
+ else
+ {
+ // set group type
+ newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
+
+ // make a name
+ const bool isTop = ( nbNewGroups == 2 &&
+ newGroupDS->GetType() == oldGroupDS->GetType() );
+ string name = oldGroupDS->GetStoreName();
+ if ( !targetMesh ) {
+ string suffix = ( isTop ? "top": postfix.c_str() );
+ name += "_";
+ name += suffix;
+ int nb = 1;
+ while ( !groupNames.insert( name ).second ) // name exists
+ name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
+ }
+ else if ( isTop ) {
+ name += "_top";
+ }
+ newGroupDS->SetStoreName( name.c_str() );
+
+ // make a SMESH_Groups
+ mesh->AddGroup( newGroupDS );
+ if ( isTop )
+ topGrouIds.push_back( newGroupDS->GetID() );
+ else
+ newGroupIDs->push_back( newGroupDS->GetID() );
}
- newGroupDS->SetStoreName( name.c_str() );
-
- // make a SMESH_Groups
- mesh->AddGroup( newGroupDS );
- newGroupIDs->push_back( newGroupDS->GetID() );
-
- // set group type
- newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
}
}
+ newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
return newGroupIDs;
}
//purpose : Return list of group of elements built on the same nodes.
// Search among theElements or in the whole mesh if theElements is empty
//=======================================================================
+
void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements,
TListOfListOfElementsID & theGroupsOfElementsID)
{