1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : implementaion of SMESH idl descriptions
24 // File : StdMeshers_Projection_2D.cxx
26 // Created : Fri Oct 20 11:37:07 2006
27 // Author : Edward AGAPOV (eap)
29 #include "StdMeshers_Projection_2D.hxx"
31 #include "StdMeshers_ProjectionSource2D.hxx"
32 #include "StdMeshers_ProjectionUtils.hxx"
34 #include "SMESHDS_Hypothesis.hxx"
35 #include "SMESHDS_SubMesh.hxx"
36 #include "SMESH_Block.hxx"
37 #include "SMESH_Gen.hxx"
38 #include "SMESH_Mesh.hxx"
39 #include "SMESH_MesherHelper.hxx"
40 #include "SMESH_Pattern.hxx"
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_subMeshEventListener.hxx"
43 #include "SMESH_Comment.hxx"
44 #include "SMDS_EdgePosition.hxx"
46 #include "utilities.h"
48 #include <BRep_Tool.hxx>
49 #include <Bnd_B2d.hxx>
51 #include <TopExp_Explorer.hxx>
52 #include <TopTools_ListIteratorOfListOfShape.hxx>
60 #define RETURN_BAD_RESULT(msg) { MESSAGE(")-: Error: " << msg); return false; }
62 typedef StdMeshers_ProjectionUtils TAssocTool;
64 //=======================================================================
65 //function : StdMeshers_Projection_2D
67 //=======================================================================
69 StdMeshers_Projection_2D::StdMeshers_Projection_2D(int hypId, int studyId, SMESH_Gen* gen)
70 :SMESH_2D_Algo(hypId, studyId, gen)
72 _name = "Projection_2D";
73 _shapeType = (1 << TopAbs_FACE); // 1 bit per shape type
75 _compatibleHypothesis.push_back("ProjectionSource2D");
79 //================================================================================
83 //================================================================================
85 StdMeshers_Projection_2D::~StdMeshers_Projection_2D()
88 //=======================================================================
89 //function : CheckHypothesis
91 //=======================================================================
93 bool StdMeshers_Projection_2D::CheckHypothesis(SMESH_Mesh& theMesh,
94 const TopoDS_Shape& theShape,
95 SMESH_Hypothesis::Hypothesis_Status& theStatus)
97 list <const SMESHDS_Hypothesis * >::const_iterator itl;
99 const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(theMesh, theShape);
100 if ( hyps.size() == 0 )
102 theStatus = HYP_MISSING;
103 return false; // can't work with no hypothesis
106 if ( hyps.size() > 1 )
108 theStatus = HYP_ALREADY_EXIST;
112 const SMESHDS_Hypothesis *theHyp = hyps.front();
114 string hypName = theHyp->GetName();
118 if (hypName == "ProjectionSource2D")
120 _sourceHypo = static_cast<const StdMeshers_ProjectionSource2D *>(theHyp);
122 // Check hypo parameters
124 SMESH_Mesh* srcMesh = _sourceHypo->GetSourceMesh();
125 SMESH_Mesh* tgtMesh = & theMesh;
130 if ( _sourceHypo->HasVertexAssociation() )
133 TopoDS_Shape edge = TAssocTool::GetEdgeByVertices
134 ( srcMesh, _sourceHypo->GetSourceVertex(1), _sourceHypo->GetSourceVertex(2) );
135 if ( edge.IsNull() ||
136 !SMESH_MesherHelper::IsSubShape( edge, srcMesh ) ||
137 !SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() ))
139 theStatus = HYP_BAD_PARAMETER;
140 SCRUTE((edge.IsNull()));
141 SCRUTE((SMESH_MesherHelper::IsSubShape( edge, srcMesh )));
142 SCRUTE((SMESH_MesherHelper::IsSubShape( edge, _sourceHypo->GetSourceFace() )));
147 edge = TAssocTool::GetEdgeByVertices
148 ( tgtMesh, _sourceHypo->GetTargetVertex(1), _sourceHypo->GetTargetVertex(2) );
149 if ( edge.IsNull() || !SMESH_MesherHelper::IsSubShape( edge, tgtMesh ))
151 theStatus = HYP_BAD_PARAMETER;
152 SCRUTE((edge.IsNull()));
153 SCRUTE((SMESH_MesherHelper::IsSubShape( edge, tgtMesh )));
156 else if ( !_sourceHypo->IsCompoundSource() &&
157 !SMESH_MesherHelper::IsSubShape( edge, theShape ))
159 theStatus = HYP_BAD_PARAMETER;
160 SCRUTE((SMESH_MesherHelper::IsSubShape( edge, theShape )));
164 // check a source face
165 if ( !SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh ) ||
166 ( srcMesh == tgtMesh && theShape == _sourceHypo->GetSourceFace() ))
168 theStatus = HYP_BAD_PARAMETER;
169 SCRUTE((SMESH_MesherHelper::IsSubShape( _sourceHypo->GetSourceFace(), srcMesh )));
170 SCRUTE((srcMesh == tgtMesh));
171 SCRUTE(( theShape == _sourceHypo->GetSourceFace() ));
176 theStatus = HYP_INCOMPATIBLE;
178 return ( theStatus == HYP_OK );
183 //================================================================================
185 * \brief define if a node is new or old
186 * \param node - node to check
187 * \retval bool - true if the node existed before Compute() is called
189 //================================================================================
191 bool isOldNode( const SMDS_MeshNode* node )
193 // old nodes are shared by edges and new ones are shared
194 // only by faces created by mapper
195 SMDS_ElemIteratorPtr invEdge = node->GetInverseElementIterator(SMDSAbs_Edge);
196 bool isOld = invEdge->more();
200 //================================================================================
202 * \brief Class to remove mesh built by pattern mapper on edges
203 * and vertices in the case of failure of projection algo.
204 * It does it's job at destruction
206 //================================================================================
211 MeshCleaner( SMESH_subMesh* faceSubMesh ): sm(faceSubMesh) {}
212 ~MeshCleaner() { Clean(sm); }
213 void Release() { sm = 0; } // mesh will not be removed
214 static void Clean( SMESH_subMesh* sm, bool withSub=true )
217 // PAL16567, 18920. Remove face nodes as well
218 // switch ( sm->GetSubShape().ShapeType() ) {
219 // case TopAbs_VERTEX:
220 // case TopAbs_EDGE: {
221 SMDS_NodeIteratorPtr nIt = sm->GetSubMeshDS()->GetNodes();
222 SMESHDS_Mesh* mesh = sm->GetFather()->GetMeshDS();
223 while ( nIt->more() ) {
224 const SMDS_MeshNode* node = nIt->next();
225 if ( !isOldNode( node ) )
226 mesh->RemoveNode( node );
228 // do not break but iterate over DependsOn()
231 if ( !withSub ) return;
232 SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(false,false);
233 while ( smIt->more() )
234 Clean( smIt->next(), false );
239 //================================================================================
241 * \brief find new nodes belonging to one free border of mesh on face
242 * \param sm - submesh on edge or vertex containg nodes to choose from
243 * \param face - the face bound the submesh
244 * \param u2nodes - map to fill with nodes
245 * \param seamNodes - set of found nodes
246 * \retval bool - is a success
248 //================================================================================
250 bool getBoundaryNodes ( SMESH_subMesh* sm,
251 const TopoDS_Face& face,
252 map< double, const SMDS_MeshNode* > & u2nodes,
253 set< const SMDS_MeshNode* > & seamNodes)
257 if ( !sm || !sm->GetSubMeshDS() )
258 RETURN_BAD_RESULT("Null submesh");
260 SMDS_NodeIteratorPtr nIt = sm->GetSubMeshDS()->GetNodes();
261 switch ( sm->GetSubShape().ShapeType() ) {
263 case TopAbs_VERTEX: {
264 while ( nIt->more() ) {
265 const SMDS_MeshNode* node = nIt->next();
266 if ( isOldNode( node ) ) continue;
267 u2nodes.insert( make_pair( 0., node ));
268 seamNodes.insert( node );
275 // Get submeshes of sub-vertices
276 const map< int, SMESH_subMesh * >& subSM = sm->DependsOn();
277 if ( subSM.size() != 2 )
278 RETURN_BAD_RESULT("there must be 2 submeshes of sub-vertices"
279 " but we have " << subSM.size());
280 SMESH_subMesh* smV1 = subSM.begin()->second;
281 SMESH_subMesh* smV2 = subSM.rbegin()->second;
282 if ( !smV1->IsMeshComputed() || !smV2->IsMeshComputed() )
283 RETURN_BAD_RESULT("Empty vertex submeshes");
285 // Look for a new node on V1
286 nIt = smV1->GetSubMeshDS()->GetNodes();
287 const SMDS_MeshNode* nV1 = 0;
288 while ( nIt->more() && !nV1 ) {
289 const SMDS_MeshNode* node = nIt->next();
290 if ( !isOldNode( node ) ) nV1 = node;
293 RETURN_BAD_RESULT("No new node found on V1");
295 // Find a new node connected to nV1 and belonging to edge submesh;
296 const SMDS_MeshNode* nE = 0;
297 SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
298 SMDS_ElemIteratorPtr vElems = nV1->GetInverseElementIterator(SMDSAbs_Face);
299 while ( vElems->more() && !nE ) {
300 const SMDS_MeshElement* elem = vElems->next();
301 int nbNodes = elem->NbNodes();
302 if ( elem->IsQuadratic() )
304 int iV1 = elem->GetNodeIndex( nV1 );
305 // try next after nV1
306 int iE = SMESH_MesherHelper::WrapIndex( iV1 + 1, nbNodes );
307 if ( smDS->Contains( elem->GetNode( iE ) ))
308 nE = elem->GetNode( iE );
310 // try node before nV1
311 iE = SMESH_MesherHelper::WrapIndex( iV1 - 1, nbNodes );
312 if ( smDS->Contains( elem->GetNode( iE )))
313 nE = elem->GetNode( iE );
315 if ( nE && elem->IsQuadratic() ) { // find medium node between nV1 and nE
316 if ( Abs( iV1 - iE ) == 1 )
317 nE = elem->GetNode( Min ( iV1, iE ) + nbNodes );
319 nE = elem->GetNode( elem->NbNodes() - 1 );
323 RETURN_BAD_RESULT("new node on edge not found");
325 // Get the whole free border of a face
326 list< const SMDS_MeshNode* > bordNodes;
327 list< const SMDS_MeshElement* > bordFaces;
328 if ( !SMESH_MeshEditor::FindFreeBorder (nV1, nE, nV1, bordNodes, bordFaces ))
329 RETURN_BAD_RESULT("free border of a face not found by nodes " <<
330 nV1->GetID() << " " << nE->GetID() );
332 // Insert nodes of the free border to the map until node on V2 encountered
333 SMESHDS_SubMesh* v2smDS = smV2->GetSubMeshDS();
334 list< const SMDS_MeshNode* >::iterator bordIt = bordNodes.begin();
335 bordIt++; // skip nV1
336 for ( ; bordIt != bordNodes.end(); ++bordIt ) {
337 const SMDS_MeshNode* node = *bordIt;
338 if ( v2smDS->Contains( node ))
340 if ( node->GetPosition()->GetTypeOfPosition() != SMDS_TOP_EDGE )
341 RETURN_BAD_RESULT("Bad node position type: node " << node->GetID() <<
342 " pos type " << node->GetPosition()->GetTypeOfPosition());
343 const SMDS_EdgePosition* pos =
344 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
345 u2nodes.insert( make_pair( pos->GetUParameter(), node ));
346 seamNodes.insert( node );
348 if ( u2nodes.size() != seamNodes.size() )
349 RETURN_BAD_RESULT("Bad node params on edge " << sm->GetId() <<
350 ", " << u2nodes.size() << " != " << seamNodes.size() );
355 RETURN_BAD_RESULT ("Unexpected submesh type");
357 } // bool getBoundaryNodes()
359 //================================================================================
361 * \brief Preform projection in case if tgtFace.IsPartner( srcFace ) and in case
362 * if projection by transformation is possible
363 * \param tgtFace - target face
364 * \param srcFace - source face
365 * \param tgtMesh - target mesh
366 * \param srcMesh - source mesh
367 * \retval bool - true if succeeded
369 //================================================================================
371 bool projectPartner(const TopoDS_Face& tgtFace,
372 const TopoDS_Face& srcFace,
373 SMESH_Mesh * tgtMesh,
374 SMESH_Mesh * srcMesh,
375 const TAssocTool::TShapeShapeMap& shape2ShapeMap)
377 const double tol = 1e-6;
379 gp_Trsf trsf; // transformation to get location of target nodes from source ones
380 if ( tgtFace.IsPartner( srcFace ))
382 gp_Trsf srcTrsf = srcFace.Location();
383 gp_Trsf tgtTrsf = tgtFace.Location();
384 trsf = srcTrsf.Inverted() * tgtTrsf;
388 // Try to find the transformation
390 // make any local coord systems of src and tgt faces
391 vector<gp_Pnt> srcPP, tgtPP; // 3 points on face boundaries to make axes of CS
392 SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace );
393 SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false);
394 srcSM = smIt->next(); // sm of a vertex
395 while ( smIt->more() && srcPP.size() < 3 )
397 srcSM = smIt->next();
398 SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS();
399 if ( !srcSmds ) continue;
400 SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes();
401 while ( nIt->more() )
403 SMESH_MeshEditor::TNodeXYZ p ( nIt->next());
405 switch ( srcPP.size() )
407 case 0: pOK = true; break;
409 case 1: pOK = ( srcPP[0].SquareDistance( p ) > tol ); break;
413 gp_Vec p0p1( srcPP[0], srcPP[1] ), p0p( srcPP[0], p );
414 pOK = !p0p1.IsParallel( p0p, tol );
421 // find corresponding point on target shape
424 const TopoDS_Shape& tgtShape = shape2ShapeMap( srcSM->GetSubShape() );
425 if ( tgtShape.ShapeType() == TopAbs_VERTEX )
427 tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape ));
429 //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMesh->GetMeshDS())->GetID() << endl;
431 else if ( tgtPP.size() > 0 )
433 if ( SMESHDS_SubMesh* tgtSmds = tgtMesh->GetMeshDS()->MeshElements( tgtShape ))
435 double srcDist = srcPP[0].Distance( p );
436 double eTol = BRep_Tool::Tolerance( TopoDS::Edge( tgtShape ));
437 SMDS_NodeIteratorPtr nItT = tgtSmds->GetNodes();
438 while ( nItT->more() && !pOK )
440 const SMDS_MeshNode* n = nItT->next();
441 tgtP = SMESH_MeshEditor::TNodeXYZ( n );
442 pOK = ( fabs( srcDist - tgtPP[0].Distance( tgtP )) < 2*eTol );
443 //cout << "E - nS " << p._node->GetID() << " - nT " << n->GetID()<< " OK - " << pOK<< " " << fabs( srcDist - tgtPP[0].Distance( tgtP ))<< " tol " << eTol<< endl;
450 srcPP.push_back( p );
451 tgtPP.push_back( tgtP );
454 if ( srcPP.size() != 3 )
457 // make transformation
458 gp_Trsf fromTgtCS, toSrcCS; // from/to global CS
459 gp_Ax2 srcCS( srcPP[0], gp_Vec( srcPP[0], srcPP[1] ), gp_Vec( srcPP[0], srcPP[2]));
460 gp_Ax2 tgtCS( tgtPP[0], gp_Vec( tgtPP[0], tgtPP[1] ), gp_Vec( tgtPP[0], tgtPP[2]));
461 toSrcCS .SetTransformation( gp_Ax3( srcCS ));
462 fromTgtCS.SetTransformation( gp_Ax3( tgtCS ));
465 trsf = fromTgtCS * toSrcCS;
468 // Fill map of src to tgt nodes with nodes on edges
470 map<const SMDS_MeshNode* , const SMDS_MeshNode*> src2tgtNodes;
471 map<const SMDS_MeshNode* , const SMDS_MeshNode*>::iterator srcN_tgtN;
473 for ( TopExp_Explorer srcEdge( srcFace, TopAbs_EDGE); srcEdge.More(); srcEdge.Next() )
475 const TopoDS_Shape& tgtEdge = shape2ShapeMap( srcEdge.Current() );
477 map< double, const SMDS_MeshNode* > srcNodes, tgtNodes;
478 if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMesh->GetMeshDS(),
479 TopoDS::Edge( srcEdge.Current() ),
480 /*ignoreMediumNodes = */true,
483 !SMESH_Algo::GetSortedNodesOnEdge( tgtMesh->GetMeshDS(),
484 TopoDS::Edge( tgtEdge ),
485 /*ignoreMediumNodes = */true,
488 srcNodes.size() != tgtNodes.size())
491 if ( !tgtEdge.IsPartner( srcEdge.Current() ))
493 // check that transormation is OK by three nodes
494 gp_Pnt p0S = SMESH_MeshEditor::TNodeXYZ( (srcNodes.begin()) ->second);
495 gp_Pnt p1S = SMESH_MeshEditor::TNodeXYZ( (srcNodes.rbegin()) ->second);
496 gp_Pnt p2S = SMESH_MeshEditor::TNodeXYZ( (++srcNodes.begin())->second);
498 gp_Pnt p0T = SMESH_MeshEditor::TNodeXYZ( (tgtNodes.begin()) ->second);
499 gp_Pnt p1T = SMESH_MeshEditor::TNodeXYZ( (tgtNodes.rbegin()) ->second);
500 gp_Pnt p2T = SMESH_MeshEditor::TNodeXYZ( (++tgtNodes.begin())->second);
502 // transform source points, they must coinside with target ones
503 if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol ||
504 p1T.SquareDistance( p1S.Transformed( trsf )) > tol ||
505 p2T.SquareDistance( p2S.Transformed( trsf )) > tol )
507 //cout << "KO trsf, 3 dist: "
508 //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", "
509 //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", "
510 //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<<endl;
515 map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
516 map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin();
517 for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn)
518 src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second ));
523 // prepare the helper adding quadratic elements if necessary
524 SMESH_MesherHelper helper( *tgtMesh );
525 helper.IsQuadraticSubMesh( tgtFace );
526 helper.SetElementsOnShape( true );
528 const SMDS_MeshNode* nullNode = 0;
530 SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
531 SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
532 while ( elemIt->more() ) // loop on all mesh faces on srcFace
534 const SMDS_MeshElement* elem = elemIt->next();
535 vector< const SMDS_MeshNode* > tgtFaceNodes;
536 tgtFaceNodes.reserve( elem->NbNodes() );
537 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
538 while ( nodeIt->more() ) // loop on nodes of the source element
540 const SMDS_MeshNode* srcNode = (const SMDS_MeshNode*) nodeIt->next();
541 srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
542 if ( srcN_tgtN->second == nullNode )
545 gp_Pnt tgtP = gp_Pnt(srcNode->X(),srcNode->Y(),srcNode->Z()).Transformed( trsf );
546 srcN_tgtN->second = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
548 tgtFaceNodes.push_back( srcN_tgtN->second );
550 // create a new face (with reversed orientation)
551 if ( tgtFaceNodes.size() == 3 )
552 helper.AddFace( tgtFaceNodes[0],tgtFaceNodes[2],tgtFaceNodes[1]);
554 helper.AddFace( tgtFaceNodes[0],tgtFaceNodes[3],tgtFaceNodes[2],tgtFaceNodes[1]);
562 //=======================================================================
565 //=======================================================================
567 bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
572 SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
573 SMESH_Mesh * tgtMesh = & theMesh;
577 SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
579 // ---------------------------
580 // Make subshapes association
581 // ---------------------------
583 TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
584 TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
586 TAssocTool::TShapeShapeMap shape2ShapeMap;
587 TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap, tgtFace );
588 if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
590 !shape2ShapeMap.IsBound( tgtFace ))
591 return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
593 TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
595 // ----------------------------------------------
596 // Assure that mesh on a source Face is computed
597 // ----------------------------------------------
599 SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace );
600 SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtFace );
602 if ( tgtMesh == srcMesh ) {
603 if ( !TAssocTool::MakeComputed( srcSubMesh ))
604 return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
607 if ( !srcSubMesh->IsMeshComputed() )
608 return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
611 // try to project from same face with different location
612 if ( projectPartner( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap ))
615 // --------------------
616 // Prepare to mapping
617 // --------------------
619 SMESH_MesherHelper helper( theMesh );
620 helper.SetSubShape( tgtFace );
622 // Check if node projection to a face is needed
624 SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements();
626 for ( ; nbFaceNodes < 3 && faceIt->more(); ) {
627 const SMDS_MeshElement* face = faceIt->next();
628 SMDS_ElemIteratorPtr nodeIt = face->nodesIterator();
629 while ( nodeIt->more() ) {
630 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
631 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) {
633 uvBox.Add( helper.GetNodeUV( srcFace, node ));
637 const bool toProjectNodes =
638 ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN ));
640 // Load pattern from the source face
641 SMESH_Pattern mapper;
642 mapper.Load( srcMesh, srcFace, toProjectNodes );
643 if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
644 return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face");
646 // Find the first target vertex corresponding to first vertex of the <mapper>
647 // and <theReverse> flag needed to call mapper.Apply()
649 TopoDS_Vertex srcV1 = TopoDS::Vertex( mapper.GetSubShape( 1 ));
650 if ( srcV1.IsNull() )
651 RETURN_BAD_RESULT("Mesh is not bound to the face");
652 if ( !shape2ShapeMap.IsBound( srcV1 ))
653 RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() );
654 TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1 ));
656 if ( !SMESH_MesherHelper::IsSubShape( srcV1, srcFace ))
657 RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->());
658 if ( !SMESH_MesherHelper::IsSubShape( tgtV1, tgtFace ))
659 RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->());
661 // try to find out orientation by order of edges
662 bool reverse = false;
663 list< TopoDS_Edge > tgtEdges, srcEdges;
664 list< int > nbEdgesInWires;
665 SMESH_Block::GetOrderedEdges( tgtFace, tgtV1, tgtEdges, nbEdgesInWires);
666 SMESH_Block::GetOrderedEdges( srcFace, srcV1, srcEdges, nbEdgesInWires);
667 if ( nbEdgesInWires.front() > 1 ) // possible to find out
669 TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front();
670 TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 );
671 reverse = ( ! srcE1.IsSame( srcE1bis ));
673 else if ( nbEdgesInWires.front() == 1 )
675 // TODO::Compare orientation of curves in a sole edge
676 //RETURN_BAD_RESULT("Not implemented case");
680 RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()");
683 // --------------------
684 // Perform 2D mapping
685 // --------------------
687 // Compute mesh on a target face
689 mapper.Apply( tgtFace, tgtV1, reverse );
690 if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
691 return error("Can't apply source mesh pattern to the face");
695 const bool toCreatePolygons = false, toCreatePolyedrs = false;
696 mapper.MakeMesh( tgtMesh, toCreatePolygons, toCreatePolyedrs );
697 if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
698 return error("Can't make mesh by source mesh pattern");
700 // it will remove mesh built by pattern mapper on edges and vertices
702 MeshCleaner cleaner( tgtSubMesh );
704 // -------------------------------------------------------------------------
705 // mapper doesn't take care of nodes already existing on edges and vertices,
706 // so we must merge nodes created by it with existing ones
707 // -------------------------------------------------------------------------
709 SMESH_MeshEditor editor( tgtMesh );
710 SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes;
712 // Make groups of nodes to merge
714 // loop on edge and vertex submeshes of a target face
715 SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(false,false);
716 while ( smIt->more() )
718 SMESH_subMesh* sm = smIt->next();
719 SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
721 // Sort new and old nodes of a submesh separately
723 bool isSeam = helper.IsRealSeam( sm->GetId() );
725 enum { NEW_NODES = 0, OLD_NODES };
726 map< double, const SMDS_MeshNode* > u2nodesMaps[2], u2nodesOnSeam;
727 map< double, const SMDS_MeshNode* >::iterator u_oldNode, u_newNode, u_newOnSeam, newEnd;
728 set< const SMDS_MeshNode* > seamNodes;
730 // mapper puts on a seam edge nodes from 2 edges
731 if ( isSeam && ! getBoundaryNodes ( sm, tgtFace, u2nodesOnSeam, seamNodes ))
732 RETURN_BAD_RESULT("getBoundaryNodes() failed");
734 SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
735 while ( nIt->more() )
737 const SMDS_MeshNode* node = nIt->next();
738 bool isOld = isOldNode( node );
740 if ( !isOld && isSeam ) { // new node on a seam edge
741 if ( seamNodes.find( node ) != seamNodes.end())
742 continue; // node is already in the map
745 // sort nodes on edges by their position
746 map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[isOld ? OLD_NODES : NEW_NODES];
747 switch ( node->GetPosition()->GetTypeOfPosition() )
749 case SMDS_TOP_VERTEX: {
750 pos2nodes.insert( make_pair( 0, node ));
753 case SMDS_TOP_EDGE: {
754 const SMDS_EdgePosition* pos =
755 static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
756 pos2nodes.insert( make_pair( pos->GetUParameter(), node ));
760 RETURN_BAD_RESULT("Wrong node position type: "<<
761 node->GetPosition()->GetTypeOfPosition());
764 if ( u2nodesMaps[ NEW_NODES ].size() != u2nodesMaps[ OLD_NODES ].size() )
766 if ( u2nodesMaps[ NEW_NODES ].size() == 0 &&
767 sm->GetSubShape().ShapeType() == TopAbs_EDGE &&
768 helper.IsDegenShape( sm->GetId() ) )
769 // NPAL15894 (tt88bis.py) - project mesh built by NETGEN_1d_2D that
770 // does not make segments/nodes on degenerated edges
773 RETURN_BAD_RESULT("Different nb of old and new nodes on shape #"<< sm->GetId() <<" "<<
774 u2nodesMaps[ OLD_NODES ].size() << " != " <<
775 u2nodesMaps[ NEW_NODES ].size());
777 if ( isSeam && u2nodesMaps[ OLD_NODES ].size() != u2nodesOnSeam.size() ) {
778 RETURN_BAD_RESULT("Different nb of old and seam nodes " <<
779 u2nodesMaps[ OLD_NODES ].size() << " != " << u2nodesOnSeam.size());
781 // Make groups of nodes to merge
782 u_oldNode = u2nodesMaps[ OLD_NODES ].begin();
783 u_newNode = u2nodesMaps[ NEW_NODES ].begin();
784 newEnd = u2nodesMaps[ NEW_NODES ].end();
785 u_newOnSeam = u2nodesOnSeam.begin();
786 for ( ; u_newNode != newEnd; ++u_newNode, ++u_oldNode ) {
787 groupsOfNodes.push_back( list< const SMDS_MeshNode* >() );
788 groupsOfNodes.back().push_back( u_oldNode->second );
789 groupsOfNodes.back().push_back( u_newNode->second );
791 groupsOfNodes.back().push_back( (u_newOnSeam++)->second );
797 int nbFaceBeforeMerge = tgtSubMesh->GetSubMeshDS()->NbElements();
798 editor.MergeNodes( groupsOfNodes );
799 int nbFaceAtferMerge = tgtSubMesh->GetSubMeshDS()->NbElements();
800 if ( nbFaceBeforeMerge != nbFaceAtferMerge )
801 return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces");
803 // ---------------------------
804 // Check elements orientation
805 // ---------------------------
807 TopoDS_Face face = tgtFace;
808 if ( !theMesh.IsMainShape( tgtFace ))
810 // find the main shape
811 TopoDS_Shape mainShape = meshDS->ShapeToMesh();
812 switch ( mainShape.ShapeType() ) {
814 case TopAbs_SOLID: break;
816 TopTools_ListIteratorOfListOfShape ancestIt = theMesh.GetAncestors( face );
817 for ( ; ancestIt.More(); ancestIt.Next() ) {
818 TopAbs_ShapeEnum type = ancestIt.Value().ShapeType();
819 if ( type == TopAbs_SOLID ) {
820 mainShape = ancestIt.Value();
822 } else if ( type == TopAbs_SHELL ) {
823 mainShape = ancestIt.Value();
827 // find tgtFace in the main solid or shell to know it's true orientation.
828 TopExp_Explorer exp( mainShape, TopAbs_FACE );
829 for ( ; exp.More(); exp.Next() ) {
830 if ( tgtFace.IsSame( exp.Current() )) {
831 face = TopoDS::Face( exp.Current() );
837 if ( SMESH_Algo::IsReversedSubMesh( face, meshDS ))
839 SMDS_ElemIteratorPtr eIt = meshDS->MeshElements( face )->GetElements();
840 while ( eIt->more() ) {
841 const SMDS_MeshElement* e = eIt->next();
842 if ( e->GetType() == SMDSAbs_Face && !editor.Reorient( e ))
843 RETURN_BAD_RESULT("Pb of SMESH_MeshEditor::Reorient()");
847 cleaner.Release(); // do not remove mesh
853 //=======================================================================
854 //function : Evaluate
856 //=======================================================================
858 bool StdMeshers_Projection_2D::Evaluate(SMESH_Mesh& theMesh,
859 const TopoDS_Shape& theShape,
860 MapShapeNbElems& aResMap)
865 SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
866 SMESH_Mesh * tgtMesh = & theMesh;
870 // ---------------------------
871 // Make subshapes association
872 // ---------------------------
874 TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
875 TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
877 TAssocTool::TShapeShapeMap shape2ShapeMap;
878 TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap, tgtFace );
879 if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
881 !shape2ShapeMap.IsBound( tgtFace ))
882 return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
884 TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
886 // ----------------------------------------------
887 // Assure that mesh on a source Face is computed
888 // ----------------------------------------------
890 SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace );
892 if ( !srcSubMesh->IsMeshComputed() )
893 return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
896 std::vector<int> aVec(SMDSEntity_Last);
897 for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i] = 0;
899 aVec[SMDSEntity_Node] = srcSubMesh->GetSubMeshDS()->NbNodes();
901 //bool quadratic = false;
902 SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements();
903 while ( elemIt->more() ) {
904 const SMDS_MeshElement* E = elemIt->next();
905 if( E->NbNodes()==3 ) {
906 aVec[SMDSEntity_Triangle]++;
908 else if( E->NbNodes()==4 ) {
909 aVec[SMDSEntity_Quadrangle]++;
911 else if( E->NbNodes()==6 && E->IsQuadratic() ) {
912 aVec[SMDSEntity_Quad_Triangle]++;
914 else if( E->NbNodes()==8 && E->IsQuadratic() ) {
915 aVec[SMDSEntity_Quad_Quadrangle]++;
918 aVec[SMDSEntity_Polygon]++;
922 SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
923 aResMap.insert(std::make_pair(sm,aVec));
929 //=============================================================================
931 * \brief Sets a default event listener to submesh of the source face
932 * \param subMesh - submesh where algo is set
934 * This method is called when a submesh gets HYP_OK algo_state.
935 * After being set, event listener is notified on each event of a submesh.
936 * Arranges that CLEAN event is translated from source submesh to
939 //=============================================================================
941 void StdMeshers_Projection_2D::SetEventListener(SMESH_subMesh* subMesh)
943 TAssocTool::SetEventListener( subMesh,
944 _sourceHypo->GetSourceFace(),
945 _sourceHypo->GetSourceMesh() );