+ //================================================================================
+ /*!
+ * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case
+ * if projection by transformation is possible
+ */
+ //================================================================================
+
+ bool projectPartner(const TopoDS_Face& tgtFace,
+ const TopoDS_Face& srcFace,
+ SMESH_Mesh * tgtMesh,
+ SMESH_Mesh * srcMesh,
+ const TAssocTool::TShapeShapeMap& shape2ShapeMap)
+ {
+ MESSAGE("projectPartner");
+ const double tol = 1.e-7*srcMesh->GetMeshDS()->getMaxDim();
+
+ gp_Trsf trsf; // transformation to get location of target nodes from source ones
+ if ( tgtFace.IsPartner( srcFace ))
+ {
+ gp_Trsf srcTrsf = srcFace.Location();
+ gp_Trsf tgtTrsf = tgtFace.Location();
+ trsf = srcTrsf.Inverted() * tgtTrsf;
+ }
+ else
+ {
+ // Try to find the transformation
+
+ // make any local coord systems of src and tgt faces
+ vector<gp_Pnt> srcPP, tgtPP; // 3 points on face boundaries to make axes of CS
+ int tgtNbVert = SMESH_MesherHelper::Count( tgtFace, TopAbs_VERTEX, /*ignoreSame=*/true );
+ int srcNbVert = SMESH_MesherHelper::Count( srcFace, TopAbs_VERTEX, /*ignoreSame=*/true );
+ SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace );
+ SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false);
+ srcSM = smIt->next(); // sm of a vertex
+ while ( smIt->more() && srcPP.size() < 3 )
+ {
+ srcSM = smIt->next();
+ SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS();
+ if ( !srcSmds ) continue;
+ SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes();
+ while ( nIt->more() )
+ {
+ SMESH_TNodeXYZ p ( nIt->next());
+ bool pOK = false;
+ switch ( srcPP.size() )
+ {
+ case 0: pOK = true; break;
+
+ case 1: pOK = ( srcPP[0].SquareDistance( p ) > 10*tol ); break;
+
+ case 2:
+ {
+ gp_Vec p0p1( srcPP[0], srcPP[1] ), p0p( srcPP[0], p );
+ // pOK = !p0p1.IsParallel( p0p, tol );
+ pOK = !p0p1.IsParallel( p0p, 3.14/20 ); // angle min 18 degrees
+ break;
+ }
+ }
+ if ( !pOK )
+ continue;
+
+ // find corresponding point on target shape
+ pOK = false;
+ gp_Pnt tgtP;
+ const TopoDS_Shape& tgtShape = shape2ShapeMap( srcSM->GetSubShape(), /*isSrc=*/true );
+ if ( tgtShape.ShapeType() == TopAbs_VERTEX )
+ {
+ tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape ));
+ if ( srcNbVert == tgtNbVert || tgtPP.empty() )
+ pOK = true;
+ else
+ pOK = (( tgtP.Distance( tgtPP[0] ) > tol*tol ) &&
+ ( tgtPP.size() == 1 || tgtP.Distance( tgtPP[1] ) > tol*tol ));
+ //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMesh->GetMeshDS())->GetID() << endl;
+ }
+ else if ( tgtPP.size() > 0 )
+ {
+ if ( SMESHDS_SubMesh* tgtSmds = tgtMesh->GetMeshDS()->MeshElements( tgtShape ))
+ {
+ double srcDist = srcPP[0].Distance( p );
+ double eTol = BRep_Tool::Tolerance( TopoDS::Edge( tgtShape ));
+ if (eTol < tol) eTol = tol;
+ SMDS_NodeIteratorPtr nItT = tgtSmds->GetNodes();
+ while ( nItT->more() && !pOK )
+ {
+ const SMDS_MeshNode* n = nItT->next();
+ tgtP = SMESH_TNodeXYZ( n );
+ pOK = ( fabs( srcDist - tgtPP[0].Distance( tgtP )) < 2*eTol );
+ //cout << "E - nS " << p._node->GetID() << " - nT " << n->GetID()<< " OK - " << pOK<< " " << fabs( srcDist - tgtPP[0].Distance( tgtP ))<< " tol " << eTol<< endl;
+ }
+ }
+ }
+ if ( !pOK )
+ continue;
+
+ srcPP.push_back( p );
+ tgtPP.push_back( tgtP );
+ }
+ }
+ if ( srcPP.size() != 3 )
+ return false;
+
+ // make transformation
+ gp_Trsf fromTgtCS, toSrcCS; // from/to global CS
+ gp_Ax2 srcCS( srcPP[0], gp_Vec( srcPP[0], srcPP[1] ), gp_Vec( srcPP[0], srcPP[2]));
+ gp_Ax2 tgtCS( tgtPP[0], gp_Vec( tgtPP[0], tgtPP[1] ), gp_Vec( tgtPP[0], tgtPP[2]));
+ toSrcCS .SetTransformation( gp_Ax3( srcCS ));
+ fromTgtCS.SetTransformation( gp_Ax3( tgtCS ));
+ fromTgtCS.Invert();
+
+ trsf = fromTgtCS * toSrcCS;
+ }
+
+ // Fill map of src to tgt nodes with nodes on edges
+
+ map<const SMDS_MeshNode* , const SMDS_MeshNode*> src2tgtNodes;
+ map<const SMDS_MeshNode* , const SMDS_MeshNode*>::iterator srcN_tgtN;
+
+ for ( TopExp_Explorer srcEdge( srcFace, TopAbs_EDGE); srcEdge.More(); srcEdge.Next() )
+ {
+ const TopoDS_Shape& tgtEdge = shape2ShapeMap( srcEdge.Current(), /*isSrc=*/true );
+
+ map< double, const SMDS_MeshNode* > srcNodes, tgtNodes;
+ if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMesh->GetMeshDS(),
+ TopoDS::Edge( srcEdge.Current() ),
+ /*ignoreMediumNodes = */true,
+ srcNodes )
+ ||
+ !SMESH_Algo::GetSortedNodesOnEdge( tgtMesh->GetMeshDS(),
+ TopoDS::Edge( tgtEdge ),
+ /*ignoreMediumNodes = */true,
+ tgtNodes )
+ ||
+ srcNodes.size() != tgtNodes.size())
+ return false;
+
+ if ( !tgtEdge.IsPartner( srcEdge.Current() ))
+ {
+ // check that transformation is OK by three nodes
+ gp_Pnt p0S = SMESH_TNodeXYZ( (srcNodes.begin()) ->second);
+ gp_Pnt p1S = SMESH_TNodeXYZ( (srcNodes.rbegin()) ->second);
+ gp_Pnt p2S = SMESH_TNodeXYZ( (++srcNodes.begin())->second);
+
+ gp_Pnt p0T = SMESH_TNodeXYZ( (tgtNodes.begin()) ->second);
+ gp_Pnt p1T = SMESH_TNodeXYZ( (tgtNodes.rbegin()) ->second);
+ gp_Pnt p2T = SMESH_TNodeXYZ( (++tgtNodes.begin())->second);
+
+ // transform source points, they must coincide with target ones
+ if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol ||
+ p1T.SquareDistance( p1S.Transformed( trsf )) > tol ||
+ p2T.SquareDistance( p2S.Transformed( trsf )) > tol )
+ {
+ //cout << "KO trsf, 3 dist: "
+ //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", "
+ //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", "
+ //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<<endl;
+ return false;
+ }
+ }
+
+ map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
+ map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin();
+ for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn)
+ src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second ));
+ }
+
+ // Make new faces
+
+ // prepare the helper to adding quadratic elements if necessary
+ SMESH_MesherHelper helper( *tgtMesh );
+ helper.SetSubShape( tgtFace );
+ helper.IsQuadraticSubMesh( tgtFace );
+ helper.SetElementsOnShape( true );
+
+ SMESH_MesherHelper srcHelper( *srcMesh );
+ srcHelper.SetSubShape( srcFace );
+
+ const SMDS_MeshNode* nullNode = 0;
+
+ // indices of nodes to create properly oriented faces
+ int tri1 = 1, tri2 = 2, quad1 = 1, quad3 = 3;
+ if ( trsf.Form() != gp_Identity )
+ std::swap( tri1, tri2 ), std::swap( quad1, quad3 );
+
+ SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
+ SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
+ vector< const SMDS_MeshNode* > tgtNodes;
+ while ( elemIt->more() ) // loop on all mesh faces on srcFace
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ const int nbN = elem->NbCornerNodes();
+ tgtNodes.resize( nbN );
+ for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
+ {
+ const SMDS_MeshNode* srcNode = elem->GetNode(i);
+ srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
+ if ( srcN_tgtN->second == nullNode )
+ {
+ // create a new node
+ gp_Pnt tgtP = gp_Pnt(srcNode->X(),srcNode->Y(),srcNode->Z()).Transformed( trsf );
+ SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
+ srcN_tgtN->second = n;
+
+ gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode,
+ elem->GetNode( helper.WrapIndex(i+1,nbN)));
+ n->SetPosition( new SMDS_FacePosition( srcUV.X(), srcUV.Y() ));
+ }
+ tgtNodes[i] = srcN_tgtN->second;
+ }
+ // create a new face
+ switch ( nbN )
+ {
+ case 3: helper.AddFace(tgtNodes[0], tgtNodes[tri1], tgtNodes[tri2]); break;
+ case 4: helper.AddFace(tgtNodes[0], tgtNodes[quad1], tgtNodes[2], tgtNodes[quad3]); break;
+ }
+ }
+ return true;
+
+ } // bool projectPartner()
+
+ //================================================================================
+ /*!
+ * \brief Preform projection in case if the faces are similar in 2D space
+ */
+ //================================================================================
+
+ bool projectBy2DSimilarity(const TopoDS_Face& tgtFace,
+ const TopoDS_Face& srcFace,
+ SMESH_Mesh * tgtMesh,
+ SMESH_Mesh * srcMesh,
+ const TAssocTool::TShapeShapeMap& shape2ShapeMap,
+ const bool is1DComputed)
+ {
+ // 1) Preparation
+
+ // get ordered src EDGEs
+ TError err;
+ TSideVector srcWires =
+ StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*ignoreMediumNodes = */false, err);
+ if ( err && !err->IsOK() )
+ return false;
+
+ // make corresponding sequence of tgt EDGEs
+ TSideVector tgtWires( srcWires.size() );
+ for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
+ {
+ list< TopoDS_Edge > tgtEdges;
+ StdMeshers_FaceSidePtr srcWire = srcWires[iW];
+ TopTools_IndexedMapOfShape edgeMap; // to detect seam edges
+ for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
+ {
+ tgtEdges.push_back( TopoDS::Edge( shape2ShapeMap( srcWire->Edge( iE ), /*isSrc=*/true)));
+ // reverse a seam edge encountered for the second time
+ const int oldExtent = edgeMap.Extent();
+ edgeMap.Add( tgtEdges.back() );
+ if ( oldExtent == edgeMap.Extent() )
+ tgtEdges.back().Reverse();
+ }
+ tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
+ /*theIsForward = */ true,
+ /*theIgnoreMediumNodes = */false));
+ if ( is1DComputed &&
+ srcWires[iW]->GetUVPtStruct().size() !=
+ tgtWires[iW]->GetUVPtStruct().size())
+ return false;
+ }
+
+ // 2) Find transformation
+
+ gp_Trsf2d trsf;
+ {
+ // get 2 pairs of corresponding UVs
+ gp_Pnt2d srcP0 = srcWires[0]->Value2d(0.0);
+ gp_Pnt2d srcP1 = srcWires[0]->Value2d(0.333);
+ gp_Pnt2d tgtP0 = tgtWires[0]->Value2d(0.0);
+ gp_Pnt2d tgtP1 = tgtWires[0]->Value2d(0.333);
+
+ // make transformation
+ gp_Trsf2d fromTgtCS, toSrcCS; // from/to global CS
+ gp_Ax2d srcCS( srcP0, gp_Vec2d( srcP0, srcP1 ));
+ gp_Ax2d tgtCS( tgtP0, gp_Vec2d( tgtP0, tgtP1 ));
+ toSrcCS .SetTransformation( srcCS );
+ fromTgtCS.SetTransformation( tgtCS );
+ fromTgtCS.Invert();
+
+ trsf = fromTgtCS * toSrcCS;
+
+ // check transformation
+ const double tol = 1e-5 * gp_Vec2d( srcP0, srcP1 ).Magnitude();
+ for ( double u = 0.12; u < 1.; u += 0.1 )
+ {
+ gp_Pnt2d srcUV = srcWires[0]->Value2d( u );
+ gp_Pnt2d tgtUV = tgtWires[0]->Value2d( u );
+ gp_Pnt2d tgtUV2 = srcUV.Transformed( trsf );
+ if ( tgtUV.Distance( tgtUV2 ) > tol )
+ return false;
+ }
+ }
+
+ // 3) Projection
+
+ typedef map<const SMDS_MeshNode* , const SMDS_MeshNode*, TIDCompare> TN2NMap;
+ TN2NMap src2tgtNodes;
+ TN2NMap::iterator srcN_tgtN;
+
+ // fill src2tgtNodes in with nodes on EDGEs
+ for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
+ if ( is1DComputed )
+ {
+ const vector<UVPtStruct>& srcUVs = srcWires[iW]->GetUVPtStruct();
+ const vector<UVPtStruct>& tgtUVs = tgtWires[iW]->GetUVPtStruct();
+ for ( unsigned i = 0; i < srcUVs.size(); ++i )
+ src2tgtNodes.insert( make_pair( srcUVs[i].node, tgtUVs[i].node ));
+ }
+ else
+ {
+ for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE )
+ {
+ TopoDS_Vertex srcV = srcWires[iW]->FirstVertex(iE);
+ TopoDS_Vertex tgtV = tgtWires[iW]->FirstVertex(iE);
+ const SMDS_MeshNode* srcNode = SMESH_Algo::VertexNode( srcV, srcMesh->GetMeshDS() );
+ const SMDS_MeshNode* tgtNode = SMESH_Algo::VertexNode( tgtV, tgtMesh->GetMeshDS() );
+ if ( tgtNode && srcNode )
+ src2tgtNodes.insert( make_pair( srcNode, tgtNode ));
+ }
+ }
+
+ // make elements
+
+ SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
+
+ SMESH_MesherHelper helper( *tgtMesh );
+ helper.SetSubShape( tgtFace );
+ if ( is1DComputed )
+ helper.IsQuadraticSubMesh( tgtFace );
+ else
+ helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() );
+ helper.SetElementsOnShape( true );
+ Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace );
+ SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
+
+ SMESH_MesherHelper srcHelper( *srcMesh );
+ srcHelper.SetSubShape( srcFace );
+
+ const SMDS_MeshNode* nullNode = 0;
+
+ SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
+ vector< const SMDS_MeshNode* > tgtNodes;
+ bool uvOK;
+ while ( elemIt->more() ) // loop on all mesh faces on srcFace
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ const int nbN = elem->NbCornerNodes();
+ tgtNodes.resize( nbN );
+ for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
+ {
+ const SMDS_MeshNode* srcNode = elem->GetNode(i);
+ srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
+ if ( srcN_tgtN->second == nullNode )
+ {
+ // create a new node
+ gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode,
+ elem->GetNode( helper.WrapIndex(i+1,nbN)), &uvOK);
+ gp_Pnt2d tgtUV = srcUV.Transformed( trsf );
+ gp_Pnt tgtP = tgtSurface->Value( tgtUV.X(), tgtUV.Y() );
+ SMDS_MeshNode* n = tgtMeshDS->AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
+ switch ( srcNode->GetPosition()->GetTypeOfPosition() )
+ {
+ case SMDS_TOP_FACE: {
+ tgtMeshDS->SetNodeOnFace( n, helper.GetSubShapeID(), tgtUV.X(), tgtUV.Y() );
+ break;
+ }
+ case SMDS_TOP_EDGE: {
+ TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
+ TopoDS_Edge tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true ));
+ tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ));
+ double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode );
+ helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion());
+ n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U )));
+ break;
+ }
+ case SMDS_TOP_VERTEX: {
+ TopoDS_Shape srcV = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
+ TopoDS_Shape tgtV = shape2ShapeMap( srcV, /*isSrc=*/true );
+ tgtMeshDS->SetNodeOnVertex( n, TopoDS::Vertex( tgtV ));
+ break;
+ }
+ }
+ srcN_tgtN->second = n;
+ }
+ tgtNodes[i] = srcN_tgtN->second;
+ }
+ // create a new face (with reversed orientation)
+ switch ( nbN )
+ {
+ case 3: helper.AddFace(tgtNodes[0], tgtNodes[2], tgtNodes[1]); break;
+ case 4: helper.AddFace(tgtNodes[0], tgtNodes[3], tgtNodes[2], tgtNodes[1]); break;
+ }
+ }
+ return true;
+
+ } // bool projectBy2DSimilarity(...)
+