+ // definitions of volumes sharing id
+ list< TElemDef* >& defList = myReverseConnectivity[ *id ];
+ ASSERT( !defList.empty() );
+ // loop on volume definitions
+ list< TElemDef* >::iterator pIdList = defList.begin();
+ for ( ; pIdList != defList.end(); ++pIdList)
+ {
+ if ( !checkedVolDefs.insert( *pIdList ).second )
+ continue; // skip already checked volume definition
+ vector< int > idVec( (*pIdList)->begin(), (*pIdList)->end() );
+ // loop on face defs of a volume
+ SMDS_VolumeTool::VolumeType volType = vol.GetType( idVec.size() );
+ if ( volType == SMDS_VolumeTool::UNKNOWN )
+ continue;
+ int nbFaces = vol.NbFaces( volType );
+ for ( int iF = 0; iF < nbFaces; ++iF )
+ {
+ const int* nodeInds = vol.GetFaceNodesIndices( volType, iF, true );
+ int iN, nbN = vol.NbFaceNodes( volType, iF );
+ // check if all nodes of a faces are in <ids>
+ bool all = true;
+ for ( iN = 0; iN < nbN && all; ++iN ) {
+ int nodeId = idVec[ nodeInds[ iN ]];
+ all = ( ids.find( nodeId ) != ids.end() );
+ }
+ if ( all ) {
+ // store a face definition
+ for ( iN = 0; iN < nbN; ++iN ) {
+ theFaceDefs.push_back( idVec[ nodeInds[ iN ]]);
+ }
+ theQuantity.push_back( nbN );
+ defsAdded = true;
+ }
+ }
+ }
+ }
+ }
+ if ( !defsAdded ) {
+ theQuantity.push_back( faceDef.size() );
+ theFaceDefs.splice( theFaceDefs.end(), faceDef );
+ }
+
+ return makePoly;
+}
+
+//=======================================================================
+//function : clearSubMesh
+//purpose :
+//=======================================================================
+
+static bool clearSubMesh( SMESH_Mesh* theMesh,
+ const TopoDS_Shape& theShape)
+{
+ bool removed = false;
+ if ( SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( theShape ))
+ {
+ removed = !aSubMesh->IsEmpty();
+ if ( removed )
+ aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
+ }
+ else {
+ SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
+ if ( SMESHDS_SubMesh* aSubMeshDS = aMeshDS->MeshElements( theShape ))
+ {
+ SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
+ removed = eIt->more();
+ while ( eIt->more() )
+ aMeshDS->RemoveElement( eIt->next() );
+ SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
+ removed = removed || nIt->more();
+ while ( nIt->more() )
+ aMeshDS->RemoveNode( smdsNode( nIt->next() ));
+ }
+ }
+ return removed;
+}
+
+//=======================================================================
+//function : clearMesh
+//purpose : clear mesh elements existing on myShape in theMesh
+//=======================================================================
+
+void SMESH_Pattern::clearMesh(SMESH_Mesh* theMesh) const
+{
+
+ if ( !myShape.IsNull() )
+ {
+ if ( !clearSubMesh( theMesh, myShape ) && !myIs2D ) { // myShape is SHELL but volumes may be bound to SOLID
+ TopTools_ListIteratorOfListOfShape it( theMesh->GetAncestors( myShape ));
+ for (; it.More() && it.Value().ShapeType() == TopAbs_SOLID; it.Next())
+ {
+ clearSubMesh( theMesh, it.Value() );
+ }
+ }
+ }
+}
+
+//=======================================================================
+//function : findExistingNodes
+//purpose : fills nodes vector with nodes existing on a given shape (IMP 22368)
+// Returns true if all nodes for all points on S are found
+//=======================================================================
+
+bool SMESH_Pattern::findExistingNodes( SMESH_Mesh* mesh,
+ const TopoDS_Shape& S,
+ const std::list< TPoint* > & points,
+ vector< const SMDS_MeshNode* > & nodesVector)
+{
+ if ( S.IsNull() || points.empty() )
+ return false;
+
+ SMESHDS_Mesh* aMeshDS = mesh->GetMeshDS();
+
+ switch ( S.ShapeType() )
+ {
+ case TopAbs_VERTEX:
+ {
+ int pIndex = points.back() - &myPoints[0];
+ if ( !nodesVector[ pIndex ] )
+ nodesVector[ pIndex ] = SMESH_Algo::VertexNode( TopoDS::Vertex( S ), aMeshDS );
+ return nodesVector[ pIndex ];
+ }
+ case TopAbs_EDGE:
+ {
+ const TopoDS_Edge& edge = TopoDS::Edge( S );
+ map< double, const SMDS_MeshNode* > paramsOfNodes;
+ if ( !SMESH_Algo::GetSortedNodesOnEdge( aMeshDS, edge,
+ /*ignoreMediumNodes=*/false,
+ paramsOfNodes )
+ || paramsOfNodes.size() < 3 )
+ break;
+ // points on VERTEXes are included with wrong myU
+ list< TPoint* >::const_reverse_iterator pItR = ++points.rbegin();
+ list< TPoint* >::const_iterator pItF = ++points.begin();
+ const bool isForward = ( (*pItF)->myU < (*pItR)->myU );
+ map< double, const SMDS_MeshNode* >::iterator u2n = ++paramsOfNodes.begin();
+ map< double, const SMDS_MeshNode* >::iterator u2nEnd = --paramsOfNodes.end();
+ TPoint* p;
+ if ( paramsOfNodes.size() == points.size() )
+ {
+ for ( ; u2n != u2nEnd; ++u2n )
+ {
+ p = ( isForward ? *pItF : *pItR );
+ int pIndex = p - &myPoints[0];
+ if ( !nodesVector [ pIndex ] )
+ nodesVector [ pIndex ] = u2n->second;
+ ++pItF;
+ ++pItR;
+ }
+ return true;
+ }
+ else
+ {
+ const double tolFact = 0.05;
+ while ( u2n != u2nEnd && pItF != points.end() )
+ {
+ const double u = u2n->first;
+ const SMDS_MeshNode* n = u2n->second;
+ const double tol = ( (++u2n)->first - u ) * tolFact;
+ do
+ {
+ p = ( isForward ? *pItF : *pItR );
+ if ( Abs( u - p->myU ) < tol )
+ {
+ int pIndex = p - &myPoints[0];
+ if ( !nodesVector [ pIndex ] )
+ nodesVector [ pIndex ] = n;
+ ++pItF;
+ ++pItR;
+ break;
+ }
+ }
+ while ( p->myU < u && ( ++pItF, ++pItR != points.rend() ));
+ }
+ }
+ break;
+ } // case TopAbs_EDGE:
+
+ default:;
+ } // switch ( S.ShapeType() )
+
+ return false;
+}
+
+//=======================================================================
+//function : MakeMesh
+//purpose : Create nodes and elements in <theMesh> using nodes
+// coordinates computed by either of Apply...() methods
+//=======================================================================
+
+bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh,
+ const bool toCreatePolygons,
+ const bool toCreatePolyedrs)
+{
+ if ( !myIsComputed )
+ return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
+
+ mergePoints( toCreatePolygons );
+
+ SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
+
+ // clear elements and nodes existing on myShape
+ clearMesh(theMesh);
+
+ bool onMeshElements = ( !myElements.empty() );
+
+ // Create missing nodes
+
+ vector< const SMDS_MeshNode* > nodesVector; // i-th point/xyz -> node
+ if ( onMeshElements )
+ {
+ nodesVector.resize( Max( myXYZ.size(), myXYZIdToNodeMap.rbegin()->first ), 0 );
+ map< int, const SMDS_MeshNode*>::iterator i_node = myXYZIdToNodeMap.begin();
+ for ( ; i_node != myXYZIdToNodeMap.end(); i_node++ ) {
+ nodesVector[ i_node->first ] = i_node->second;
+ }
+ for ( size_t i = 0; i < myXYZ.size(); ++i ) {
+ if ( !nodesVector[ i ] && isDefined( myXYZ[ i ] ) )
+ nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
+ myXYZ[ i ].Y(),
+ myXYZ[ i ].Z());
+ }
+ if ( theMesh->HasShapeToMesh() )
+ {
+ // set nodes on EDGEs (IMP 22368)
+ SMESH_MesherHelper helper( *theMesh );
+ helper.ToFixNodeParameters( true );
+ map< TNodeSet, list< list< int > > >::iterator idListIt = myIdsOnBoundary.begin();
+ for ( ; idListIt != myIdsOnBoundary.end(); idListIt++ )
+ {
+ list<list< int > >& groups = idListIt->second;
+ const TNodeSet& nodes = idListIt->first;
+ if ( nodes.size() != 2 )
+ continue; // not a link
+ const SMDS_MeshNode* n1 = *nodes.begin();
+ const SMDS_MeshNode* n2 = *nodes.rbegin();
+ TopoDS_Shape S1 = helper.GetSubShapeByNode( n1, aMeshDS );
+ TopoDS_Shape S2 = helper.GetSubShapeByNode( n2, aMeshDS );
+ if ( S1.IsNull() || S1.ShapeType() < TopAbs_EDGE ||
+ S2.IsNull() || S2.ShapeType() < TopAbs_EDGE )
+ continue;
+ TopoDS_Shape S;
+ if ( S1.ShapeType() == TopAbs_EDGE )
+ {
+ if ( S1 == S2 || helper.IsSubShape( S2, S1 ))
+ S = S1;
+ }
+ else if ( S2.ShapeType() == TopAbs_EDGE )
+ {
+ if ( helper.IsSubShape( S1, S2 ))
+ S = S2;
+ }
+ else
+ {
+ S = helper.GetCommonAncestor( S1, S2, *theMesh, TopAbs_EDGE );
+ }
+ if ( S.IsNull() )
+ continue;
+ const TopoDS_Edge & E = TopoDS::Edge( S );
+ helper.SetSubShape( E );
+ list<list< int > >::iterator g = groups.begin();
+ for ( ; g != groups.end(); ++g )
+ {
+ list< int >& ids = *g;
+ list< int >::iterator id = ids.begin();
+ for ( ; id != ids.end(); ++id )
+ if ( nodesVector[ *id ] && nodesVector[ *id ]->getshapeId() < 1 )
+ {
+ double u = 1e100;
+ aMeshDS->SetNodeOnEdge( nodesVector[ *id ], E, u );
+ helper.CheckNodeU( E, nodesVector[ *id ], u, 1e-7, true );
+ }
+ }
+ }
+ }
+ } // if ( onMeshElements )
+
+ else
+ {
+ nodesVector.resize( myPoints.size(), 0 );
+
+ // loop on sub-shapes of myShape: create nodes
+ map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
+ for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
+ {
+ list< TPoint* > & points = idPointIt->second;
+ TopoDS_Shape S;
+ if ( !myShapeIDMap.IsEmpty() )
+ S = myShapeIDMap( idPointIt->first );
+
+ // find existing nodes on EDGEs and VERTEXes
+ if ( findExistingNodes( theMesh, S, points, nodesVector ))
+ continue;
+
+ list< TPoint* >::iterator pIt = points.begin();
+ for ( ; pIt != points.end(); pIt++ )
+ {
+ TPoint* point = *pIt;
+ int pIndex = point - &myPoints[0];
+ if ( nodesVector [ pIndex ] )
+ continue;
+ SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
+ point->myXYZ.Y(),
+ point->myXYZ.Z());
+ nodesVector [ pIndex ] = node;
+
+ if ( !S.IsNull() ) {
+
+ switch ( S.ShapeType() ) {
+ case TopAbs_VERTEX: {
+ aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S )); break;
+ }
+ case TopAbs_EDGE: {
+ aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ), point->myU ); break;
+ }
+ case TopAbs_FACE: {
+ aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ),
+ point->myUV.X(), point->myUV.Y() ); break;
+ }
+ default:
+ aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
+ }
+ }
+ }
+ }
+ }
+
+ // create elements
+
+ if ( onMeshElements )
+ {
+ // prepare data to create poly elements
+ makePolyElements( nodesVector, toCreatePolygons, toCreatePolyedrs );
+
+ // refine elements
+ createElements( theMesh, nodesVector, myElemXYZIDs, myElements );
+ // sew old and new elements
+ createElements( theMesh, nodesVector, myPolyElemXYZIDs, myPolyElems );
+ }
+ else
+ {
+ createElements( theMesh, nodesVector, myElemPointIDs, myElements );
+ }
+
+ aMeshDS->Modified();
+ aMeshDS->CompactMesh();
+
+ if ( myToKeepNodes )
+ myOutNodes.swap( nodesVector );
+
+// const map<int,SMESHDS_SubMesh*>& sm = aMeshDS->SubMeshes();
+// map<int,SMESHDS_SubMesh*>::const_iterator i_sm = sm.begin();
+// for ( ; i_sm != sm.end(); i_sm++ )
+// {
+// cout << " SM " << i_sm->first << " ";
+// TopAbs::Print( aMeshDS->IndexToShape( i_sm->first ).ShapeType(), cout)<< " ";
+// //SMDS_ElemIteratorPtr GetElements();
+// SMDS_NodeIteratorPtr nit = i_sm->second->GetNodes();
+// while ( nit->more() )
+// cout << nit->next()->GetID() << " ";
+// cout << endl;
+// }
+ return setErrorCode( ERR_OK );
+}
+
+//=======================================================================
+//function : createElements
+//purpose : add elements to the mesh
+//=======================================================================
+
+void SMESH_Pattern::createElements(SMESH_Mesh* theMesh,
+ const vector<const SMDS_MeshNode* >& theNodesVector,
+ const list< TElemDef > & theElemNodeIDs,
+ const vector<const SMDS_MeshElement*>& theElements)
+{
+ SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
+ SMESH_MeshEditor editor( theMesh );
+
+ bool onMeshElements = !theElements.empty();
+
+ // shapes and groups theElements are on
+ vector< int > shapeIDs;
+ vector< list< SMESHDS_Group* > > groups;
+ set< const SMDS_MeshNode* > shellNodes;
+ if ( onMeshElements )
+ {
+ shapeIDs.resize( theElements.size() );
+ groups.resize( theElements.size() );
+ const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
+ set<SMESHDS_GroupBase*>::const_iterator grIt;
+ for ( size_t i = 0; i < theElements.size(); i++ )
+ {
+ shapeIDs[ i ] = editor.FindShape( theElements[ i ] );
+ for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
+ SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+ if ( group && group->SMDSGroup().Contains( theElements[ i ] ))
+ groups[ i ].push_back( group );
+ }
+ }
+ // get all nodes bound to shells because their SpacePosition is not set
+ // by SMESHDS_Mesh::SetNodeInVolume()
+ TopoDS_Shape aMainShape = aMeshDS->ShapeToMesh();
+ if ( !aMainShape.IsNull() ) {
+ TopExp_Explorer shellExp( aMainShape, TopAbs_SHELL );
+ for ( ; shellExp.More(); shellExp.Next() )
+ {
+ SMESHDS_SubMesh * sm = aMeshDS->MeshElements( shellExp.Current() );
+ if ( sm ) {
+ SMDS_NodeIteratorPtr nIt = sm->GetNodes();
+ while ( nIt->more() )
+ shellNodes.insert( nIt->next() );
+ }
+ }
+ }
+ }
+ // nb new elements per a refined element
+ int nbNewElemsPerOld = 1;
+ if ( onMeshElements )
+ nbNewElemsPerOld = theElemNodeIDs.size() / theElements.size();
+
+ bool is2d = myIs2D;
+
+ list< TElemDef >::const_iterator enIt = theElemNodeIDs.begin();
+ list< vector<int> >::iterator quantity = myPolyhedronQuantities.begin();
+ for ( int iElem = 0; enIt != theElemNodeIDs.end(); enIt++, iElem++ )
+ {
+ const TElemDef & elemNodeInd = *enIt;
+ // retrieve nodes
+ vector< const SMDS_MeshNode* > nodes( elemNodeInd.size() );
+ TElemDef::const_iterator id = elemNodeInd.begin();
+ int nbNodes;
+ for ( nbNodes = 0; id != elemNodeInd.end(); id++ ) {
+ if ( *id < (int) theNodesVector.size() )
+ nodes[ nbNodes++ ] = theNodesVector[ *id ];
+ else
+ nodes[ nbNodes++ ] = myXYZIdToNodeMap[ *id ];
+ }
+ // dim of refined elem
+ int elemIndex = iElem / nbNewElemsPerOld; // refined element index
+ if ( onMeshElements ) {
+ is2d = ( theElements[ elemIndex ]->GetType() == SMDSAbs_Face );
+ }
+ // add an element
+ const SMDS_MeshElement* elem = 0;
+ if ( is2d ) {
+ switch ( nbNodes ) {
+ case 3:
+ elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
+ case 4:
+ elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
+ case 6:
+ if ( !onMeshElements ) {// create a quadratic face
+ elem = aMeshDS->AddFace (nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5] ); break;
+ } // else do not break but create a polygon
+ // fall through
+ case 8:
+ if ( !onMeshElements ) {// create a quadratic face
+ elem = aMeshDS->AddFace (nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7] ); break;
+ } // else do not break but create a polygon
+ // fall through
+ default:
+ elem = aMeshDS->AddPolygonalFace( nodes );
+ }
+ }
+ else {
+ switch ( nbNodes ) {
+ case 4:
+ elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
+ case 5:
+ elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4] ); break;
+ case 6:
+ elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5] ); break;
+ case 8:
+ elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7] ); break;
+ default:
+ elem = aMeshDS->AddPolyhedralVolume( nodes, *quantity++ );
+ }
+ }
+ // set element on a shape
+ if ( elem && onMeshElements ) // applied to mesh elements
+ {
+ int shapeID = shapeIDs[ elemIndex ];
+ if ( shapeID > 0 ) {
+ aMeshDS->SetMeshElementOnShape( elem, shapeID );
+ // set nodes on a shape
+ TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
+ if ( S.ShapeType() == TopAbs_SOLID ) {
+ TopoDS_Iterator shellIt( S );
+ if ( shellIt.More() )
+ shapeID = aMeshDS->ShapeToIndex( shellIt.Value() );
+ }
+ SMDS_ElemIteratorPtr noIt = elem->nodesIterator();
+ while ( noIt->more() ) {
+ SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>(smdsNode( noIt->next() ));
+ if ( node->getshapeId() < 1 &&
+ shellNodes.find( node ) == shellNodes.end() )
+ {
+ if ( S.ShapeType() == TopAbs_FACE )
+ aMeshDS->SetNodeOnFace( node, shapeID,
+ Precision::Infinite(),// <- it's a sign that UV is not set
+ Precision::Infinite());
+ else {
+ aMeshDS->SetNodeInVolume( node, shapeID );
+ shellNodes.insert( node );
+ }
+ }
+ }
+ }
+ // add elem in groups
+ list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
+ for ( ; g != groups[ elemIndex ].end(); ++g )
+ (*g)->SMDSGroup().Add( elem );
+ }
+ if ( elem && !myShape.IsNull() ) // applied to shape
+ aMeshDS->SetMeshElementOnShape( elem, myShape );
+ }
+
+ // make that SMESH_subMesh::_computeState == COMPUTE_OK
+ // so that operations with hypotheses will erase the mesh being built
+
+ SMESH_subMesh * subMesh;
+ if ( !myShape.IsNull() ) {
+ subMesh = theMesh->GetSubMesh( myShape );
+ if ( subMesh )
+ subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+ }
+ if ( onMeshElements ) {
+ list< smIdType > elemIDs;
+ for ( size_t i = 0; i < theElements.size(); i++ )
+ {
+ subMesh = theMesh->GetSubMeshContaining( shapeIDs[ i ] );
+ if ( subMesh )
+ subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
+
+ elemIDs.push_back( theElements[ i ]->GetID() );
+ }
+ // remove refined elements
+ editor.Remove( elemIDs, false );
+ }
+}
+
+//=======================================================================
+//function : isReversed
+//purpose : check xyz ids order in theIdsList taking into account
+// theFirstNode on a link
+//=======================================================================
+
+bool SMESH_Pattern::isReversed(const SMDS_MeshNode* theFirstNode,
+ const list< int >& theIdsList) const
+{
+ if ( theIdsList.size() < 2 )
+ return false;
+
+ gp_Pnt Pf ( theFirstNode->X(), theFirstNode->Y(), theFirstNode->Z() );
+ gp_Pnt P[2];
+ list<int>::const_iterator id = theIdsList.begin();
+ for ( int i = 0; i < 2; ++i, ++id ) {
+ if ( *id < (int) myXYZ.size() )
+ P[ i ] = myXYZ[ *id ];
+ else {
+ map< int, const SMDS_MeshNode*>::const_iterator i_n;
+ i_n = myXYZIdToNodeMap.find( *id );
+ ASSERT( i_n != myXYZIdToNodeMap.end() );
+ const SMDS_MeshNode* n = i_n->second;
+ P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
+ }
+ }
+ return Pf.SquareDistance( P[ 1 ] ) < Pf.SquareDistance( P[ 0 ] );
+}
+
+
+//=======================================================================
+//function : arrangeBoundaries
+//purpose : if there are several wires, arrange boundaryPoints so that
+// the outer wire goes first and fix inner wires orientation
+// update myKeyPointIDs to correspond to the order of key-points
+// in boundaries; sort internal boundaries by the nb of key-points
+//=======================================================================
+
+void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
+{
+ typedef list< list< TPoint* > >::iterator TListOfListIt;
+ TListOfListIt bndIt;
+ list< TPoint* >::iterator pIt;
+
+ int nbBoundaries = boundaryList.size();
+ if ( nbBoundaries > 1 )
+ {
+ // sort boundaries by nb of key-points
+ if ( nbBoundaries > 2 )
+ {
+ // move boundaries in tmp list
+ list< list< TPoint* > > tmpList;
+ tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
+ // make a map nb-key-points to boundary-position-in-tmpList,
+ // boundary-positions get ordered in it
+ typedef map< int, TListOfListIt > TNbKpBndPosMap;
+ TNbKpBndPosMap nbKpBndPosMap;
+ bndIt = tmpList.begin();
+ list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
+ for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
+ int nb = *nbKpIt * nbBoundaries;
+ while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
+ nb++;
+ nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
+ }
+ // move boundaries back to boundaryList
+ TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
+ for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
+ TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
+ TListOfListIt bndPos1 = bndPos2++;
+ boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
+ }
+ }
+
+ // Look for the outer boundary: the one with the point with the least X
+ double leastX = DBL_MAX;
+ TListOfListIt outerBndPos;
+ for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
+ {
+ list< TPoint* >& boundary = (*bndIt);
+ for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
+ {
+ TPoint* point = *pIt;
+ if ( point->myInitXYZ.X() < leastX ) {
+ leastX = point->myInitXYZ.X();
+ outerBndPos = bndIt;
+ }
+ }
+ }
+
+ if ( outerBndPos != boundaryList.begin() )
+ boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos );
+
+ } // if nbBoundaries > 1
+
+ // Check boundaries orientation and re-fill myKeyPointIDs
+
+ set< TPoint* > keyPointSet;
+ list< int >::iterator kpIt = myKeyPointIDs.begin();
+ for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
+ keyPointSet.insert( & myPoints[ *kpIt ]);
+ myKeyPointIDs.clear();
+
+ // update myNbKeyPntInBoundary also
+ list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
+
+ for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
+ {
+ // find the point with the least X
+ double leastX = DBL_MAX;
+ list< TPoint* >::iterator xpIt;
+ list< TPoint* >& boundary = (*bndIt);
+ for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
+ {
+ TPoint* point = *pIt;
+ if ( point->myInitXYZ.X() < leastX ) {
+ leastX = point->myInitXYZ.X();
+ xpIt = pIt;
+ }
+ }
+ // find points next to the point with the least X
+ TPoint* p = *xpIt, *pPrev, *pNext;
+ if ( p == boundary.front() )
+ pPrev = *(++boundary.rbegin());
+ else {
+ xpIt--;
+ pPrev = *xpIt;
+ xpIt++;
+ }
+ if ( p == boundary.back() )
+ pNext = *(++boundary.begin());
+ else {
+ xpIt++;
+ pNext = *xpIt;
+ }
+ // vectors of boundary direction near <p>
+ gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
+ double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
+ if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
+ double yPrev = v1.Y() / sqrt( sqMag1 );
+ double yNext = v2.Y() / sqrt( sqMag2 );
+ double sumY = yPrev + yNext;
+ bool reverse;
+ if ( bndIt == boundaryList.begin() ) // outer boundary
+ reverse = sumY > 0;
+ else
+ reverse = sumY < 0;
+ if ( reverse )
+ boundary.reverse();
+ }
+
+ // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
+ (*nbKpIt) = 0; // count nb of key-points again
+ pIt = boundary.begin();
+ for ( ; pIt != boundary.end(); pIt++)
+ {
+ TPoint* point = *pIt;
+ if ( keyPointSet.find( point ) == keyPointSet.end() )
+ continue;
+ // find an index of a keypoint
+ int index = 0;
+ vector< TPoint >::const_iterator pVecIt = myPoints.begin();
+ for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
+ if ( &(*pVecIt) == point )
+ break;
+ myKeyPointIDs.push_back( index );
+ (*nbKpIt)++;
+ }
+ myKeyPointIDs.pop_back(); // remove the first key-point from the back
+ (*nbKpIt)--;
+
+ } // loop on a list of boundaries
+
+ ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
+}
+
+//=======================================================================
+//function : findBoundaryPoints
+//purpose : if loaded from file, find points to map on edges and faces and
+// compute their parameters
+//=======================================================================
+
+bool SMESH_Pattern::findBoundaryPoints()
+{
+ if ( myIsBoundaryPointsFound ) return true;
+
+ myNbKeyPntInBoundary.clear();
+
+ if ( myIs2D )
+ {
+ set< TPoint* > pointsInElems;
+
+ // Find free links of elements:
+ // put links of all elements in a set and remove links encountered twice
+
+ typedef pair< TPoint*, TPoint*> TLink;
+ set< TLink > linkSet;
+ list<TElemDef >::iterator epIt = myElemPointIDs.begin();
+ for ( ; epIt != myElemPointIDs.end(); epIt++ )
+ {
+ TElemDef & elemPoints = *epIt;
+ TElemDef::iterator pIt = elemPoints.begin();
+ int prevP = elemPoints.back();
+ for ( ; pIt != elemPoints.end(); pIt++ ) {
+ TPoint* p1 = & myPoints[ prevP ];
+ TPoint* p2 = & myPoints[ *pIt ];