1 // Copyright (C) 2007-2023 CEA, EDF
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : BLSURFPlugin_EnforcedMesh1D.cxx
20 // Author : Edward AGAPOV (OCC)
22 #include "BLSURFPlugin_EnforcedMesh1D.hxx"
24 #include "BLSURFPlugin_BLSURF.hxx"
26 #include <SMDS_IteratorOnIterators.hxx>
27 #include <SMDS_MeshEdge.hxx>
28 #include <SMDS_MeshGroup.hxx>
29 #include <SMESHDS_Group.hxx>
30 #include <SMESHDS_Mesh.hxx>
31 #include <SMESH_Group.hxx>
32 #include <SMESH_Mesh.hxx>
33 #include <SMESH_MeshAlgos.hxx>
34 #include <SMESH_MeshEditor.hxx>
35 #include <SMESH_MesherHelper.hxx>
36 #include <SMESH_TypeDefs.hxx>
38 #include <BRepAdaptor_Curve.hxx>
39 #include <BRepBuilderAPI_MakeVertex.hxx>
40 #include <BRep_Tool.hxx>
41 #include <Extrema_ExtCC.hxx>
42 #include <Extrema_ExtElC.hxx>
43 #include <Geom_Line.hxx>
44 #include <ShapeAnalysis_Curve.hxx>
45 #include <Geom2d_Line.hxx>
47 // allow range iteration on NCollection_IndexedMap
48 template < class IMAP >
49 typename IMAP::const_iterator begin( const IMAP & m ) { return m.cbegin(); }
50 template < class IMAP >
51 typename IMAP::const_iterator end( const IMAP & m ) { return m.cend(); }
56 //================================================================================
58 * \brief Look for a node coincident with a given nodes among end nodes of a segment
59 * and among its internal nodes
60 * \param [in] p - the epoint
61 * \param [in] tol - 3D tolarace
62 * \param [in] segment - the segment
63 * \param [in] segInternalNodes - map of segment internal nodes
64 * \param [out] index - return index of found internal node; -1 if an end node is found
65 * \return const SMDS_MeshNode* - found node
67 //================================================================================
69 const SMDS_MeshNode* findNode( const gp_Pnt& p,
71 const SMDS_MeshElement* segment,
72 BLSURFPlugin_EnforcedMesh1D::TNodesOnSeg & segInternalNodes,
76 SMESH_NodeXYZ node0 = segment->GetNode(0);
77 if ( p.IsEqual( node0, tol ))
78 return index = -1, node0.Node();
79 SMESH_NodeXYZ node1 = segment->GetNode(1);
80 if ( p.IsEqual( node1, tol ))
81 return index = -1, node1.Node();
83 auto seg2nodes = segInternalNodes.find( segment );
84 if ( seg2nodes != segInternalNodes.end() )
86 const std::vector< const SMDS_MeshNode* >& nodes = seg2nodes->second;
87 for ( size_t i = 0; i < nodes.size(); ++i )
88 if ( p.IsEqual( SMESH_NodeXYZ( nodes[i] ), tol ))
97 //================================================================================
99 * \brief Orient segments to correspond to order of nodes in a branch
100 * \param [in] braSegs - segments of the branch
101 * \param [in] braNodes - nodes of the branch
102 * \param [in] nodeIndex - index of a node of the branch
103 * \param [inout] mesh - mesh holding the nodes and segments
105 //================================================================================
107 void orientSegments( const std::vector< const SMDS_MeshElement* > & braSegs,
108 const std::vector< const SMDS_MeshNode* > & braNodes,
109 const size_t nodeIndex,
112 const SMDS_MeshElement* toReverse[2] = { nullptr, nullptr };
114 if ( nodeIndex > 0 &&
115 braSegs[ nodeIndex - 1 ]->GetNode(1) != braNodes[ nodeIndex ])
116 toReverse[ 0 ] = braSegs[ nodeIndex - 1 ];
118 if ( nodeIndex < braSegs.size() &&
119 braSegs[ nodeIndex ]->GetNode(0) != braNodes[ nodeIndex ])
120 toReverse[ bool( toReverse[0]) ] = braSegs[ nodeIndex ];
125 SMESH_MeshEditor editor( mesh );
126 for ( int i = 0; i < 2; ++i )
128 editor.Reorient( toReverse[ i ]);
133 //================================================================================
135 * \brief Create enforced mesh segments in a mesh
136 * \param [in] helper - contains the mesh and the shape to compute
137 * \param [in] hyp - hypothesis containing data of enforced meshes
139 //================================================================================
141 BLSURFPlugin_EnforcedMesh1D::BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper& helper,
142 const BLSURFPlugin_Hypothesis* hyp )
143 : _mesh ( helper.GetMesh() ),
144 _shape( helper.GetSubShape() ),
146 _isQuadratic( helper.GetIsQuadratic() ),
149 if ( !hyp || !_mesh || hyp->GetEnforcedMeshes().empty() )
152 _tol = 2 * BRep_Tool::MaxTolerance( _shape, TopAbs_VERTEX );
153 _segTag = 1000 + helper.Count( _shape, TopAbs_EDGE, /*ignoreSame=*/false );
155 _nodeTag0 = 1000 + helper.Count( _shape, TopAbs_VERTEX, /*ignoreSame=*/false );
157 for ( const BLSURFPlugin_Hypothesis::EnforcedMesh& enfMesh : hyp->GetEnforcedMeshes() )
159 copyEnforcedMesh( enfMesh, hyp, _shape );
162 for ( const SMDS_MeshElement* segment : _segmentsOnSeveralShapes )
164 splitSegmentOnSeveralShapes( segment );
167 for ( const TopoDS_Shape & face : _faces )
169 splitSelfIntersectingSegments( face );
172 // for ( TEdge2Nodes::Iterator e2nn( _nodesOnEdge ); e2nn.More(); e2nn.Next() )
174 // splitEdgeByNodes( e2nn.Key(), e2nn.Value() );
178 //================================================================================
180 * \brief Convert enforced segments to quadratic
182 //================================================================================
184 BLSURFPlugin_EnforcedMesh1D::~BLSURFPlugin_EnforcedMesh1D()
189 _helper.SetIsQuadratic( true );
191 SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
192 std::vector<const SMDS_MeshNode *> nodes(2);
193 std::vector<const SMDS_MeshElement *> trias;
195 SMDS_MeshGroup* group = nullptr;
196 if ( !_name2Group.empty() )
197 group = _name2Group.begin()->second;
199 for ( const TopoDS_Shape& f : _faces )
200 if ( HasSegmentsOnFace( TopoDS::Face( f )))
201 while ( _segIterator->more() )
203 const SMDS_MeshElement* segment = _segIterator->next();
204 if ( segment->GetType() != SMDSAbs_Edge )
207 nodes[0] = segment->GetNode(0);
208 nodes[1] = segment->GetNode(1);
209 if ( meshDS->GetElementsByNodes( nodes, trias, SMDSAbs_Face ))
211 if ( !group || !group->Contains( segment ))
213 SMDS_MeshGroup* otherGroup = nullptr;
214 if ( _name2Group.size() > bool( group ))
215 for ( auto & n2g : _name2Group )
216 if ( n2g.second != group && n2g.second->Contains( segment ))
218 otherGroup = n2g.second;
224 _helper.AddTLinks( static_cast< const SMDS_MeshFace* >( trias[0] ));
226 meshDS->RemoveFreeElement( segment, meshDS->MeshElements( f ), /*fromGroup=*/false );
228 SMDS_MeshElement* quadSegment = _helper.AddEdge( nodes[0], nodes[1],
229 /*id=*/0, /*force3d=*/false );
230 if ( group && segment != quadSegment )
232 group->Remove( segment );
233 group->Add( quadSegment );
240 //================================================================================
242 * \brief Add a vertex on EDGE
244 //================================================================================
246 void BLSURFPlugin_EnforcedMesh1D::AddVertexOnEdge( const double* theXYZ )
248 // setup predicates to find the supporting EDGE
249 setupPredicates( _shape );
251 SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
252 const SMDS_MeshNode* nodeOnE = meshDS->AddNode( theXYZ[0], theXYZ[1], theXYZ[2] );
254 // check if enfNode is on VERTEX
255 bool toRemove = true;
256 TopoDS_Vertex vertex;
258 if ( _onVertexPredicate->IsSatisfy( nodeOnE, &vertex ))
260 toRemove = SMESH_Algo::VertexNode( vertex, meshDS );
262 meshDS->SetNodeOnVertex( nodeOnE, vertex );
264 // find the EDGE supporting theXYZ
265 else if ( _onEdgePredicate->IsSatisfy( nodeOnE, &edge ))
267 gp_Pnt pnt( theXYZ[0], theXYZ[1], theXYZ[2] );
268 toRemove = findNodeOnEdge( pnt, edge );
270 addNodeOnEdge( nodeOnE, edge );
274 meshDS->RemoveFreeNode( nodeOnE, /*submesh=*/nullptr, /*fromGroup=*/false );
277 //================================================================================
279 * \brief Return EDGEs resulted from division of FACE boundary by enforced segments
280 * and enforced vertices
281 * \param [in] edge - possibly divided EDGE
282 * \param [out] splits - split EDGEs
283 * \return bool - true if the EDGE is split
285 //================================================================================
287 bool BLSURFPlugin_EnforcedMesh1D::GetSplitsOfEdge( const TopoDS_Edge& edge,
288 std::vector< TopoDS_Edge > & splits,
289 TopTools_IndexedMapOfShape & edgeTags )
291 if ( _nodesOnEdge.IsBound( edge )) // divide the EDGE
293 splitEdgeByNodes( edge, _nodesOnEdge( edge ));
295 _nodesOnEdge.UnBind( edge );
300 std::vector< TopoDS_Edge > * splitsInMap = _edgeSplitsOfEdge.ChangeSeek( edge );
304 splits.insert( splits.end(), splitsInMap->begin(), splitsInMap->end() );
306 int eTag = edgeTags.Add( edge );
308 size_t index = splits.size() - 1;
309 for ( size_t i = 0; i < splitsInMap->size(); ++i, --index )
311 int splitTag = edgeTags.Add( splits[ index ]);
312 _splitTags2EdgeTag[ splitTag ] = eTag;
314 if ( edge.Orientation() == TopAbs_REVERSED )
315 splits[ index ].Reverse();
322 //================================================================================
324 * \brief Add 1D elements to the mesh
326 //================================================================================
328 void BLSURFPlugin_EnforcedMesh1D::
330 copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh,
331 const BLSURFPlugin_Hypothesis* theHyp,
332 const TopoDS_Shape& theShape)
335 SMDS_ElemIteratorPtr segIt = theHyp->GetEnforcedSegments( theEnfMesh, mesh1D );
336 if ( !segIt->more() )
337 throw SALOME_Exception("No edges in an enforced mesh");
339 // setup predicates to detect nodes on FACE boundary
340 setupPredicates( theShape );
342 SMDS_MeshGroup* group = getGroup( theEnfMesh._groupName );
343 SMESHDS_Mesh* meshDS = _helper.GetMeshDS();
345 // get ordered nodes and segments of theEnfMesh
346 SMESH_MeshAlgos::TElemGroupVector edgeBranches;
347 SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
348 SMESH_MeshAlgos::Get1DBranches( segIt, edgeBranches, nodeBranches );
351 // Copy nodes and segments from an enforced mesh to my mesh
353 TopoDS_Shape vertex, edge;
355 // first treat ends of branches that can be shared by branches
356 for ( size_t iB = 0; iB < nodeBranches.size(); ++iB )
358 std::vector< const SMDS_MeshNode* > & braNodes = nodeBranches[ iB ];
359 std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ];
361 for ( int isLast = 0; isLast < 2; ++isLast )
363 const SMDS_MeshNode* enfNode = isLast ? braNodes.back() : braNodes[0];
364 if ( meshDS->Contains( enfNode ))
365 continue; // already in my mesh
367 const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode );
369 orientSegments( braSegs, braNodes, isLast ? 0 : braNodes.size() - 1, mesh1D );
371 // replace enfNode at branch ends by newNode
372 SMESH_NodeXYZ enfPnt( newNode ? newNode : enfNode );
373 for ( std::vector< const SMDS_MeshNode* > & braNodes : nodeBranches )
375 for ( int isLast = 0; isLast < 2; ++isLast )
377 const SMDS_MeshNode* & endNode = isLast ? braNodes.back() : braNodes[0];
378 if ( endNode == enfNode || enfPnt.SquareDistance( endNode ) < _tol*_tol )
383 } // loop on branch ends
384 } // loop on nodeBranches
386 // copy nodes and segments
388 for ( size_t iB = 0; iB < nodeBranches.size(); ++iB )
390 std::vector< const SMDS_MeshNode* > & braNodes = nodeBranches[ iB ];
391 std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ];
393 // copy nodes of the branch
394 for ( size_t i = 0; i < braNodes.size(); ++i )
396 const SMDS_MeshNode* & enfNode = braNodes[ i ];
397 const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode );
399 if ( !newNode ) // orient segments to be able to get enforced not projected node
400 orientSegments( braSegs, braNodes, i, mesh1D );
405 // copy segments of the branch
406 for ( size_t i = 0; i < braSegs.size(); ++i )
408 //braSegs[ i ] = nullptr;
410 const SMDS_MeshNode* node0 = braNodes[ i ];
411 const SMDS_MeshNode* node1 = braNodes[ i + 1 ];
412 if ( !node0 && !node1 )
415 TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS );
416 TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS );
417 if ( shape0.IsNull() && shape1.IsNull() )
420 if ( !node0 && shape1.ShapeType() != TopAbs_FACE )
422 if ( !node1 && shape0.ShapeType() != TopAbs_FACE )
425 if ( !node0 || !node1 ) // create missing node at location of enforced node projected nowhere
427 SMESH_NodeXYZ pn = braSegs[i]->GetNode( !node1 );
428 ( node0 ? node1 : node0 ) = _helper.AddNode( pn->X(), pn->Y(), pn->Z() );
431 SMDS_MeshEdge* newSeg = _helper.AddEdge( node0, node1 );
433 group->Add( newSeg );
434 braSegs[ i ] = newSeg;
436 // check if the both nodes are on the same FACE
437 TopoDS_Shape face = shape0;
438 if ( !shape0.IsSame( shape1 ) && !shape0.IsNull() && !shape1.IsNull() )
440 if ( shape0.ShapeType() == TopAbs_FACE &&
441 _helper.IsSubShape( shape1, shape0 ))
445 else if ( shape1.ShapeType() == TopAbs_FACE &&
446 _helper.IsSubShape( shape0, shape1 ))
450 else // try to find a FACE by projecting a segment middle point
453 gp_Pnt middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 ));
454 //BLSURFPlugin_BLSURF::projectionPoint projPnt =
455 BLSURFPlugin_BLSURF::getProjectionPoint( TopoDS::Face( face ), middlePnt );
457 if ( !face.IsNull() &&
458 ( !_helper.IsSubShape( shape0, face ) ||
459 !_helper.IsSubShape( shape1, face ) ))
463 if ( !face.IsNull() && face.ShapeType() == TopAbs_FACE )
465 meshDS->SetMeshElementOnShape( newSeg, face );
469 if ( face.IsNull() || shape0.IsNull() || shape1.IsNull() )
471 _segmentsOnSeveralShapes.push_back( newSeg );
474 } // loop on branch segments
476 } // loop on branches
481 //================================================================================
483 * \brief Create a copy of a node of enforced mesh in my mesh
484 * \param [in] enfNode - enforced node
485 * \return const SMDS_MeshNode* - a node in my mesh
487 //================================================================================
489 const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::copyEnforcedNode( const SMDS_MeshNode* enfNode )
491 SMESHDS_Mesh * meshDS = _helper.GetMeshDS();
493 if ( !enfNode || meshDS->Contains( enfNode ))
494 return enfNode; // already in my mesh
496 SMESH_NodeXYZ enfPnt = enfNode;
498 const SMDS_MeshNode* newNode = nullptr;
500 // check if enfNode is on VERTEX
501 TopoDS_Vertex vertex;
502 if ( _onVertexPredicate->IsSatisfy( enfNode, &vertex ))
504 _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
505 newNode = SMESH_Algo::VertexNode( vertex, meshDS );
508 // check if enfNode is on EDGE
509 bool setNodeOnEdge = false;
513 setNodeOnEdge = _onEdgePredicate->IsSatisfy( enfNode, &edge );
516 newNode = findNodeOnEdge( enfPnt, edge );
517 setNodeOnEdge = !newNode;
521 // create a new node and set it on FACE
525 BLSURFPlugin_BLSURF::projectionPoint projPnt =
526 BLSURFPlugin_BLSURF::getProjectionPoint( face, enfPnt, /*allowStateON=*/true );
527 if ( face.IsNull() ) return newNode;
529 if ( projPnt.state == TopAbs_ON )
531 SMDS_MeshNode* projNode = const_cast< SMDS_MeshNode* >( enfNode );
532 projNode->setXYZ( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() );
535 if ( _onVertexPredicate->IsSatisfy( projNode, &vertex ))
537 _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
538 newNode = SMESH_Algo::VertexNode( vertex, meshDS );
540 else if (( setNodeOnEdge = _onEdgePredicate->IsSatisfy( projNode, &edge )))
542 newNode = findNodeOnEdge( projPnt.xyz, edge );
543 setNodeOnEdge = !newNode;
545 projNode->setXYZ( enfPnt.X(), enfPnt.Y(), enfPnt.Z() );
549 newNode = meshDS->AddNode( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() );
551 if ( vertex.IsNull() && edge.IsNull() )
552 meshDS->SetNodeOnFace( newNode, face, projPnt.uv.X(), projPnt.uv.Y() );
555 // set the new node on EDGE
556 if ( newNode && setNodeOnEdge )
558 addNodeOnEdge( newNode, edge );
564 //================================================================================
566 * \brief Split a segment whose nodes are on different FACEs into smaller parts
567 * lying each on one FACE
569 //================================================================================
571 void BLSURFPlugin_EnforcedMesh1D::splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment )
573 const SMDS_MeshNode* node0 = segment->GetNode(0);
574 const SMDS_MeshNode* node1 = segment->GetNode(1);
575 SMESHDS_Mesh * meshDS = _helper.GetMeshDS();
577 TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS );
578 TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS );
580 if ( shape0.IsNull() )
582 std::swap( node0, node1 );
587 gp_XYZ xyz0 = SMESH_NodeXYZ( node0 );
588 gp_XYZ xyz1 = SMESH_NodeXYZ( node1 );
589 gp_XYZ segDir = ( xyz1 - xyz0 ).Normalized();
591 //std::map< double, const SMDS_MeshNode* > mediumNodes; // nodes splitting the segment
593 while ( !shape0.IsSame( shape1 )) // move along the segment till shape1
595 if ( shape0.ShapeType() == TopAbs_FACE ) // make a node on an EDGE of the FACE
596 { // ----------------------------------
599 gp_Pnt edgeIntPnt = getEdgeIntersection( shape0, xyz0, xyz1, edge, paramOnE );
603 // check if edgeIntPnt in on VERTEX
604 TopoDS_Vertex vertex;
605 for ( int iV = 0; iV < 2 && vertex.IsNull(); ++iV )
607 TopoDS_Vertex v = _helper.IthVertex( iV, edge );
608 if ( edgeIntPnt.SquareDistance( BRep_Tool::Pnt( v )) < _tol *_tol )
612 // make a node on the EDGE
613 const SMDS_MeshNode* nodeOnEdge = nullptr;
614 if ( vertex.IsNull() )
616 nodeOnEdge = findNodeOnEdge( edgeIntPnt, edge );
619 if ( shape1.IsNull() && node1 )
623 meshDS->MoveNode( nodeOnEdge, edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() );
627 nodeOnEdge = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() );
629 addNodeOnEdge( nodeOnEdge, edge, paramOnE );
634 _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
635 nodeOnEdge = SMESH_Algo::VertexNode( vertex, meshDS );
638 // create a sub-segment
639 SMDS_MeshElement* newSeg = _helper.AddEdge( node0, nodeOnEdge );
640 meshDS->SetMeshElementOnShape( newSeg, shape0 );
642 SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS );
645 xyz0 = SMESH_NodeXYZ( node0 );
646 if ( vertex.IsNull() )
652 else // shape0 is EDGE or VERTEX; look for the next FACE
653 { // ------------------------------------------------
655 if ( !shape1.IsNull() &&
656 shape1.ShapeType() == TopAbs_FACE &&
657 _helper.IsSubShape( shape0, shape1 )) // shape0 belongs to FACE shape1
659 SMDS_MeshElement* newSeg = _helper.AddEdge( node0, node1 );
660 SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS );
661 meshDS->SetMeshElementOnShape( newSeg, shape1 );
666 double shift = 10 * _tol;
667 for ( int nbAttemp = 0; face.IsNull() && nbAttemp < 10; ++nbAttemp )
669 xyz0 += segDir * shift;
671 BLSURFPlugin_BLSURF::getProjectionPoint( face, xyz0 );
673 if ( !face.IsNull() )
675 if ( _helper.IsSubShape( shape0, face ))
687 } //while ( !shape0.IsSame( shape1 ))
689 meshDS->RemoveFreeElement( segment, /*submesh=*/nullptr );
692 //================================================================================
694 * \brief Find intersection of FACE EDGEs and a segment
695 * \param [in] theFace - the FACE
696 * \param [in] thePnt0 - first end of the segment
697 * \param [in] thePnt1 - last end of the segment
698 * \param [out] theFounfEdge - return the intersected EDGE
699 * \param [out] theParamOnEdge - return parameter of intersection point on EDGE
700 * \return gp_XYZ - point on an EDGE closest to the segment
702 //================================================================================
704 gp_Pnt BLSURFPlugin_EnforcedMesh1D::getEdgeIntersection( const TopoDS_Shape& theFaceOrEdge,
705 const gp_XYZ& thePnt0,
706 const gp_XYZ& thePnt1,
707 TopoDS_Edge & theFounfEdge,
708 double & theParamOnEdge)
710 const double segLen = ( thePnt1 - thePnt0 ).Modulus();
711 const double maxSegDist2 = segLen * segLen * 0.5 * 0.5;
713 Handle(Geom_Line) segLine = new Geom_Line( thePnt0, thePnt1 - thePnt0 );
714 GeomAdaptor_Curve segLineAdpt( segLine, 0, segLen );
716 TopTools_MapOfShape edges;
717 double minParamOnSeg = segLen;
719 for ( TopExp_Explorer edgeExp( theFaceOrEdge, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
721 const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() );
722 if ( !edges.Add( edge ))
725 Extrema_ExtCC extrema( segLineAdpt, BRepAdaptor_Curve( edge ), _tol, _tol );
727 if ( extrema.IsDone() && !extrema.IsParallel() )
728 for ( int i = 1, nb = extrema.NbExt(); i <= nb; ++i )
729 if ( extrema.SquareDistance( i ) < maxSegDist2 )
731 Extrema_POnCurv pOnSeg, pOnEdge;
732 extrema.Points( i, pOnSeg, pOnEdge );
733 double paramOnSeg = pOnSeg.Parameter();
734 if ( 0 < paramOnSeg && paramOnSeg < minParamOnSeg )
736 minParamOnSeg = paramOnSeg;
737 foundPnt = pOnEdge.Value();
739 theParamOnEdge = pOnEdge.Parameter();
746 //================================================================================
748 * \brief Split self-intersecting segments on a given FACE
750 //================================================================================
752 void BLSURFPlugin_EnforcedMesh1D::splitSelfIntersectingSegments( const TopoDS_Shape & theFace )
754 const TopoDS_Face& face = TopoDS::Face( theFace );
756 SMESHDS_Mesh* meshDS = _helper.GetMeshDS();
757 SMESHDS_SubMesh* sm = meshDS->MeshElements( face );
758 if ( !sm || sm->NbElements() <= 1 )
761 // get ordered nodes and segments on the face
762 SMESH_MeshAlgos::TElemGroupVector edgeBranches;
763 SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
764 SMESH_MeshAlgos::Get1DBranches( sm->GetElements(), edgeBranches, nodeBranches );
766 // create element searcher
767 SMESH_ElementSearcher* elemSearcher;
768 SMESHUtils::Deleter< SMESH_ElementSearcher > elSearchdeleter;
769 std::vector< const SMDS_MeshElement* > foundElems;
771 std::vector< SMDS_ElemIteratorPtr > elemItVec;
772 for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches )
774 SMDS_ElemIteratorPtr segIt =
775 boost::make_shared< SMDS_ElementVectorIterator >( braSegs.begin(), braSegs.end() );
776 elemItVec.push_back( segIt );
778 typedef SMDS_IteratorOnIterators< const SMDS_MeshElement*,
779 std::vector< SMDS_ElemIteratorPtr > > TVecIterator;
780 SMDS_ElemIteratorPtr segIt = boost::make_shared< TVecIterator >( elemItVec );
782 elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS, segIt, _tol );
783 elSearchdeleter._obj = elemSearcher;
785 // force usage of iterators before they die
786 elemSearcher->FindElementsByPoint( gp_Pnt( 0,0,1e+20), SMDSAbs_Edge, foundElems );
790 // Find intersecting segments
792 std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > segInternalNodes;
793 SMESH_MeshEditor::TListOfListOfNodes nodeGroupsToMerge;
795 for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches )
797 braSegs.push_back( braSegs.back() );
798 const SMDS_MeshElement* prevSeg = nullptr;
800 for ( size_t i = 0, nb = braSegs.size() - 1; i < nb; ++i )
802 const SMDS_MeshElement* seg = braSegs[ i ];
803 const SMDS_MeshElement* nextSeg = braSegs[ i + 1 ];
804 const SMDS_MeshNode* node0 = seg->GetNode(0);
805 const SMDS_MeshNode* node1 = seg->GetNode(1);
807 gp_XYZ xyz0 = SMESH_NodeXYZ( node0 );
808 gp_XYZ xyz1 = SMESH_NodeXYZ( node1 );
809 gp_XYZ middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 ));
810 double segLen = ( xyz0 - xyz1 ).Modulus();
813 elemSearcher->GetElementsInSphere( middlePnt, 0.5 * segLen + _tol, SMDSAbs_Edge, foundElems );
815 for ( const SMDS_MeshElement* closeSeg : foundElems )
817 if ( closeSeg == prevSeg ||
819 closeSeg == nextSeg )
824 if ( intersectSegments( seg, closeSeg, face, intPnt, uv ))
827 const SMDS_MeshNode* intNode0 = findNode( intPnt, _tol, seg, segInternalNodes, i0 );
828 const SMDS_MeshNode* intNode1 = findNode( intPnt, _tol, closeSeg, segInternalNodes, i1 );
829 if ( !intNode0 && intNode1 )
831 segInternalNodes[ seg ].push_back( intNode1 );
833 else if ( !intNode1 && intNode0 )
835 segInternalNodes[ closeSeg ].push_back( intNode0 );
837 else if ( intNode1 && intNode0 )
839 if ( intNode1 == intNode0 )
841 if ( i0 < 0 && i1 < 0 )
843 nodeGroupsToMerge.push_back // merge end nodes
844 ( std::list< const SMDS_MeshNode* >({ intNode0, intNode1 }));
848 segInternalNodes[ closeSeg ][ i1 ] = intNode0;
852 segInternalNodes[ seg ][ i0 ] = intNode1;
854 else // two internal nodes coincide
856 segInternalNodes[ seg ][ i0 ] = intNode1;
857 nodeGroupsToMerge.push_back
858 ( std::list< const SMDS_MeshNode* >({ intNode1, intNode0 }));
861 else // ( !intNode1 && !intNode0 )
863 intNode0 = _helper.AddNode( intPnt.X(), intPnt.Y(), intPnt.Z() );
864 meshDS->SetNodeOnFace( intNode0, face, uv.X(), uv.Y() );
865 segInternalNodes[ seg ].push_back( intNode0 );
866 segInternalNodes[ closeSeg ].push_back( intNode0 );
873 } // loop on segments of a branch
874 } // loop on branches
877 findIntersectionWithSeamEdge( face, segInternalNodes ); // on periodic FACE
882 for ( auto& seg2nodes : segInternalNodes )
884 const SMDS_MeshElement* seg = seg2nodes.first;
885 std::vector< const SMDS_MeshNode* > & nodes = seg2nodes.second;
886 if ( nodes.empty() ) continue;
888 const SMDS_MeshNode* n0 = seg->GetNode( 0 );
889 const SMDS_MeshNode* n1 = seg->GetNode( 1 );
890 nodes.push_back( n1 );
892 // sort nodes on the segment
893 gp_Pnt p0 = SMESH_NodeXYZ( n0 );
894 std::map< double, const SMDS_MeshNode* > sortedNodes;
895 for ( SMESH_NodeXYZ pn : nodes )
896 sortedNodes.insert({ p0.SquareDistance( pn ), pn.Node() });
899 for ( auto & d2n : sortedNodes )
902 SMDS_MeshElement* newSeg = _helper.AddEdge( n0, n1 );
904 meshDS->SetMeshElementOnShape( newSeg, face );
905 SMESH_MeshEditor::AddToSameGroups( newSeg, seg, meshDS );
907 meshDS->RemoveFreeElement( seg, /*submesh=*/nullptr );
912 SMESH_MeshEditor( _mesh ).MergeNodes( nodeGroupsToMerge );
915 //================================================================================
917 * \brief Find intersections of segments with a seam EDGE on a periodic FACE
919 //================================================================================
921 void BLSURFPlugin_EnforcedMesh1D::findIntersectionWithSeamEdge( const TopoDS_Face & face,
922 TNodesOnSeg & segInternalNodes )
924 _helper.SetSubShape( face );
925 if ( !_helper.HasSeam() )
928 SMESHDS_Mesh* meshDS = _helper.GetMeshDS();
929 SMESHDS_SubMesh* sm = meshDS->MeshElements( face );
930 if ( !sm || sm->NbElements() == 0 )
933 TopTools_MapOfShape treatedEdges;
934 for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
936 const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() );
937 if ( !_helper.IsSeamShape( edge ) || !treatedEdges.Add( edge ))
940 for ( SMDS_ElemIteratorPtr setIt = sm->GetElements(); setIt->more(); )
942 const SMDS_MeshElement* segment = setIt->next();
943 const SMESH_NodeXYZ pn0 = segment->GetNode( 0 );
944 const SMESH_NodeXYZ pn1 = segment->GetNode( 1 );
946 gp_XY uv0 = _helper.GetNodeUV( face, pn0.Node() );
947 gp_XY uv1 = _helper.GetNodeUV( face, pn1.Node() );
949 for ( int iCoo = 1; iCoo <= 2; ++iCoo )
950 if ( iCoo & _helper.GetPeriodicIndex() )
952 double distParam = Abs( uv0.Coord( iCoo ) - uv1.Coord( iCoo ));
953 if ( distParam > 0.5 * _helper.GetPeriod( iCoo ))
955 double paramOnE; TopoDS_Edge edge2;
956 gp_Pnt edgeIntPnt = getEdgeIntersection( edge, pn0, pn1, edge2, paramOnE );
957 if ( edge2.IsNull() )
960 const SMDS_MeshNode* nodeOnSeam = findNodeOnEdge( edgeIntPnt, edge );
961 bool isOnEdge = nodeOnSeam;
963 int indexOnSegment = 3;
965 nodeOnSeam = findNode( edgeIntPnt, _tol, segment, segInternalNodes, indexOnSegment );
969 nodeOnSeam = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() );
974 addNodeOnEdge( nodeOnSeam, edge, paramOnE );
976 if ( indexOnSegment == 3 )
977 segInternalNodes[ segment ].push_back( nodeOnSeam );
984 //================================================================================
986 * \brief Intersect two segments
987 * \param [in] seg1 - segment 1
988 * \param [in] seg2 - segment 2
989 * \param [in] face - the FACE on which segments lie
990 * \param [out] intPnt - intersection point
991 * \param [out] intUV - UV of intersection point on the FACE
992 * \return bool - true if intersection found
994 //================================================================================
996 bool BLSURFPlugin_EnforcedMesh1D::intersectSegments( const SMDS_MeshElement* seg1,
997 const SMDS_MeshElement* seg2,
998 const TopoDS_Face& face,
1000 gp_Pnt2d & intUV ) const
1002 SMESH_NodeXYZ n10 = seg1->GetNode(0);
1003 SMESH_NodeXYZ n11 = seg1->GetNode(1);
1004 SMESH_NodeXYZ n20 = seg2->GetNode(0);
1005 SMESH_NodeXYZ n21 = seg2->GetNode(1);
1006 if ( n10 == n20 || n10 == n21 || n11 == n20 || n10 == n21 )
1009 gp_Lin lin1( n10, n11 - n10 );
1010 gp_Lin lin2( n20, n21 - n20 );
1012 Extrema_ExtElC extrema( lin1, lin2, Precision::Angular() );
1014 if ( !extrema.IsDone() || extrema.IsParallel() )
1017 Extrema_POnCurv poc1, poc2;
1018 extrema.Points( 1, poc1, poc2 );
1020 double len1 = lin1.Direction().XYZ() * ( n11 - n10 );
1021 double len2 = lin2.Direction().XYZ() * ( n21 - n20 );
1022 double u1 = poc1.Parameter();
1023 double u2 = poc2.Parameter();
1025 if ( u1 < -_tol || u1 > len1 + _tol )
1027 if ( u2 < -_tol || u2 > len2 + _tol )
1030 intPnt = 0.5 * ( poc1.Value().XYZ() + poc2.Value().XYZ() );
1032 // compute approximate UV
1037 gp_XY uv10 = _helper.GetNodeUV( face, n10.Node(), n11.Node() );
1038 gp_XY uv11 = _helper.GetNodeUV( face, n11.Node(), n10.Node() );
1039 gp_XY uv1 = uv10 * ( 1 - u1 ) + uv11 * u1;
1041 gp_XY uv20 = _helper.GetNodeUV( face, n20.Node(), n21.Node() );
1042 gp_XY uv21 = _helper.GetNodeUV( face, n21.Node(), n20.Node() );
1043 gp_XY uv2 = uv20 * ( 1 - u2 ) + uv21 * u2;
1045 intUV = 0.5 * ( uv1 + uv2 );
1047 // compute precise UV and XYZ by projecting intPnt to the FACE
1049 Handle(ShapeAnalysis_Surface) surface = _helper.GetSurface( face );
1050 intUV = surface->NextValueOfUV( intUV, intPnt, _tol );
1051 if ( surface->Gap() > Min( len1, len2 ))
1052 intUV = surface->ValueOfUV( intPnt, _tol );
1054 intPnt = surface->Value( intUV );
1059 //================================================================================
1061 * \brief Setup predicates to detect nodes on FACE boundary
1062 * \param [in] shape - shape containing FACEs to mesh
1064 //================================================================================
1066 void BLSURFPlugin_EnforcedMesh1D::setupPredicates( const TopoDS_Shape& theShape )
1068 if ( _onVertexPredicate )
1071 _onVertexPredicate.reset( new TPredicate() );
1072 _onVertexPredicate->SetTolerance( _tol );
1073 _onVertexPredicate->SetMesh( _helper.GetMeshDS() );
1075 TopTools_IndexedMapOfShape vertices;
1076 TopExp::MapShapes( theShape, TopAbs_VERTEX, vertices );
1077 TopoDS_Compound vCompound;
1078 BRep_Builder builder;
1079 builder.MakeCompound( vCompound );
1080 for ( const TopoDS_Shape& v : vertices )
1081 builder.Add( vCompound, v );
1083 _onVertexPredicate->SetShape( vCompound, SMDSAbs_Node );
1087 _onEdgePredicate.reset( new TPredicate() );
1088 _onEdgePredicate->SetTolerance( _tol );
1089 _onEdgePredicate->SetMesh( _helper.GetMeshDS() );
1091 TopTools_IndexedMapOfShape edges;
1092 TopExp::MapShapes( theShape, TopAbs_EDGE, edges );
1093 TopoDS_Compound eCompound;
1094 BRep_Builder builder;
1095 builder.MakeCompound( eCompound );
1096 for ( const TopoDS_Shape& e : edges )
1097 builder.Add( eCompound, e );
1099 _onEdgePredicate->SetShape( eCompound, SMDSAbs_Node );
1104 //================================================================================
1106 * \brief Find or create a group of edges with given name
1108 //================================================================================
1110 SMDS_MeshGroup* BLSURFPlugin_EnforcedMesh1D::getGroup( const std::string& groupName )
1112 SMDS_MeshGroup* group = nullptr;
1113 if ( !groupName.empty() )
1115 if ( _name2Group.count( groupName ))
1116 return _name2Group[ groupName ];
1118 // find existing group
1119 for ( SMESH_Mesh::GroupIteratorPtr grIt = _mesh->GetGroups(); grIt->more(); )
1121 SMESH_Group* grp = grIt->next();
1122 SMESHDS_Group* grpDS = dynamic_cast< SMESHDS_Group* >( grp->GetGroupDS() );
1124 grpDS->GetType() == SMDSAbs_Edge &&
1125 groupName == grp->GetName() )
1127 _name2Group[ groupName ] = & grpDS->SMDSGroup();
1128 return & grpDS->SMDSGroup();
1132 // create a new group
1133 SMESH_Group* grp = _mesh->AddGroup( SMDSAbs_Edge, groupName.c_str() );
1134 SMESHDS_Group* grpDS = static_cast< SMESHDS_Group* >( grp->GetGroupDS() );
1136 group = & grpDS->SMDSGroup();
1137 _name2Group[ groupName ] = group;
1142 //================================================================================
1144 * \brief Look for a node dividing a given EDGE
1146 //================================================================================
1148 const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::findNodeOnEdge( const gp_Pnt& p,
1149 const TopoDS_Edge& edge )
1151 // look for an equal node on the EDGE
1152 if ( std::vector< const SMDS_MeshNode* >* nodesOnE = _nodesOnEdge.ChangeSeek( edge ))
1153 for ( const SMDS_MeshNode* n : *nodesOnE )
1154 if ( p.SquareDistance( SMESH_NodeXYZ( n )) < _tol * _tol )
1162 //================================================================================
1164 * \brief Add a node to an EDGE
1166 //================================================================================
1168 void BLSURFPlugin_EnforcedMesh1D::addNodeOnEdge( const SMDS_MeshNode* node,
1169 const TopoDS_Edge& edge,
1172 _mesh->GetMeshDS()->SetNodeOnEdge( node, edge, u );
1174 std::vector< const SMDS_MeshNode* > * nodesOnE = _nodesOnEdge.ChangeSeek( edge );
1176 nodesOnE = _nodesOnEdge.Bound( edge, std::vector< const SMDS_MeshNode* >() );
1178 nodesOnE->push_back( node );
1181 //================================================================================
1183 * \brief Create EDGEs by dividing a given EDGE by nodes on it
1184 * \param [in] edge - the EDGE to divide
1185 * \param [in] nodes - the nodes to divide by
1187 //================================================================================
1189 void BLSURFPlugin_EnforcedMesh1D::
1191 splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes )
1193 if ( nodes.empty() )
1196 edge.Orientation( TopAbs_FORWARD );
1198 TopoDS_Vertex v0 = _helper.IthVertex( 0, edge );
1199 TopoDS_Vertex v1 = _helper.IthVertex( 1, edge );
1201 // create VERTEXes and sort them along the EDGE
1203 std::map< double, TopoDS_Vertex > sortedVertices;
1205 BRepAdaptor_Curve curve( edge );
1206 for ( SMESH_NodeXYZ pn : nodes )
1210 ShapeAnalysis_Curve().Project( curve, pn, _tol, projPnt, u, false );
1211 projPnt = curve.Value( u );
1213 TopoDS_Vertex v = BRepBuilderAPI_MakeVertex( projPnt );
1215 sortedVertices.insert({ u, v });
1217 _nOnE2Vertex[ pn.Node() ] = v;
1219 sortedVertices.insert({ BRep_Tool::Parameter( v1, edge ), v1 });
1224 BRep_Builder builder;
1225 std::vector< TopoDS_Edge >& newEdges = *_edgeSplitsOfEdge.Bound( edge, TEdge2Edges::value_type());
1227 double u0 = BRep_Tool::Parameter( v0, edge );
1228 for ( auto& u2v : sortedVertices )
1230 double u1 = u2v.first;
1233 TopoDS_Shape newShape = edge.EmptyCopied();
1234 TopoDS_Edge newEdge = TopoDS::Edge( newShape );
1235 builder.Add( newEdge, v0 );
1236 builder.Add( newEdge, v1 );
1237 builder.Range( newEdge, u0, u1 );
1238 newEdges.push_back( newEdge );
1247 //================================================================================
1249 * \brief Return true if there are enforced segments on a FACE. Start iteration on segments
1251 //================================================================================
1253 bool BLSURFPlugin_EnforcedMesh1D::HasSegmentsOnFace( const TopoDS_Face& face )
1255 _segIterator.reset();
1257 if ( _faces.Contains( face ))
1259 _currentFace = face;
1260 _segIterator = _helper.GetMeshDS()->MeshElements( face )->GetElements();
1262 _helper.SetSubShape( face );
1264 return _segIterator->more();
1270 //================================================================================
1272 * \brief Return next segment on the FACE
1274 //================================================================================
1276 bool BLSURFPlugin_EnforcedMesh1D::NextSegment( Segmemnt & seg,
1277 TopTools_IndexedMapOfShape & vertexTags )
1279 if ( _segIterator && _segIterator->more() )
1281 const SMDS_MeshElement* segment = _segIterator->next();
1283 while ( segment->GetType() != SMDSAbs_Edge && _segIterator->more() )
1284 segment = _segIterator->next();
1285 if ( segment->GetType() != SMDSAbs_Edge )
1288 const SMDS_MeshNode * node[2] = { segment->GetNode(0),
1289 segment->GetNode(1) };
1291 seg._tag = _segTag++;
1293 seg._xyz[0] = SMESH_NodeXYZ( node[0]);
1294 seg._xyz[1] = SMESH_NodeXYZ( node[1]);
1296 seg._uv[0] = _helper.GetNodeUV( _currentFace, node[0], node[1] );
1297 seg._uv[1] = _helper.GetNodeUV( _currentFace, node[1], node[0] );
1299 seg._pcurve = new Geom2d_Line( seg._uv[0], ( seg._uv[1] - seg._uv[0] ));
1302 seg._u[1] = ( seg._uv[1] - seg._uv[0] ).Modulus();
1304 for ( int i = 0; i < 2; ++i )
1306 auto n2v = _nOnE2Vertex.find( node[i] ); // find VERTEX by node
1308 if ( n2v != _nOnE2Vertex.end() )
1309 seg._vTag[i] = vertexTags.Add( n2v->second );
1311 seg._vTag[i] = _nodeTag0 + _nodeTags.Add( node[i] );
1314 if ( !_isQuadratic )
1315 _mesh->GetMeshDS()->UnSetMeshElementOnShape( segment, _currentFace );
1322 //================================================================================
1324 * \brief Return enforced node by the tag that was returned by Segmemnt::_vTag[i]
1326 //================================================================================
1328 const SMDS_MeshNode*
1329 BLSURFPlugin_EnforcedMesh1D::GetNodeByTag( int tag,
1330 const TopTools_IndexedMapOfShape & vertexTags )
1332 const SMDS_MeshNode* node = nullptr;
1334 if ( tag <= vertexTags.Size() && !_nOnE2Vertex.empty() )
1336 const TopoDS_Shape& vertex = vertexTags( tag );
1338 for ( auto n2v = _nOnE2Vertex.begin(); n2v != _nOnE2Vertex.end(); ++n2v )
1339 if ( vertex.IsSame( n2v->second ))
1342 _nOnE2Vertex.erase( n2v );
1349 bool isValid = ( 0 < tag && tag <= _nodeTags.Size() );
1351 node = _nodeTags( tag );
1356 //================================================================================
1358 * \brief Return true if a tag corresponds to the tag of enforced segment
1359 * that was returned by Segment::_tag
1361 //================================================================================
1363 bool BLSURFPlugin_EnforcedMesh1D::IsSegmentTag( int tag ) const
1365 return ( _segTag0 <= tag && tag <= _segTag );
1368 //================================================================================
1370 * \brief Return tag of EDGE by tags of its splits
1372 //================================================================================
1374 int BLSURFPlugin_EnforcedMesh1D::GetTagOfSplitEdge( int splitTag ) const
1376 auto sTag2eTag = _splitTags2EdgeTag.find( splitTag );
1377 return ( sTag2eTag == _splitTags2EdgeTag.end() ) ? splitTag : sTag2eTag->second;