+ 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 );
+ }
+ list<SMESH_MeshEditor_PathPoint> LPP;
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ LLPPs.push_back(LPP);
+ UsedNums.Add(k);
+ // update startN for search following egde
+ if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+ else startNid = aN1->GetID();
+ break;
+ }
+ }
+ list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+ list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+ fullList.pop_back();
+ itLLPP++;
+ for(; itLLPP!=LLPPs.end(); itLLPP++) {
+ list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+ itPP = currList.begin();
+ SMESH_MeshEditor_PathPoint PP2 = currList.front();
+ gp_Dir D1 = PP1.Tangent();
+ gp_Dir D2 = PP2.Tangent();
+ gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+ (D1.Z()+D2.Z())/2 ) );
+ PP1.SetTangent(Dnew);
+ fullList.push_back(PP1);
+ itPP++;
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ PP1 = fullList.back();
+ fullList.pop_back();
+ }
+ // if wire not closed
+ fullList.push_back(PP1);
+ // else ???
+ }
+ else {
+ return EXTR_BAD_PATH_SHAPE;
+ }
+
+ return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ theHasRefPoint, theRefPoint, theMakeGroups);
+}
+
+
+//=======================================================================
+//function : ExtrusionAlongTrack
+//purpose :
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
+ SMESH_Mesh* 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_Mesh* pMeshDS = theTrack->GetMeshDS();
+
+ aItE = pMeshDS->elementsIterator();
+ 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->GetShapeToMesh();
+ // 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->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+ const SMDS_MeshNode* aN1 = aItN->next();
+ aItN = theTrack->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 = pMeshDS->nodesIterator();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ if( pNode==aN1 || pNode==aN2 ) continue;
+ 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;
+ TopExp_Explorer eExp(aS, TopAbs_EDGE);
+ for(; eExp.More(); eExp.Next()) {
+ TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
+ if( BRep_Tool::Degenerated(E) ) continue;
+ SMESH_subMesh* SM = theTrack->GetSubMesh(E);
+ if(SM) {
+ LSM.push_back(SM);
+ Edges.Append(E);
+ }
+ }
+ 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 );
+ }
+ list<SMESH_MeshEditor_PathPoint> LPP;
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ LLPPs.push_back(LPP);
+ UsedNums.Add(k);
+ // update startN for search following egde
+ if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+ else startNid = aN1->GetID();
+ break;
+ }
+ }
+ list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+ list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+ fullList.pop_back();
+ itLLPP++;
+ for(; itLLPP!=LLPPs.end(); itLLPP++) {
+ list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+ itPP = currList.begin();
+ SMESH_MeshEditor_PathPoint PP2 = currList.front();
+ gp_Pnt P1 = PP1.Pnt();
+ //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
+ gp_Pnt P2 = PP2.Pnt();
+ gp_Dir D1 = PP1.Tangent();
+ gp_Dir D2 = PP2.Tangent();
+ gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+ (D1.Z()+D2.Z())/2 ) );
+ PP1.SetTangent(Dnew);
+ fullList.push_back(PP1);
+ itPP++;
+ for(; itPP!=currList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ PP1 = fullList.back();
+ fullList.pop_back();
+ }
+ // if wire not closed
+ fullList.push_back(PP1);
+ // else ???
+ }
+ else {
+ return EXTR_BAD_PATH_SHAPE;
+ }
+
+ return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+ theHasRefPoint, theRefPoint, theMakeGroups);
+}
+
+
+//=======================================================================
+//function : MakeEdgePathPoints
+//purpose : auxilary for ExtrusionAlongTrack
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
+ const TopoDS_Edge& aTrackEdge,
+ bool FirstIsStart,
+ list<SMESH_MeshEditor_PathPoint>& LPP)
+{
+ Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
+ aTolVec=1.e-7;
+ aTolVec2=aTolVec*aTolVec;
+ double aT1, aT2;
+ TopoDS_Vertex aV1, aV2;
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
+ aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
+ // 2. Collect parameters on the track edge
+ aPrms.push_front( aT1 );
+ aPrms.push_back( aT2 );
+ // sort parameters
+ aPrms.sort();
+ if( FirstIsStart ) {
+ if ( aT1 > aT2 ) {
+ aPrms.reverse();
+ }
+ }
+ else {
+ if ( aT2 > aT1 ) {
+ aPrms.reverse();
+ }
+ }
+ // 3. Path Points
+ SMESH_MeshEditor_PathPoint aPP;
+ Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
+ std::list<double>::iterator aItD = aPrms.begin();
+ for(; aItD != aPrms.end(); ++aItD) {
+ double aT = *aItD;
+ gp_Pnt aP3D;
+ gp_Vec aVec;
+ aC3D->D1( aT, aP3D, aVec );
+ aL2 = aVec.SquareMagnitude();
+ if ( aL2 < aTolVec2 )
+ return EXTR_CANT_GET_TANGENT;
+ gp_Dir aTgt( aVec );
+ aPP.SetPnt( aP3D );
+ aPP.SetTangent( aTgt );
+ aPP.SetParameter( aT );
+ LPP.push_back(aPP);
+ }
+ return EXTR_OK;
+}
+
+
+//=======================================================================
+//function : MakeExtrElements
+//purpose : auxilary for ExtrusionAlongTrack
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
+ list<SMESH_MeshEditor_PathPoint>& fullList,
+ const bool theHasAngles,
+ list<double>& theAngles,
+ const bool theLinearVariation,
+ const bool theHasRefPoint,
+ const gp_Pnt& theRefPoint,
+ const bool theMakeGroups)
+{
+ //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
+ int aNbTP = fullList.size();
+ vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
+ // Angles
+ if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
+ LinearAngleVariation(aNbTP-1, theAngles);
+ }
+ vector<double> aAngles( aNbTP );
+ int j = 0;
+ for(; j<aNbTP; ++j) {
+ aAngles[j] = 0.;
+ }
+ if ( theHasAngles ) {
+ double anAngle;;
+ std::list<double>::iterator aItD = theAngles.begin();
+ for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
+ anAngle = *aItD;
+ aAngles[j] = anAngle;
+ }
+ }
+ // fill vector of path points with angles
+ //aPPs.resize(fullList.size());
+ j = -1;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
+ for(; itPP!=fullList.end(); itPP++) {
+ j++;
+ SMESH_MeshEditor_PathPoint PP = *itPP;
+ PP.SetAngle(aAngles[j]);
+ aPPs[j] = PP;
+ }
+
+ TNodeOfNodeListMap mapNewNodes;
+ TElemOfVecOfNnlmiMap mapElemNewNodes;
+ TElemOfElemListMap newElemsMap;
+ TIDSortedElemSet::iterator itElem;
+ double aX, aY, aZ;
+ int aNb;
+ SMDSAbs_ElementType aTypeE;
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
+ // 3. Center of rotation aV0
+ gp_Pnt aV0 = theRefPoint;
+ gp_XYZ aGC;
+ if ( !theHasRefPoint ) {
+ aNb = 0;
+ aGC.SetCoord( 0.,0.,0. );
+
+ itElem = theElements.begin();
+ for ( ; itElem != theElements.end(); itElem++ ) {
+ const SMDS_MeshElement* elem = *itElem;
+
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
+ aX = node->X();
+ aY = node->Y();
+ aZ = node->Z();
+
+ if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
+ list<const SMDS_MeshNode*> aLNx;
+ mapNewNodes[node] = aLNx;
+ //
+ gp_XYZ aXYZ( aX, aY, aZ );
+ aGC += aXYZ;
+ ++aNb;
+ }
+ }
+ }
+ aGC /= aNb;
+ aV0.SetXYZ( aGC );
+ } // if (!theHasRefPoint) {
+ mapNewNodes.clear();
+
+ // 4. Processing the elements
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
+ // check element type
+ const SMDS_MeshElement* elem = *itElem;
+ aTypeE = elem->GetType();
+ if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
+ continue;
+
+ vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
+ newNodesItVec.reserve( elem->NbNodes() );
+
+ // loop on elem nodes
+ int nodeIndex = -1;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() )
+ {
+ ++nodeIndex;
+ // check if a node has been already processed
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>( itN->next() );
+ TNodeOfNodeListMap::iterator 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
+ aX = node->X(); aY = node->Y(); aZ = node->Z();
+
+ Standard_Real aAngle1x, aAngleT1T0, aTolAng;
+ gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
+ gp_Ax1 anAx1, anAxT1T0;
+ gp_Dir aDT1x, aDT0x, aDT1T0;
+
+ aTolAng=1.e-4;
+
+ aV0x = aV0;
+ aPN0.SetCoord(aX, aY, aZ);
+
+ const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
+ aP0x = aPP0.Pnt();
+ aDT0x= aPP0.Tangent();
+ //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
+
+ for ( j = 1; j < aNbTP; ++j ) {
+ const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
+ aP1x = aPP1.Pnt();
+ aDT1x = aPP1.Tangent();
+ aAngle1x = aPP1.Angle();
+
+ gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
+ // Translation
+ gp_Vec aV01x( aP0x, aP1x );
+ aTrsf.SetTranslation( aV01x );
+
+ // traslated point
+ aV1x = aV0x.Transformed( aTrsf );
+ aPN1 = aPN0.Transformed( aTrsf );
+
+ // rotation 1 [ T1,T0 ]
+ aAngleT1T0=-aDT1x.Angle( aDT0x );
+ if (fabs(aAngleT1T0) > aTolAng) {
+ aDT1T0=aDT1x^aDT0x;
+ anAxT1T0.SetLocation( aV1x );
+ anAxT1T0.SetDirection( aDT1T0 );
+ aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
+
+ aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
+ }
+
+ // rotation 2
+ if ( theHasAngles ) {
+ anAx1.SetLocation( aV1x );
+ anAx1.SetDirection( aDT1x );
+ aTrsfRot.SetRotation( anAx1, aAngle1x );
+
+ aPN1 = aPN1.Transformed( aTrsfRot );
+ }
+
+ // make new node
+ if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+ // create additional node
+ double x = ( aPN1.X() + aPN0.X() )/2.;
+ double y = ( aPN1.Y() + aPN0.Y() )/2.;
+ double z = ( aPN1.Z() + aPN0.Z() )/2.;
+ const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+ }
+ aX = aPN1.X();
+ aY = aPN1.Y();
+ aZ = aPN1.Z();
+ const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ listNewNodes.push_back( newNode );
+
+ aPN0 = aPN1;
+ aP0x = aP1x;
+ aV0x = aV1x;
+ aDT0x = aDT1x;
+ }
+ }
+
+ 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()==aNbTP-1) {
+ vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
+ gp_XYZ P(node->X(), node->Y(), node->Z());
+ list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
+ int i;
+ for(i=0; i<aNbTP-1; i++) {
+ const SMDS_MeshNode* N = *it;
+ double x = ( N->X() + P.X() )/2.;
+ double y = ( N->Y() + P.Y() )/2.;
+ double z = ( N->Z() + P.Z() )/2.;
+ const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
+ srcNodes.Append( node );
+ myLastCreatedNodes.Append(newN);
+ aNodes[2*i] = newN;
+ aNodes[2*i+1] = N;
+ P = gp_XYZ(N->X(),N->Y(),N->Z());
+ }
+ listNewNodes.clear();
+ for(i=0; i<2*(aNbTP-1); i++) {
+ listNewNodes.push_back(aNodes[i]);
+ }
+ }
+ }
+ }
+
+ newNodesItVec.push_back( nIt );
+ }
+ // make new elements
+ //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
+ // newNodesItVec[0]->second.size(), myLastCreatedElems );
+ sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
+ }
+
+ makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
+
+ if ( theMakeGroups )
+ generateGroups( srcNodes, srcElems, "extruded");
+
+ return EXTR_OK;
+}
+
+
+//=======================================================================
+//function : LinearAngleVariation
+//purpose : auxilary for ExtrusionAlongTrack
+//=======================================================================
+void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
+ list<double>& Angles)
+{
+ int nbAngles = Angles.size();
+ if( nbSteps > nbAngles ) {
+ vector<double> theAngles(nbAngles);
+ list<double>::iterator it = Angles.begin();
+ int i = -1;
+ for(; it!=Angles.end(); it++) {
+ i++;
+ theAngles[i] = (*it);
+ }
+ 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.clear();
+ it = res.begin();
+ for(; it!=res.end(); it++)
+ Angles.push_back( *it );
+ }
+}
+
+
+//=======================================================================
+//function : Transform
+//purpose :
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
+ const gp_Trsf& theTrsf,
+ const bool theCopy,
+ const bool theMakeGroups,
+ SMESH_Mesh* theTargetMesh)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ bool needReverse = false;
+ string groupPostfix;
+ switch ( theTrsf.Form() ) {
+ case gp_PntMirror:
+ case gp_Ax1Mirror:
+ case gp_Ax2Mirror:
+ needReverse = true;
+ groupPostfix = "mirrored";
+ break;
+ case gp_Rotation:
+ groupPostfix = "rotated";
+ break;
+ case gp_Translation:
+ groupPostfix = "translated";
+ break;
+ case gp_Scale:
+ groupPostfix = "scaled";
+ break;
+ default:
+ needReverse = false;
+ groupPostfix = "transformed";
+ }
+
+ SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+ SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+
+ // map old node to new one
+ TNodeNodeMap nodeMap;
+
+ // elements sharing moved nodes; those of them which have all
+ // nodes mirrored but are not in theElems are to be reversed
+ TIDSortedElemSet inverseElemSet;
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
+ // loop on theElems
+ TIDSortedElemSet::iterator itElem;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem )
+ continue;
+
+ // loop on elem nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+
+ // check if a node has been already transformed
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
+ pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+ nodeMap.insert( make_pair ( node, node ));
+ if ( !n2n_isnew.second )
+ continue;
+
+ double coord[3];
+ coord[0] = node->X();
+ coord[1] = node->Y();
+ coord[2] = node->Z();
+ theTrsf.Transforms( coord[0], coord[1], coord[2] );
+ if ( theTargetMesh ) {
+ const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+ n2n_isnew.first->second = newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ }
+ else if ( theCopy ) {
+ const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ n2n_isnew.first->second = newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ }
+ else {
+ aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+ // node position on shape becomes invalid
+ const_cast< SMDS_MeshNode* > ( node )->SetPosition
+ ( SMDS_SpacePosition::originSpacePosition() );
+ }
+
+ // keep inverse elements
+ if ( !theCopy && !theTargetMesh && needReverse ) {
+ SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
+ while ( invElemIt->more() ) {
+ const SMDS_MeshElement* iel = invElemIt->next();
+ inverseElemSet.insert( iel );
+ }
+ }
+ }
+ }
+
+ // either create new elements or reverse mirrored ones
+ if ( !theCopy && !needReverse && !theTargetMesh )
+ return PGroupIDs();
+
+ TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
+ for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
+ theElems.insert( *invElemIt );
+
+ // replicate or reverse elements
+
+ enum {
+ REV_TETRA = 0, // = nbNodes - 4
+ REV_PYRAMID = 1, // = nbNodes - 4
+ REV_PENTA = 2, // = nbNodes - 4
+ REV_FACE = 3,
+ REV_HEXA = 4, // = nbNodes - 4
+ FORWARD = 5
+ };
+ int index[][8] = {
+ { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
+ { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
+ { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
+ { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
+ { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
+ { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
+ };
+
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Node )
+ continue;
+
+ int nbNodes = elem->NbNodes();
+ int elemType = elem->GetType();
+
+ if (elem->IsPoly()) {
+ // Polygon or Polyhedral Volume
+ switch ( elemType ) {
+ case SMDSAbs_Face:
+ {
+ vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
+ int iNode = 0;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while (itN->more()) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>(itN->next());
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+ if (nodeMapIt == nodeMap.end())
+ break; // not all nodes transformed
+ if (needReverse) {
+ // reverse mirrored faces and volumes
+ poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
+ } else {
+ poly_nodes[iNode] = (*nodeMapIt).second;
+ }
+ iNode++;
+ }
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else {
+ aMesh->ChangePolygonNodes(elem, poly_nodes);
+ }
+ }
+ break;
+ case SMDSAbs_Volume:
+ {
+ // ATTENTION: Reversing is not yet done!!!
+ const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
+ dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+ if (!aPolyedre) {
+ MESSAGE("Warning: bad volumic element");
+ continue;
+ }
+
+ vector<const SMDS_MeshNode*> poly_nodes;
+ vector<int> quantities;
+
+ bool allTransformed = true;
+ int nbFaces = aPolyedre->NbFaces();
+ for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
+ const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+ if (nodeMapIt == nodeMap.end()) {
+ allTransformed = false; // not all nodes transformed
+ } else {
+ poly_nodes.push_back((*nodeMapIt).second);
+ }
+ }
+ quantities.push_back(nbFaceNodes);
+ }
+ if ( !allTransformed )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
+ myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
+ }
+ else {
+ aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
+ }
+ }
+ break;
+ default:;
+ }
+ continue;
+ }
+
+ // Regular elements
+ int* i = index[ FORWARD ];
+ if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+ if ( elemType == SMDSAbs_Face )
+ i = index[ REV_FACE ];
+ else
+ i = index[ nbNodes - 4 ];
+
+ if(elem->IsQuadratic()) {
+ static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+ i = anIds;
+ if(needReverse) {
+ if(nbNodes==3) { // quadratic edge
+ static int anIds[] = {1,0,2};
+ i = anIds;
+ }
+ else if(nbNodes==6) { // quadratic triangle
+ static int anIds[] = {0,2,1,5,4,3};
+ i = anIds;
+ }
+ else if(nbNodes==8) { // quadratic quadrangle
+ static int anIds[] = {0,3,2,1,7,6,5,4};
+ i = anIds;
+ }
+ else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
+ static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
+ i = anIds;
+ }
+ else if(nbNodes==13) { // quadratic pyramid of 13 nodes
+ static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
+ i = anIds;
+ }
+ else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
+ static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
+ i = anIds;
+ }
+ else { // nbNodes==20 - quadratic hexahedron with 20 nodes
+ static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
+ i = anIds;
+ }
+ }
+ }
+
+ // find transformed nodes
+ vector<const SMDS_MeshNode*> nodes(nbNodes);
+ int iNode = 0;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>( itN->next() );
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
+ if ( nodeMapIt == nodeMap.end() )
+ break; // not all nodes transformed
+ nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
+ }
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ if ( SMDS_MeshElement* copy =
+ targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+ myLastCreatedElems.Append( copy );
+ srcElems.Append( elem );
+ }
+ }
+ else if ( theCopy ) {
+ if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+ myLastCreatedElems.Append( copy );
+ srcElems.Append( elem );
+ }
+ }
+ else {
+ // reverse element as it was reversed by transformation
+ if ( nbNodes > 2 )
+ aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+ }
+ }
+
+ PGroupIDs newGroupIDs;
+
+ if ( theMakeGroups && theCopy ||
+ theMakeGroups && theTargetMesh )
+ newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+
+ return newGroupIDs;
+}
+
+
+//=======================================================================
+//function : Scale
+//purpose :
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
+ const gp_Pnt& thePoint,
+ const std::list<double>& theScaleFact,
+ const bool theCopy,
+ const bool theMakeGroups,
+ SMESH_Mesh* theTargetMesh)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ SMESH_MeshEditor targetMeshEditor( theTargetMesh );
+ SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
+ SMESHDS_Mesh* aMesh = GetMeshDS();
+
+ double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
+ std::list<double>::const_iterator itS = theScaleFact.begin();
+ scaleX = (*itS);
+ if(theScaleFact.size()==1) {
+ scaleY = (*itS);
+ scaleZ= (*itS);
+ }
+ if(theScaleFact.size()==2) {
+ itS++;
+ scaleY = (*itS);
+ scaleZ= (*itS);
+ }
+ if(theScaleFact.size()>2) {
+ itS++;
+ scaleY = (*itS);
+ itS++;
+ scaleZ= (*itS);
+ }
+
+ // map old node to new one
+ TNodeNodeMap nodeMap;
+
+ // elements sharing moved nodes; those of them which have all
+ // nodes mirrored but are not in theElems are to be reversed
+ TIDSortedElemSet inverseElemSet;
+
+ // source elements for each generated one
+ SMESH_SequenceOfElemPtr srcElems, srcNodes;
+
+ // loop on theElems
+ TIDSortedElemSet::iterator itElem;
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem )
+ continue;
+
+ // loop on elem nodes
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+
+ // check if a node has been already transformed
+ const SMDS_MeshNode* node = cast2Node( itN->next() );
+ pair<TNodeNodeMap::iterator,bool> n2n_isnew =
+ nodeMap.insert( make_pair ( node, node ));
+ if ( !n2n_isnew.second )
+ continue;
+
+ //double coord[3];
+ //coord[0] = node->X();
+ //coord[1] = node->Y();
+ //coord[2] = node->Z();
+ //theTrsf.Transforms( coord[0], coord[1], coord[2] );
+ double dx = (node->X() - thePoint.X()) * scaleX;
+ double dy = (node->Y() - thePoint.Y()) * scaleY;
+ double dz = (node->Z() - thePoint.Z()) * scaleZ;
+ if ( theTargetMesh ) {
+ //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
+ const SMDS_MeshNode * newNode =
+ aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+ n2n_isnew.first->second = newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ }
+ else if ( theCopy ) {
+ //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+ const SMDS_MeshNode * newNode =
+ aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+ n2n_isnew.first->second = newNode;
+ myLastCreatedNodes.Append(newNode);
+ srcNodes.Append( node );
+ }
+ else {
+ //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
+ aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
+ // node position on shape becomes invalid
+ const_cast< SMDS_MeshNode* > ( node )->SetPosition
+ ( SMDS_SpacePosition::originSpacePosition() );
+ }
+
+ // keep inverse elements
+ //if ( !theCopy && !theTargetMesh && needReverse ) {
+ // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
+ // while ( invElemIt->more() ) {
+ // const SMDS_MeshElement* iel = invElemIt->next();
+ // inverseElemSet.insert( iel );
+ // }
+ //}
+ }
+ }
+
+ // either create new elements or reverse mirrored ones
+ //if ( !theCopy && !needReverse && !theTargetMesh )
+ if ( !theCopy && !theTargetMesh )
+ return PGroupIDs();
+
+ TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
+ for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
+ theElems.insert( *invElemIt );
+
+ // replicate or reverse elements
+
+ enum {
+ REV_TETRA = 0, // = nbNodes - 4
+ REV_PYRAMID = 1, // = nbNodes - 4
+ REV_PENTA = 2, // = nbNodes - 4
+ REV_FACE = 3,
+ REV_HEXA = 4, // = nbNodes - 4
+ FORWARD = 5
+ };
+ int index[][8] = {
+ { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
+ { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
+ { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
+ { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
+ { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
+ { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
+ };
+
+ for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
+ {
+ const SMDS_MeshElement* elem = *itElem;
+ if ( !elem || elem->GetType() == SMDSAbs_Node )
+ continue;
+
+ int nbNodes = elem->NbNodes();
+ int elemType = elem->GetType();
+
+ if (elem->IsPoly()) {
+ // Polygon or Polyhedral Volume
+ switch ( elemType ) {
+ case SMDSAbs_Face:
+ {
+ vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
+ int iNode = 0;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while (itN->more()) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>(itN->next());
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+ if (nodeMapIt == nodeMap.end())
+ break; // not all nodes transformed
+ //if (needReverse) {
+ // // reverse mirrored faces and volumes
+ // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
+ //} else {
+ poly_nodes[iNode] = (*nodeMapIt).second;
+ //}
+ iNode++;
+ }
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else {
+ aMesh->ChangePolygonNodes(elem, poly_nodes);
+ }
+ }
+ break;
+ case SMDSAbs_Volume:
+ {
+ // ATTENTION: Reversing is not yet done!!!
+ const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
+ dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
+ if (!aPolyedre) {
+ MESSAGE("Warning: bad volumic element");
+ continue;
+ }
+
+ vector<const SMDS_MeshNode*> poly_nodes;
+ vector<int> quantities;
+
+ bool allTransformed = true;
+ int nbFaces = aPolyedre->NbFaces();
+ for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
+ const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+ if (nodeMapIt == nodeMap.end()) {
+ allTransformed = false; // not all nodes transformed
+ } else {
+ poly_nodes.push_back((*nodeMapIt).second);
+ }
+ }
+ quantities.push_back(nbFaceNodes);
+ }
+ if ( !allTransformed )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
+ myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
+ }
+ else {
+ aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
+ }
+ }
+ break;
+ default:;
+ }
+ continue;
+ }
+
+ // Regular elements
+ int* i = index[ FORWARD ];
+ //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
+ // if ( elemType == SMDSAbs_Face )
+ // i = index[ REV_FACE ];
+ // else
+ // i = index[ nbNodes - 4 ];
+
+ if(elem->IsQuadratic()) {
+ static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+ i = anIds;
+ //if(needReverse) {
+ // if(nbNodes==3) { // quadratic edge
+ // static int anIds[] = {1,0,2};
+ // i = anIds;
+ // }
+ // else if(nbNodes==6) { // quadratic triangle
+ // static int anIds[] = {0,2,1,5,4,3};
+ // i = anIds;
+ // }
+ // else if(nbNodes==8) { // quadratic quadrangle
+ // static int anIds[] = {0,3,2,1,7,6,5,4};
+ // i = anIds;
+ // }
+ // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
+ // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
+ // i = anIds;
+ // }
+ // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
+ // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
+ // i = anIds;
+ // }
+ // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
+ // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
+ // i = anIds;
+ // }
+ // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
+ // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
+ // i = anIds;
+ // }
+ //}
+ }
+
+ // find transformed nodes
+ vector<const SMDS_MeshNode*> nodes(nbNodes);
+ int iNode = 0;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>( itN->next() );
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
+ if ( nodeMapIt == nodeMap.end() )
+ break; // not all nodes transformed
+ nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
+ }
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ if ( SMDS_MeshElement* copy =
+ targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+ myLastCreatedElems.Append( copy );
+ srcElems.Append( elem );
+ }
+ }
+ else if ( theCopy ) {
+ if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+ myLastCreatedElems.Append( copy );
+ srcElems.Append( elem );
+ }
+ }
+ else {
+ // reverse element as it was reversed by transformation
+ if ( nbNodes > 2 )
+ aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+ }
+ }
+
+ PGroupIDs newGroupIDs;
+
+ if ( theMakeGroups && theCopy ||
+ theMakeGroups && theTargetMesh ) {
+ string groupPostfix = "scaled";
+ newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
+ }
+
+ return newGroupIDs;
+}
+
+
+//=======================================================================
+/*!
+ * \brief Create groups of elements made during transformation
+ * \param nodeGens - nodes making corresponding myLastCreatedNodes
+ * \param elemGens - elements making corresponding myLastCreatedElems
+ * \param postfix - to append to names of new groups
+ */
+//=======================================================================
+
+SMESH_MeshEditor::PGroupIDs
+SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
+ const SMESH_SequenceOfElemPtr& elemGens,
+ const std::string& postfix,
+ SMESH_Mesh* targetMesh)
+{
+ PGroupIDs newGroupIDs( new list<int> );
+ SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
+
+ // Sort existing groups by types and collect their names
+
+ // to store an old group and a generated new one
+ typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
+ vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
+ // group names
+ set< string > groupNames;
+ //
+ SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
+ SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
+ while ( groupIt->more() ) {
+ SMESH_Group * group = groupIt->next();
+ if ( !group ) continue;
+ SMESHDS_GroupBase* groupDS = group->GetGroupDS();
+ if ( !groupDS || groupDS->IsEmpty() ) continue;
+ groupNames.insert( group->GetName() );
+ groupDS->SetStoreName( group->GetName() );
+ groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
+ }
+
+ // Groups creation
+
+ // loop on nodes and elements
+ for ( int isNodes = 0; isNodes < 2; ++isNodes )
+ {
+ const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
+ const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
+ if ( gens.Length() != elems.Length() )
+ throw SALOME_Exception(LOCALIZED("invalid args"));
+
+ // loop on created elements
+ for (int iElem = 1; iElem <= elems.Length(); ++iElem )
+ {
+ const SMDS_MeshElement* sourceElem = gens( iElem );
+ if ( !sourceElem ) {
+ MESSAGE("generateGroups(): NULL source element");
+ continue;
+ }
+ list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
+ if ( groupsOldNew.empty() ) {
+ while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+ ++iElem; // skip all elements made by sourceElem
+ continue;
+ }
+ // collect all elements made by sourceElem
+ list< const SMDS_MeshElement* > resultElems;
+ if ( const SMDS_MeshElement* resElem = elems( iElem ))
+ if ( resElem != sourceElem )
+ resultElems.push_back( resElem );
+ while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
+ if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
+ if ( resElem != sourceElem )
+ resultElems.push_back( resElem );
+ // do not generate element groups from node ones
+ if ( sourceElem->GetType() == SMDSAbs_Node &&
+ elems( iElem )->GetType() != SMDSAbs_Node )
+ continue;
+
+ // add resultElems to groups made by ones the sourceElem belongs to
+ list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
+ for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
+ {
+ SMESHDS_GroupBase* oldGroup = gOldNew->first;
+ if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
+ {
+ SMDS_MeshGroup* & newGroup = gOldNew->second;
+ if ( !newGroup )// create a new group
+ {
+ // make a name
+ string name = oldGroup->GetStoreName();
+ if ( !targetMesh ) {
+ name += "_";
+ name += postfix;
+ int nb = 0;
+ while ( !groupNames.insert( name ).second ) // name exists
+ {
+ if ( nb == 0 ) {
+ name += "_1";
+ }
+ else {
+ TCollection_AsciiString nbStr(nb+1);
+ name.resize( name.rfind('_')+1 );
+ name += nbStr.ToCString();
+ }
+ ++nb;
+ }
+ }
+ // make a group
+ int id;
+ SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
+ name.c_str(), id );
+ SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
+ newGroup = & groupDS->SMDSGroup();
+ newGroupIDs->push_back( id );
+ }
+
+ // fill in a new group
+ list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
+ for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
+ newGroup->Add( *resElemIt );
+ }
+ }
+ } // loop on created elements
+ }// loop on nodes and elements
+
+ return newGroupIDs;
+}
+
+//================================================================================
+/*!
+ * \brief Return list of group of nodes close to each other within theTolerance
+ * Search among theNodes or in the whole mesh if theNodes is empty using
+ * an Octree algorithm
+ */
+//================================================================================
+
+void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
+ const double theTolerance,
+ TListOfListOfNodes & theGroupsOfNodes)
+{
+ myLastCreatedElems.Clear();
+ myLastCreatedNodes.Clear();
+
+ set<const SMDS_MeshNode*> nodes;
+ if ( theNodes.empty() )
+ { // get all nodes in the mesh
+ SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
+ while ( nIt->more() )
+ nodes.insert( nodes.end(),nIt->next());
+ }
+ else
+ nodes=theNodes;
+
+ SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
+}
+
+
+//=======================================================================
+/*!
+ * \brief Implementation of search for the node closest to point
+ */
+//=======================================================================
+
+struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
+{
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Constructor
+ */
+ SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
+ {
+ myMesh = ( SMESHDS_Mesh* ) theMesh;
+
+ set<const SMDS_MeshNode*> nodes;
+ if ( theMesh ) {
+ SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
+ while ( nIt->more() )
+ nodes.insert( nodes.end(), nIt->next() );
+ }
+ myOctreeNode = new SMESH_OctreeNode(nodes) ;
+
+ // get max size of a leaf box
+ SMESH_OctreeNode* tree = myOctreeNode;
+ while ( !tree->isLeaf() )
+ {
+ SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+ if ( cIt->more() )
+ tree = cIt->next();
+ }
+ myHalfLeafSize = tree->maxSize() / 2.;
+ }
+
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Move node and update myOctreeNode accordingly
+ */
+ void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
+ {
+ myOctreeNode->UpdateByMoveNode( node, toPnt );
+ myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
+ }
+
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Do it's job
+ */
+ const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
+ {
+ SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+ map<double, const SMDS_MeshNode*> dist2Nodes;
+ myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
+ if ( !dist2Nodes.empty() )
+ return dist2Nodes.begin()->second;
+ list<const SMDS_MeshNode*> nodes;
+ //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
+
+ double minSqDist = DBL_MAX;
+ if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
+ {
+ // sort leafs by their distance from thePnt
+ typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
+ TDistTreeMap treeMap;
+ list< SMESH_OctreeNode* > treeList;
+ list< SMESH_OctreeNode* >::iterator trIt;
+ treeList.push_back( myOctreeNode );
+
+ SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
+ for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
+ {
+ SMESH_OctreeNode* tree = *trIt;
+ if ( !tree->isLeaf() ) // put children to the queue
+ {
+ if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
+ SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
+ while ( cIt->more() )
+ treeList.push_back( cIt->next() );
+ }
+ else if ( tree->NbNodes() ) // put a tree to the treeMap
+ {
+ const Bnd_B3d& box = tree->getBox();
+ double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
+ pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
+ if ( !it_in.second ) // not unique distance to box center
+ treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
+ }
+ }
+ // find distance after which there is no sense to check tree's
+ double sqLimit = DBL_MAX;
+ TDistTreeMap::iterator sqDist_tree = treeMap.begin();
+ if ( treeMap.size() > 5 ) {
+ SMESH_OctreeNode* closestTree = sqDist_tree->second;
+ const Bnd_B3d& box = closestTree->getBox();
+ double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
+ sqLimit = limit * limit;
+ }
+ // get all nodes from trees
+ for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
+ if ( sqDist_tree->first > sqLimit )
+ break;
+ SMESH_OctreeNode* tree = sqDist_tree->second;
+ tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
+ }
+ }
+ // find closest among nodes
+ minSqDist = DBL_MAX;
+ const SMDS_MeshNode* closestNode = 0;
+ list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
+ for ( ; nIt != nodes.end(); ++nIt ) {
+ double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+ if ( minSqDist > sqDist ) {
+ closestNode = *nIt;
+ minSqDist = sqDist;
+ }
+ }
+ return closestNode;
+ }
+
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Destructor
+ */
+ ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
+
+ //---------------------------------------------------------------------
+ /*!
+ * \brief Return the node tree
+ */
+ const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
+
+private:
+ SMESH_OctreeNode* myOctreeNode;
+ SMESHDS_Mesh* myMesh;
+ double myHalfLeafSize; // max size of a leaf box
+};
+
+//=======================================================================
+/*!
+ * \brief Return SMESH_NodeSearcher
+ */
+//=======================================================================
+
+SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
+{
+ return new SMESH_NodeSearcherImpl( GetMeshDS() );
+}
+
+// ========================================================================
+namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
+{
+ const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
+ const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
+ const double NodeRadius = 1e-9; // to enlarge bnd box of element
+
+ //=======================================================================
+ /*!
+ * \brief Octal tree of bounding boxes of elements
+ */
+ //=======================================================================
+
+ class ElementBndBoxTree : public SMESH_Octree
+ {
+ public:
+
+ ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
+ void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
+ void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
+ ~ElementBndBoxTree();
+
+ protected:
+ ElementBndBoxTree() {}
+ SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
+ void buildChildrenData();
+ Bnd_B3d* buildRootBox();
+ private:
+ //!< Bounding box of element
+ struct ElementBox : public Bnd_B3d
+ {
+ const SMDS_MeshElement* _element;
+ int _refCount; // an ElementBox can be included in several tree branches
+ ElementBox(const SMDS_MeshElement* elem);
+ };
+ vector< ElementBox* > _elements;
+ };
+
+ //================================================================================
+ /*!
+ * \brief ElementBndBoxTree creation
+ */
+ //================================================================================
+
+ ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
+ :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
+ {
+ int nbElems = mesh.GetMeshInfo().NbElements( elemType );
+ _elements.reserve( nbElems );
+
+ SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
+ while ( elemIt->more() )
+ _elements.push_back( new ElementBox( elemIt->next() ));
+
+ if ( _elements.size() > MaxNbElemsInLeaf )
+ compute();
+ else
+ myIsLeaf = true;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Destructor
+ */
+ //================================================================================
+
+ ElementBndBoxTree::~ElementBndBoxTree()
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( --_elements[i]->_refCount <= 0 )
+ delete _elements[i];
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return the maximal box
+ */
+ //================================================================================
+
+ Bnd_B3d* ElementBndBoxTree::buildRootBox()
+ {
+ Bnd_B3d* box = new Bnd_B3d;
+ for ( int i = 0; i < _elements.size(); ++i )
+ box->Add( *_elements[i] );
+ return box;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Redistrubute element boxes among children
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::buildChildrenData()
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
+ {
+ _elements[i]->_refCount++;
+ ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
+ }
+ }
+ _elements[i]->_refCount--;
+ }
+ _elements.clear();
+
+ for (int j = 0; j < 8; j++)
+ {
+ ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
+ if ( child->_elements.size() <= MaxNbElemsInLeaf )
+ child->myIsLeaf = true;
+
+ if ( child->_elements.capacity() - child->_elements.size() > 1000 )
+ child->_elements.resize( child->_elements.size() ); // compact
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return elements which can include the point
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
+ TIDSortedElemSet& foundElems)
+ {
+ if ( level() && getBox().IsOut( point.XYZ() ))
+ return;
+
+ if ( isLeaf() )
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( !_elements[i]->IsOut( point.XYZ() ))
+ foundElems.insert( _elements[i]->_element );
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return elements which can be intersected by the line
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
+ TIDSortedElemSet& foundElems)
+ {
+ if ( level() && getBox().IsOut( line ))
+ return;
+
+ if ( isLeaf() )
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( !_elements[i]->IsOut( line ))
+ foundElems.insert( _elements[i]->_element );
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Construct the element box
+ */
+ //================================================================================
+
+ ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
+ {
+ _element = elem;
+ _refCount = 1;
+ SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
+ while ( nIt->more() )
+ Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+ Enlarge( NodeRadius );
+ }
+
+} // namespace
+
+//=======================================================================
+/*!
+ * \brief Implementation of search for the elements by point and
+ * of classification of point in 2D mesh
+ */
+//=======================================================================
+
+struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
+{
+ SMESHDS_Mesh* _mesh;
+ ElementBndBoxTree* _ebbTree;
+ SMESH_NodeSearcherImpl* _nodeSearcher;
+ SMDSAbs_ElementType _elementType;
+ double _tolerance;
+ bool _outerFacesFound;
+ set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
+
+ SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
+ : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
+ ~SMESH_ElementSearcherImpl()
+ {
+ if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
+ if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
+ }
+ virtual int FindElementsByPoint(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElements);
+ virtual TopAbs_State GetPointState(const gp_Pnt& point);
+
+ double getTolerance();
+ bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
+ const double tolerance, double & param);
+ void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
+ bool isOuterBoundary(const SMDS_MeshElement* face) const
+ {
+ return _outerFaces.empty() || _outerFaces.count(face);
+ }
+ struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
+ {
+ const SMDS_MeshElement* _face;
+ gp_Vec _faceNorm;
+ bool _coincides; //!< the line lays in face plane
+ TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
+ : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
+ };
+ struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
+ {
+ SMESH_TLink _link;
+ TIDSortedElemSet _faces;
+ TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
+ : _link( n1, n2 ), _faces( &face, &face + 1) {}
+ };
+};
+
+ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
+{
+ return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
+ << ", _coincides="<<i._coincides << ")";
+}
+
+//=======================================================================
+/*!
+ * \brief define tolerance for search
+ */
+//=======================================================================
+
+double SMESH_ElementSearcherImpl::getTolerance()
+{
+ if ( _tolerance < 0 )
+ {
+ const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
+
+ _tolerance = 0;
+ if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
+ {
+ double boxSize = _nodeSearcher->getTree()->maxSize();
+ _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
+ }
+ else if ( _ebbTree && meshInfo.NbElements() > 0 )
+ {
+ double boxSize = _ebbTree->maxSize();
+ _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
+ }
+ if ( _tolerance == 0 )
+ {
+ // define tolerance by size of a most complex element
+ int complexType = SMDSAbs_Volume;
+ while ( complexType > SMDSAbs_All &&
+ meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
+ --complexType;
+ if ( complexType == SMDSAbs_All ) return 0; // empty mesh
+
+ double elemSize;
+ if ( complexType == int( SMDSAbs_Node ))
+ {
+ SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
+ elemSize = 1;
+ if ( meshInfo.NbNodes() > 2 )
+ elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+ }
+ else
+ {
+ const SMDS_MeshElement* elem =
+ _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
+ SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+ SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+ while ( nodeIt->more() )
+ {
+ double dist = n1.Distance( cast2Node( nodeIt->next() ));
+ elemSize = max( dist, elemSize );
+ }
+ }
+ _tolerance = 1e-6 * elemSize;
+ }
+ }
+ return _tolerance;
+}
+
+//================================================================================
+/*!
+ * \brief Find intersection of the line and an edge of face and return parameter on line
+ */
+//================================================================================
+
+bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
+ const SMDS_MeshElement* face,
+ const double tol,
+ double & param)
+{
+ int nbInts = 0;
+ param = 0;
+
+ GeomAPI_ExtremaCurveCurve anExtCC;
+ Handle(Geom_Curve) lineCurve = new Geom_Line( line );
+
+ int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
+ for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
+ {
+ GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
+ SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
+ anExtCC.Init( lineCurve, edge);
+ if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
+ {
+ Quantity_Parameter pl, pe;
+ anExtCC.LowerDistanceParameters( pl, pe );
+ param += pl;
+ if ( ++nbInts == 2 )
+ break;
+ }
+ }
+ if ( nbInts > 0 ) param /= nbInts;
+ return nbInts > 0;
+}
+//================================================================================
+/*!
+ * \brief Find all faces belonging to the outer boundary of mesh
+ */
+//================================================================================
+
+void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
+{
+ if ( _outerFacesFound ) return;
+
+ // Collect all outer faces by passing from one outer face to another via their links
+ // and BTW find out if there are internal faces at all.
+
+ // checked links and links where outer boundary meets internal one
+ set< SMESH_TLink > visitedLinks, seamLinks;
+
+ // links to treat with already visited faces sharing them
+ list < TFaceLink > startLinks;
+
+ // load startLinks with the first outerFace
+ startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
+ _outerFaces.insert( outerFace );
+
+ TIDSortedElemSet emptySet;
+ while ( !startLinks.empty() )
+ {
+ const SMESH_TLink& link = startLinks.front()._link;
+ TIDSortedElemSet& faces = startLinks.front()._faces;
+
+ outerFace = *faces.begin();
+ // find other faces sharing the link
+ const SMDS_MeshElement* f;
+ while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
+ faces.insert( f );
+
+ // select another outer face among the found
+ const SMDS_MeshElement* outerFace2 = 0;
+ if ( faces.size() == 2 )
+ {
+ outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
+ }
+ else if ( faces.size() > 2 )
+ {
+ seamLinks.insert( link );
+
+ // link direction within the outerFace
+ gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
+ SMESH_MeshEditor::TNodeXYZ( link.node2()));
+ int i1 = outerFace->GetNodeIndex( link.node1() );
+ int i2 = outerFace->GetNodeIndex( link.node2() );
+ bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
+ if ( rev ) n1n2.Reverse();
+ // outerFace normal
+ gp_XYZ ofNorm, fNorm;
+ if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
+ {
+ // direction from the link inside outerFace
+ gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
+ // sort all other faces by angle with the dirInOF
+ map< double, const SMDS_MeshElement* > angle2Face;
+ set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
+ for ( ; face != faces.end(); ++face )
+ {
+ if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
+ continue;
+ gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
+ double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
+ if ( angle < 0 ) angle += 2*PI;
+ angle2Face.insert( make_pair( angle, *face ));
+ }
+ if ( !angle2Face.empty() )
+ outerFace2 = angle2Face.begin()->second;
+ }
+ }
+ // store the found outer face and add its links to continue seaching from
+ if ( outerFace2 )
+ {
+ _outerFaces.insert( outerFace );
+ int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
+ for ( int i = 0; i < nbNodes; ++i )
+ {
+ SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
+ if ( visitedLinks.insert( link2 ).second )
+ startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
+ }
+ }
+ startLinks.pop_front();
+ }
+ _outerFacesFound = true;
+
+ if ( !seamLinks.empty() )
+ {
+ // There are internal boundaries touching the outher one,
+ // find all faces of internal boundaries in order to find
+ // faces of boundaries of holes, if any.
+
+ }
+ else
+ {
+ _outerFaces.clear();
+ }
+}
+
+//=======================================================================
+/*!
+ * \brief Find elements of given type where the given point is IN or ON.
+ * Returns nb of found elements and elements them-selves.
+ *
+ * 'ALL' type means elements of any type excluding nodes and 0D elements
+ */
+//=======================================================================
+
+int SMESH_ElementSearcherImpl::
+FindElementsByPoint(const gp_Pnt& point,
+ SMDSAbs_ElementType type,
+ vector< const SMDS_MeshElement* >& foundElements)
+{
+ foundElements.clear();
+
+ double tolerance = getTolerance();
+
+ // =================================================================================
+ if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
+ {
+ if ( !_nodeSearcher )
+ _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
+
+ const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
+ if ( !closeNode ) return foundElements.size();
+
+ if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+ return foundElements.size(); // to far from any node
+
+ if ( type == SMDSAbs_Node )
+ {
+ foundElements.push_back( closeNode );
+ }
+ else
+ {
+ SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
+ while ( elemIt->more() )
+ foundElements.push_back( elemIt->next() );
+ }
+ }
+ // =================================================================================
+ else // elements more complex than 0D
+ {
+ if ( !_ebbTree || _elementType != type )
+ {
+ if ( _ebbTree ) delete _ebbTree;
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
+ }
+ TIDSortedElemSet suspectElems;
+ _ebbTree->getElementsNearPoint( point, suspectElems );
+ TIDSortedElemSet::iterator elem = suspectElems.begin();
+ for ( ; elem != suspectElems.end(); ++elem )
+ if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
+ foundElements.push_back( *elem );
+ }
+ return foundElements.size();
+}
+
+//================================================================================
+/*!
+ * \brief Classify the given point in the closed 2D mesh
+ */
+//================================================================================
+
+TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
+{
+ double tolerance = getTolerance();
+ if ( !_ebbTree || _elementType != SMDSAbs_Face )
+ {
+ if ( _ebbTree ) delete _ebbTree;
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
+ }
+ // Algo: analyse transition of a line starting at the point through mesh boundary;
+ // try three lines parallel to axis of the coordinate system and perform rough
+ // analysis. If solution is not clear perform thorough analysis.
+
+ const int nbAxes = 3;
+ gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
+ map< double, TInters > paramOnLine2TInters[ nbAxes ];
+ list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
+ multimap< int, int > nbInt2Axis; // to find the simplest case
+ for ( int axis = 0; axis < nbAxes; ++axis )
+ {
+ gp_Ax1 lineAxis( point, axisDir[axis]);
+ gp_Lin line ( lineAxis );
+
+ TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
+ _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
+
+ // Intersect faces with the line
+
+ map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+ TIDSortedElemSet::iterator face = suspectFaces.begin();
+ for ( ; face != suspectFaces.end(); ++face )
+ {
+ // get face plane
+ gp_XYZ fNorm;
+ if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
+ gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+
+ // perform intersection
+ IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
+ if ( !intersection.IsDone() )
+ continue;
+ if ( intersection.IsInQuadric() )
+ {
+ tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
+ }
+ else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
+ {
+ gp_Pnt intersectionPoint = intersection.Point(1);
+ if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
+ u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
+ }
+ }
+ // Analyse intersections roughly
+
+ int nbInter = u2inters.size();
+ if ( nbInter == 0 )
+ return TopAbs_OUT;
+
+ double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
+ if ( nbInter == 1 ) // not closed mesh
+ return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
+
+ if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
+ return TopAbs_ON;
+
+ if ( (f<0) == (l<0) )
+ return TopAbs_OUT;
+
+ int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
+ int nbIntAfterPoint = nbInter - nbIntBeforePoint;
+ if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
+ return TopAbs_IN;
+
+ nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
+
+ if ( _outerFacesFound ) break; // pass to thorough analysis
+
+ } // three attempts - loop on CS axes
+
+ // Analyse intersections thoroughly.
+ // We make two loops maximum, on the first one we only exclude touching intersections,
+ // on the second, if situation is still unclear, we gather and use information on
+ // position of faces (internal or outer). If faces position is already gathered,
+ // we make the second loop right away.
+
+ for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
+ {
+ multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
+ for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
+ {
+ int axis = nb_axis->second;
+ map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+
+ gp_Ax1 lineAxis( point, axisDir[axis]);
+ gp_Lin line ( lineAxis );
+
+ // add tangent intersections to u2inters
+ double param;
+ list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
+ for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
+ if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
+ u2inters.insert(make_pair( param, *tgtInt ));
+ tangentInters[ axis ].clear();
+
+ // Count intersections before and after the point excluding touching ones.
+ // If hasPositionInfo we count intersections of outer boundary only
+
+ int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
+ double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
+ map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
+ bool ok = ! u_int1->second._coincides;
+ while ( ok && u_int1 != u2inters.end() )
+ {
+ double u = u_int1->first;
+ bool touchingInt = false;
+ if ( ++u_int2 != u2inters.end() )
+ {
+ // skip intersections at the same point (if the line passes through edge or node)
+ int nbSamePnt = 0;
+ while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
+ {
+ ++nbSamePnt;
+ ++u_int2;
+ }
+
+ // skip tangent intersections
+ int nbTgt = 0;
+ const SMDS_MeshElement* prevFace = u_int1->second._face;
+ while ( ok && u_int2->second._coincides )
+ {
+ if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
+ ok = false;
+ else
+ {
+ nbTgt++;
+ u_int2++;
+ ok = ( u_int2 != u2inters.end() );
+ }
+ }
+ if ( !ok ) break;
+
+ // skip intersections at the same point after tangent intersections
+ if ( nbTgt > 0 )
+ {
+ double u2 = u_int2->first;
+ ++u_int2;
+ while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
+ {
+ ++nbSamePnt;
+ ++u_int2;
+ }
+ }
+ // decide if we skipped a touching intersection
+ if ( nbSamePnt + nbTgt > 0 )
+ {
+ double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
+ map< double, TInters >::iterator u_int = u_int1;
+ for ( ; u_int != u_int2; ++u_int )
+ {
+ if ( u_int->second._coincides ) continue;
+ double dot = u_int->second._faceNorm * line.Direction();
+ if ( dot > maxDot ) maxDot = dot;
+ if ( dot < minDot ) minDot = dot;
+ }
+ touchingInt = ( minDot*maxDot < 0 );
+ }
+ }
+ if ( !touchingInt )
+ {
+ if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
+ {
+ if ( u < 0 )
+ ++nbIntBeforePoint;
+ else
+ ++nbIntAfterPoint;
+ }
+ if ( u < f ) f = u;
+ if ( u > l ) l = u;
+ }
+
+ u_int1 = u_int2; // to next intersection