Back to index

salome-smesh  6.5.0
StdMeshers_Projection_2D.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 //  SMESH SMESH : implementaion of SMESH idl descriptions
00024 // File      : StdMeshers_Projection_2D.cxx
00025 // Module    : SMESH
00026 // Created   : Fri Oct 20 11:37:07 2006
00027 // Author    : Edward AGAPOV (eap)
00028 //
00029 #include "StdMeshers_Projection_2D.hxx"
00030 
00031 #include "StdMeshers_ProjectionSource2D.hxx"
00032 #include "StdMeshers_ProjectionUtils.hxx"
00033 #include "StdMeshers_FaceSide.hxx"
00034 
00035 #include "SMDS_EdgePosition.hxx"
00036 #include "SMDS_FacePosition.hxx"
00037 #include "SMESHDS_Hypothesis.hxx"
00038 #include "SMESHDS_SubMesh.hxx"
00039 #include "SMESH_Block.hxx"
00040 #include "SMESH_Comment.hxx"
00041 #include "SMESH_Gen.hxx"
00042 #include "SMESH_Mesh.hxx"
00043 #include "SMESH_MesherHelper.hxx"
00044 #include "SMESH_Pattern.hxx"
00045 #include "SMESH_subMesh.hxx"
00046 #include "SMESH_subMeshEventListener.hxx"
00047 
00048 #include "utilities.h"
00049 
00050 #include <BRep_Tool.hxx>
00051 #include <Bnd_B2d.hxx>
00052 #include <TopExp.hxx>
00053 #include <TopExp_Explorer.hxx>
00054 #include <TopTools_ListIteratorOfListOfShape.hxx>
00055 #include <TopoDS.hxx>
00056 #include <gp_Ax2.hxx>
00057 #include <gp_Ax3.hxx>
00058 
00059 
00060 using namespace std;
00061 
00062 #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; }
00063 
00064 typedef StdMeshers_ProjectionUtils TAssocTool;
00065 
00066 //=======================================================================
00067 //function : StdMeshers_Projection_2D
00068 //purpose  : 
00069 //=======================================================================
00070 
00071 StdMeshers_Projection_2D::StdMeshers_Projection_2D(int hypId, int studyId, SMESH_Gen* gen)
00072   :SMESH_2D_Algo(hypId, studyId, gen)
00073 {
00074   _name = "Projection_2D";
00075   _shapeType = (1 << TopAbs_FACE);      // 1 bit per shape type
00076 
00077   _compatibleHypothesis.push_back("ProjectionSource2D");
00078   _sourceHypo = 0;
00079 }
00080 
00081 //================================================================================
00085 //================================================================================
00086 
00087 StdMeshers_Projection_2D::~StdMeshers_Projection_2D()
00088 {}
00089 
00090 //=======================================================================
00091 //function : CheckHypothesis
00092 //purpose  : 
00093 //=======================================================================
00094 
00095 bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh&                          theMesh,
00096                                                const TopoDS_Shape&                  theShape,
00097                                                SMESH_Hypothesis::Hypothesis_Status& theStatus)
00098 {
00099   list <const SMESHDS_Hypothesis * >::const_iterator itl;
00100 
00101   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(theMesh, theShape);
00102   if ( hyps.size() == 0 )
00103   {
00104     theStatus = HYP_MISSING;
00105     return false;  // can't work with no hypothesis
00106   }
00107 
00108   if ( hyps.size() > 1 )
00109   {
00110     theStatus = HYP_ALREADY_EXIST;
00111     return false;
00112   }
00113 
00114   const SMESHDS_Hypothesis *theHyp = hyps.front();
00115 
00116   string hypName = theHyp->GetName();
00117 
00118   theStatus = HYP_OK;
00119 
00120   if (hypName == "ProjectionSource2D")
00121   {
00122     _sourceHypo = static_cast<const StdMeshers_ProjectionSource2D *>(theHyp);
00123 
00124     // Check hypo parameters
00125 
00126     SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh();
00127     SMESH_Mesh* tgtMesh = & theMesh;
00128     if ( !srcMesh )
00129       srcMesh = tgtMesh;
00130 
00131     // check vertices
00132     if ( _sourceHypo->HasVertexAssociation() )
00133     {
00134       // source vertices
00135       TopoDS_Shape edge = TAssocTool::GetEdgeByVertices
00136         ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) );
00137       if ( edge.IsNull() ||
00138            !SMESH_MesherHelper::IsSubShape( edge, srcMesh ) ||
00139            !SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() ))
00140       {
00141         theStatus = HYP_BAD_PARAMETER;
00142         SCRUTE((edge.IsNull()));
00143         SCRUTE((SMESH_MesherHelper::IsSubShape( edge, srcMesh )));
00144         SCRUTE((SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() )));
00145       }
00146       else
00147       {
00148         // target vertices
00149         edge = TAssocTool::GetEdgeByVertices
00150           ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) );
00151         if ( edge.IsNull() || !SMESH_MesherHelper::IsSubShape( edge, tgtMesh ))
00152         {
00153           theStatus = HYP_BAD_PARAMETER;
00154           SCRUTE((edge.IsNull()));
00155           SCRUTE((SMESH_MesherHelper::IsSubShape( edge, tgtMesh )));
00156         }
00157         // PAL16203
00158         else if ( !_sourceHypo->IsCompoundSource() &&
00159                   !SMESH_MesherHelper::IsSubShape( edge, theShape ))
00160         {
00161           theStatus = HYP_BAD_PARAMETER;
00162           SCRUTE((SMESH_MesherHelper::IsSubShape( edge, theShape )));
00163         }
00164       }
00165     }
00166     // check a source face
00167     if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ) ||
00168          ( srcMesh == tgtMesh && theShape == _sourceHypo->GetSourceFace() ))
00169     {
00170       theStatus = HYP_BAD_PARAMETER;
00171       SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh )));
00172       SCRUTE((srcMesh == tgtMesh));
00173       SCRUTE(( theShape == _sourceHypo->GetSourceFace() ));
00174     }
00175   }
00176   else
00177   {
00178     theStatus = HYP_INCOMPATIBLE;
00179   }
00180   return ( theStatus == HYP_OK );
00181 }
00182 
00183 namespace {
00184 
00185   //================================================================================
00191   //================================================================================
00192 
00193   bool isOldNode( const SMDS_MeshNode* node/*, const bool is1DComputed*/ )
00194   {
00195     // old nodes are shared by edges and new ones are shared
00196     // only by faces created by mapper
00197     //if ( is1DComputed )
00198     {
00199       bool isOld = node->NbInverseElements(SMDSAbs_Edge) > 0;
00200       return isOld;
00201     }
00202     // else
00203     // {
00204     //   SMDS_ElemIteratorPtr invFace = node->GetInverseElementIterator(SMDSAbs_Face);
00205     //   bool isNew = invFace->more();
00206     //   return !isNew;
00207     // }
00208   }
00209 
00210   //================================================================================
00216   //================================================================================
00217 
00218   class MeshCleaner {
00219     SMESH_subMesh* sm;
00220   public:
00221     MeshCleaner( SMESH_subMesh* faceSubMesh ): sm(faceSubMesh) {}
00222     ~MeshCleaner() { Clean(sm); }
00223     void Release() { sm = 0; } // mesh will not be removed
00224     static void Clean( SMESH_subMesh* sm, bool withSub=true )
00225     {
00226       if ( !sm || !sm->GetSubMeshDS() ) return;
00227       // PAL16567, 18920. Remove face nodes as well
00228 //       switch ( sm->GetSubShape().ShapeType() ) {
00229 //       case TopAbs_VERTEX:
00230 //       case TopAbs_EDGE: {
00231         SMDS_NodeIteratorPtr nIt = sm->GetSubMeshDS()->GetNodes();
00232         SMESHDS_Mesh* mesh = sm->GetFather()->GetMeshDS();
00233         while ( nIt->more() ) {
00234           const SMDS_MeshNode* node = nIt->next();
00235           if ( !isOldNode( node ) )
00236             mesh->RemoveNode( node );
00237         }
00238         // do not break but iterate over DependsOn()
00239 //       }
00240 //       default:
00241         if ( !withSub ) return;
00242         SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false);
00243         while ( smIt->more() )
00244           Clean( smIt->next(), false );
00245 //       }
00246     }
00247   };
00248 
00249   //================================================================================
00258   //================================================================================
00259 
00260   bool getBoundaryNodes ( SMESH_subMesh*                        sm,
00261                           const TopoDS_Face&                    face,
00262                           map< double, const SMDS_MeshNode* > & u2nodes,
00263                           set< const SMDS_MeshNode* > &         seamNodes)
00264   {
00265     u2nodes.clear();
00266     seamNodes.clear();
00267     if ( !sm || !sm->GetSubMeshDS() )
00268       RETURN_BAD_RESULT("Null submesh");
00269 
00270     SMDS_NodeIteratorPtr nIt = sm->GetSubMeshDS()->GetNodes();
00271     switch ( sm->GetSubShape().ShapeType() ) {
00272 
00273     case TopAbs_VERTEX: {
00274       while ( nIt->more() ) {
00275         const SMDS_MeshNode* node = nIt->next();
00276         if ( isOldNode( node ) ) continue;
00277         u2nodes.insert( make_pair( 0., node ));
00278         seamNodes.insert( node );
00279         return true;
00280       }
00281       break;
00282     }
00283     case TopAbs_EDGE: {
00284       
00285       // Get submeshes of sub-vertices
00286       const map< int, SMESH_subMesh * >& subSM = sm->DependsOn();
00287       if ( subSM.size() != 2 )
00288         RETURN_BAD_RESULT("there must be 2 submeshes of sub-vertices"
00289                           " but we have " << subSM.size());
00290       SMESH_subMesh* smV1 = subSM.begin()->second;
00291       SMESH_subMesh* smV2 = subSM.rbegin()->second;
00292       if ( !smV1->IsMeshComputed() || !smV2->IsMeshComputed() )
00293         RETURN_BAD_RESULT("Empty vertex submeshes");
00294 
00295       // Look for a new node on V1
00296       nIt = smV1->GetSubMeshDS()->GetNodes();
00297       const SMDS_MeshNode* nV1 = 0;
00298       while ( nIt->more() && !nV1 ) {
00299         const SMDS_MeshNode* node = nIt->next();
00300         if ( !isOldNode( node ) ) nV1 = node;
00301       }
00302       if ( !nV1 )
00303         RETURN_BAD_RESULT("No new node found on V1");
00304 
00305       // Find a new node connected to nV1 and belonging to edge submesh;
00306       const SMDS_MeshNode* nE = 0;
00307       SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
00308       SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(SMDSAbs_Face);
00309       while ( vElems->more() && !nE ) {
00310         const SMDS_MeshElement* elem = vElems->next();
00311         int nbNodes = elem->NbNodes();
00312         if ( elem->IsQuadratic() )
00313           nbNodes /= 2;
00314         int iV1 = elem->GetNodeIndex( nV1 );
00315         // try next after nV1
00316         int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes );
00317         if ( smDS->Contains( elem->GetNode( iE ) ))
00318           nE = elem->GetNode( iE );
00319         if ( !nE ) {
00320           // try node before nV1
00321           iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes );
00322           if ( smDS->Contains( elem->GetNode( iE )))
00323             nE = elem->GetNode( iE );
00324         }
00325         if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE
00326           if ( Abs( iV1 - iE ) == 1 )
00327             nE = elem->GetNode( Min ( iV1, iE ) + nbNodes );
00328           else
00329             nE = elem->GetNode( elem->NbNodes() - 1 );
00330         }
00331       }
00332       if ( !nE )
00333         RETURN_BAD_RESULT("new node on edge not found");
00334 
00335       // Get the whole free border of a face
00336       list< const SMDS_MeshNode* > bordNodes;
00337       list< const SMDS_MeshElement* > bordFaces;
00338       if ( !SMESH_MeshEditor::FindFreeBorder (nV1, nE, nV1, bordNodes, bordFaces ))
00339         RETURN_BAD_RESULT("free border of a face not found by nodes " <<
00340                           nV1->GetID() << " " << nE->GetID() );
00341 
00342       // Insert nodes of the free border to the map until node on V2 encountered
00343       SMESHDS_SubMesh* v2smDS = smV2->GetSubMeshDS();
00344       list< const SMDS_MeshNode* >::iterator bordIt = bordNodes.begin();
00345       bordIt++; // skip nV1
00346       for ( ; bordIt != bordNodes.end(); ++bordIt ) {
00347         const SMDS_MeshNode* node = *bordIt;
00348         if ( v2smDS->Contains( node ))
00349           break;
00350         if ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_EDGE )
00351           RETURN_BAD_RESULT("Bad node position type: node " << node->GetID() <<
00352                             " pos type " << node->GetPosition()->GetTypeOfPosition());
00353         const SMDS_EdgePosition* pos =
00354           static_cast<const SMDS_EdgePosition*>(node->GetPosition());
00355         u2nodes.insert( make_pair( pos->GetUParameter(), node ));
00356         seamNodes.insert( node );
00357       }
00358       if ( u2nodes.size() != seamNodes.size() )
00359         RETURN_BAD_RESULT("Bad node params on edge " << sm->GetId() <<
00360                           ", " << u2nodes.size() << " != " << seamNodes.size() );
00361       return true;
00362     }
00363     default:;
00364     }
00365     RETURN_BAD_RESULT ("Unexpected submesh type");
00366 
00367   } // bool getBoundaryNodes()
00368 
00369   //================================================================================
00374   //================================================================================
00375 
00376   bool projectPartner(const TopoDS_Face&                tgtFace,
00377                       const TopoDS_Face&                srcFace,
00378                       SMESH_Mesh *                      tgtMesh,
00379                       SMESH_Mesh *                      srcMesh,
00380                       const TAssocTool::TShapeShapeMap& shape2ShapeMap)
00381   {
00382     MESSAGE("projectPartner");
00383     const double tol = 1.e-7*srcMesh->GetMeshDS()->getMaxDim();
00384 
00385     gp_Trsf trsf; // transformation to get location of target nodes from source ones
00386     if ( tgtFace.IsPartner( srcFace ))
00387     {
00388       gp_Trsf srcTrsf = srcFace.Location();
00389       gp_Trsf tgtTrsf = tgtFace.Location();
00390       trsf = srcTrsf.Inverted() * tgtTrsf;
00391     }
00392     else
00393     {
00394       // Try to find the transformation
00395 
00396       // make any local coord systems of src and tgt faces
00397       vector<gp_Pnt> srcPP, tgtPP; // 3 points on face boundaries to make axes of CS
00398       SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace );
00399       SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false);
00400       srcSM = smIt->next(); // sm of a vertex
00401       while ( smIt->more() && srcPP.size() < 3 )
00402       {
00403         srcSM = smIt->next();
00404         SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS();
00405         if ( !srcSmds ) continue;
00406         SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes();
00407         while ( nIt->more() )
00408         {
00409           SMESH_TNodeXYZ p ( nIt->next());
00410           bool pOK = false;
00411           switch ( srcPP.size() )
00412           {
00413           case 0: pOK = true; break;
00414 
00415           case 1: pOK = ( srcPP[0].SquareDistance( p ) > 10*tol ); break;
00416             
00417           case 2:
00418             {
00419               gp_Vec p0p1( srcPP[0], srcPP[1] ), p0p( srcPP[0], p );
00420               // pOK = !p0p1.IsParallel( p0p, tol );
00421               pOK = !p0p1.IsParallel( p0p, 3.14/20 ); // angle min 18 degrees
00422               break;
00423             }
00424           }
00425           if ( !pOK )
00426             continue;
00427 
00428           // find corresponding point on target shape
00429           pOK = false;
00430           gp_Pnt tgtP;
00431           const TopoDS_Shape& tgtShape = shape2ShapeMap( srcSM->GetSubShape(), /*isSrc=*/true );
00432           if ( tgtShape.ShapeType() == TopAbs_VERTEX )
00433           {
00434             tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape ));
00435             pOK = true;
00436             //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMesh->GetMeshDS())->GetID() << endl;
00437           }
00438           else if ( tgtPP.size() > 0 )
00439           {
00440             if ( SMESHDS_SubMesh* tgtSmds = tgtMesh->GetMeshDS()->MeshElements( tgtShape ))
00441             {
00442               double srcDist = srcPP[0].Distance( p );
00443               double eTol = BRep_Tool::Tolerance( TopoDS::Edge( tgtShape ));
00444               if (eTol < tol) eTol = tol;
00445               SMDS_NodeIteratorPtr nItT = tgtSmds->GetNodes();
00446               while ( nItT->more() && !pOK )
00447               {
00448                 const SMDS_MeshNode* n = nItT->next();
00449                 tgtP = SMESH_TNodeXYZ( n );
00450                 pOK = ( fabs( srcDist - tgtPP[0].Distance( tgtP )) < 2*eTol );
00451                 //cout << "E - nS " << p._node->GetID() << " - nT " << n->GetID()<< " OK - " << pOK<< " " << fabs( srcDist - tgtPP[0].Distance( tgtP ))<< " tol " << eTol<< endl;
00452               }
00453             }
00454           }
00455           if ( !pOK )
00456             continue;
00457 
00458           srcPP.push_back( p );
00459           tgtPP.push_back( tgtP );
00460         }
00461       }
00462       if ( srcPP.size() != 3 )
00463         return false;
00464 
00465       // make transformation
00466       gp_Trsf fromTgtCS, toSrcCS; // from/to global CS
00467       gp_Ax2 srcCS( srcPP[0], gp_Vec( srcPP[0], srcPP[1] ), gp_Vec( srcPP[0], srcPP[2]));
00468       gp_Ax2 tgtCS( tgtPP[0], gp_Vec( tgtPP[0], tgtPP[1] ), gp_Vec( tgtPP[0], tgtPP[2]));
00469       toSrcCS  .SetTransformation( gp_Ax3( srcCS ));
00470       fromTgtCS.SetTransformation( gp_Ax3( tgtCS ));
00471       fromTgtCS.Invert();
00472 
00473       trsf = fromTgtCS * toSrcCS;
00474     }
00475 
00476     // Fill map of src to tgt nodes with nodes on edges
00477 
00478     map<const SMDS_MeshNode* , const SMDS_MeshNode*> src2tgtNodes;
00479     map<const SMDS_MeshNode* , const SMDS_MeshNode*>::iterator srcN_tgtN;
00480 
00481     for ( TopExp_Explorer srcEdge( srcFace, TopAbs_EDGE); srcEdge.More(); srcEdge.Next() )
00482     {
00483       const TopoDS_Shape& tgtEdge = shape2ShapeMap( srcEdge.Current(), /*isSrc=*/true );
00484 
00485       map< double, const SMDS_MeshNode* > srcNodes, tgtNodes;
00486       if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMesh->GetMeshDS(),
00487                                               TopoDS::Edge( srcEdge.Current() ),
00488                                               /*ignoreMediumNodes = */true,
00489                                               srcNodes )
00490            ||
00491            !SMESH_Algo::GetSortedNodesOnEdge( tgtMesh->GetMeshDS(),
00492                                               TopoDS::Edge( tgtEdge ),
00493                                               /*ignoreMediumNodes = */true,
00494                                               tgtNodes )
00495            ||
00496            srcNodes.size() != tgtNodes.size())
00497         return false;
00498 
00499       if ( !tgtEdge.IsPartner( srcEdge.Current() ))
00500       {
00501         // check that transformation is OK by three nodes
00502         gp_Pnt p0S = SMESH_TNodeXYZ( (srcNodes.begin())  ->second);
00503         gp_Pnt p1S = SMESH_TNodeXYZ( (srcNodes.rbegin()) ->second);
00504         gp_Pnt p2S = SMESH_TNodeXYZ( (++srcNodes.begin())->second);
00505 
00506         gp_Pnt p0T = SMESH_TNodeXYZ( (tgtNodes.begin())  ->second);
00507         gp_Pnt p1T = SMESH_TNodeXYZ( (tgtNodes.rbegin()) ->second);
00508         gp_Pnt p2T = SMESH_TNodeXYZ( (++tgtNodes.begin())->second);
00509 
00510         // transform source points, they must coincide with target ones
00511         if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol ||
00512              p1T.SquareDistance( p1S.Transformed( trsf )) > tol ||
00513              p2T.SquareDistance( p2S.Transformed( trsf )) > tol )
00514         {
00515           //cout << "KO trsf, 3 dist: "
00516           //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", "
00517           //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", "
00518           //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<<endl;
00519           return false;
00520         }
00521       }
00522 
00523       map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
00524       map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin();
00525       for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn)
00526         src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second ));
00527     }
00528 
00529     // Make new faces
00530 
00531     // prepare the helper to adding quadratic elements if necessary
00532     SMESH_MesherHelper helper( *tgtMesh );
00533     helper.SetSubShape( tgtFace );
00534     helper.IsQuadraticSubMesh( tgtFace );
00535     helper.SetElementsOnShape( true );
00536 
00537     SMESH_MesherHelper srcHelper( *srcMesh );
00538     srcHelper.SetSubShape( srcFace );
00539 
00540     const SMDS_MeshNode* nullNode = 0;
00541 
00542     // indices of nodes to create properly oriented faces
00543     int tri1 = 1, tri2 = 2, quad1 = 1, quad3 = 3;
00544     if ( trsf.Form() != gp_Identity )
00545       std::swap( tri1, tri2 ), std::swap( quad1, quad3 );
00546 
00547     SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
00548     SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
00549     vector< const SMDS_MeshNode* > tgtNodes;
00550     while ( elemIt->more() ) // loop on all mesh faces on srcFace
00551     {
00552       const SMDS_MeshElement* elem = elemIt->next();
00553       const int nbN = elem->NbCornerNodes(); 
00554       tgtNodes.resize( nbN );
00555       for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
00556       {
00557         const SMDS_MeshNode* srcNode = elem->GetNode(i);
00558         srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
00559         if ( srcN_tgtN->second == nullNode )
00560         {
00561           // create a new node
00562           gp_Pnt tgtP = gp_Pnt(srcNode->X(),srcNode->Y(),srcNode->Z()).Transformed( trsf );
00563           SMDS_MeshNode* n = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
00564           srcN_tgtN->second = n;
00565 
00566           gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode,
00567                                                 elem->GetNode( helper.WrapIndex(i+1,nbN)));
00568           n->SetPosition( new SMDS_FacePosition( srcUV.X(), srcUV.Y() ));
00569         }
00570         tgtNodes[i] = srcN_tgtN->second;
00571       }
00572       // create a new face
00573       switch ( nbN )
00574       {
00575       case 3: helper.AddFace(tgtNodes[0], tgtNodes[tri1], tgtNodes[tri2]); break;
00576       case 4: helper.AddFace(tgtNodes[0], tgtNodes[quad1], tgtNodes[2], tgtNodes[quad3]); break;
00577       }
00578     }
00579     return true;
00580 
00581   } //   bool projectPartner()
00582 
00583   //================================================================================
00587   //================================================================================
00588 
00589   bool projectBy2DSimilarity(const TopoDS_Face&                tgtFace,
00590                              const TopoDS_Face&                srcFace,
00591                              SMESH_Mesh *                      tgtMesh,
00592                              SMESH_Mesh *                      srcMesh,
00593                              const TAssocTool::TShapeShapeMap& shape2ShapeMap,
00594                              const bool                        is1DComputed)
00595   {
00596     // 1) Preparation
00597 
00598     // get ordered src EDGEs
00599     TError err;
00600     TSideVector srcWires =
00601       StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*ignoreMediumNodes = */false, err);
00602     if ( err && !err->IsOK() )
00603       return false;
00604 
00605     // make corresponding sequence of tgt EDGEs
00606     TSideVector tgtWires( srcWires.size() );
00607     for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
00608     {
00609       list< TopoDS_Edge > tgtEdges;
00610       StdMeshers_FaceSidePtr srcWire = srcWires[iW];
00611       TopTools_IndexedMapOfShape edgeMap; // to detect seam edges
00612       for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
00613       {
00614         tgtEdges.push_back( TopoDS::Edge( shape2ShapeMap( srcWire->Edge( iE ), /*isSrc=*/true)));
00615         // reverse a seam edge encountered for the second time
00616         const int oldExtent = edgeMap.Extent();
00617         edgeMap.Add( tgtEdges.back() );
00618         if ( oldExtent == edgeMap.Extent() )
00619           tgtEdges.back().Reverse();
00620       }
00621       tgtWires[ iW ].reset( new StdMeshers_FaceSide( tgtFace, tgtEdges, tgtMesh,
00622                                                      /*theIsForward = */ true,
00623                                                      /*theIgnoreMediumNodes = */false));
00624       if ( is1DComputed &&
00625            srcWires[iW]->GetUVPtStruct().size() !=
00626            tgtWires[iW]->GetUVPtStruct().size())
00627         return false;
00628     }
00629 
00630     // 2) Find transformation
00631 
00632     gp_Trsf2d trsf;
00633     {
00634       // get 2 pairs of corresponding UVs
00635       gp_Pnt2d srcP0 = srcWires[0]->Value2d(0.0);
00636       gp_Pnt2d srcP1 = srcWires[0]->Value2d(0.333);
00637       gp_Pnt2d tgtP0 = tgtWires[0]->Value2d(0.0);
00638       gp_Pnt2d tgtP1 = tgtWires[0]->Value2d(0.333);
00639 
00640       // make transformation
00641       gp_Trsf2d fromTgtCS, toSrcCS; // from/to global CS
00642       gp_Ax2d srcCS( srcP0, gp_Vec2d( srcP0, srcP1 ));
00643       gp_Ax2d tgtCS( tgtP0, gp_Vec2d( tgtP0, tgtP1 ));
00644       toSrcCS  .SetTransformation( srcCS );
00645       fromTgtCS.SetTransformation( tgtCS );
00646       fromTgtCS.Invert();
00647 
00648       trsf = fromTgtCS * toSrcCS;
00649 
00650       // check transformation
00651       const double tol = 1e-5 * gp_Vec2d( srcP0, srcP1 ).Magnitude();
00652       for ( double u = 0.12; u < 1.; u += 0.1 )
00653       {
00654         gp_Pnt2d srcUV = srcWires[0]->Value2d( u );
00655         gp_Pnt2d tgtUV = tgtWires[0]->Value2d( u );
00656         gp_Pnt2d tgtUV2 = srcUV.Transformed( trsf );
00657         if ( tgtUV.Distance( tgtUV2 ) > tol )
00658           return false;
00659       }
00660     }
00661 
00662     // 3) Projection
00663 
00664     typedef map<const SMDS_MeshNode* , const SMDS_MeshNode*, TIDCompare> TN2NMap;
00665     TN2NMap src2tgtNodes;
00666     TN2NMap::iterator srcN_tgtN;
00667 
00668     // fill src2tgtNodes in with nodes on EDGEs
00669     for ( unsigned iW = 0; iW < srcWires.size(); ++iW )
00670       if ( is1DComputed )
00671       {
00672         const vector<UVPtStruct>& srcUVs = srcWires[iW]->GetUVPtStruct();
00673         const vector<UVPtStruct>& tgtUVs = tgtWires[iW]->GetUVPtStruct();
00674         for ( unsigned i = 0; i < srcUVs.size(); ++i )
00675           src2tgtNodes.insert( make_pair( srcUVs[i].node, tgtUVs[i].node ));
00676       }
00677       else
00678       {
00679         for ( int iE = 0; iE < srcWires[iW]->NbEdges(); ++iE )
00680         {
00681           TopoDS_Vertex srcV = srcWires[iW]->FirstVertex(iE);
00682           TopoDS_Vertex tgtV = tgtWires[iW]->FirstVertex(iE);
00683           const SMDS_MeshNode* srcNode = SMESH_Algo::VertexNode( srcV, srcMesh->GetMeshDS() );
00684           const SMDS_MeshNode* tgtNode = SMESH_Algo::VertexNode( tgtV, tgtMesh->GetMeshDS() );
00685           if ( tgtNode && srcNode )
00686             src2tgtNodes.insert( make_pair( srcNode, tgtNode ));
00687         }
00688       }
00689 
00690     // make elements
00691 
00692     SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
00693 
00694     SMESH_MesherHelper helper( *tgtMesh );
00695     helper.SetSubShape( tgtFace );
00696     if ( is1DComputed )
00697       helper.IsQuadraticSubMesh( tgtFace );
00698     else
00699       helper.SetIsQuadratic( srcSubDS->GetElements()->next()->IsQuadratic() );
00700     helper.SetElementsOnShape( true );
00701     Handle(Geom_Surface) tgtSurface = BRep_Tool::Surface( tgtFace );
00702     SMESHDS_Mesh* tgtMeshDS = tgtMesh->GetMeshDS();
00703 
00704     SMESH_MesherHelper srcHelper( *srcMesh );
00705     srcHelper.SetSubShape( srcFace );
00706 
00707     const SMDS_MeshNode* nullNode = 0;
00708 
00709     SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
00710     vector< const SMDS_MeshNode* > tgtNodes;
00711     bool uvOK;
00712     while ( elemIt->more() ) // loop on all mesh faces on srcFace
00713     {
00714       const SMDS_MeshElement* elem = elemIt->next();
00715       const int nbN = elem->NbCornerNodes(); 
00716       tgtNodes.resize( nbN );
00717       for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
00718       {
00719         const SMDS_MeshNode* srcNode = elem->GetNode(i);
00720         srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
00721         if ( srcN_tgtN->second == nullNode )
00722         {
00723           // create a new node
00724           gp_Pnt2d srcUV = srcHelper.GetNodeUV( srcFace, srcNode,
00725                                                 elem->GetNode( helper.WrapIndex(i+1,nbN)), &uvOK);
00726           gp_Pnt2d tgtUV = srcUV.Transformed( trsf );
00727           gp_Pnt   tgtP  = tgtSurface->Value( tgtUV.X(), tgtUV.Y() );
00728           SMDS_MeshNode* n = tgtMeshDS->AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
00729           switch ( srcNode->GetPosition()->GetTypeOfPosition() )
00730           {
00731           case SMDS_TOP_FACE: {
00732             tgtMeshDS->SetNodeOnFace( n, helper.GetSubShapeID(), tgtUV.X(), tgtUV.Y() );
00733             break;
00734           }
00735           case SMDS_TOP_EDGE: {
00736             TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
00737             TopoDS_Edge  tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true ));
00738             tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ));
00739             double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode );
00740             helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion());
00741             n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U )));
00742             break;
00743           }
00744           case SMDS_TOP_VERTEX: {
00745             TopoDS_Shape srcV = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
00746             TopoDS_Shape tgtV = shape2ShapeMap( srcV, /*isSrc=*/true );
00747             tgtMeshDS->SetNodeOnVertex( n, TopoDS::Vertex( tgtV ));
00748             break;
00749           }
00750           }
00751           srcN_tgtN->second = n;
00752         }
00753         tgtNodes[i] = srcN_tgtN->second;
00754       }
00755       // create a new face (with reversed orientation)
00756       switch ( nbN )
00757       {
00758       case 3: helper.AddFace(tgtNodes[0], tgtNodes[2], tgtNodes[1]); break;
00759       case 4: helper.AddFace(tgtNodes[0], tgtNodes[3], tgtNodes[2], tgtNodes[1]); break;
00760       }
00761     }
00762     return true;
00763 
00764   } // bool projectBy2DSimilarity(...)
00765 
00766 } // namespace
00767 
00768 
00769 //=======================================================================
00770 //function : Compute
00771 //purpose  : 
00772 //=======================================================================
00773 
00774 bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
00775 {
00776   MESSAGE("Projection_2D Compute");
00777   if ( !_sourceHypo )
00778     return false;
00779 
00780   SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
00781   SMESH_Mesh * tgtMesh = & theMesh;
00782   if ( !srcMesh )
00783     srcMesh = tgtMesh;
00784 
00785   SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
00786 
00787   // ---------------------------
00788   // Make sub-shapes association
00789   // ---------------------------
00790 
00791   TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
00792   TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
00793 
00794   TAssocTool::TShapeShapeMap shape2ShapeMap;
00795   TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap );
00796   if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
00797                                              shape2ShapeMap)  ||
00798        !shape2ShapeMap.IsBound( tgtFace ))
00799     return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
00800 
00801   TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
00802 
00803   // ----------------------------------------------
00804   // Assure that mesh on a source Face is computed
00805   // ----------------------------------------------
00806 
00807   SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace );
00808   SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtFace );
00809 
00810   if ( tgtMesh == srcMesh ) {
00811     if ( !TAssocTool::MakeComputed( srcSubMesh ))
00812       return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
00813   }
00814   else {
00815     if ( !srcSubMesh->IsMeshComputed() )
00816       return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
00817   }
00818 
00819   // ===========
00820   // Projection
00821   // ===========
00822 
00823   // find out if EDGEs are meshed or not
00824   bool is1DComputed = false;
00825   SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false,
00826                                                                    /*complexShapeFirst=*/true);
00827   while ( smIt->more() && !is1DComputed )
00828   {
00829     SMESH_subMesh* sm = smIt->next();
00830     if ( sm->GetSubShape().ShapeType() == TopAbs_EDGE )
00831       is1DComputed = sm->IsMeshComputed();
00832   }
00833 
00834   bool done = false;
00835 
00836   if ( !done )
00837   {
00838     // try to project from the same face with different location
00839     done = projectPartner( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap );
00840   }
00841   if ( !done )
00842   {
00843     // projection in case if the faces are similar in 2D space
00844     done = projectBy2DSimilarity( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap, is1DComputed);
00845   }
00846 
00847   if ( !done )
00848   {
00849     // --------------------
00850     // Prepare to mapping 
00851     // --------------------
00852 
00853     SMESH_MesherHelper helper( theMesh );
00854     helper.SetSubShape( tgtFace );
00855 
00856     // Check if node projection to a face is needed
00857     Bnd_B2d uvBox;
00858     SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements();
00859     int nbFaceNodes = 0;
00860     for ( ; nbFaceNodes < 3 && faceIt->more();  ) {
00861       const SMDS_MeshElement* face = faceIt->next();
00862       SMDS_ElemIteratorPtr nodeIt = face->nodesIterator();
00863       while ( nodeIt->more() ) {
00864         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
00865         if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) {
00866           nbFaceNodes++;
00867           uvBox.Add( helper.GetNodeUV( srcFace, node ));
00868         }
00869       }
00870     }
00871     const bool toProjectNodes =
00872       ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN ));
00873 
00874     // Load pattern from the source face
00875     SMESH_Pattern mapper;
00876     mapper.Load( srcMesh, srcFace, toProjectNodes );
00877     if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
00878       return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face");
00879 
00880     // Find the first target vertex corresponding to first vertex of the <mapper>
00881     // and <theReverse> flag needed to call mapper.Apply()
00882 
00883     TopoDS_Vertex srcV1 = TopoDS::Vertex( mapper.GetSubShape( 1 ));
00884     if ( srcV1.IsNull() )
00885       RETURN_BAD_RESULT("Mesh is not bound to the face");
00886     if ( !shape2ShapeMap.IsBound( srcV1, /*isSrc=*/true ))
00887       RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() );
00888     TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true ));
00889 
00890     if ( !SMESH_MesherHelper::IsSubShape( srcV1, srcFace ))
00891       RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->());
00892     if ( !SMESH_MesherHelper::IsSubShape( tgtV1, tgtFace ))
00893       RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->());
00894 
00895     // try to find out orientation by order of edges
00896     bool reverse = false;
00897     list< TopoDS_Edge > tgtEdges, srcEdges;
00898     list< int > nbEdgesInWires;
00899     SMESH_Block::GetOrderedEdges( tgtFace, tgtV1, tgtEdges, nbEdgesInWires);
00900     SMESH_Block::GetOrderedEdges( srcFace, srcV1, srcEdges, nbEdgesInWires);
00901     if ( nbEdgesInWires.front() > 1 ) // possible to find out
00902     {
00903       TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front();
00904       TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 );
00905       reverse = ( ! srcE1.IsSame( srcE1bis ));
00906     }
00907     else if ( nbEdgesInWires.front() == 1 )
00908     {
00909       // TODO::Compare orientation of curves in a sole edge
00910       //RETURN_BAD_RESULT("Not implemented case");
00911     }
00912     else
00913     {
00914       RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()");
00915     }
00916 
00917     // --------------------
00918     // Perform 2D mapping 
00919     // --------------------
00920 
00921     // Compute mesh on a target face
00922 
00923     mapper.Apply( tgtFace, tgtV1, reverse );
00924     if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
00925       return error("Can't apply source mesh pattern to the face");
00926 
00927     // Create the mesh
00928 
00929     const bool toCreatePolygons = false, toCreatePolyedrs = false;
00930     mapper.MakeMesh( tgtMesh, toCreatePolygons, toCreatePolyedrs );
00931     if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
00932       return error("Can't make mesh by source mesh pattern");
00933 
00934     // it will remove mesh built by pattern mapper on edges and vertices
00935     // in failure case
00936     MeshCleaner cleaner( tgtSubMesh );
00937 
00938     // -------------------------------------------------------------------------
00939     // mapper doesn't take care of nodes already existing on edges and vertices,
00940     // so we must merge nodes created by it with existing ones 
00941     // -------------------------------------------------------------------------
00942 
00943     SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes;
00944 
00945     // Make groups of nodes to merge
00946 
00947     // loop on edge and vertex submeshes of a target face
00948     smIt = tgtSubMesh->getDependsOnIterator(/*includeSelf=*/false,/*complexShapeFirst=*/false);
00949     while ( smIt->more() )
00950     {
00951       SMESH_subMesh*     sm = smIt->next();
00952       SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
00953       if ( !smDS || smDS->NbNodes() == 0 )
00954         continue;
00955       //if ( !is1DComputed && sm->GetSubShape().ShapeType() == TopAbs_EDGE )
00956       //break;
00957 
00958       // Sort new and old nodes of a submesh separately
00959 
00960       bool isSeam = helper.IsRealSeam( sm->GetId() );
00961 
00962       enum { NEW_NODES = 0, OLD_NODES };
00963       map< double, const SMDS_MeshNode* > u2nodesMaps[2], u2nodesOnSeam;
00964       map< double, const SMDS_MeshNode* >::iterator u_oldNode, u_newNode, u_newOnSeam, newEnd;
00965       set< const SMDS_MeshNode* > seamNodes;
00966 
00967       // mapper puts on a seam edge nodes from 2 edges
00968       if ( isSeam && ! getBoundaryNodes ( sm, tgtFace, u2nodesOnSeam, seamNodes ))
00969         RETURN_BAD_RESULT("getBoundaryNodes() failed");
00970 
00971       SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
00972       while ( nIt->more() )
00973       {
00974         const SMDS_MeshNode* node = nIt->next();
00975         bool isOld = isOldNode( node );
00976 
00977         if ( !isOld && isSeam ) { // new node on a seam edge
00978           if ( seamNodes.count( node ) )
00979             continue; // node is already in the map
00980         }
00981 
00982         // sort nodes on edges by their position
00983         map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[isOld ? OLD_NODES : NEW_NODES];
00984         switch ( node->GetPosition()->GetTypeOfPosition() )
00985         {
00986         case  SMDS_TOP_VERTEX: {
00987           if ( !is1DComputed && !pos2nodes.empty() )
00988             u2nodesMaps[isOld ? NEW_NODES : OLD_NODES].insert( make_pair( 0, node ));
00989           else
00990             pos2nodes.insert( make_pair( 0, node ));
00991           break;
00992         }
00993         case  SMDS_TOP_EDGE:   {
00994           const SMDS_EdgePosition* pos =
00995             static_cast<const SMDS_EdgePosition*>(node->GetPosition());
00996           pos2nodes.insert( make_pair( pos->GetUParameter(), node ));
00997           break;
00998         }
00999         default:
01000           RETURN_BAD_RESULT("Wrong node position type: "<<
01001                             node->GetPosition()->GetTypeOfPosition());
01002         }
01003       }
01004       const bool mergeNewToOld =
01005         ( u2nodesMaps[ NEW_NODES ].size() == u2nodesMaps[ OLD_NODES ].size() );
01006       const bool mergeSeamToNew =
01007         ( u2nodesMaps[ NEW_NODES ].size() == u2nodesOnSeam.size() );
01008 
01009       if ( !mergeNewToOld )
01010       {
01011         // if ( u2nodesMaps[ NEW_NODES ].size() == 0         &&
01012         //      sm->GetSubShape().ShapeType() == TopAbs_EDGE &&
01013         //      helper.IsDegenShape( sm->GetId() )             )
01014         //   // NPAL15894 (tt88bis.py) - project mesh built by NETGEN_1d_2D that
01015         //   // does not make segments/nodes on degenerated edges
01016         //   continue;
01017 
01018         // if ( u2nodesMaps[ OLD_NODES ].size() == 0           &&
01019         //      sm->GetSubShape().ShapeType() == TopAbs_VERTEX )
01020         //   // old nodes are optional on vertices in the case of 1D-2D projection
01021         //   continue;
01022 
01023         //RETURN_BAD_RESULT
01024         MESSAGE("Different nb of old and new nodes on shape #"<< sm->GetId() <<" "<<
01025                 u2nodesMaps[ OLD_NODES ].size() << " != " <<
01026                 u2nodesMaps[ NEW_NODES ].size());
01027       }
01028       if ( isSeam && !mergeSeamToNew ) {
01029         //RETURN_BAD_RESULT
01030         MESSAGE("Different nb of old and seam nodes " <<
01031                 u2nodesMaps[ OLD_NODES ].size() << " != " << u2nodesOnSeam.size());
01032       }
01033       // Make groups of nodes to merge
01034       u_oldNode = u2nodesMaps[ OLD_NODES ].begin(); 
01035       u_newNode = u2nodesMaps[ NEW_NODES ].begin();
01036       newEnd    = u2nodesMaps[ NEW_NODES ].end();
01037       u_newOnSeam = u2nodesOnSeam.begin();
01038       if ( mergeNewToOld )
01039         for ( ; u_newNode != newEnd; ++u_newNode, ++u_oldNode )
01040         {
01041           groupsOfNodes.push_back( list< const SMDS_MeshNode* >() );
01042           groupsOfNodes.back().push_back( u_oldNode->second );
01043           groupsOfNodes.back().push_back( u_newNode->second );
01044           if ( mergeSeamToNew )
01045             groupsOfNodes.back().push_back( (u_newOnSeam++)->second );
01046         }
01047       else if ( mergeSeamToNew )
01048         for ( ; u_newNode != newEnd; ++u_newNode, ++u_newOnSeam )
01049         {
01050           groupsOfNodes.push_back( list< const SMDS_MeshNode* >() );
01051           groupsOfNodes.back().push_back( u_newNode->second );
01052           groupsOfNodes.back().push_back( u_newOnSeam->second );
01053         }
01054     }
01055 
01056     // Merge
01057 
01058     SMESH_MeshEditor editor( tgtMesh );
01059     int nbFaceBeforeMerge = tgtSubMesh->GetSubMeshDS()->NbElements();
01060     editor.MergeNodes( groupsOfNodes );
01061     int nbFaceAtferMerge = tgtSubMesh->GetSubMeshDS()->NbElements();
01062     if ( nbFaceBeforeMerge != nbFaceAtferMerge )
01063       return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces");
01064 
01065     // ----------------------------------------------------------------
01066     // The mapper can't create quadratic elements, so convert if needed
01067     // ----------------------------------------------------------------
01068 
01069     faceIt         = srcSubMesh->GetSubMeshDS()->GetElements();
01070     bool srcIsQuad = faceIt->next()->IsQuadratic();
01071     faceIt         = tgtSubMesh->GetSubMeshDS()->GetElements();
01072     bool tgtIsQuad = faceIt->next()->IsQuadratic();
01073     if ( srcIsQuad && !tgtIsQuad )
01074     {
01075       TIDSortedElemSet tgtFaces;
01076       faceIt = tgtSubMesh->GetSubMeshDS()->GetElements();
01077       while ( faceIt->more() )
01078         tgtFaces.insert( tgtFaces.end(), faceIt->next() );
01079 
01080       editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces);
01081     }
01082 
01083     cleaner.Release(); // not to remove mesh
01084 
01085   } // end of projection using Pattern mapping
01086 
01087 
01088   // ---------------------------
01089   // Check elements orientation
01090   // ---------------------------
01091 
01092   TopoDS_Face face = TopoDS::Face( theShape );
01093   if ( !theMesh.IsMainShape( tgtFace ))
01094   {
01095     // find the main shape
01096     TopoDS_Shape mainShape = meshDS->ShapeToMesh();
01097     switch ( mainShape.ShapeType() ) {
01098     case TopAbs_SHELL:
01099     case TopAbs_SOLID: break;
01100     default:
01101       TopTools_ListIteratorOfListOfShape ancestIt = theMesh.GetAncestors( face );
01102       for ( ; ancestIt.More(); ancestIt.Next() ) {
01103         TopAbs_ShapeEnum type = ancestIt.Value().ShapeType();
01104         if ( type == TopAbs_SOLID ) {
01105           mainShape = ancestIt.Value();
01106           break;
01107         } else if ( type == TopAbs_SHELL ) {
01108           mainShape = ancestIt.Value();
01109         }
01110       }
01111     }
01112     // find tgtFace in the main solid or shell to know it's true orientation.
01113     TopExp_Explorer exp( mainShape, TopAbs_FACE );
01114     for ( ; exp.More(); exp.Next() ) {
01115       if ( tgtFace.IsSame( exp.Current() )) {
01116         face = TopoDS::Face( exp.Current() );
01117         break;
01118       }
01119     }
01120   }
01121   // Fix orientation
01122   if ( SMESH_Algo::IsReversedSubMesh( face, meshDS ))
01123   {
01124     SMESH_MeshEditor editor( tgtMesh );
01125     SMDS_ElemIteratorPtr eIt = meshDS->MeshElements( face )->GetElements();
01126     while ( eIt->more() ) {
01127       const SMDS_MeshElement* e = eIt->next();
01128       if ( e->GetType() == SMDSAbs_Face && !editor.Reorient( e ))
01129         RETURN_BAD_RESULT("Pb of SMESH_MeshEditor::Reorient()");
01130     }
01131   }
01132 
01133   return true;
01134 }
01135 
01136 
01137 //=======================================================================
01138 //function : Evaluate
01139 //purpose  : 
01140 //=======================================================================
01141 
01142 bool StdMeshers_Projection_2D::Evaluate(SMESH_Mesh&         theMesh,
01143                                         const TopoDS_Shape& theShape,
01144                                         MapShapeNbElems&    aResMap)
01145 {
01146   if ( !_sourceHypo )
01147     return false;
01148 
01149   SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
01150   SMESH_Mesh * tgtMesh = & theMesh;
01151   if ( !srcMesh )
01152     srcMesh = tgtMesh;
01153 
01154   // ---------------------------
01155   // Make sub-shapes association
01156   // ---------------------------
01157 
01158   TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
01159   TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
01160 
01161   TAssocTool::TShapeShapeMap shape2ShapeMap;
01162   TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap );
01163   if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
01164                                              shape2ShapeMap)  ||
01165        !shape2ShapeMap.IsBound( tgtFace ))
01166     return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
01167 
01168   TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
01169 
01170   // -------------------------------------------------------
01171   // Assure that mesh on a source Face is computed/evaluated
01172   // -------------------------------------------------------
01173 
01174   std::vector<int> aVec;
01175 
01176   SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace );
01177   if ( srcSubMesh->IsMeshComputed() )
01178   {
01179     aVec.resize( SMDSEntity_Last, 0 );
01180     aVec[SMDSEntity_Node] = srcSubMesh->GetSubMeshDS()->NbNodes();
01181 
01182     SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements();
01183     while ( elemIt->more() )
01184       aVec[ elemIt->next()->GetEntityType() ]++;
01185   }
01186   else
01187   {
01188     MapShapeNbElems  tmpResMap;
01189     MapShapeNbElems& srcResMap = (srcMesh == tgtMesh) ? aResMap : tmpResMap;
01190     if ( !_gen->Evaluate( *srcMesh, srcShape, srcResMap ))
01191       return error(COMPERR_BAD_INPUT_MESH,"Source mesh not evaluatable");
01192     aVec = srcResMap[ srcSubMesh ];
01193     if ( aVec.empty() )
01194       return error(COMPERR_BAD_INPUT_MESH,"Source mesh is wrongly evaluated");
01195   }
01196 
01197   SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
01198   aResMap.insert(std::make_pair(sm,aVec));
01199 
01200   return true;
01201 }
01202 
01203 
01204 //=============================================================================
01214 //=============================================================================
01215 
01216 void StdMeshers_Projection_2D::SetEventListener(SMESH_subMesh* subMesh)
01217 {
01218   TAssocTool::SetEventListener( subMesh,
01219                                 _sourceHypo->GetSourceFace(),
01220                                 _sourceHypo->GetSourceMesh() );
01221 }