+ // keep best solution
+ if ( sameSide && minDist < leastDist ) {
+ leastDist = minDist;
+ faceNodes.clear();
+ faceNodes.insert( idNodes[ 1 ] );
+ faceNodes.insert( idNodes[ 2 ] );
+ faceNodes.insert( idNodes[ iMin ] );
+ DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
+ << " leastDist = " << leastDist);
+ if ( leastDist <= DBL_MIN )
+ break;
+ }
+ }
+
+ // set next 3-d node to check
+ int iNext = 2 + iLoop2;
+ if ( iNext < 8 ) {
+ DUMPSO( "Try 2-nd");
+ swap ( 2, iNext, idNodes, P );
+ }
+ } // while ( iLoop2 < 6 )
+ } // iLoop1
+
+ if ( faceNodes.empty() ) return false;
+
+ // Put the faceNodes in proper places
+ for ( i = 4; i < 8; i++ ) {
+ if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
+ // find a place to put
+ int iTo = 1;
+ while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
+ iTo++;
+ DUMPSO( "Set faceNodes");
+ swap ( iTo, i, idNodes, P );
+ }
+ }
+
+
+ // Set nodes of the found bottom face in good order
+ DUMPSO( " Found bottom face: ");
+ i = SortQuadNodes( theMesh, idNodes );
+ if ( i ) {
+ gp_Pnt Ptmp = P[ i ];
+ P[ i ] = P[ i+1 ];
+ P[ i+1 ] = Ptmp;
+ }
+ // else
+ // for ( int ii = 0; ii < 4; ii++ ) {
+ // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
+ // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
+ // }
+
+ // Gravity center of the top and bottom faces
+ gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
+ gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
+
+ // Get direction from the bottom to the top face
+ gp_Vec upDir ( aGCb, aGCt );
+ Standard_Real upDirSize = upDir.Magnitude();
+ if ( upDirSize <= gp::Resolution() ) return false;
+ upDir / upDirSize;
+
+ // Assure that the bottom face normal points up
+ gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
+ Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
+ if ( Nb.Dot( upDir ) < 0 ) {
+ DUMPSO( "Reverse bottom face");
+ swap( 1, 3, idNodes, P );
+ }
+
+ // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
+ Standard_Real minDist = DBL_MAX;
+ for ( i = 4; i < 8; i++ ) {
+ // projection of P[i] to the plane defined by P[0] and upDir
+ gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
+ Standard_Real sqDist = P[0].SquareDistance( Pp );
+ if ( sqDist < minDist ) {
+ minDist = sqDist;
+ iMin = i;
+ }
+ }
+ DUMPSO( "Set 4-th");
+ swap ( 4, iMin, idNodes, P );
+
+ // Set nodes of the top face in good order
+ DUMPSO( "Sort top face");
+ i = SortQuadNodes( theMesh, &idNodes[4] );
+ if ( i ) {
+ i += 4;
+ gp_Pnt Ptmp = P[ i ];
+ P[ i ] = P[ i+1 ];
+ P[ i+1 ] = Ptmp;
+ }
+
+ // Assure that direction of the top face normal is from the bottom face
+ gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
+ Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
+ if ( Nt.Dot( upDir ) < 0 ) {
+ DUMPSO( "Reverse top face");
+ swap( 5, 7, idNodes, P );
+ }
+
+ // DUMPSO( "OUTPUT: ========================================");
+ // for ( i = 0; i < 8; i++ ) {
+ // float *p = ugrid->GetPoint(idNodes[i]);
+ // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
+ // }
+
+ return true;
+}*/
+
+//================================================================================
+/*!
+ * \brief Return nodes linked to the given one
+ * \param theNode - the node
+ * \param linkedNodes - the found nodes
+ * \param type - the type of elements to check
+ *
+ * Medium nodes are ignored
+ */
+//================================================================================
+
+void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
+ TIDSortedElemSet & linkedNodes,
+ SMDSAbs_ElementType type )
+{
+ SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+ if ( elem->GetType() == SMDSAbs_Volume )
+ {
+ SMDS_VolumeTool vol( elem );
+ while ( nodeIt->more() ) {
+ const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+ if ( theNode != n && vol.IsLinked( theNode, n ))
+ linkedNodes.insert( n );
+ }
+ }
+ else
+ {
+ for ( int i = 0; nodeIt->more(); ++i ) {
+ const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+ if ( n == theNode ) {
+ int iBefore = i - 1;
+ int iAfter = i + 1;
+ if ( elem->IsQuadratic() ) {
+ int nb = elem->NbNodes() / 2;
+ iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
+ iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
+ }
+ linkedNodes.insert( elem->GetNodeWrap( iAfter ));
+ linkedNodes.insert( elem->GetNodeWrap( iBefore ));
+ }
+ }
+ }
+ }
+}
+
+//=======================================================================
+//function : laplacianSmooth
+//purpose : pulls theNode toward the center of surrounding nodes directly
+// connected to that node along an element edge
+//=======================================================================
+
+void laplacianSmooth(const SMDS_MeshNode* theNode,
+ const Handle(Geom_Surface)& theSurface,
+ map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
+{
+ // find surrounding nodes
+
+ TIDSortedElemSet nodeSet;
+ SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
+
+ // compute new coodrs
+
+ double coord[] = { 0., 0., 0. };
+ TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
+ for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
+ const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
+ if ( theSurface.IsNull() ) { // smooth in 3D
+ coord[0] += node->X();
+ coord[1] += node->Y();
+ coord[2] += node->Z();
+ }
+ else { // smooth in 2D
+ ASSERT( theUVMap.find( node ) != theUVMap.end() );
+ gp_XY* uv = theUVMap[ node ];
+ coord[0] += uv->X();
+ coord[1] += uv->Y();
+ }
+ }
+ int nbNodes = nodeSet.size();
+ if ( !nbNodes )
+ return;
+ coord[0] /= nbNodes;
+ coord[1] /= nbNodes;
+
+ if ( !theSurface.IsNull() ) {
+ ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
+ theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
+ gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
+ coord[0] = p3d.X();
+ coord[1] = p3d.Y();
+ coord[2] = p3d.Z();
+ }
+ else
+ coord[2] /= nbNodes;
+
+ // move node
+
+ const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
+}
+
+//=======================================================================
+//function : centroidalSmooth
+//purpose : pulls theNode toward the element-area-weighted centroid of the
+// surrounding elements
+//=======================================================================
+
+void centroidalSmooth(const SMDS_MeshNode* theNode,
+ const Handle(Geom_Surface)& theSurface,
+ map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
+{
+ gp_XYZ aNewXYZ(0.,0.,0.);
+ SMESH::Controls::Area anAreaFunc;
+ double totalArea = 0.;
+ int nbElems = 0;
+
+ // compute new XYZ
+
+ SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ nbElems++;
+
+ gp_XYZ elemCenter(0.,0.,0.);
+ SMESH::Controls::TSequenceOfXYZ aNodePoints;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ int nn = elem->NbNodes();
+ if(elem->IsQuadratic()) nn = nn/2;
+ int i=0;
+ //while ( itN->more() ) {
+ while ( i<nn ) {
+ const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
+ i++;
+ gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
+ aNodePoints.push_back( aP );
+ if ( !theSurface.IsNull() ) { // smooth in 2D
+ ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
+ gp_XY* uv = theUVMap[ aNode ];
+ aP.SetCoord( uv->X(), uv->Y(), 0. );
+ }
+ elemCenter += aP;
+ }
+ double elemArea = anAreaFunc.GetValue( aNodePoints );
+ totalArea += elemArea;
+ elemCenter /= nn;
+ aNewXYZ += elemCenter * elemArea;
+ }
+ aNewXYZ /= totalArea;
+ if ( !theSurface.IsNull() ) {
+ theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
+ aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
+ }
+
+ // move node
+
+ const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
+}
+
+//=======================================================================
+//function : getClosestUV
+//purpose : return UV of closest projection
+//=======================================================================
+
+static bool getClosestUV (Extrema_GenExtPS& projector,
+ const gp_Pnt& point,
+ gp_XY & result)
+{
+ projector.Perform( point );
+ if ( projector.IsDone() ) {
+ double u, v, minVal = DBL_MAX;
+ for ( int i = projector.NbExt(); i > 0; i-- )
+ if ( projector.Value( i ) < minVal ) {
+ minVal = projector.Value( i );
+ projector.Point( i ).Parameter( u, v );
+ }
+ result.SetCoord( u, v );
+ return true;
+ }
+ return false;
+}
+
+//=======================================================================
+//function : Smooth
+//purpose : Smooth theElements during theNbIterations or until a worst
+// element has aspect ratio <= theTgtAspectRatio.
+// Aspect Ratio varies in range [1.0, inf].
+// If theElements is empty, the whole mesh is smoothed.
+// theFixedNodes contains additionally fixed nodes. Nodes built
+// on edges and boundary nodes are always fixed.
+//=======================================================================
+
+void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
+ set<const SMDS_MeshNode*> & theFixedNodes,
+ const SmoothMethod theSmoothMethod,
+ const int theNbIterations,
+ double theTgtAspectRatio,
+ const bool the2D)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
+
+ if ( theTgtAspectRatio < 1.0 )
+ theTgtAspectRatio = 1.0;
+
+ const double disttol = 1.e-16;
+
+ SMESH::Controls::AspectRatio aQualityFunc;
+
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ if ( theElems.empty() ) {
+ // add all faces to theElems
+ SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
+ while ( fIt->more() ) {
+ const SMDS_MeshElement* face = fIt->next();
+ theElems.insert( face );
+ }
+ }
+ // get all face ids theElems are on
+ set< int > faceIdSet;
+ TIDSortedElemSet::iterator itElem;
+ if ( the2D )
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ int fId = FindShape( *itElem );
+ // check that corresponding submesh exists and a shape is face
+ if (fId &&
+ faceIdSet.find( fId ) == faceIdSet.end() &&
+ aMesh->MeshElements( fId )) {
+ TopoDS_Shape F = aMesh->IndexToShape( fId );
+ if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
+ faceIdSet.insert( fId );
+ }
+ }
+ faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
+
+ // ===============================================
+ // smooth elements on each TopoDS_Face separately
+ // ===============================================
+
+ set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
+ for ( ; fId != faceIdSet.rend(); ++fId ) {
+ // get face surface and submesh
+ Handle(Geom_Surface) surface;
+ SMESHDS_SubMesh* faceSubMesh = 0;
+ TopoDS_Face face;
+ double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
+ double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
+ bool isUPeriodic = false, isVPeriodic = false;
+ if ( *fId ) {
+ face = TopoDS::Face( aMesh->IndexToShape( *fId ));
+ surface = BRep_Tool::Surface( face );
+ faceSubMesh = aMesh->MeshElements( *fId );
+ fToler2 = BRep_Tool::Tolerance( face );
+ fToler2 *= fToler2 * 10.;
+ isUPeriodic = surface->IsUPeriodic();
+ if ( isUPeriodic )
+ vPeriod = surface->UPeriod();
+ isVPeriodic = surface->IsVPeriodic();
+ if ( isVPeriodic )
+ uPeriod = surface->VPeriod();
+ surface->Bounds( u1, u2, v1, v2 );
+ }
+ // ---------------------------------------------------------
+ // for elements on a face, find movable and fixed nodes and
+ // compute UV for them
+ // ---------------------------------------------------------
+ bool checkBoundaryNodes = false;
+ bool isQuadratic = false;
+ set<const SMDS_MeshNode*> setMovableNodes;
+ map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
+ list< gp_XY > listUV; // uvs the 2 uvMaps refer to
+ list< const SMDS_MeshElement* > elemsOnFace;
+
+ Extrema_GenExtPS projector;
+ GeomAdaptor_Surface surfAdaptor;
+ if ( !surface.IsNull() ) {
+ surfAdaptor.Load( surface );
+ projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
+ }
+ int nbElemOnFace = 0;
+ itElem = theElems.begin();
+ // loop on not yet smoothed elements: look for elems on a face
+ while ( itElem != theElems.end() ) {
+ if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
+ break; // all elements found
+
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
+ ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
+ ++itElem;
+ continue;
+ }
+ elemsOnFace.push_back( elem );
+ theElems.erase( itElem++ );
+ nbElemOnFace++;
+
+ if ( !isQuadratic )
+ isQuadratic = elem->IsQuadratic();
+
+ // get movable nodes of elem
+ const SMDS_MeshNode* node;
+ SMDS_TypeOfPosition posType;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ int nn = 0, nbn = elem->NbNodes();
+ if(elem->IsQuadratic())
+ nbn = nbn/2;
+ while ( nn++ < nbn ) {
+ node = static_cast<const SMDS_MeshNode*>( itN->next() );
+ const SMDS_PositionPtr& pos = node->GetPosition();
+ posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
+ if (posType != SMDS_TOP_EDGE &&
+ posType != SMDS_TOP_VERTEX &&
+ theFixedNodes.find( node ) == theFixedNodes.end())
+ {
+ // check if all faces around the node are on faceSubMesh
+ // because a node on edge may be bound to face
+ SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
+ bool all = true;
+ if ( faceSubMesh ) {
+ while ( eIt->more() && all ) {
+ const SMDS_MeshElement* e = eIt->next();
+ all = faceSubMesh->Contains( e );
+ }
+ }
+ if ( all )
+ setMovableNodes.insert( node );
+ else
+ checkBoundaryNodes = true;
+ }
+ if ( posType == SMDS_TOP_3DSPACE )
+ checkBoundaryNodes = true;
+ }
+
+ if ( surface.IsNull() )
+ continue;
+
+ // get nodes to check UV
+ list< const SMDS_MeshNode* > uvCheckNodes;
+ itN = elem->nodesIterator();
+ nn = 0; nbn = elem->NbNodes();
+ if(elem->IsQuadratic())
+ nbn = nbn/2;
+ while ( nn++ < nbn ) {
+ node = static_cast<const SMDS_MeshNode*>( itN->next() );
+ if ( uvMap.find( node ) == uvMap.end() )
+ uvCheckNodes.push_back( node );
+ // add nodes of elems sharing node
+ // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
+ // while ( eIt->more() ) {
+ // const SMDS_MeshElement* e = eIt->next();
+ // if ( e != elem ) {
+ // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+ // while ( nIt->more() ) {
+ // const SMDS_MeshNode* n =
+ // static_cast<const SMDS_MeshNode*>( nIt->next() );
+ // if ( uvMap.find( n ) == uvMap.end() )
+ // uvCheckNodes.push_back( n );
+ // }
+ // }
+ // }
+ }
+ // check UV on face
+ list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
+ for ( ; n != uvCheckNodes.end(); ++n ) {
+ node = *n;
+ gp_XY uv( 0, 0 );
+ const SMDS_PositionPtr& pos = node->GetPosition();
+ posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
+ // get existing UV
+ switch ( posType ) {
+ case SMDS_TOP_FACE: {
+ SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
+ uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
+ break;
+ }
+ case SMDS_TOP_EDGE: {
+ TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
+ Handle(Geom2d_Curve) pcurve;
+ if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
+ pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
+ if ( !pcurve.IsNull() ) {
+ double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
+ uv = pcurve->Value( u ).XY();
+ }
+ break;
+ }
+ case SMDS_TOP_VERTEX: {
+ TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
+ if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
+ uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
+ break;
+ }
+ default:;
+ }
+ // check existing UV
+ bool project = true;
+ gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
+ double dist1 = DBL_MAX, dist2 = 0;
+ if ( posType != SMDS_TOP_3DSPACE ) {
+ dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
+ project = dist1 > fToler2;
+ }
+ if ( project ) { // compute new UV
+ gp_XY newUV;
+ if ( !getClosestUV( projector, pNode, newUV )) {
+ MESSAGE("Node Projection Failed " << node);
+ }
+ else {
+ if ( isUPeriodic )
+ newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
+ if ( isVPeriodic )
+ newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
+ // check new UV
+ if ( posType != SMDS_TOP_3DSPACE )
+ dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
+ if ( dist2 < dist1 )
+ uv = newUV;
+ }
+ }
+ // store UV in the map
+ listUV.push_back( uv );
+ uvMap.insert( make_pair( node, &listUV.back() ));
+ }
+ } // loop on not yet smoothed elements
+
+ if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
+ checkBoundaryNodes = true;
+
+ // fix nodes on mesh boundary
+
+ if ( checkBoundaryNodes ) {
+ map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
+ map< NLink, int >::iterator link_nb;
+ // put all elements links to linkNbMap
+ list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
+ for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
+ const SMDS_MeshElement* elem = (*elemIt);
+ int nbn = elem->NbNodes();
+ if(elem->IsQuadratic())
+ nbn = nbn/2;
+ // loop on elem links: insert them in linkNbMap
+ const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
+ for ( int iN = 0; iN < nbn; ++iN ) {
+ curNode = elem->GetNode( iN );
+ NLink link;
+ if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
+ else link = make_pair( prevNode , curNode );
+ prevNode = curNode;
+ link_nb = linkNbMap.find( link );
+ if ( link_nb == linkNbMap.end() )
+ linkNbMap.insert( make_pair ( link, 1 ));
+ else
+ link_nb->second++;
+ }
+ }
+ // remove nodes that are in links encountered only once from setMovableNodes
+ for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
+ if ( link_nb->second == 1 ) {
+ setMovableNodes.erase( link_nb->first.first );
+ setMovableNodes.erase( link_nb->first.second );
+ }
+ }
+ }
+
+ // -----------------------------------------------------
+ // for nodes on seam edge, compute one more UV ( uvMap2 );
+ // find movable nodes linked to nodes on seam and which
+ // are to be smoothed using the second UV ( uvMap2 )
+ // -----------------------------------------------------
+
+ set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
+ if ( !surface.IsNull() ) {
+ TopExp_Explorer eExp( face, TopAbs_EDGE );
+ for ( ; eExp.More(); eExp.Next() ) {
+ TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
+ if ( !BRep_Tool::IsClosed( edge, face ))
+ continue;
+ SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
+ if ( !sm ) continue;
+ // find out which parameter varies for a node on seam
+ double f,l;
+ gp_Pnt2d uv1, uv2;
+ Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
+ if ( pcurve.IsNull() ) continue;
+ uv1 = pcurve->Value( f );
+ edge.Reverse();
+ pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
+ if ( pcurve.IsNull() ) continue;
+ uv2 = pcurve->Value( f );
+ int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
+ // assure uv1 < uv2
+ if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
+ gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
+ }
+ // get nodes on seam and its vertices
+ list< const SMDS_MeshNode* > seamNodes;
+ SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
+ while ( nSeamIt->more() ) {
+ const SMDS_MeshNode* node = nSeamIt->next();
+ if ( !isQuadratic || !IsMedium( node ))
+ seamNodes.push_back( node );
+ }
+ TopExp_Explorer vExp( edge, TopAbs_VERTEX );
+ for ( ; vExp.More(); vExp.Next() ) {
+ sm = aMesh->MeshElements( vExp.Current() );
+ if ( sm ) {
+ nSeamIt = sm->GetNodes();
+ while ( nSeamIt->more() )
+ seamNodes.push_back( nSeamIt->next() );
+ }
+ }
+ // loop on nodes on seam
+ list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
+ for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
+ const SMDS_MeshNode* nSeam = *noSeIt;
+ map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
+ if ( n_uv == uvMap.end() )
+ continue;
+ // set the first UV
+ n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
+ // set the second UV
+ listUV.push_back( *n_uv->second );
+ listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
+ if ( uvMap2.empty() )
+ uvMap2 = uvMap; // copy the uvMap contents
+ uvMap2[ nSeam ] = &listUV.back();
+
+ // collect movable nodes linked to ones on seam in nodesNearSeam
+ SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
+ while ( eIt->more() ) {
+ const SMDS_MeshElement* e = eIt->next();
+ int nbUseMap1 = 0, nbUseMap2 = 0;
+ SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+ int nn = 0, nbn = e->NbNodes();
+ if(e->IsQuadratic()) nbn = nbn/2;
+ while ( nn++ < nbn )
+ {
+ const SMDS_MeshNode* n =
+ static_cast<const SMDS_MeshNode*>( nIt->next() );
+ if (n == nSeam ||
+ setMovableNodes.find( n ) == setMovableNodes.end() )
+ continue;
+ // add only nodes being closer to uv2 than to uv1
+ gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
+ 0.5 * ( n->Y() + nSeam->Y() ),
+ 0.5 * ( n->Z() + nSeam->Z() ));
+ gp_XY uv;
+ getClosestUV( projector, pMid, uv );
+ if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
+ nodesNearSeam.insert( n );
+ nbUseMap2++;
+ }
+ else
+ nbUseMap1++;
+ }
+ // for centroidalSmooth all element nodes must
+ // be on one side of a seam
+ if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
+ SMDS_ElemIteratorPtr nIt = e->nodesIterator();
+ nn = 0;
+ while ( nn++ < nbn ) {
+ const SMDS_MeshNode* n =
+ static_cast<const SMDS_MeshNode*>( nIt->next() );
+ setMovableNodes.erase( n );
+ }
+ }
+ }
+ } // loop on nodes on seam
+ } // loop on edge of a face
+ } // if ( !face.IsNull() )
+
+ if ( setMovableNodes.empty() ) {
+ MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
+ continue; // goto next face
+ }
+
+ // -------------
+ // SMOOTHING //
+ // -------------
+
+ int it = -1;
+ double maxRatio = -1., maxDisplacement = -1.;
+ set<const SMDS_MeshNode*>::iterator nodeToMove;
+ for ( it = 0; it < theNbIterations; it++ ) {
+ maxDisplacement = 0.;
+ nodeToMove = setMovableNodes.begin();
+ for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
+ const SMDS_MeshNode* node = (*nodeToMove);
+ gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
+
+ // smooth
+ bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
+ if ( theSmoothMethod == LAPLACIAN )
+ laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
+ else
+ centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
+
+ // node displacement
+ gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
+ Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
+ if ( aDispl > maxDisplacement )
+ maxDisplacement = aDispl;
+ }
+ // no node movement => exit
+ //if ( maxDisplacement < 1.e-16 ) {
+ if ( maxDisplacement < disttol ) {
+ MESSAGE("-- no node movement --");
+ break;
+ }
+
+ // check elements quality
+ maxRatio = 0;
+ list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
+ for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
+ const SMDS_MeshElement* elem = (*elemIt);
+ if ( !elem || elem->GetType() != SMDSAbs_Face )
+ continue;
+ SMESH::Controls::TSequenceOfXYZ aPoints;
+ if ( aQualityFunc.GetPoints( elem, aPoints )) {
+ double aValue = aQualityFunc.GetValue( aPoints );
+ if ( aValue > maxRatio )
+ maxRatio = aValue;
+ }
+ }
+ if ( maxRatio <= theTgtAspectRatio ) {
+ MESSAGE("-- quality achived --");
+ break;
+ }
+ if (it+1 == theNbIterations) {
+ MESSAGE("-- Iteration limit exceeded --");
+ }
+ } // smoothing iterations
+
+ MESSAGE(" Face id: " << *fId <<
+ " Nb iterstions: " << it <<
+ " Displacement: " << maxDisplacement <<
+ " Aspect Ratio " << maxRatio);
+
+ // ---------------------------------------
+ // new nodes positions are computed,
+ // record movement in DS and set new UV
+ // ---------------------------------------
+ nodeToMove = setMovableNodes.begin();
+ for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
+ SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
+ aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
+ map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
+ if ( node_uv != uvMap.end() ) {
+ gp_XY* uv = node_uv->second;
+ node->SetPosition
+ ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
+ }
+ }
+
+ // move medium nodes of quadratic elements
+ if ( isQuadratic )
+ {
+ SMESH_MesherHelper helper( *GetMesh() );
+ if ( !face.IsNull() )
+ helper.SetSubShape( face );
+ list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
+ for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
+ const SMDS_QuadraticFaceOfNodes* QF =
+ dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
+ if(QF) {
+ vector<const SMDS_MeshNode*> Ns;
+ Ns.reserve(QF->NbNodes()+1);
+ SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
+ while ( anIter->more() )
+ Ns.push_back( anIter->next() );
+ Ns.push_back( Ns[0] );
+ double x, y, z;
+ for(int i=0; i<QF->NbNodes(); i=i+2) {
+ if ( !surface.IsNull() ) {
+ gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
+ gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
+ gp_XY uv = ( uv1 + uv2 ) / 2.;
+ gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
+ x = xyz.X(); y = xyz.Y(); z = xyz.Z();
+ }
+ else {
+ x = (Ns[i]->X() + Ns[i+2]->X())/2;
+ y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
+ z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
+ }
+ if( fabs( Ns[i+1]->X() - x ) > disttol ||
+ fabs( Ns[i+1]->Y() - y ) > disttol ||
+ fabs( Ns[i+1]->Z() - z ) > disttol ) {
+ // we have to move i+1 node
+ aMesh->MoveNode( Ns[i+1], x, y, z );
+ }
+ }
+ }
+ }
+ }
+
+ } // loop on face ids
+
+}
+
+//=======================================================================
+//function : isReverse
+//purpose : Return true if normal of prevNodes is not co-directied with
+// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
+// iNotSame is where prevNodes and nextNodes are different
+//=======================================================================
+
+static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
+ vector<const SMDS_MeshNode*> nextNodes,
+ const int nbNodes,
+ const int iNotSame)
+{
+ int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
+ int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
+
+ const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
+ const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
+ const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
+ const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
+
+ gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
+ gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
+ gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
+ gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
+
+ gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
+
+ return (vA ^ vB) * vN < 0.0;
+}
+
+//=======================================================================
+/*!
+ * \brief Create elements by sweeping an element
+ * \param elem - element to sweep
+ * \param newNodesItVec - nodes generated from each node of the element
+ * \param newElems - generated elements
+ * \param nbSteps - number of sweeping steps
+ * \param srcElements - to append elem for each generated element
+ */
+//=======================================================================
+
+void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
+ const vector<TNodeOfNodeListMapItr> & newNodesItVec,
+ list<const SMDS_MeshElement*>& newElems,
+ const int nbSteps,
+ SMESH_SequenceOfElemPtr& srcElements)
+{
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ // Loop on elem nodes:
+ // find new nodes and detect same nodes indices
+ int nbNodes = elem->NbNodes();
+ vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
+ vector<const SMDS_MeshNode*> prevNod( nbNodes );
+ vector<const SMDS_MeshNode*> nextNod( nbNodes );
+ vector<const SMDS_MeshNode*> midlNod( nbNodes );
+
+ int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
+ vector<int> sames(nbNodes);
+ vector<bool> issimple(nbNodes);
+
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+ TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
+ const SMDS_MeshNode* node = nnIt->first;
+ const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
+ if ( listNewNodes.empty() ) {
+ return;
+ }
+
+ issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
+
+ itNN[ iNode ] = listNewNodes.begin();
+ prevNod[ iNode ] = node;
+ nextNod[ iNode ] = listNewNodes.front();
+ if( !elem->IsQuadratic() || !issimple[iNode] ) {
+ if ( prevNod[ iNode ] != nextNod [ iNode ])
+ iNotSameNode = iNode;
+ else {
+ iSameNode = iNode;
+ //nbSame++;
+ sames[nbSame++] = iNode;
+ }
+ }
+ }
+
+ //cout<<" nbSame = "<<nbSame<<endl;
+ if ( nbSame == nbNodes || nbSame > 2) {
+ MESSAGE( " Too many same nodes of element " << elem->GetID() );
+ //INFOS( " Too many same nodes of element " << elem->GetID() );
+ return;
+ }
+
+ // if( elem->IsQuadratic() && nbSame>0 ) {
+ // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
+ // return;
+ // }
+
+ int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
+ int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
+ if ( nbSame > 0 ) {
+ iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
+ iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
+ iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
+ }
+
+ //if(nbNodes==8)
+ //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
+ // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
+ // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
+ // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
+
+ // check element orientation
+ int i0 = 0, i2 = 2;
+ if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
+ //MESSAGE("Reversed elem " << elem );
+ i0 = 2;
+ i2 = 0;
+ if ( nbSame > 0 )
+ std::swap( iBeforeSame, iAfterSame );
+ }
+
+ // make new elements
+ for (int iStep = 0; iStep < nbSteps; iStep++ ) {
+ // get next nodes
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+ if(issimple[iNode]) {
+ nextNod[ iNode ] = *itNN[ iNode ];
+ itNN[ iNode ]++;
+ }
+ else {
+ if( elem->GetType()==SMDSAbs_Node ) {
+ // we have to use two nodes
+ midlNod[ iNode ] = *itNN[ iNode ];
+ itNN[ iNode ]++;
+ nextNod[ iNode ] = *itNN[ iNode ];
+ itNN[ iNode ]++;
+ }
+ else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
+ // we have to use each second node
+ //itNN[ iNode ]++;
+ nextNod[ iNode ] = *itNN[ iNode ];
+ itNN[ iNode ]++;
+ }
+ else {
+ // we have to use two nodes
+ midlNod[ iNode ] = *itNN[ iNode ];
+ itNN[ iNode ]++;
+ nextNod[ iNode ] = *itNN[ iNode ];
+ itNN[ iNode ]++;
+ }
+ }
+ }
+ SMDS_MeshElement* aNewElem = 0;
+ if(!elem->IsPoly()) {
+ switch ( nbNodes ) {
+ case 0:
+ return;
+ case 1: { // NODE
+ if ( nbSame == 0 ) {
+ if(issimple[0])
+ aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
+ else
+ aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
+ }
+ break;
+ }
+ case 2: { // EDGE
+ if ( nbSame == 0 )
+ aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
+ nextNod[ 1 ], nextNod[ 0 ] );
+ else
+ aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
+ nextNod[ iNotSameNode ] );
+ break;
+ }
+
+ case 3: { // TRIANGLE or quadratic edge
+ if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
+
+ if ( nbSame == 0 ) // --- pentahedron
+ aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
+ nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
+
+ else if ( nbSame == 1 ) // --- pyramid
+ aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
+ nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+ nextNod[ iSameNode ]);
+
+ else // 2 same nodes: --- tetrahedron
+ aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
+ nextNod[ iNotSameNode ]);
+ }
+ else { // quadratic edge
+ if(nbSame==0) { // quadratic quadrangle
+ aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
+ midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
+ }
+ else if(nbSame==1) { // quadratic triangle
+ if(sames[0]==2) {
+ return; // medium node on axis
+ }
+ else if(sames[0]==0) {
+ aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
+ nextNod[2], midlNod[1], prevNod[2]);
+ }
+ else { // sames[0]==1
+ aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
+ midlNod[0], nextNod[2], prevNod[2]);
+ }
+ }
+ else {
+ return;
+ }
+ }
+ break;
+ }
+ case 4: { // QUADRANGLE
+
+ if ( nbSame == 0 ) // --- hexahedron
+ aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
+ nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
+
+ else if ( nbSame == 1 ) { // --- pyramid + pentahedron
+ aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
+ nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+ nextNod[ iSameNode ]);
+ newElems.push_back( aNewElem );
+ aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
+ prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
+ nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
+ }
+ else if ( nbSame == 2 ) { // pentahedron
+ if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
+ // iBeforeSame is same too
+ aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
+ nextNod[ iOpposSame ], prevNod[ iSameNode ],
+ prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
+ else
+ // iAfterSame is same too
+ aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
+ nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
+ prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
+ }
+ break;
+ }
+ case 6: { // quadratic triangle
+ // create pentahedron with 15 nodes
+ if(nbSame==0) {
+ if(i0>0) { // reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
+ nextNod[0], nextNod[2], nextNod[1],
+ prevNod[5], prevNod[4], prevNod[3],
+ nextNod[5], nextNod[4], nextNod[3],
+ midlNod[0], midlNod[2], midlNod[1]);
+ }
+ else { // not reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
+ nextNod[0], nextNod[1], nextNod[2],
+ prevNod[3], prevNod[4], prevNod[5],
+ nextNod[3], nextNod[4], nextNod[5],
+ midlNod[0], midlNod[1], midlNod[2]);
+ }
+ }
+ else if(nbSame==1) {
+ // 2d order pyramid of 13 nodes
+ //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
+ // int n12,int n23,int n34,int n41,
+ // int n15,int n25,int n35,int n45, int ID);
+ int n5 = iSameNode;
+ int n1,n4,n41,n15,n45;
+ if(i0>0) { // reversed case
+ n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+ n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+ n41 = n1 + 3;
+ n15 = n5 + 3;
+ n45 = n4 + 3;
+ }
+ else {
+ n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+ n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+ n41 = n4 + 3;
+ n15 = n1 + 3;
+ n45 = n5 + 3;
+ }
+ aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
+ nextNod[n4], prevNod[n4], prevNod[n5],
+ midlNod[n1], nextNod[n41],
+ midlNod[n4], prevNod[n41],
+ prevNod[n15], nextNod[n15],
+ nextNod[n45], prevNod[n45]);
+ }
+ else if(nbSame==2) {
+ // 2d order tetrahedron of 10 nodes
+ //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
+ // int n12,int n23,int n31,
+ // int n14,int n24,int n34, int ID);
+ int n1 = iNotSameNode;
+ int n2,n3,n12,n23,n31;
+ if(i0>0) { // reversed case
+ n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+ n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+ n12 = n2 + 3;
+ n23 = n3 + 3;
+ n31 = n1 + 3;
+ }
+ else {
+ n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+ n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+ n12 = n1 + 3;
+ n23 = n2 + 3;
+ n31 = n3 + 3;
+ }
+ aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
+ prevNod[n12], prevNod[n23], prevNod[n31],
+ midlNod[n1], nextNod[n12], nextNod[n31]);
+ }
+ break;
+ }
+ case 8: { // quadratic quadrangle
+ if(nbSame==0) {
+ // create hexahedron with 20 nodes
+ if(i0>0) { // reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
+ nextNod[0], nextNod[3], nextNod[2], nextNod[1],
+ prevNod[7], prevNod[6], prevNod[5], prevNod[4],
+ nextNod[7], nextNod[6], nextNod[5], nextNod[4],
+ midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
+ }
+ else { // not reversed case
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
+ nextNod[0], nextNod[1], nextNod[2], nextNod[3],
+ prevNod[4], prevNod[5], prevNod[6], prevNod[7],
+ nextNod[4], nextNod[5], nextNod[6], nextNod[7],
+ midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
+ }
+ }
+ else if(nbSame==1) {
+ // --- pyramid + pentahedron - can not be created since it is needed
+ // additional middle node ot the center of face
+ INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
+ return;
+ }
+ else if(nbSame==2) {
+ // 2d order Pentahedron with 15 nodes
+ //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
+ // int n12,int n23,int n31,int n45,int n56,int n64,
+ // int n14,int n25,int n36, int ID);
+ int n1,n2,n4,n5;
+ if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
+ // iBeforeSame is same too
+ n1 = iBeforeSame;
+ n2 = iOpposSame;
+ n4 = iSameNode;
+ n5 = iAfterSame;
+ }
+ else {
+ // iAfterSame is same too
+ n1 = iSameNode;
+ n2 = iBeforeSame;
+ n4 = iAfterSame;
+ n5 = iOpposSame;
+ }
+ int n12,n45,n14,n25;
+ if(i0>0) { //reversed case
+ n12 = n1 + 4;
+ n45 = n5 + 4;
+ n14 = n4 + 4;
+ n25 = n2 + 4;
+ }
+ else {
+ n12 = n2 + 4;
+ n45 = n4 + 4;
+ n14 = n1 + 4;
+ n25 = n5 + 4;
+ }
+ aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
+ prevNod[n4], prevNod[n5], nextNod[n5],
+ prevNod[n12], midlNod[n2], nextNod[n12],
+ prevNod[n45], midlNod[n5], nextNod[n45],
+ prevNod[n14], prevNod[n25], nextNod[n25]);
+ }
+ break;
+ }
+ default: {
+ // realized for extrusion only
+ //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
+ //vector<int> quantities (nbNodes + 2);
+
+ //quantities[0] = nbNodes; // bottom of prism
+ //for (int inode = 0; inode < nbNodes; inode++) {
+ // polyedre_nodes[inode] = prevNod[inode];
+ //}
+
+ //quantities[1] = nbNodes; // top of prism
+ //for (int inode = 0; inode < nbNodes; inode++) {
+ // polyedre_nodes[nbNodes + inode] = nextNod[inode];
+ //}
+
+ //for (int iface = 0; iface < nbNodes; iface++) {
+ // quantities[iface + 2] = 4;
+ // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
+ // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
+ // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
+ // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
+ // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
+ //}
+ //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
+ break;
+ }
+ }
+ }
+
+ if(!aNewElem) {
+ // realized for extrusion only
+ vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
+ vector<int> quantities (nbNodes + 2);
+
+ quantities[0] = nbNodes; // bottom of prism
+ for (int inode = 0; inode < nbNodes; inode++) {
+ polyedre_nodes[inode] = prevNod[inode];
+ }
+
+ quantities[1] = nbNodes; // top of prism
+ for (int inode = 0; inode < nbNodes; inode++) {
+ polyedre_nodes[nbNodes + inode] = nextNod[inode];
+ }
+
+ for (int iface = 0; iface < nbNodes; iface++) {
+ quantities[iface + 2] = 4;
+ int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
+ polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
+ polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
+ polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
+ polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
+ }
+ aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
+ }
+
+ if ( aNewElem ) {
+ newElems.push_back( aNewElem );
+ myLastCreatedElems.Append(aNewElem);
+ srcElements.Append( elem );
+ }
+
+ // set new prev nodes
+ for ( iNode = 0; iNode < nbNodes; iNode++ )
+ prevNod[ iNode ] = nextNod[ iNode ];
+
+ } // for steps
+}
+
+//=======================================================================
+/*!
+ * \brief Create 1D and 2D elements around swept elements
+ * \param mapNewNodes - source nodes and ones generated from them
+ * \param newElemsMap - source elements and ones generated from them
+ * \param elemNewNodesMap - nodes generated from each node of each element
+ * \param elemSet - all swept elements
+ * \param nbSteps - number of sweeping steps
+ * \param srcElements - to append elem for each generated element
+ */
+//=======================================================================
+
+void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
+ TElemOfElemListMap & newElemsMap,
+ TElemOfVecOfNnlmiMap & elemNewNodesMap,
+ TIDSortedElemSet& elemSet,
+ const int nbSteps,
+ SMESH_SequenceOfElemPtr& srcElements)
+{
+ ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ // Find nodes belonging to only one initial element - sweep them to get edges.
+
+ TNodeOfNodeListMapItr nList = mapNewNodes.begin();
+ for ( ; nList != mapNewNodes.end(); nList++ ) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>( nList->first );
+ SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
+ int nbInitElems = 0;
+ const SMDS_MeshElement* el = 0;
+ SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
+ while ( eIt->more() && nbInitElems < 2 ) {
+ el = eIt->next();
+ SMDSAbs_ElementType type = el->GetType();
+ if ( type == SMDSAbs_Volume || type < highType ) continue;
+ if ( type > highType ) {
+ nbInitElems = 0;
+ highType = type;
+ }
+ if ( elemSet.find(el) != elemSet.end() )
+ nbInitElems++;
+ }
+ if ( nbInitElems < 2 ) {
+ bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
+ if(!NotCreateEdge) {
+ vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
+ list<const SMDS_MeshElement*> newEdges;
+ sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
+ }
+ }
+ }
+
+ // Make a ceiling for each element ie an equal element of last new nodes.
+ // Find free links of faces - make edges and sweep them into faces.
+
+ TElemOfElemListMap::iterator itElem = newElemsMap.begin();
+ TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
+ for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
+ const SMDS_MeshElement* elem = itElem->first;
+ vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
+
+ if ( elem->GetType() == SMDSAbs_Edge ) {
+ // create a ceiling edge
+ if (!elem->IsQuadratic()) {
+ if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back())) {
+ myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back()));
+ srcElements.Append( myLastCreatedElems.Last() );
+ }
+ }
+ else {
+ if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back(),
+ vecNewNodes[ 2 ]->second.back())) {
+ myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
+ vecNewNodes[ 1 ]->second.back(),
+ vecNewNodes[ 2 ]->second.back()));
+ srcElements.Append( myLastCreatedElems.Last() );
+ }
+ }
+ }
+ if ( elem->GetType() != SMDSAbs_Face )
+ continue;
+
+ if(itElem->second.size()==0) continue;
+
+ bool hasFreeLinks = false;
+
+ TIDSortedElemSet avoidSet;
+ avoidSet.insert( elem );
+
+ set<const SMDS_MeshNode*> aFaceLastNodes;
+ int iNode, nbNodes = vecNewNodes.size();
+ if(!elem->IsQuadratic()) {
+ // loop on the face nodes
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+ aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
+ // look for free links of the face
+ 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
+ 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
+ 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() );
+ }
+ }
+ }
+ }
+ else { // elem is quadratic face
+ int nbn = nbNodes/2;
+ for ( iNode = 0; iNode < nbn; iNode++ ) {
+ aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
+ int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
+ const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
+ const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
+ // check if a link is free
+ if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+ hasFreeLinks = true;
+ // make an edge and a ceiling for a new edge
+ // find medium node
+ const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
+ if ( !aMesh->FindEdge( n1, n2, n3 )) {
+ myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
+ srcElements.Append( myLastCreatedElems.Last() );
+ }
+ 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() );
+ }
+ }
+ }
+ for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
+ aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
+ }
+ }
+
+ // sweep free links into faces
+
+ if ( hasFreeLinks ) {
+ list<const SMDS_MeshElement*> & newVolumes = itElem->second;
+ int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
+
+ set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
+ for ( iNode = 0; iNode < nbNodes; iNode++ ) {
+ initNodeSet.insert( vecNewNodes[ iNode ]->first );
+ topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
+ }
+ for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
+ list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
+ iVol = 0;
+ while ( iVol++ < volNb ) v++;
+ // find indices of free faces of a volume and their source edges
+ list< int > freeInd;
+ list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
+ SMDS_VolumeTool vTool( *v );
+ int iF, nbF = vTool.NbFaces();
+ for ( iF = 0; iF < nbF; iF ++ ) {
+ if (vTool.IsFreeFace( iF ) &&
+ vTool.GetFaceNodes( iF, faceNodeSet ) &&
+ initNodeSet != faceNodeSet) // except an initial face
+ {
+ if ( nbSteps == 1 && faceNodeSet == topNodeSet )
+ continue;
+ freeInd.push_back( iF );
+ // find source edge of a free face iF
+ vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
+ commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
+ std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
+ initNodeSet.begin(), initNodeSet.end(),
+ commonNodes.begin());
+ if ( (*v)->IsQuadratic() )
+ srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
+ else
+ srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
+#ifdef _DEBUG_
+ if ( !srcEdges.back() )
+ {
+ cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
+ << iF << " of volume #" << vTool.ID() << endl;
+ }
+#endif
+ }
+ }
+ if ( freeInd.empty() )
+ continue;
+
+ // create faces for all steps;
+ // if such a face has been already created by sweep of edge,
+ // assure that its orientation is OK
+ for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
+ vTool.Set( *v );
+ vTool.SetExternalNormal();
+ list< int >::iterator ind = freeInd.begin();
+ list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
+ for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
+ {
+ const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
+ int nbn = vTool.NbFaceNodes( *ind );
+ switch ( nbn ) {
+ case 3: { ///// triangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
+ if ( !f )
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
+ else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+ aMesh->ChangeElementNodes( f, nodes, nbn );
+ break;
+ }
+ case 4: { ///// quadrangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
+ if ( !f )
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
+ else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+ aMesh->ChangeElementNodes( f, nodes, nbn );
+ break;
+ }
+ default:
+ if( (*v)->IsQuadratic() ) {
+ if(nbn==6) { /////// quadratic triangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5] );
+ if ( !f ) {
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]));
+ }
+ else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
+ const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
+ tmpnodes[0] = nodes[0];
+ tmpnodes[1] = nodes[2];
+ tmpnodes[2] = nodes[4];
+ tmpnodes[3] = nodes[1];
+ tmpnodes[4] = nodes[3];
+ tmpnodes[5] = nodes[5];
+ aMesh->ChangeElementNodes( f, tmpnodes, nbn );
+ }
+ }
+ else { /////// quadratic quadrangle
+ const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7] );
+ if ( !f ) {
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]));
+ }
+ else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
+ const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
+ tmpnodes[0] = nodes[0];
+ tmpnodes[1] = nodes[2];
+ tmpnodes[2] = nodes[4];
+ tmpnodes[3] = nodes[6];
+ tmpnodes[4] = nodes[1];
+ tmpnodes[5] = nodes[3];
+ tmpnodes[6] = nodes[5];
+ tmpnodes[7] = nodes[7];
+ aMesh->ChangeElementNodes( f, tmpnodes, nbn );
+ }
+ }
+ }
+ else { //////// polygon
+ vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
+ const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
+ if ( !f )
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+ else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+ aMesh->ChangeElementNodes( f, nodes, nbn );
+ }
+ }
+ while ( srcElements.Length() < myLastCreatedElems.Length() )
+ srcElements.Append( *srcEdge );
+
+ } // loop on free faces
+
+ // go to the next volume
+ iVol = 0;
+ while ( iVol++ < nbVolumesByStep ) v++;
+ }
+ }
+ } // sweep free links into faces
+
+ // Make a ceiling face with a normal external to a volume
+
+ SMDS_VolumeTool lastVol( itElem->second.back() );
+
+ int iF = lastVol.GetFaceIndex( aFaceLastNodes );
+ if ( iF >= 0 ) {
+ lastVol.SetExternalNormal();
+ const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
+ int nbn = lastVol.NbFaceNodes( iF );
+ switch ( nbn ) {
+ case 3:
+ if (!hasFreeLinks ||
+ !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
+ break;
+ case 4:
+ if (!hasFreeLinks ||
+ !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
+ break;
+ default:
+ if(itElem->second.back()->IsQuadratic()) {
+ if(nbn==6) {
+ if (!hasFreeLinks ||
+ !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]) ) {
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]));
+ }
+ }
+ else { // nbn==8
+ if (!hasFreeLinks ||
+ !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]) )
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]));
+ }
+ }
+ else {
+ vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
+ if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+ }
+ } // switch
+
+ while ( srcElements.Length() < myLastCreatedElems.Length() )
+ srcElements.Append( myLastCreatedElems.Last() );
+ }
+ } // loop on swept elements
+}
+
+//=======================================================================
+//function : RotationSweep
+//purpose :
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
+ const gp_Ax1& theAxis,
+ const double theAngle,
+ const int theNbSteps,
+ const double theTol,
+ const bool theMakeGroups,
+ const bool theMakeWalls)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
+ MESSAGE( "RotationSweep()");
+ gp_Trsf aTrsf;
+ aTrsf.SetRotation( theAxis, theAngle );
+ gp_Trsf aTrsf2;
+ aTrsf2.SetRotation( theAxis, theAngle/2. );
+
+ gp_Lin aLine( theAxis );
+ double aSqTol = theTol * theTol;
+
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ TNodeOfNodeListMap mapNewNodes;
+ TElemOfVecOfNnlmiMap mapElemNewNodes;
+ TElemOfElemListMap newElemsMap;
+
+ // loop on theElems
+ TIDSortedElemSet::iterator itElem;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Volume )
+ continue;
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( elem->NbNodes() );
+
+ // loop on elem nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ // check if a node has been already sweeped
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
+
+ gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+ double coord[3];
+ aXYZ.Coord( coord[0], coord[1], coord[2] );
+ bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+
+ TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
+ if ( nIt == mapNewNodes.end() ) {
+ nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+
+ // make new nodes
+ //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+ //double coord[3];
+ //aXYZ.Coord( coord[0], coord[1], coord[2] );
+ //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+ const SMDS_MeshNode * newNode = node;
+ for ( int i = 0; i < theNbSteps; i++ ) {
+ if ( !isOnAxis ) {
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ // create two nodes
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ }
+ else {
+ aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ }
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ else {
+ listNewNodes.push_back( newNode );
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ listNewNodes.push_back( newNode );
+ }
+ }
+ }
+ }
+ /*
+ else {
+ // if current elem is quadratic and current node is not medium
+ // we have to check - may be it is needed to insert additional nodes
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+ if(listNewNodes.size()==theNbSteps) {
+ listNewNodes.clear();
+ // make new nodes
+ //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+ //double coord[3];
+ //aXYZ.Coord( coord[0], coord[1], coord[2] );
+ const SMDS_MeshNode * newNode = node;
+ if ( !isOnAxis ) {
+ for(int i = 0; i<theNbSteps; i++) {
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ cout<<" 3 AddNode: "<<newNode;
+ myLastCreatedNodes.Append(newNode);
+ listNewNodes.push_back( newNode );
+ srcNodes.Append( node );
+ aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+ newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ cout<<" 4 AddNode: "<<newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ }
+ else {
+ listNewNodes.push_back( newNode );
+ }
+ }
+ }
+ }
+ */
+ newNodesItVec.push_back( nIt );
+ }
+ // make new elements
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
+ }
+
+ if ( theMakeWalls )
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
+
+ PGroupIDs newGroupIDs;
+ if ( theMakeGroups )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
+
+ return newGroupIDs;
+}
+
+
+//=======================================================================
+//function : CreateNode
+//purpose :
+//=======================================================================
+const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
+ const double y,
+ const double z,
+ const double tolnode,
+ SMESH_SequenceOfNode& aNodes)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ gp_Pnt P1(x,y,z);
+ SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
+
+ // try to search in sequence of existing nodes
+ // if aNodes.Length()>0 we 'nave to use given sequence
+ // else - use all nodes of mesh
+ if(aNodes.Length()>0) {
+ int i;
+ for(i=1; i<=aNodes.Length(); i++) {
+ gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
+ if(P1.Distance(P2)<tolnode)
+ return aNodes.Value(i);
+ }
+ }
+ else {
+ SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
+ while(itn->more()) {
+ const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
+ gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
+ if(P1.Distance(P2)<tolnode)
+ return aN;
+ }
+ }
+
+ // create new node and return it
+ const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
+ myLastCreatedNodes.Append(NewNode);
+ return NewNode;
+}
+
+
+//=======================================================================
+//function : ExtrusionSweep
+//purpose :
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
+ const gp_Vec& theStep,
+ const int theNbSteps,
+ TElemOfElemListMap& newElemsMap,
+ const bool theMakeGroups,
+ const int theFlags,
+ const double theTolerance)
+{
+ ExtrusParam aParams;
+ aParams.myDir = gp_Dir(theStep);
+ aParams.myNodes.Clear();
+ aParams.mySteps = new TColStd_HSequenceOfReal;
+ int i;
+ for(i=1; i<=theNbSteps; i++)
+ aParams.mySteps->Append(theStep.Magnitude());
+
+ return
+ ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
+}
+
+
+//=======================================================================
+//function : ExtrusionSweep
+//purpose :
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
+ ExtrusParam& theParams,
+ TElemOfElemListMap& newElemsMap,
+ const bool theMakeGroups,
+ const int theFlags,
+ const double theTolerance)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ int nbsteps = theParams.mySteps->Length();
+
+ TNodeOfNodeListMap mapNewNodes;
+ //TNodeOfNodeVecMap mapNewNodes;
+ TElemOfVecOfNnlmiMap mapElemNewNodes;
+ //TElemOfVecOfMapNodesMap mapElemNewNodes;
+
+ // loop on theElems
+ TIDSortedElemSet::iterator itElem;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ // check element type
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Volume )
+ continue;
+
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( elem->NbNodes() );
+
+ // loop on elem nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
+ {
+ // check if a node has been already sweeped
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
+ TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
+ //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
+ if ( nIt == mapNewNodes.end() ) {
+ nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
+ //vecNewNodes.reserve(nbsteps);
+
+ // make new nodes
+ double coord[] = { node->X(), node->Y(), node->Z() };
+ //int nbsteps = theParams.mySteps->Length();
+ for ( int i = 0; i < nbsteps; i++ ) {
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ // create additional node
+ double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
+ double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
+ double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
+ if( theFlags & EXTRUSION_FLAG_SEW ) {
+ const SMDS_MeshNode * newNode = CreateNode(x, y, z,
+ theTolerance, theParams.myNodes);
+ listNewNodes.push_back( newNode );
+ }
+ else {
+ const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ }
+ //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
+ coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
+ coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
+ if( theFlags & EXTRUSION_FLAG_SEW ) {
+ const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
+ theTolerance, theParams.myNodes);
+ listNewNodes.push_back( newNode );
+ //vecNewNodes[i]=newNode;
+ }
+ else {
+ const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ //vecNewNodes[i]=newNode;
+ }
+ }
+ }
+ else {
+ // if current elem is quadratic and current node is not medium
+ // we have to check - may be it is needed to insert additional nodes
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
+ if(listNewNodes.size()==nbsteps) {
+ listNewNodes.clear();
+ double coord[] = { node->X(), node->Y(), node->Z() };
+ for ( int i = 0; i < nbsteps; i++ ) {
+ double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
+ double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
+ double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
+ if( theFlags & EXTRUSION_FLAG_SEW ) {
+ const SMDS_MeshNode * newNode = CreateNode(x, y, z,
+ theTolerance, theParams.myNodes);
+ listNewNodes.push_back( newNode );
+ }
+ else {
+ const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
+ coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
+ coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
+ if( theFlags & EXTRUSION_FLAG_SEW ) {
+ const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
+ theTolerance, theParams.myNodes);
+ listNewNodes.push_back( newNode );
+ }
+ else {
+ const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ }
+ }
+ }
+ }
+ newNodesItVec.push_back( nIt );
+ }
+ // make new elements
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
+ }
+
+ if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
+ }
+ PGroupIDs newGroupIDs;
+ if ( theMakeGroups )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
+
+ return newGroupIDs;
+}
+
+/*
+//=======================================================================
+//class : SMESH_MeshEditor_PathPoint
+//purpose : auxiliary class
+//=======================================================================
+class SMESH_MeshEditor_PathPoint {
+public:
+SMESH_MeshEditor_PathPoint() {
+myPnt.SetCoord(99., 99., 99.);
+myTgt.SetCoord(1.,0.,0.);
+myAngle=0.;
+myPrm=0.;
+}
+void SetPnt(const gp_Pnt& aP3D){
+myPnt=aP3D;
+}
+void SetTangent(const gp_Dir& aTgt){
+myTgt=aTgt;
+}
+void SetAngle(const double& aBeta){
+myAngle=aBeta;
+}
+void SetParameter(const double& aPrm){
+myPrm=aPrm;
+}
+const gp_Pnt& Pnt()const{
+return myPnt;
+}
+const gp_Dir& Tangent()const{
+return myTgt;
+}
+double Angle()const{
+return myAngle;
+}
+double Parameter()const{
+return myPrm;
+}
+
+protected:
+gp_Pnt myPnt;
+gp_Dir myTgt;
+double myAngle;
+double myPrm;
+};
+*/
+
+//=======================================================================
+//function : ExtrusionAlongTrack
+//purpose :
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
+ SMESH_subMesh* theTrack,
+ const SMDS_MeshNode* theN1,
+ const bool theHasAngles,
+ list<double>& theAngles,
+ const bool theLinearVariation,
+ const bool theHasRefPoint,
+ const gp_Pnt& theRefPoint,
+ const bool theMakeGroups)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ int aNbE;
+ std::list<double> aPrms;
+ TIDSortedElemSet::iterator itElem;
+
+ gp_XYZ aGC;
+ TopoDS_Edge aTrackEdge;
+ TopoDS_Vertex aV1, aV2;
+
+ SMDS_ElemIteratorPtr aItE;
+ SMDS_NodeIteratorPtr aItN;
+ SMDSAbs_ElementType aTypeE;
+
+ TNodeOfNodeListMap mapNewNodes;
+
+ // 1. Check data
+ aNbE = theElements.size();
+ // nothing to do
+ if ( !aNbE )
+ return EXTR_NO_ELEMENTS;
+
+ // 1.1 Track Pattern
+ ASSERT( theTrack );
+
+ SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
+
+ aItE = pSubMeshDS->GetElements();
+ while ( aItE->more() ) {
+ const SMDS_MeshElement* pE = aItE->next();
+ aTypeE = pE->GetType();
+ // Pattern must contain links only
+ if ( aTypeE != SMDSAbs_Edge )
+ return EXTR_PATH_NOT_EDGE;
+ }
+
+ list<SMESH_MeshEditor_PathPoint> fullList;
+
+ const TopoDS_Shape& aS = theTrack->GetSubShape();
+ // Sub shape for the Pattern must be an Edge or Wire
+ if( aS.ShapeType() == TopAbs_EDGE ) {
+ aTrackEdge = TopoDS::Edge( aS );
+ // the Edge must not be degenerated
+ if ( BRep_Tool::Degenerated( aTrackEdge ) )
+ return EXTR_BAD_PATH_SHAPE;
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN1 = aItN->next();
+ aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN2 = aItN->next();
+ // starting node must be aN1 or aN2
+ if ( !( aN1 == theN1 || aN2 == theN1 ) )
+ return EXTR_BAD_STARTING_NODE;
+ aItN = pSubMeshDS->GetNodes();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );
+ }
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+ }
+ else if( aS.ShapeType() == TopAbs_WIRE ) {
+ list< SMESH_subMesh* > LSM;
+ TopTools_SequenceOfShape Edges;
+ SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
+ while(itSM->more()) {
+ SMESH_subMesh* SM = itSM->next();
+ LSM.push_back(SM);
+ const TopoDS_Shape& aS = SM->GetSubShape();
+ Edges.Append(aS);
+ }
+ list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+ int startNid = theN1->GetID();
+ TColStd_MapOfInteger UsedNums;
+ int NbEdges = Edges.Length();
+ int i = 1;
+ for(; i<=NbEdges; i++) {
+ int k = 0;
+ list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
+ for(; itLSM!=LSM.end(); itLSM++) {
+ k++;
+ if(UsedNums.Contains(k)) continue;
+ aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+ 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;
+ // 2. Collect parameters on the track edge
+ aPrms.clear();
+ aItN = locMeshDS->GetNodes();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );