+namespace
+{
+
+//=======================================================================
+//function : getOriFactor
+//purpose : Return -1 or 1 depending on if order of given nodes corresponds to
+// edge curve orientation
+//=======================================================================
+
+ double getOriFactor( const TopoDS_Edge& edge,
+ const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ SMESH_MesherHelper& helper)
+ {
+ double u1 = helper.GetNodeU( edge, n1, n2 );
+ double u2 = helper.GetNodeU( edge, n2, n1 );
+ return u1 < u2 ? 1. : -1.;
+ }
+}
+
+//=======================================================================
+//function : ExtrusionSweep
+//purpose :
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet theElemSets[2],
+ ExtrusParam& theParams,
+ TTElemOfElemListMap& newElemsMap)
+{
+ ClearLastCreated();
+
+ setElemsFirst( theElemSets );
+ myLastCreatedElems.reserve( theElemSets[0].size() * theParams.NbSteps() );
+ myLastCreatedNodes.reserve( theElemSets[1].size() * theParams.NbSteps() );
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+ srcElems.reserve( theElemSets[0].size() );
+ srcNodes.reserve( theElemSets[1].size() );
+
+ const int nbSteps = theParams.NbSteps();
+ theParams.SetElementsToUse( theElemSets[0], theElemSets[1] );
+
+ TNodeOfNodeListMap mapNewNodes;
+ TElemOfVecOfNnlmiMap mapElemNewNodes;
+
+ const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
+ myMesh->NbFaces(ORDER_QUADRATIC) +
+ myMesh->NbVolumes(ORDER_QUADRATIC) );
+ // loop on theElems
+ TIDSortedElemSet::iterator itElem;
+ for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
+ {
+ TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
+ // check element type
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Volume )
+ continue;
+
+ const size_t nbNodes = elem->NbNodes();
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( nbNodes );
+
+ // loop on elem nodes
+ SMDS_NodeIteratorPtr itN = elem->nodeIterator();
+ while ( itN->more() )
+ {
+ // check if a node has been already sweeped
+ const SMDS_MeshNode* node = itN->next();
+ TNodeOfNodeListMap::iterator nIt =
+ mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ if ( listNewNodes.empty() )
+ {
+ // make new nodes
+
+ // check if we are to create medium nodes between corner ones
+ bool needMediumNodes = false;
+ if ( isQuadraticMesh )
+ {
+ SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+ while (it->more() && !needMediumNodes )
+ {
+ const SMDS_MeshElement* invElem = it->next();
+ if ( invElem != elem && !theElems.count( invElem )) continue;
+ needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+ if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+ needMediumNodes = true;
+ }
+ }
+ // create nodes for all steps
+ if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes ))
+ {
+ list<const SMDS_MeshNode*>::iterator newNodesIt = listNewNodes.begin();
+ for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt )
+ {
+ myLastCreatedNodes.push_back( *newNodesIt );
+ srcNodes.push_back( node );
+ }
+ }
+ else
+ {
+ if ( theParams.ToMakeBoundary() )
+ {
+ GetMeshDS()->Modified();
+ throw SALOME_Exception( SMESH_Comment("Can't extrude node #") << node->GetID() );
+ }
+ break; // newNodesItVec will be shorter than nbNodes
+ }
+ }
+ newNodesItVec.push_back( nIt );
+ }
+ // make new elements
+ if ( newNodesItVec.size() == nbNodes )
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems );
+ }
+ }
+
+ if ( theParams.ToMakeBoundary() ) {
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems );
+ }
+ PGroupIDs newGroupIDs;
+ if ( theParams.ToMakeGroups() )
+ newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
+
+ return newGroupIDs;
+}
+
+//=======================================================================
+//function : ExtrusionAlongTrack
+//purpose :
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
+ SMESH_Mesh* theTrackMesh,
+ SMDS_ElemIteratorPtr theTrackIterator,
+ const SMDS_MeshNode* theN1,
+ std::list<double>& theAngles,
+ const bool theAngleVariation,
+ std::list<double>& theScales,
+ const bool theScaleVariation,
+ const gp_Pnt* theRefPoint,
+ const bool theMakeGroups)
+{
+ ClearLastCreated();
+
+ // 1. Check data
+ if ( theElements[0].empty() && theElements[1].empty() )
+ return EXTR_NO_ELEMENTS;
+
+ ASSERT( theTrackMesh );
+ if ( ! theTrackIterator || !theTrackIterator->more() )
+ return EXTR_NO_ELEMENTS;
+
+ // 2. Get ordered nodes
+ SMESH_MeshAlgos::TElemGroupVector branchEdges;
+ SMESH_MeshAlgos::TNodeGroupVector branchNods;
+ SMESH_MeshAlgos::Get1DBranches( theTrackIterator, branchEdges, branchNods, theN1 );
+ if ( branchEdges.empty() )
+ return EXTR_PATH_NOT_EDGE;
+
+ if ( branchEdges.size() > 1 )
+ return EXTR_BAD_PATH_SHAPE;
+
+ std::vector< const SMDS_MeshNode* >& pathNodes = branchNods[0];
+ std::vector< const SMDS_MeshElement* >& pathEdges = branchEdges[0];
+ if ( pathNodes[0] != theN1 && pathNodes[1] != theN1 )
+ return EXTR_BAD_STARTING_NODE;
+
+ if ( theTrackMesh->NbEdges( ORDER_QUADRATIC ) > 0 )
+ {
+ // add medium nodes to pathNodes
+ std::vector< const SMDS_MeshNode* > pathNodes2;
+ std::vector< const SMDS_MeshElement* > pathEdges2;
+ pathNodes2.reserve( pathNodes.size() * 2 );
+ pathEdges2.reserve( pathEdges.size() * 2 );
+ for ( size_t i = 0; i < pathEdges.size(); ++i )
+ {
+ pathNodes2.push_back( pathNodes[i] );
+ pathEdges2.push_back( pathEdges[i] );
+ if ( pathEdges[i]->IsQuadratic() )
+ {
+ pathNodes2.push_back( pathEdges[i]->GetNode(2) );
+ pathEdges2.push_back( pathEdges[i] );
+ }
+ }
+ pathNodes2.push_back( pathNodes.back() );
+ pathEdges.swap( pathEdges2 );
+ pathNodes.swap( pathNodes2 );
+ }
+
+ // 3. Get path data at pathNodes
+
+ std::vector< ExtrusParam::PathPoint > points( pathNodes.size() );
+
+ if ( theAngleVariation )
+ linearAngleVariation( points.size()-1, theAngles );
+ if ( theScaleVariation )
+ linearScaleVariation( points.size()-1, theScales );
+
+ theAngles.push_front( 0 ); // for the 1st point that is not transformed
+ std::list<double>::iterator angle = theAngles.begin();
+
+ SMESHDS_Mesh* pathMeshDS = theTrackMesh->GetMeshDS();
+
+ std::map< int, double > edgeID2OriFactor; // orientation of EDGEs
+ std::map< int, double >::iterator id2factor;
+ SMESH_MesherHelper pathHelper( *theTrackMesh );
+ gp_Pnt p; gp_Vec tangent;
+ const double tol2 = gp::Resolution() * gp::Resolution();
+
+ for ( size_t i = 0; i < pathNodes.size(); ++i )
+ {
+ ExtrusParam::PathPoint & point = points[ i ];
+
+ point.myPnt = SMESH_NodeXYZ( pathNodes[ i ]);
+
+ if ( angle != theAngles.end() )
+ point.myAngle = *angle++;
+
+ tangent.SetCoord( 0,0,0 );
+ const int shapeID = pathNodes[ i ]->GetShapeID();
+ const TopoDS_Shape& shape = pathMeshDS->IndexToShape( shapeID );
+ TopAbs_ShapeEnum shapeType = shape.IsNull() ? TopAbs_SHAPE : shape.ShapeType();
+ switch ( shapeType )
+ {
+ case TopAbs_EDGE:
+ {
+ TopoDS_Edge edge = TopoDS::Edge( shape );
+ id2factor = edgeID2OriFactor.insert( std::make_pair( shapeID, 0 )).first;
+ if ( id2factor->second == 0 )
+ {
+ if ( i ) id2factor->second = getOriFactor( edge, pathNodes[i-1], pathNodes[i], pathHelper );
+ else id2factor->second = getOriFactor( edge, pathNodes[i], pathNodes[i+1], pathHelper );
+ }
+ double u = pathHelper.GetNodeU( edge, pathNodes[i] ), u0, u1;
+ Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, u0, u1 );
+ curve->D1( u, p, tangent );
+ tangent *= id2factor->second;
+ break;
+ }
+ case TopAbs_VERTEX:
+ {
+ int nbEdges = 0;
+ PShapeIteratorPtr shapeIt = pathHelper.GetAncestors( shape, *theTrackMesh, TopAbs_EDGE );
+ while ( const TopoDS_Shape* edgePtr = shapeIt->next() )
+ {
+ int edgeID = pathMeshDS->ShapeToIndex( *edgePtr );
+ for ( int di = -1; di <= 0; ++di )
+ {
+ size_t j = i + di;
+ if ( j < pathEdges.size() && edgeID == pathEdges[ j ]->GetShapeID() )
+ {
+ TopoDS_Edge edge = TopoDS::Edge( *edgePtr );
+ id2factor = edgeID2OriFactor.insert( std::make_pair( edgeID, 0 )).first;
+ if ( id2factor->second == 0 )
+ {
+ if ( j < i )
+ id2factor->second = getOriFactor( edge, pathNodes[i-1], pathNodes[i], pathHelper );
+ else
+ id2factor->second = getOriFactor( edge, pathNodes[i], pathNodes[i+1], pathHelper );
+ }
+ double u = pathHelper.GetNodeU( edge, pathNodes[i] ), u0, u1;
+ Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, u0, u1 );
+ gp_Vec du;
+ curve->D1( u, p, du );
+ double size2 = du.SquareMagnitude();
+ if ( du.SquareMagnitude() > tol2 )
+ {
+ tangent += du.Divided( Sqrt( size2 )) * id2factor->second;
+ nbEdges++;
+ }
+ break;
+ }
+ }
+ }
+ if ( nbEdges > 0 )
+ break;
+ }
+ // fall through
+ default:
+ {
+ for ( int di = -1; di <= 1; di += 2 )
+ {
+ size_t j = i + di;
+ if ( j < pathNodes.size() )
+ {
+ gp_Vec dir( point.myPnt, SMESH_NodeXYZ( pathNodes[ j ]));
+ double size2 = dir.SquareMagnitude();
+ if ( size2 > tol2 )
+ tangent += dir.Divided( Sqrt( size2 )) * di;
+ }
+ }
+ }
+ } // switch ( shapeType )
+
+ if ( tangent.SquareMagnitude() < tol2 )
+ return EXTR_CANT_GET_TANGENT;
+
+ point.myTgt = tangent;
+
+ } // loop on pathNodes
+
+
+ ExtrusParam nodeMaker( points, theRefPoint, theScales, theMakeGroups );
+ TTElemOfElemListMap newElemsMap;
+
+ ExtrusionSweep( theElements, nodeMaker, newElemsMap );
+
+ return EXTR_OK;
+}
+
+//=======================================================================
+//function : linearAngleVariation
+//purpose : spread values over nbSteps
+//=======================================================================
+
+void SMESH_MeshEditor::linearAngleVariation(const int nbSteps,
+ list<double>& Angles)
+{
+ int nbAngles = Angles.size();
+ if( nbSteps > nbAngles && nbAngles > 0 )
+ {
+ vector<double> theAngles(nbAngles);
+ theAngles.assign( Angles.begin(), Angles.end() );
+
+ list<double> res;
+ double rAn2St = double( nbAngles ) / double( nbSteps );
+ double angPrev = 0, angle;
+ for ( int iSt = 0; iSt < nbSteps; ++iSt )
+ {
+ double angCur = rAn2St * ( iSt+1 );
+ double angCurFloor = floor( angCur );
+ double angPrevFloor = floor( angPrev );
+ if ( angPrevFloor == angCurFloor )
+ angle = rAn2St * theAngles[ int( angCurFloor ) ];
+ else {
+ int iP = int( angPrevFloor );
+ double angPrevCeil = ceil(angPrev);
+ angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
+
+ int iC = int( angCurFloor );
+ if ( iC < nbAngles )
+ angle += ( angCur - angCurFloor ) * theAngles[ iC ];
+
+ iP = int( angPrevCeil );
+ while ( iC-- > iP )
+ angle += theAngles[ iC ];
+ }
+ res.push_back(angle);
+ angPrev = angCur;
+ }
+ Angles.swap( res );
+ }
+}
+
+//=======================================================================
+//function : linearScaleVariation
+//purpose : spread values over nbSteps
+//=======================================================================
+
+void SMESH_MeshEditor::linearScaleVariation(const int theNbSteps,
+ std::list<double>& theScales)
+{
+ int nbScales = theScales.size();
+ std::vector<double> myScales;
+ myScales.reserve( theNbSteps );
+ std::list<double>::const_iterator scale = theScales.begin();
+ double prevScale = 1.0;
+ for ( int iSc = 1; scale != theScales.end(); ++scale, ++iSc )
+ {
+ int iStep = int( iSc / double( nbScales ) * theNbSteps + 0.5 );
+ int stDelta = Max( 1, iStep - myScales.size());
+ double scDelta = ( *scale - prevScale ) / stDelta;
+ for ( int iStep = 0; iStep < stDelta; ++iStep )
+ {
+ myScales.push_back( prevScale + scDelta );
+ prevScale = myScales.back();
+ }
+ prevScale = *scale;
+ }
+ theScales.assign( myScales.begin(), myScales.end() );
+}
+
+//================================================================================
+/*!
+ * \brief Move or copy theElements applying theTrsf to their nodes
+ * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
+ * \param theTrsf - transformation to apply
+ * \param theCopy - if true, create translated copies of theElems
+ * \param theMakeGroups - if true and theCopy, create translated groups
+ * \param theTargetMesh - mesh to copy translated elements into
+ * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
+ */
+//================================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
+ const gp_Trsf& theTrsf,
+ const bool theCopy,
+ const bool theMakeGroups,
+ SMESH_Mesh* theTargetMesh)
+{
+ ClearLastCreated();
+ myLastCreatedElems.reserve( theElems.size() );
+
+ bool needReverse = false;
+ string groupPostfix;
+ switch ( theTrsf.Form() ) {
+ case gp_PntMirror:
+ needReverse = true;
+ groupPostfix = "mirrored";
+ break;
+ case gp_Ax1Mirror: