1 // Copyright (C) 2018 OPEN CASCADE
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 : SMESH_Slot.cxx
20 // Created : Fri Nov 30 15:58:37 2018
21 // Author : Edward AGAPOV (eap)
23 #include "SMESH_MeshAlgos.hxx"
25 #include "ObjectPool.hxx"
26 #include "SMDS_LinearEdge.hxx"
27 #include "SMDS_Mesh.hxx"
29 #include <IntAna_IntConicQuad.hxx>
30 #include <IntAna_Quadric.hxx>
31 #include <NCollection_DataMap.hxx>
32 #include <NCollection_Map.hxx>
33 #include <Precision.hxx>
35 #include <gp_Cylinder.hxx>
42 #include <Utils_SALOME_Exception.hxx>
44 #include <boost/container/flat_set.hpp>
48 typedef SMESH_MeshAlgos::Edge TEdge;
50 //================================================================================
51 //! point of intersection of a face edge with the cylinder
54 SMESH_NodeXYZ myNode; // point and a node
55 int myEdgeIndex; // face edge index
56 bool myIsOutPln[2]; // isOut of two planes
59 //================================================================================
63 typedef boost::container::flat_set< const SMDS_MeshNode* > TNodeSet;
64 //typedef std::list< TEdge > TEdgeList;
66 const SMDS_MeshElement* myEdge;
67 TNodeSet myEndNodes; // ends of cut edges
68 //TEdgeList myCutEdges[2];
72 gp_Ax1 Ax1( bool reversed = false ) const
74 SMESH_NodeXYZ n1 = myEdge->GetNode( reversed );
75 SMESH_NodeXYZ n2 = myEdge->GetNode( !reversed );
76 return gp_Ax1( n1, gp_Dir( n2 - n1 ));
79 const SMDS_MeshNode* Node(int i) const
81 return myEdge->GetNode( i % 2 );
83 // store an intersection edge forming the slot border
84 void AddEdge( TEdge& e, double tol )
86 const SMDS_MeshNode** nodes = & e._node1;
87 for ( int i = 0; i < 2; ++i )
89 std::pair< TNodeSet::iterator, bool > nItAdded = myEndNodes.insert( nodes[ i ]);
90 if ( !nItAdded.second )
91 myEndNodes.erase( nItAdded.first );
95 // int i = myCutEdges[0].empty() ? 0 : 1;
96 // std::insert_iterator< TEdgeList > where = inserter( myCutEdges[i], myCutEdges[i].begin() );
98 // //double minDist = 1e100;
99 // SMESH_NodeXYZ nNew[2] = { e._node1, e._node2 };
100 // int iNewMin = 0, iCurMin = 1;
101 // for ( i = 0; i < 2; ++i )
103 // if ( myCutEdges[i].empty() )
105 // SMESH_NodeXYZ nCur[2] = { myCutEdges[i].front()._node1,
106 // myCutEdges[i].back()._node2 };
107 // for ( int iN = 0; iN < 2; ++iN )
108 // for ( int iC = 0; iC < 2; ++iC )
110 // if (( nCur[iC].Node() && nCur[iC] == nNew[iN] ) ||
111 // ( nCur[iC] - nNew[iN] ).SquareModulus() < tol * tol )
113 // where = inserter( myCutEdges[i], iC ? myCutEdges[i].end() : myCutEdges[i].begin() );
122 // if ( iNewMin == iCurMin )
123 // std::swap( e._node1, e._node2 );
127 Segment( const SMDS_MeshElement* e = 0 ): myEdge(e) { myEndNodes.reserve( 4 ); }
129 typedef ObjectPoolIterator<Segment> TSegmentIterator;
132 //================================================================================
134 * \brief Intersect a face edge given by its nodes with a cylinder.
136 //================================================================================
138 void intersectEdge( const gp_Cylinder& cyl,
139 const SMESH_NodeXYZ& n1,
140 const SMESH_NodeXYZ& n2,
142 std::vector< IntPoint >& intPoints )
144 gp_Lin line( gp_Ax1( n1, gp_Dir( n2 - n1 )));
145 IntAna_IntConicQuad intersection( line, IntAna_Quadric( cyl ));
147 if ( !intersection.IsDone() ||
148 intersection.IsParallel() ||
149 intersection.IsInQuadric() ||
150 intersection.NbPoints() == 0 )
153 gp_Vec edge( n1, n2 );
155 size_t oldNbPnts = intPoints.size();
156 for ( int iP = 1; iP <= intersection.NbPoints(); ++iP )
158 const gp_Pnt& p = intersection.Point( iP );
160 gp_Vec n1p ( n1, p );
161 const SMDS_MeshNode* n = 0;
163 double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
165 if ( p.SquareDistance( n1 ) < tol * tol )
170 else if ( u >= 1. ) {
171 if ( p.SquareDistance( n2 ) < tol * tol )
177 if ( p.SquareDistance( n1 ) < tol * tol )
179 else if ( p.SquareDistance( n2 ) < tol * tol )
183 intPoints.push_back( IntPoint() );
185 intPoints.back().myNode.Set( n );
187 intPoints.back().myNode.SetCoord( p.X(),p.Y(),p.Z() );
190 // set points order along an edge
191 if ( intPoints.size() - oldNbPnts == 2 &&
192 intersection.ParamOnConic( 1 ) > intersection.ParamOnConic( 2 ))
194 int i = intPoints.size() - 1;
195 std::swap( intPoints[ i ], intPoints[ i - 1 ]);
201 //================================================================================
203 * \brief Return signed distance between a point and a plane
205 //================================================================================
207 double signedDist( const gp_Pnt& p, const gp_Ax1& planeNormal )
209 const gp_Pnt& O = planeNormal.Location();
211 return Op * planeNormal.Direction();
214 //================================================================================
216 * \brief Check if a point is outside a segment domain bound by two planes
218 //================================================================================
220 bool isOut( const gp_Pnt& p, const gp_Ax1* planeNormal, bool* isOutPtr )
222 isOutPtr[0] = isOutPtr[1] = false;
224 for ( int i = 0; i < 2; ++i )
226 isOutPtr[i] = ( signedDist( p, planeNormal[i] ) <= 0. );
228 return ( isOutPtr[0] && isOutPtr[1] );
231 //================================================================================
233 * \brief Check if a segment between two points is outside a segment domain bound by two planes
235 //================================================================================
237 bool isSegmentOut( bool* isOutPtr1, bool* isOutPtr2 )
239 return (( isOutPtr1[0] && isOutPtr2[0] ) ||
240 ( isOutPtr1[1] && isOutPtr2[1] ));
243 //================================================================================
245 * \brief cut off ip1 from edge (ip1 - ip2) by a plane
247 //================================================================================
249 void cutOff( IntPoint & ip1, const IntPoint & ip2, const gp_Ax1& planeNormal, double tol )
251 gp_Lin lin( ip1.myNode, ( ip2.myNode - ip1.myNode ));
252 gp_Pln pln( planeNormal.Location(), planeNormal.Direction() );
254 IntAna_IntConicQuad intersection( lin, pln, Precision::Angular/*Tolerance*/() );
255 if ( intersection.IsDone() &&
256 !intersection.IsParallel() &&
257 !intersection.IsInQuadric() &&
258 intersection.NbPoints() == 1 )
260 if ( intersection.Point( 1 ).SquareDistance( ip1.myNode ) > tol * tol )
262 static_cast< gp_XYZ& >( ip1.myNode ) = intersection.Point( 1 ).XYZ();
263 ip1.myNode._node = 0;
264 ip1.myEdgeIndex = -1;
269 //================================================================================
271 * \brief Assure that face normal is computed in faceNormals vector
273 //================================================================================
275 const gp_XYZ& computeNormal( const SMDS_MeshElement* face,
276 std::vector< gp_XYZ >& faceNormals )
279 if ((int) faceNormals.size() <= face->GetID() )
282 faceNormals.resize( face->GetID() + 1 );
286 toCompute = faceNormals[ face->GetID() ].SquareModulus() == 0.;
289 SMESH_MeshAlgos::FaceNormal( face, faceNormals[ face->GetID() ], /*normalized=*/false );
291 return faceNormals[ face->GetID() ];
295 //================================================================================
297 * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
298 * The slot is consrtucted by cutting faces by cylindrical surfaces made around each segment.
299 * \return Edges located at the slot boundary
301 //================================================================================
303 std::vector< SMESH_MeshAlgos::Edge >
304 SMESH_MeshAlgos::MakeSlot( SMDS_ElemIteratorPtr theSegmentIt,
308 std::vector< Edge > bndEdges;
310 if ( !theSegmentIt || !theSegmentIt->more() || !theMesh || theWidth == 0.)
313 // put the input segments to a data map in order to be able finding neighboring ones
315 typedef std::vector< Segment* > TSegmentVec;
316 typedef NCollection_DataMap< const SMDS_MeshNode*, TSegmentVec, SMESH_Hasher > TSegmentsOfNode;
317 TSegmentsOfNode segmentsOfNode;
318 ObjectPool< Segment > segmentPool;
320 while( theSegmentIt->more() )
322 const SMDS_MeshElement* edge = theSegmentIt->next();
323 if ( edge->GetType() != SMDSAbs_Edge )
324 throw SALOME_Exception( "A segment is not a mesh edge");
326 Segment* segment = segmentPool.getNew();
327 segment->myEdge = edge;
329 for ( SMDS_NodeIteratorPtr nIt = edge->nodeIterator(); nIt->more(); )
331 const SMDS_MeshNode* n = nIt->next();
332 TSegmentVec* segVec = segmentsOfNode.ChangeSeek( n );
334 segVec = segmentsOfNode.Bound( n, TSegmentVec() );
336 segVec->push_back( segment );
340 // Cut the mesh around the segments
342 const double tol = Precision::Confusion();
343 std::vector< gp_XYZ > faceNormals;
344 SMESH_MeshAlgos::Intersector meshIntersector( theMesh, tol, faceNormals );
345 std::unique_ptr< SMESH_ElementSearcher> faceSearcher;
347 std::vector< NLink > startEdges;
348 std::vector< const SMDS_MeshNode* > faceNodes(4), edgeNodes(2);
349 std::vector<const SMDS_MeshElement *> faces(2);
350 NCollection_Map<const SMDS_MeshElement*, SMESH_Hasher > checkedFaces;
351 std::vector< IntPoint > intPoints, p(2);
352 std::vector< SMESH_NodeXYZ > facePoints(4);
353 std::vector< Intersector::TFace > cutFacePoints;
355 std::vector< gp_Ax1 > planeNormalVec(2);
356 gp_Ax1 * planeNormal = & planeNormalVec[0];
358 for ( TSegmentIterator segIt( segmentPool ); segIt.more(); ) // loop on all segments
360 Segment* segment = const_cast< Segment* >( segIt.next() );
362 gp_Lin segLine( segment->Ax1() );
363 gp_Ax3 cylAxis( segLine.Location(), segLine.Direction() );
364 gp_Cylinder segCylinder( cylAxis, 0.5 * theWidth );
365 double radius2( segCylinder.Radius() * segCylinder.Radius() );
367 // get normals of planes separating domains of neighboring segments
368 for ( int i = 0; i < 2; ++i ) // loop on 2 segment ends
370 planeNormal[i] = segment->Ax1(i);
372 const SMDS_MeshNode* n = segment->Node( i );
373 const TSegmentVec& segVec = segmentsOfNode( n );
374 for ( size_t iS = 0; iS < segVec.size(); ++iS )
376 if ( segVec[iS] == segment )
379 gp_Ax1 axis2 = segVec[iS]->Ax1();
380 if ( n != segVec[iS]->Node( 1 ))
381 axis2.Reverse(); // along a wire
383 planeNormal[i].SetDirection( planeNormal[i].Direction().XYZ() + axis2.Direction().XYZ() );
387 // we explore faces around a segment starting from face edges;
388 // initialize a list of starting edges
391 // get a face to start searching intersected faces from
392 const SMDS_MeshNode* n0 = segment->Node( 0 );
393 SMDS_ElemIteratorPtr fIt = n0->GetInverseElementIterator( SMDSAbs_Face );
394 const SMDS_MeshElement* face = ( fIt->more() ) ? fIt->next() : 0;
395 if ( !theMesh->Contains( face ))
398 faceSearcher.reset( SMESH_MeshAlgos::GetElementSearcher( *theMesh ));
399 face = faceSearcher->FindClosestTo( SMESH_NodeXYZ( n0 ), SMDSAbs_Face );
401 // collect face edges
402 int nbNodes = face->NbCornerNodes();
403 faceNodes.assign( face->begin_nodes(), face->end_nodes() );
404 faceNodes.resize( nbNodes + 1 );
405 faceNodes[ nbNodes ] = faceNodes[ 0 ];
406 for ( int i = 0; i < nbNodes; ++i )
407 startEdges.push_back( NLink( faceNodes[i], faceNodes[i+1] ));
410 // intersect faces located around a segment
411 checkedFaces.Clear();
412 while ( !startEdges.empty() )
414 edgeNodes[0] = startEdges[0].first;
415 edgeNodes[1] = startEdges[0].second;
417 theMesh->GetElementsByNodes( edgeNodes, faces, SMDSAbs_Face );
418 for ( size_t iF = 0; iF < faces.size(); ++iF ) // loop on faces sharing a start edge
420 const SMDS_MeshElement* face = faces[iF];
421 if ( !checkedFaces.Add( face ))
424 int nbNodes = face->NbCornerNodes();
426 throw SALOME_Exception( "MakeSlot() accepts triangles only" );
427 facePoints.assign( face->begin_nodes(), face->end_nodes() );
428 facePoints.resize( nbNodes + 1 );
429 facePoints[ nbNodes ] = facePoints[ 0 ];
431 // check if cylinder axis || face
432 const gp_XYZ& faceNorm = computeNormal( face, faceNormals );
433 bool isCylinderOnFace = ( Abs( faceNorm * cylAxis.Direction().XYZ() ) < tol );
435 if ( !isCylinderOnFace )
437 if ( Intersector::CutByPlanes( face, planeNormalVec, tol, cutFacePoints ))
438 continue; // whole face cut off
439 facePoints.swap( cutFacePoints[0] );
440 facePoints.push_back( facePoints[0] );
443 // find intersection points on face edges
445 int nbPoints = facePoints.size()-1;
447 for ( int i = 0; i < nbPoints; ++i )
449 const SMESH_NodeXYZ& n1 = facePoints[i];
450 const SMESH_NodeXYZ& n2 = facePoints[i+1];
452 size_t iP = intPoints.size();
453 intersectEdge( segCylinder, n1, n2, tol, intPoints );
456 if ( isCylinderOnFace )
457 for ( ; iP < intPoints.size(); ++iP )
458 intPoints[ iP ].myEdgeIndex = i;
460 for ( ; iP < intPoints.size(); ++iP )
461 if ( n1.Node() && n2.Node() )
462 intPoints[ iP ].myEdgeIndex = face->GetNodeIndex( n1.Node() );
464 intPoints[ iP ].myEdgeIndex = -(i+1);
466 nbFarPoints += ( segLine.SquareDistance( n1 ) > radius2 );
470 if ( nbFarPoints < nbPoints || !intPoints.empty() )
471 for ( int i = 0; i < nbPoints; ++i )
473 const SMESH_NodeXYZ& n1 = facePoints[i];
474 const SMESH_NodeXYZ& n2 = facePoints[i+1];
475 if ( n1.Node() && n2.Node() )
477 isOut( n1, planeNormal, p[0].myIsOutPln );
478 isOut( n2, planeNormal, p[1].myIsOutPln );
479 if ( !isSegmentOut( p[0].myIsOutPln, p[1].myIsOutPln ))
481 startEdges.push_back( NLink( n1.Node(), n2.Node() ));
486 if ( intPoints.size() < 2 )
489 // classify intPoints by planes
490 for ( size_t i = 0; i < intPoints.size(); ++i )
491 isOut( intPoints[i].myNode, planeNormal, intPoints[i].myIsOutPln );
495 if ( intPoints.size() > 2 )
496 intPoints.push_back( intPoints[0] );
498 for ( size_t iE = 1; iE < intPoints.size(); ++iE ) // 2 <= intPoints.size() <= 5
500 if (( intPoints[iE].myIsOutPln[0] && intPoints[iE].myIsOutPln[1] ) ||
501 ( isSegmentOut( intPoints[iE].myIsOutPln, intPoints[iE-1].myIsOutPln )))
502 continue; // intPoint is out of domain
504 // check if a cutting edge connecting two intPoints is on cylinder surface
505 if ( intPoints[iE].myEdgeIndex == intPoints[iE-1].myEdgeIndex )
506 continue; // on same edge
507 if ( intPoints[iE].myNode.Node() &&
508 intPoints[iE].myNode == intPoints[iE-1].myNode ) // coincide
511 gp_XYZ edegDir = intPoints[iE].myNode - intPoints[iE-1].myNode;
513 bool toCut; // = edegDir.SquareModulus() > tol * tol;
514 if ( intPoints.size() == 2 )
516 else if ( isCylinderOnFace )
517 toCut = cylAxis.Direction().IsParallel( edegDir, tol );
520 SMESH_NodeXYZ nBetween;
521 int eInd = intPoints[iE-1].myEdgeIndex;
523 nBetween = facePoints[( 1 - (eInd-1)) % nbPoints ];
525 nBetween = faceNodes[( 1 + eInd ) % nbNodes ];
526 toCut = ( segLine.SquareDistance( nBetween ) > radius2 );
531 // limit the edge by planes
532 if ( intPoints[iE].myIsOutPln[0] ||
533 intPoints[iE].myIsOutPln[1] )
534 cutOff( intPoints[iE], intPoints[iE-1],
535 planeNormal[ intPoints[iE].myIsOutPln[1] ], tol );
537 if ( intPoints[iE-1].myIsOutPln[0] ||
538 intPoints[iE-1].myIsOutPln[1] )
539 cutOff( intPoints[iE-1], intPoints[iE],
540 planeNormal[ intPoints[iE-1].myIsOutPln[1] ], tol );
542 edegDir = intPoints[iE].myNode - intPoints[iE-1].myNode;
543 if ( edegDir.SquareModulus() < tol * tol )
544 continue; // fully cut off
547 meshIntersector.Cut( face,
548 intPoints[iE-1].myNode, intPoints[iE-1].myEdgeIndex,
549 intPoints[iE ].myNode, intPoints[iE ].myEdgeIndex );
551 Edge e = { intPoints[iE].myNode.Node(), intPoints[iE-1].myNode.Node(), 0 };
552 segment->AddEdge( e, tol );
553 bndEdges.push_back( e );
555 } // loop on faces sharing an edge
557 startEdges[0] = startEdges.back();
558 startEdges.pop_back();
560 } // loop on startEdges
561 } // loop on all input segments
564 // Make cut at the end of group of segments
566 std::vector<const SMDS_MeshElement*> polySegments;
568 for ( TSegmentsOfNode::Iterator nSegsIt( segmentsOfNode ); nSegsIt.More(); nSegsIt.Next() )
570 const TSegmentVec& segVec = nSegsIt.Value();
571 if ( segVec.size() != 1 )
574 const Segment* segment = segVec[0];
575 const SMDS_MeshNode* segNode = nSegsIt.Key();
577 // find two end nodes of cut edges to make a cut between
578 if ( segment->myEndNodes.size() != 4 )
579 throw SALOME_Exception( "MakeSlot(): too short end edge?" );
580 SMESH_MeshAlgos::PolySegment linkNodes;
581 gp_Ax1 planeNorm = segment->Ax1( segNode != segment->Node(0) );
582 double minDist[2] = { 1e100, 1e100 };
583 Segment::TNodeSet::const_iterator nIt = segment->myEndNodes.begin();
584 for ( ; nIt != segment->myEndNodes.end(); ++nIt )
586 SMESH_NodeXYZ n = *nIt;
587 double d = Abs( signedDist( n, planeNorm ));
588 double diff1 = minDist[0] - d, diff2 = minDist[1] - d;
590 if ( diff1 > 0 && diff2 > 0 )
592 i = ( diff1 < diff2 );
594 else if ( diff1 > 0 )
598 else if ( diff2 > 0 )
606 linkNodes.myXYZ[ i ] = n;
609 // for ( int iSide = 0; iSide < 2; ++iSide )
611 // if ( segment->myCutEdges[ iSide ].empty() )
612 // throw SALOME_Exception( "MakeSlot(): too short end edge?" );
613 // SMESH_NodeXYZ n1 = segment->myCutEdges[ iSide ].front()._node1;
614 // SMESH_NodeXYZ n2 = segment->myCutEdges[ iSide ].back ()._node2;
615 // double d1 = Abs( signedDist( n1, planeNorm ));
616 // double d2 = Abs( signedDist( n2, planeNorm ));
617 // linkNodes.myXYZ [ iSide ] = ( d1 < d2 ) ? n1 : n2;
618 // linkNodes.myNode1[ iSide ] = linkNodes.myNode2[ iSide ] = 0;
620 linkNodes.myVector = planeNorm.Direction() ^ (linkNodes.myXYZ[0] - linkNodes.myXYZ[1]);
621 linkNodes.myNode1[ 0 ] = linkNodes.myNode2[ 0 ] = 0;
622 linkNodes.myNode1[ 1 ] = linkNodes.myNode2[ 1 ] = 0;
624 // create segments connecting linkNodes
625 std::vector<const SMDS_MeshElement*> newSegments;
626 std::vector<const SMDS_MeshNode*> newNodes;
627 SMESH_MeshAlgos::TListOfPolySegments polySegs(1, linkNodes);
628 SMESH_MeshAlgos::MakePolyLine( theMesh, polySegs, newSegments, newNodes,
629 /*group=*/0, faceSearcher.get() );
630 // cut faces by newSegments
632 for ( size_t i = 0; i < newSegments.size(); ++i )
634 intPoints[0].myNode = edgeNodes[0] = newSegments[i]->GetNode(0);
635 intPoints[1].myNode = edgeNodes[1] = newSegments[i]->GetNode(1);
637 // find an underlying face
638 gp_XYZ middle = 0.5 * ( intPoints[0].myNode + intPoints[1].myNode );
639 const SMDS_MeshElement* face = faceSearcher->FindClosestTo( middle, SMDSAbs_Face );
641 // find intersected edges of the face
642 int nbNodes = face->NbCornerNodes();
643 faceNodes.assign( face->begin_nodes(), face->end_nodes() );
644 faceNodes.resize( nbNodes + 1 );
645 faceNodes[ nbNodes ] = faceNodes[ 0 ];
646 for ( int iP = 0; iP < 2; ++iP )
648 intPoints[iP].myEdgeIndex = -1;
649 for ( int iN = 0; iN < nbNodes && intPoints[iP].myEdgeIndex < 0; ++iN )
651 SMDS_LinearEdge edge( faceNodes[iN], faceNodes[iN+1] );
652 if ( SMESH_MeshAlgos::GetDistance( &edge, intPoints[iP].myNode) < tol )
653 intPoints[iP].myEdgeIndex = iN;
659 computeNormal( face, faceNormals );
660 meshIntersector.Cut( face,
661 intPoints[0].myNode, intPoints[0].myEdgeIndex,
662 intPoints[1].myNode, intPoints[1].myEdgeIndex );
664 Edge e = { intPoints[0].myNode.Node(), intPoints[1].myNode.Node(), 0 };
665 bndEdges.push_back( e );
667 // add cut points to an adjacent face at ends of poly-line
668 // if they fall onto face edges
669 if (( i == 0 && intPoints[0].myEdgeIndex >= 0 ) ||
670 ( i == newSegments.size() - 1 && intPoints[1].myEdgeIndex >= 0 ))
672 for ( int iE = 0; iE < 2; ++iE ) // loop on ends of a new segment
674 if ( iE ? ( i != newSegments.size() - 1 ) : ( i != 0 ))
676 int iEdge = intPoints[ iE ].myEdgeIndex;
677 edgeNodes[0] = faceNodes[ iEdge ];
678 edgeNodes[1] = faceNodes[ iEdge+1 ];
679 theMesh->GetElementsByNodes( edgeNodes, faces, SMDSAbs_Face );
680 for ( size_t iF = 0; iF < faces.size(); ++iF )
681 if ( faces[iF] != face )
683 int iN1 = faces[iF]->GetNodeIndex( edgeNodes[0] );
684 int iN2 = faces[iF]->GetNodeIndex( edgeNodes[1] );
685 intPoints[ iE ].myEdgeIndex = Abs( iN1 - iN2 ) == 1 ? Min( iN1, iN2 ) : 2;
686 computeNormal( faces[iF], faceNormals );
687 meshIntersector.Cut( faces[iF],
688 intPoints[iE].myNode, intPoints[iE].myEdgeIndex,
689 intPoints[iE].myNode, intPoints[iE].myEdgeIndex );
694 } // loop on newSegments
696 polySegments.insert( polySegments.end(), newSegments.begin(), newSegments.end() );
698 } // loop on map of input segments
700 // actual mesh splitting
701 TElemIntPairVec new2OldFaces;
702 TNodeIntPairVec new2OldNodes;
703 meshIntersector.MakeNewFaces( new2OldFaces, new2OldNodes, /*sign=*/1, /*optimize=*/true );
705 // remove poly-line edges
706 for ( size_t i = 0; i < polySegments.size(); ++i )
708 edgeNodes[0] = polySegments[i]->GetNode(0);
709 edgeNodes[1] = polySegments[i]->GetNode(1);
711 theMesh->RemoveFreeElement( polySegments[i] );
713 if ( edgeNodes[0]->NbInverseElements() == 0 )
714 theMesh->RemoveNode( edgeNodes[0] );
715 if ( edgeNodes[1]->NbInverseElements() == 0 )
716 theMesh->RemoveNode( edgeNodes[1] );