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());
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 MESSAGE("projectPartner");
378 const double tol = 1.e-7*srcMesh->GetMeshDS()->getMaxDim();
380 gp_Trsf trsf; // transformation to get location of target nodes from source ones
381 if ( tgtFace.IsPartner( srcFace ))
383 gp_Trsf srcTrsf = srcFace.Location();
384 gp_Trsf tgtTrsf = tgtFace.Location();
385 trsf = srcTrsf.Inverted() * tgtTrsf;
389 // Try to find the transformation
391 // make any local coord systems of src and tgt faces
392 vector<gp_Pnt> srcPP, tgtPP; // 3 points on face boundaries to make axes of CS
393 SMESH_subMesh * srcSM = srcMesh->GetSubMesh( srcFace );
394 SMESH_subMeshIteratorPtr smIt = srcSM->getDependsOnIterator(/*includeSelf=*/false,false);
395 srcSM = smIt->next(); // sm of a vertex
396 while ( smIt->more() && srcPP.size() < 3 )
398 srcSM = smIt->next();
399 SMESHDS_SubMesh* srcSmds = srcSM->GetSubMeshDS();
400 if ( !srcSmds ) continue;
401 SMDS_NodeIteratorPtr nIt = srcSmds->GetNodes();
402 while ( nIt->more() )
404 SMESH_MeshEditor::TNodeXYZ p ( nIt->next());
406 switch ( srcPP.size() )
408 case 0: pOK = true; break;
410 case 1: pOK = ( srcPP[0].SquareDistance( p ) > 10*tol ); break;
414 gp_Vec p0p1( srcPP[0], srcPP[1] ), p0p( srcPP[0], p );
415 // pOK = !p0p1.IsParallel( p0p, tol );
416 pOK = !p0p1.IsParallel( p0p, 3.14/20 ); // angle min 18 degrees
423 // find corresponding point on target shape
426 const TopoDS_Shape& tgtShape = shape2ShapeMap( srcSM->GetSubShape() );
427 if ( tgtShape.ShapeType() == TopAbs_VERTEX )
429 tgtP = BRep_Tool::Pnt( TopoDS::Vertex( tgtShape ));
431 //cout << "V - nS " << p._node->GetID() << " - nT " << SMESH_Algo::VertexNode(TopoDS::Vertex( tgtShape),tgtMesh->GetMeshDS())->GetID() << endl;
433 else if ( tgtPP.size() > 0 )
435 if ( SMESHDS_SubMesh* tgtSmds = tgtMesh->GetMeshDS()->MeshElements( tgtShape ))
437 double srcDist = srcPP[0].Distance( p );
438 double eTol = BRep_Tool::Tolerance( TopoDS::Edge( tgtShape ));
439 if (eTol < tol) eTol = tol;
440 SMDS_NodeIteratorPtr nItT = tgtSmds->GetNodes();
441 while ( nItT->more() && !pOK )
443 const SMDS_MeshNode* n = nItT->next();
444 tgtP = SMESH_MeshEditor::TNodeXYZ( n );
445 pOK = ( fabs( srcDist - tgtPP[0].Distance( tgtP )) < 2*eTol );
446 //cout << "E - nS " << p._node->GetID() << " - nT " << n->GetID()<< " OK - " << pOK<< " " << fabs( srcDist - tgtPP[0].Distance( tgtP ))<< " tol " << eTol<< endl;
453 srcPP.push_back( p );
454 tgtPP.push_back( tgtP );
457 if ( srcPP.size() != 3 )
460 // make transformation
461 gp_Trsf fromTgtCS, toSrcCS; // from/to global CS
462 gp_Ax2 srcCS( srcPP[0], gp_Vec( srcPP[0], srcPP[1] ), gp_Vec( srcPP[0], srcPP[2]));
463 gp_Ax2 tgtCS( tgtPP[0], gp_Vec( tgtPP[0], tgtPP[1] ), gp_Vec( tgtPP[0], tgtPP[2]));
464 toSrcCS .SetTransformation( gp_Ax3( srcCS ));
465 fromTgtCS.SetTransformation( gp_Ax3( tgtCS ));
468 trsf = fromTgtCS * toSrcCS;
471 // Fill map of src to tgt nodes with nodes on edges
473 map<const SMDS_MeshNode* , const SMDS_MeshNode*> src2tgtNodes;
474 map<const SMDS_MeshNode* , const SMDS_MeshNode*>::iterator srcN_tgtN;
476 for ( TopExp_Explorer srcEdge( srcFace, TopAbs_EDGE); srcEdge.More(); srcEdge.Next() )
478 const TopoDS_Shape& tgtEdge = shape2ShapeMap( srcEdge.Current() );
480 map< double, const SMDS_MeshNode* > srcNodes, tgtNodes;
481 if ( !SMESH_Algo::GetSortedNodesOnEdge( srcMesh->GetMeshDS(),
482 TopoDS::Edge( srcEdge.Current() ),
483 /*ignoreMediumNodes = */true,
486 !SMESH_Algo::GetSortedNodesOnEdge( tgtMesh->GetMeshDS(),
487 TopoDS::Edge( tgtEdge ),
488 /*ignoreMediumNodes = */true,
491 srcNodes.size() != tgtNodes.size())
494 if ( !tgtEdge.IsPartner( srcEdge.Current() ))
496 // check that transformation is OK by three nodes
497 gp_Pnt p0S = SMESH_MeshEditor::TNodeXYZ( (srcNodes.begin()) ->second);
498 gp_Pnt p1S = SMESH_MeshEditor::TNodeXYZ( (srcNodes.rbegin()) ->second);
499 gp_Pnt p2S = SMESH_MeshEditor::TNodeXYZ( (++srcNodes.begin())->second);
501 gp_Pnt p0T = SMESH_MeshEditor::TNodeXYZ( (tgtNodes.begin()) ->second);
502 gp_Pnt p1T = SMESH_MeshEditor::TNodeXYZ( (tgtNodes.rbegin()) ->second);
503 gp_Pnt p2T = SMESH_MeshEditor::TNodeXYZ( (++tgtNodes.begin())->second);
505 // transform source points, they must coincide with target ones
506 if ( p0T.SquareDistance( p0S.Transformed( trsf )) > tol ||
507 p1T.SquareDistance( p1S.Transformed( trsf )) > tol ||
508 p2T.SquareDistance( p2S.Transformed( trsf )) > tol )
510 //cout << "KO trsf, 3 dist: "
511 //<< p0T.SquareDistance( p0S.Transformed( trsf ))<< ", "
512 //<< p1T.SquareDistance( p1S.Transformed( trsf ))<< ", "
513 //<< p2T.SquareDistance( p2S.Transformed( trsf ))<< ", "<<endl;
518 map< double, const SMDS_MeshNode* >::iterator u_tn = tgtNodes.begin();
519 map< double, const SMDS_MeshNode* >::iterator u_sn = srcNodes.begin();
520 for ( ; u_tn != tgtNodes.end(); ++u_tn, ++u_sn)
521 src2tgtNodes.insert( make_pair( u_sn->second, u_tn->second ));
526 // prepare the helper adding quadratic elements if necessary
527 SMESH_MesherHelper helper( *tgtMesh );
528 helper.SetSubShape( tgtFace );
529 helper.IsQuadraticSubMesh( tgtFace );
530 helper.SetElementsOnShape( true );
532 const SMDS_MeshNode* nullNode = 0;
534 SMESHDS_SubMesh* srcSubDS = srcMesh->GetMeshDS()->MeshElements( srcFace );
535 SMDS_ElemIteratorPtr elemIt = srcSubDS->GetElements();
536 while ( elemIt->more() ) // loop on all mesh faces on srcFace
538 const SMDS_MeshElement* elem = elemIt->next();
539 vector< const SMDS_MeshNode* > tgtFaceNodes;
540 tgtFaceNodes.reserve( elem->NbNodes() );
541 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
542 while ( nodeIt->more() ) // loop on nodes of the source element
544 const SMDS_MeshNode* srcNode = (const SMDS_MeshNode*) nodeIt->next();
545 if (elem->IsMediumNode(srcNode))
547 srcN_tgtN = src2tgtNodes.insert( make_pair( srcNode, nullNode )).first;
548 if ( srcN_tgtN->second == nullNode )
551 gp_Pnt tgtP = gp_Pnt(srcNode->X(),srcNode->Y(),srcNode->Z()).Transformed( trsf );
552 srcN_tgtN->second = helper.AddNode( tgtP.X(), tgtP.Y(), tgtP.Z() );
553 //MESSAGE(tgtP.X() << " " << tgtP.Y() << " " << tgtP.Z());
555 tgtFaceNodes.push_back( srcN_tgtN->second );
557 // create a new face (with reversed orientation)
558 //MESSAGE("tgtFaceNodes.size() " << tgtFaceNodes.size());
559 switch (tgtFaceNodes.size())
563 helper.AddFace(tgtFaceNodes[0], tgtFaceNodes[2], tgtFaceNodes[1]);
567 helper.AddFace(tgtFaceNodes[0], tgtFaceNodes[3], tgtFaceNodes[2], tgtFaceNodes[1]);
577 //=======================================================================
580 //=======================================================================
582 bool StdMeshers_Projection_2D::Compute(SMESH_Mesh& theMesh, const TopoDS_Shape& theShape)
584 MESSAGE("Projection_2D Compute");
588 SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
589 SMESH_Mesh * tgtMesh = & theMesh;
593 SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
595 // ---------------------------
596 // Make subshapes association
597 // ---------------------------
599 TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
600 TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
602 TAssocTool::TShapeShapeMap shape2ShapeMap;
603 TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap, tgtFace );
604 if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
606 !shape2ShapeMap.IsBound( tgtFace ))
607 return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
609 TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
611 // ----------------------------------------------
612 // Assure that mesh on a source Face is computed
613 // ----------------------------------------------
615 SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace );
616 SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( tgtFace );
618 if ( tgtMesh == srcMesh ) {
619 if ( !TAssocTool::MakeComputed( srcSubMesh ))
620 return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
623 if ( !srcSubMesh->IsMeshComputed() )
624 return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
627 // try to project from same face with different location
628 if ( projectPartner( tgtFace, srcFace, tgtMesh, srcMesh, shape2ShapeMap ))
631 // --------------------
632 // Prepare to mapping
633 // --------------------
635 SMESH_MesherHelper helper( theMesh );
636 helper.SetSubShape( tgtFace );
638 // Check if node projection to a face is needed
640 SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements();
642 for ( ; nbFaceNodes < 3 && faceIt->more(); ) {
643 const SMDS_MeshElement* face = faceIt->next();
644 SMDS_ElemIteratorPtr nodeIt = face->nodesIterator();
645 while ( nodeIt->more() ) {
646 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
647 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) {
649 uvBox.Add( helper.GetNodeUV( srcFace, node ));
653 const bool toProjectNodes =
654 ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN ));
656 // Load pattern from the source face
657 SMESH_Pattern mapper;
658 mapper.Load( srcMesh, srcFace, toProjectNodes );
659 if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
660 return error(COMPERR_BAD_INPUT_MESH,"Can't load mesh pattern from the source face");
662 // Find the first target vertex corresponding to first vertex of the <mapper>
663 // and <theReverse> flag needed to call mapper.Apply()
665 TopoDS_Vertex srcV1 = TopoDS::Vertex( mapper.GetSubShape( 1 ));
666 if ( srcV1.IsNull() )
667 RETURN_BAD_RESULT("Mesh is not bound to the face");
668 if ( !shape2ShapeMap.IsBound( srcV1 ))
669 RETURN_BAD_RESULT("Not associated vertices, srcV1 " << srcV1.TShape().operator->() );
670 TopoDS_Vertex tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1 ));
672 if ( !SMESH_MesherHelper::IsSubShape( srcV1, srcFace ))
673 RETURN_BAD_RESULT("Wrong srcV1 " << srcV1.TShape().operator->());
674 if ( !SMESH_MesherHelper::IsSubShape( tgtV1, tgtFace ))
675 RETURN_BAD_RESULT("Wrong tgtV1 " << tgtV1.TShape().operator->());
677 // try to find out orientation by order of edges
678 bool reverse = false;
679 list< TopoDS_Edge > tgtEdges, srcEdges;
680 list< int > nbEdgesInWires;
681 SMESH_Block::GetOrderedEdges( tgtFace, tgtV1, tgtEdges, nbEdgesInWires);
682 SMESH_Block::GetOrderedEdges( srcFace, srcV1, srcEdges, nbEdgesInWires);
683 if ( nbEdgesInWires.front() > 1 ) // possible to find out
685 TopoDS_Edge srcE1 = srcEdges.front(), tgtE1 = tgtEdges.front();
686 TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 );
687 reverse = ( ! srcE1.IsSame( srcE1bis ));
689 else if ( nbEdgesInWires.front() == 1 )
691 // TODO::Compare orientation of curves in a sole edge
692 //RETURN_BAD_RESULT("Not implemented case");
696 RETURN_BAD_RESULT("Bad result from SMESH_Block::GetOrderedEdges()");
699 // --------------------
700 // Perform 2D mapping
701 // --------------------
703 // Compute mesh on a target face
705 mapper.Apply( tgtFace, tgtV1, reverse );
706 if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
707 return error("Can't apply source mesh pattern to the face");
711 const bool toCreatePolygons = false, toCreatePolyedrs = false;
712 mapper.MakeMesh( tgtMesh, toCreatePolygons, toCreatePolyedrs );
713 if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
714 return error("Can't make mesh by source mesh pattern");
716 // it will remove mesh built by pattern mapper on edges and vertices
718 MeshCleaner cleaner( tgtSubMesh );
720 // -------------------------------------------------------------------------
721 // mapper doesn't take care of nodes already existing on edges and vertices,
722 // so we must merge nodes created by it with existing ones
723 // -------------------------------------------------------------------------
725 SMESH_MeshEditor editor( tgtMesh );
726 SMESH_MeshEditor::TListOfListOfNodes groupsOfNodes;
728 // Make groups of nodes to merge
730 // loop on edge and vertex submeshes of a target face
731 SMESH_subMeshIteratorPtr smIt = tgtSubMesh->getDependsOnIterator(false,false);
732 while ( smIt->more() )
734 SMESH_subMesh* sm = smIt->next();
735 SMESHDS_SubMesh* smDS = sm->GetSubMeshDS();
737 // Sort new and old nodes of a submesh separately
739 bool isSeam = helper.IsRealSeam( sm->GetId() );
741 enum { NEW_NODES = 0, OLD_NODES };
742 map< double, const SMDS_MeshNode* > u2nodesMaps[2], u2nodesOnSeam;
743 map< double, const SMDS_MeshNode* >::iterator u_oldNode, u_newNode, u_newOnSeam, newEnd;
744 set< const SMDS_MeshNode* > seamNodes;
746 // mapper puts on a seam edge nodes from 2 edges
747 if ( isSeam && ! getBoundaryNodes ( sm, tgtFace, u2nodesOnSeam, seamNodes ))
748 RETURN_BAD_RESULT("getBoundaryNodes() failed");
750 SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
751 while ( nIt->more() )
753 const SMDS_MeshNode* node = nIt->next();
754 bool isOld = isOldNode( node );
756 if ( !isOld && isSeam ) { // new node on a seam edge
757 if ( seamNodes.find( node ) != seamNodes.end())
758 continue; // node is already in the map
761 // sort nodes on edges by their position
762 map< double, const SMDS_MeshNode* > & pos2nodes = u2nodesMaps[isOld ? OLD_NODES : NEW_NODES];
763 switch ( node->GetPosition()->GetTypeOfPosition() )
765 case SMDS_TOP_VERTEX: {
766 pos2nodes.insert( make_pair( 0, node ));
769 case SMDS_TOP_EDGE: {
770 const SMDS_EdgePosition* pos =
771 static_cast<const SMDS_EdgePosition*>(node->GetPosition());
772 pos2nodes.insert( make_pair( pos->GetUParameter(), node ));
776 RETURN_BAD_RESULT("Wrong node position type: "<<
777 node->GetPosition()->GetTypeOfPosition());
780 if ( u2nodesMaps[ NEW_NODES ].size() != u2nodesMaps[ OLD_NODES ].size() )
782 if ( u2nodesMaps[ NEW_NODES ].size() == 0 &&
783 sm->GetSubShape().ShapeType() == TopAbs_EDGE &&
784 helper.IsDegenShape( sm->GetId() ) )
785 // NPAL15894 (tt88bis.py) - project mesh built by NETGEN_1d_2D that
786 // does not make segments/nodes on degenerated edges
789 RETURN_BAD_RESULT("Different nb of old and new nodes on shape #"<< sm->GetId() <<" "<<
790 u2nodesMaps[ OLD_NODES ].size() << " != " <<
791 u2nodesMaps[ NEW_NODES ].size());
793 if ( isSeam && u2nodesMaps[ OLD_NODES ].size() != u2nodesOnSeam.size() ) {
794 RETURN_BAD_RESULT("Different nb of old and seam nodes " <<
795 u2nodesMaps[ OLD_NODES ].size() << " != " << u2nodesOnSeam.size());
797 // Make groups of nodes to merge
798 u_oldNode = u2nodesMaps[ OLD_NODES ].begin();
799 u_newNode = u2nodesMaps[ NEW_NODES ].begin();
800 newEnd = u2nodesMaps[ NEW_NODES ].end();
801 u_newOnSeam = u2nodesOnSeam.begin();
802 for ( ; u_newNode != newEnd; ++u_newNode, ++u_oldNode ) {
803 groupsOfNodes.push_back( list< const SMDS_MeshNode* >() );
804 groupsOfNodes.back().push_back( u_oldNode->second );
805 groupsOfNodes.back().push_back( u_newNode->second );
807 groupsOfNodes.back().push_back( (u_newOnSeam++)->second );
813 int nbFaceBeforeMerge = tgtSubMesh->GetSubMeshDS()->NbElements();
814 editor.MergeNodes( groupsOfNodes );
815 int nbFaceAtferMerge = tgtSubMesh->GetSubMeshDS()->NbElements();
816 if ( nbFaceBeforeMerge != nbFaceAtferMerge )
817 return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces");
819 // ---------------------------
820 // Check elements orientation
821 // ---------------------------
823 TopoDS_Face face = tgtFace;
824 if ( !theMesh.IsMainShape( tgtFace ))
826 // find the main shape
827 TopoDS_Shape mainShape = meshDS->ShapeToMesh();
828 switch ( mainShape.ShapeType() ) {
830 case TopAbs_SOLID: break;
832 TopTools_ListIteratorOfListOfShape ancestIt = theMesh.GetAncestors( face );
833 for ( ; ancestIt.More(); ancestIt.Next() ) {
834 TopAbs_ShapeEnum type = ancestIt.Value().ShapeType();
835 if ( type == TopAbs_SOLID ) {
836 mainShape = ancestIt.Value();
838 } else if ( type == TopAbs_SHELL ) {
839 mainShape = ancestIt.Value();
843 // find tgtFace in the main solid or shell to know it's true orientation.
844 TopExp_Explorer exp( mainShape, TopAbs_FACE );
845 for ( ; exp.More(); exp.Next() ) {
846 if ( tgtFace.IsSame( exp.Current() )) {
847 face = TopoDS::Face( exp.Current() );
853 if ( SMESH_Algo::IsReversedSubMesh( face, meshDS ))
855 SMDS_ElemIteratorPtr eIt = meshDS->MeshElements( face )->GetElements();
856 while ( eIt->more() ) {
857 const SMDS_MeshElement* e = eIt->next();
858 if ( e->GetType() == SMDSAbs_Face && !editor.Reorient( e ))
859 RETURN_BAD_RESULT("Pb of SMESH_MeshEditor::Reorient()");
863 cleaner.Release(); // do not remove mesh
869 //=======================================================================
870 //function : Evaluate
872 //=======================================================================
874 bool StdMeshers_Projection_2D::Evaluate(SMESH_Mesh& theMesh,
875 const TopoDS_Shape& theShape,
876 MapShapeNbElems& aResMap)
881 SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
882 SMESH_Mesh * tgtMesh = & theMesh;
886 // ---------------------------
887 // Make subshapes association
888 // ---------------------------
890 TopoDS_Face tgtFace = TopoDS::Face( theShape.Oriented(TopAbs_FORWARD));
891 TopoDS_Shape srcShape = _sourceHypo->GetSourceFace().Oriented(TopAbs_FORWARD);
893 TAssocTool::TShapeShapeMap shape2ShapeMap;
894 TAssocTool::InitVertexAssociation( _sourceHypo, shape2ShapeMap, tgtFace );
895 if ( !TAssocTool::FindSubShapeAssociation( tgtFace, tgtMesh, srcShape, srcMesh,
897 !shape2ShapeMap.IsBound( tgtFace ))
898 return error(COMPERR_BAD_SHAPE,"Topology of source and target faces seems different" );
900 TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
902 // ----------------------------------------------
903 // Assure that mesh on a source Face is computed
904 // ----------------------------------------------
906 SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( srcFace );
908 if ( !srcSubMesh->IsMeshComputed() )
909 return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");
912 std::vector<int> aVec(SMDSEntity_Last);
913 for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i] = 0;
915 aVec[SMDSEntity_Node] = srcSubMesh->GetSubMeshDS()->NbNodes();
917 //bool quadratic = false;
918 SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements();
919 while ( elemIt->more() ) {
920 const SMDS_MeshElement* E = elemIt->next();
921 if( E->NbNodes()==3 ) {
922 aVec[SMDSEntity_Triangle]++;
924 else if( E->NbNodes()==4 ) {
925 aVec[SMDSEntity_Quadrangle]++;
927 else if( E->NbNodes()==6 && E->IsQuadratic() ) {
928 aVec[SMDSEntity_Quad_Triangle]++;
930 else if( E->NbNodes()==8 && E->IsQuadratic() ) {
931 aVec[SMDSEntity_Quad_Quadrangle]++;
934 aVec[SMDSEntity_Polygon]++;
938 SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
939 aResMap.insert(std::make_pair(sm,aVec));
945 //=============================================================================
947 * \brief Sets a default event listener to submesh of the source face
948 * \param subMesh - submesh where algo is set
950 * This method is called when a submesh gets HYP_OK algo_state.
951 * After being set, event listener is notified on each event of a submesh.
952 * Arranges that CLEAN event is translated from source submesh to
955 //=============================================================================
957 void StdMeshers_Projection_2D::SetEventListener(SMESH_subMesh* subMesh)
959 TAssocTool::SetEventListener( subMesh,
960 _sourceHypo->GetSourceFace(),
961 _sourceHypo->GetSourceMesh() );