1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D
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.
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 : MEDMEM_Extractor.cxx
20 // Created : Thu Dec 18 11:10:11 2008
21 // Author : Edward AGAPOV (eap)
23 #include "MEDMEM_Extractor.hxx"
25 #include <MEDMEM_Field.hxx>
26 #include <MEDMEM_Mesh.hxx>
27 #include <MEDMEM_Meshing.hxx>
28 #include <MEDMEM_Support.hxx>
34 using namespace MED_EN;
36 using namespace MEDMEM;
38 namespace { // local tools
40 const int _POLYGON = -1; //!< map key to store connectivity of polygons
42 const double _TOLER = 1e-12;
44 //================================================================================
46 * \brief calculate cross product of two vectors
48 void crossProduct(const double* v1, const double* v2, double* res)
50 res[0] = v1[1] * v2[2] - v1[2] * v2[1];
51 res[1] = v1[2] * v2[0] - v1[0] * v2[2];
52 res[2] = v1[0] * v2[1] - v1[1] * v2[0];
54 //================================================================================
56 * \brief calculate dot product of two vectors
58 double dotProduct(const double* v1, const double* v2)
60 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
62 //================================================================================
64 * \brief SUPPORT owning the mesh
66 struct TSupport : public SUPPORT
68 TSupport(MESH* mesh): SUPPORT(mesh) {}
69 ~TSupport() { delete getMesh(); setMeshDirectly((MESH*)0); }
71 //================================================================================
73 * \brief Field owning the support
75 struct TField: public FIELD<double>
77 TField( const SUPPORT * Support, int nbComp ): FIELD<double>( Support, nbComp ) {}
78 ~TField() { if ( _support ) delete _support; _support = (SUPPORT*)0; }
80 //================================================================================
82 * \brief Accessor to some ids. Provides operator[] and more-next access methods
86 const int *_cur, *_end;
88 TIter(const int* start, const int* end):_cur(start), _end(end) {}
89 TIter(const int* start, int nb):_cur(start), _end(start+nb) {}
90 int size() const { return _end - _cur; }
91 int operator[] (int i) const { return _cur[i]; }
92 bool more() const { return _cur < _end; }
93 int next() { return *_cur++; }
94 const int* begin() const { return _cur; }
95 const int* end() const { return _end; }
97 //================================================================================
99 * \brief Edge linking two nodes, used to find equal edges and store edges in std containers
101 struct TEdge: public pair<int,int>
103 TEdge(const int n1=0, const int n2=0): pair<int,int>(n1,n2)
104 { if ( n2 < n1 ) first = n2, second = n1; }
105 TEdge(const TIter& nodes, int i )
106 { *this = TEdge( nodes[i], nodes[ (i+1)%nodes.size() ]); }
107 int node1() const { return first; }
108 int node2() const { return second; }
110 //================================================================================
112 * \brief Tool providing iteration on edges of the cell of given classical type
116 vector<TEdge>* _edges;
117 TEdgeIterator(const medGeometryElement type);
118 int getNbEdges() const { return _edges->size(); }
119 TEdge getEdge(int i, const int* cellConn ) const
120 { return TEdge( cellConn[(*_edges)[i].node1()], cellConn[(*_edges)[i].node2()]); }
121 TEdge getEdge(int i, const TIter& cellNodes ) const
122 { return TEdge( cellNodes[(*_edges)[i].node1()], cellNodes[(*_edges)[i].node2()]); }
124 //================================================================================
126 * \brief Comparator used to sort nodes of polygon
130 const double* _coords; //!< coordinates of mesh nodes in full interlace
131 const double* _bc; //!< polygon barycentre
132 int _i1, _i2; //!< indices of two ordinates used to compare points
134 TNodeCompare(const double* nodeCoords, int i1, int i2):
135 _coords(nodeCoords),_i1(i1),_i2(i2) {}
137 void setBaryCenter(const double* bc) { _bc = bc; }
139 bool operator()(const int pt1, const int pt2) {
140 const double* p1 = _coords + 3*(pt1-1);
141 const double* p2 = _coords + 3*(pt2-1);
142 // calculate angles of Op1 and Op2 with the i1 axis on plane (i1,i2)
143 double ang1 = atan2(p1[_i1] - _bc[0], p1[_i2] - _bc[1]);
144 double ang2 = atan2(p2[_i1] - _bc[0], p2[_i2] - _bc[1]);
148 //================================================================================
150 * \brief Return tolerance to consider nodes coincident
152 double getTolerance(const MESH* mesh )
154 vector< vector<double> > bb = mesh->getBoundingBox();
156 for ( int j = 0; j < mesh->getSpaceDimension(); ++j ) {
157 double dist = bb[0][j] - bb[1][j];
158 diagonal += dist*dist;
160 return sqrt( diagonal ) * 1e-7;
162 //================================================================================
164 * \brief Line data and some methods
169 const double* _coord;
170 int _maxDir; //!< index of maximal coordinate of _dir
171 TLine( const double* dir, const double* coord): _dir(dir), _coord(coord) {
173 if ( fabs( _dir[_maxDir] ) < fabs( _dir[1] )) _maxDir = 1;
174 if ( fabs( _dir[_maxDir] ) < fabs( _dir[2] )) _maxDir = 2;
176 //!< Check if intersection points coincide in _maxDir direction
177 bool isSame( const double* p1, const double* p2 ) const {
178 return fabs(p1[_maxDir] - p2[_maxDir]) < _TOLER;
181 //================================================================================
183 * \brief Result of transfixing a face
185 * TIntersection's make up a chain via _prevSection field. Depending on whether
186 * _prevSection is NULL or not, there are two types of TIntersection:
187 * . _prevSection == NULL: TIntersection ending the chain. It is TIntersection from
188 * which chain building starts.
189 * . _prevSection != NULL: intermediate TIntersection, stores cells cut by a result segment.
193 double _point[3]; //!< coordinates of itersection
194 set<int> _cells; //!< intersected cells
195 int _face; //!< intersected face of a cell
196 set<int> _startNodes; //!< nodes around which to look for next intersection
197 TIntersection* _prevSection; //!< neighbor intersection
199 TIntersection(): _face(-1), _prevSection(NULL)
202 if ( _prevSection ) delete _prevSection; _prevSection=0;
204 void getRange( double& min, double& max, const int j ) const {
205 if ( _point[j] < min ) min = _point[j];
206 if ( _point[j] > max ) max = _point[j];
207 if ( _prevSection ) _prevSection->getRange( min, max, j );
210 if ( _prevSection ) {
211 _prevSection->reverse();
212 _prevSection->_cells = _cells;
213 _prevSection->_prevSection = this;
217 int size() const { return 1 + ( _prevSection ? _prevSection->size() : 0 ); }
219 //================================================================================
221 * \brief Provider of comfortable access to connectivity data of MESH
227 const double* _coord;
228 const int* _cellConn;
229 const int* _cellConnIndex;
230 const int* _faceConn;
231 const int* _faceConnIndex;
232 const int* _face2Cell;
233 const int* _face2CellIndex;
234 const int* _cell2Face;
235 const int* _cell2FaceIndex;
236 const int* _node2Cell;
237 const int* _node2CellIndex;
238 TMeshData(const MESH &mesh)
240 _tolerance = getTolerance(&mesh);
241 _dim = mesh.getSpaceDimension();
242 _coord = mesh.getCoordinates(MED_FULL_INTERLACE);
243 _cellConn = mesh.getConnectivity(MED_FULL_INTERLACE, MED_NODAL,
244 MED_CELL, MED_ALL_ELEMENTS);
245 _cellConnIndex = mesh.getConnectivityIndex(MED_NODAL, MED_CELL);
246 _cell2Face = mesh.getConnectivity(MED_FULL_INTERLACE, MED_DESCENDING,
247 MED_CELL, MED_ALL_ELEMENTS);
248 _cell2FaceIndex = mesh.getConnectivityIndex( MED_DESCENDING, MED_CELL );
249 _face2Cell = mesh.getReverseConnectivity( MED_DESCENDING );
250 _face2CellIndex = mesh.getReverseConnectivityIndex( MED_DESCENDING );
251 _faceConn = mesh.getConnectivity(MED_FULL_INTERLACE, MED_NODAL,
252 MED_FACE, MED_ALL_ELEMENTS);
253 _faceConnIndex = mesh.getConnectivityIndex(MED_NODAL, MED_FACE);
254 _node2Cell = mesh.getReverseConnectivity( MED_NODAL );
255 _node2CellIndex = mesh.getReverseConnectivityIndex( MED_NODAL );
257 double tolerance() const {
259 const double* getNodeCoord( int node ) const {
260 return _coord + _dim*(node-1); }
261 TIter getFaces( int cell ) const {
262 return TIter( _cell2Face+_cell2FaceIndex[cell-1]-1, _cell2Face+_cell2FaceIndex[cell]-1 ); }
263 TIter getCellNodes( int cell ) const {
264 return TIter( _cellConn+_cellConnIndex[cell-1]-1, _cellConn+_cellConnIndex[cell]-1 ); }
265 TIter getFaceNodes( int face ) const {
267 return TIter( _faceConn+_faceConnIndex[face-1]-1, _faceConn+_faceConnIndex[face]-1 ); }
268 TIter getCellsByNode( int node ) const {
269 return TIter( _node2Cell+_node2CellIndex[node-1]-1, _node2Cell+_node2CellIndex[node]-1 ); }
270 TIter getCellsByFace( int face ) const {
272 return TIter( _face2Cell+_face2CellIndex[face-1]-1, _face2Cell+_face2CellIndex[face]-1 ); }
273 int isFreeFace( int face ) const {
274 TIter cells = getCellsByFace( face );
275 return ( cells[1] == 0 ) ? cells[0] : 0; }
277 //================================================================================
279 * \brief Calculates face normal
280 * \retval bool - false if face has zero area
282 bool calcFaceNormal( const int face,
283 const TMeshData& meshData,
286 TIter nodes = meshData.getFaceNodes( face );
287 bool zeroArea = false;
290 const double* p1 = meshData.getNodeCoord( nodes[i] );
291 const double* p2 = meshData.getNodeCoord( nodes[i+1] );
292 const double* p3 = meshData.getNodeCoord( nodes[i+2] );
293 double p2p1[3] = { p1[0]-p2[0], p1[1]-p2[1], p1[2]-p2[2] };
294 double p2p3[3] = { p3[0]-p2[0], p3[1]-p2[1], p3[2]-p2[2] };
295 crossProduct( p2p3, p2p1, norm );
296 double normSize2 = dotProduct( norm, norm );
297 zeroArea = (normSize2 < DBL_MIN);
299 while ( zeroArea && i < 2 );
302 //================================================================================
304 * \brief Fill set of cells sharing edge
306 void getCellsSharingEdge( const TEdge& edge, const TMeshData& meshData, set<int> & theCells )
308 TIter cells = meshData.getCellsByNode( edge.node1() );
309 while ( cells.more() ) {
310 int cell = cells.next();
311 TIter nodes = meshData.getCellNodes( cell );
312 TEdgeIterator edgeIter( medGeometryElement( 300 + nodes.size() ));
313 for ( int i = 0, nb = edgeIter.getNbEdges(); i < nb; ++i ) {
314 TEdge e = edgeIter.getEdge( i , nodes );
316 theCells.insert( cell );
322 bool canIntersect(const int cell,
323 const TMeshData& meshData,
326 TIntersection* intersect(const int cell,
327 const TMeshData& meshData,
329 set<int>& checkedCells,
330 TIntersection* prevInter=0);
332 } // noname namespace
337 //================================================================================
339 * \brief Creates a tool
340 * \param inputField - input field
342 * The input field is supposed to comply with following conditions <ul>
343 *<li> it is constant by element (i.e. has 1 gauss point),</li>
344 *<li> it's support mesh does not contain poly elements,</li>
345 *<li> volumic elements have planar faces,</li>
346 *<li> surfasic elements have linear edges.</li></ul>
348 //================================================================================
350 Extractor::Extractor(const FIELD<double>& inputField) throw (MEDEXCEPTION)
351 : _myInputField( & inputField )
353 const char* LOC = "Extractor::Extractor(inputField) :";
355 // Check if the input field complies with the conditions
357 if ( !inputField.getSupport() )
358 throw MEDEXCEPTION(STRING(LOC) << "InputField has NULL support");
360 medEntityMesh entity = inputField.getSupport()->getEntity();
361 if ( entity == MED_NODE || entity == MED_EDGE )
362 throw MEDEXCEPTION(STRING(LOC) << "InputField has invalid supporting entity");
364 if ( inputField.getSupport()->getNumberOfElements(MED_ALL_ELEMENTS) == 0 )
365 throw MEDEXCEPTION(STRING(LOC) << "InputField has support of zero size");
367 if ( inputField.getGaussPresence() && inputField.getNumberOfGaussPoints()[0] > 1 )
368 throw MEDEXCEPTION(STRING(LOC) << "InputField is not constant be element");
370 MESH* mesh = inputField.getSupport()->getMesh();
372 throw MEDEXCEPTION(STRING(LOC) << "InputField has support with NULL mesh");
374 if ( mesh->getSpaceDimension() < 2 )
375 throw MEDEXCEPTION(STRING(LOC) << "InputField with 1D support not acceptable");
377 if ( mesh->getNumberOfPolygons() > 0 ||
378 mesh->getNumberOfPolyhedron() > 0 )
379 throw MEDEXCEPTION(STRING(LOC) << "InputField has supporting mesh with poly elements");
381 if ( mesh->getConnectivityptr()->getEntityDimension() < 2 )
382 throw MEDEXCEPTION(STRING(LOC) << "Invalid entity dimension of connectivity");
385 //================================================================================
387 * \brief Creates a field by cutting inputField by a plane
388 * \param coords - give a point to pass through by the plane
389 * \param normal - gives the plane normal
390 * \retval FIELD<double>* - resulting field holding ownership of its support,
391 * which in its turn holds ownership of its mesh
393 * If the plane does not intersect the field, NULL is returned.
395 //================================================================================
397 FIELD<double>* Extractor::extractPlane(const double* coords, const double* normal)
400 const char* LOC = "Extractor::extractPlane(const double* coords, const double* normal) :";
402 // check agrument validity
403 if ( !coords || !normal )
404 throw MEDEXCEPTION(STRING(LOC) << "NULL argument");
406 double normalSize = sqrt(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
407 if ( normalSize <= DBL_MIN )
408 throw MEDEXCEPTION(STRING(LOC) << "normal has zero size");
410 if ( _myInputField->getSupport()->getMesh()->getSpaceDimension() < 3 )
411 throw MEDEXCEPTION(STRING(LOC) << "Extraction by plane is possible in 3D space only ");
413 double norm[3] = { normal[0] / normalSize, normal[1] / normalSize, normal[2] / normalSize };
416 map<int,set<int> > new2oldCells;
417 MESH* mesh = divideEdges( coords, norm, new2oldCells );
418 if ( !mesh ) return 0;
420 return makeField( new2oldCells, mesh );
423 //================================================================================
425 * \brief Creates a field by cutting inputField by a line
426 * \param coords - give a point to pass through by the line
427 * \param direction - gives a vector collinear to the line
428 * \retval FIELD<double>* - resulting field holding ownership of its support,
429 * which in its turn holds ownership of its mesh
431 * If the line does not intersect the field, NULL is returned.
433 //================================================================================
435 FIELD<double>* Extractor::extractLine(const double* coords, const double* direction)
438 const char* LOC = "Extractor::extractLine(const double* coords, const double* direction) :";
440 // check agrument validity
441 if ( !coords || !direction )
442 throw MEDEXCEPTION(STRING(LOC) << "NULL argument");
444 double directionSize =
445 sqrt(direction[0]*direction[0] + direction[1]*direction[1] + direction[2]*direction[2]);
446 if ( directionSize <= DBL_MIN )
447 throw MEDEXCEPTION(STRING(LOC) << "direction has zero size");
449 const SUPPORT* support = _myInputField->getSupport();
450 const medGeometryElement* inTypes = support->getTypes();
451 const int meshDim = inTypes[ support->getNumberOfTypes()-1 ] / 100;
453 if ( meshDim == 2 && support->getMesh()->getSpaceDimension() == 3 )
454 throw MEDEXCEPTION(STRING(LOC) << "Extraction from 2D mesh not supported");
456 map<int,set<int> > new2oldCells;
460 double norm[2] = { direction[1] / directionSize,
461 direction[0] / directionSize, };
463 mesh = divideEdges( coords, norm, new2oldCells );
467 double dir[3] = { direction[0] / directionSize,
468 direction[1] / directionSize,
469 direction[2] / directionSize };
470 mesh = transfixFaces( coords, dir, new2oldCells );
473 if ( !mesh ) return 0;
475 return makeField( new2oldCells, mesh );
478 //================================================================================
480 * \brief Creates a new field and fill it from the input one
481 * \param new2oldCells - mapping of new to old cells
482 * \retval FIELD<double>* - resulting field
484 //================================================================================
486 FIELD<double>* Extractor::makeField( const map<int,set<int> >& new2oldCells,
490 int nbComp = _myInputField->getNumberOfComponents();
491 FIELD<double> * outField = new TField( new TSupport( mesh ), nbComp );
492 double* outValues = const_cast<double*>( outField->getValue() );
494 outField->setComponentsNames ( _myInputField->getComponentsNames() );
495 outField->setName ( STRING("Extracted from ")<< _myInputField->getName() );
496 outField->setDescription ( STRING("Created by MEDMEM::Extractor"));
497 outField->setComponentsDescriptions( _myInputField->getComponentsDescriptions() );
498 outField->setMEDComponentsUnits ( _myInputField->getMEDComponentsUnits() );
501 // put values to the new field
502 map<int,set<int> >::const_iterator new_olds, noEnd = new2oldCells.end();
503 for ( new_olds = new2oldCells.begin(); new_olds != noEnd; ++new_olds )
505 for ( int j = 0; j < nbComp; ++j )
507 int ind = ( new_olds->first - 1 ) * nbComp + j;
508 outValues[ ind ] = 0.0;
509 set<int>::const_iterator inCells = new_olds->second.begin();
510 set<int>::const_iterator inEnd = new_olds->second.end();
511 for ( ; inCells != inEnd; ++inCells )
512 outValues[ ind ] += _myInputField->getValueIJ( *inCells, j+1 );
514 outValues[ ind ] /= new_olds->second.size();
520 //================================================================================
522 * \brief Makes a mesh by dividing edges of cells of the input mesh by plane
523 * in 3D or by line in 2D.
524 * \param coords - give a point to pass through by the plane or the line
525 * \param normal - gives the normal to plane or line
526 * \param new2oldCells - output map of new cells to cut input cell
528 //================================================================================
530 MESH* Extractor::divideEdges(const double* coords,
531 const double* normal,
532 map<int,set<int> >& new2oldCells)
534 const char* LOC = "Extractor::divideEdges()";
536 const SUPPORT* support = _myInputField->getSupport();
537 medEntityMesh entity = support->getEntity();
538 MESH* inMesh = support->getMesh();
539 const medGeometryElement* inTypes = support->getTypes();
541 const int* inConn = inMesh->getConnectivity(MED_FULL_INTERLACE, MED_NODAL,
542 entity, MED_ALL_ELEMENTS);
543 const int* inConnIndex = inMesh->getConnectivityIndex(MED_NODAL, entity);
544 const int spaceDim = inMesh->getSpaceDimension();
545 const int meshDim = inTypes[ support->getNumberOfTypes()-1 ] / 100;
548 // connectivity of new cells by nb of nodes per cell
549 map< int, vector< int > > newConnByNbNodes;
550 int nbInputCells = support->getNumberOfElements( MED_ALL_ELEMENTS );
551 int minNbNodesPerCell = 2, maxNbNodesPerCell = 2;
552 if ( meshDim == 3 ) {
553 newConnByNbNodes[ 3 ].reserve( nbInputCells/2 );
554 newConnByNbNodes[ 4 ].reserve( nbInputCells/2 );
555 minNbNodesPerCell = 3;
556 maxNbNodesPerCell = int (MED_POLYGON); // polygones allowed
559 newConnByNbNodes[ 2 ].reserve( nbInputCells/2 );
561 list<int> nbNodesPerPolygon; // to make connectivity index of polygons
564 map< set<int>, int> oldNodes2newCell; //!< map connectivity of all old nodes to new cell id
567 map< TEdge, int > cutEdge2newNodeId; // ids of nodes located between extremities of old edge
568 map< int, int > oldNode2newNodeId; // ids of nodes coincident with old node
571 double tol = getTolerance( inMesh );
574 // ----------------------------------------------
575 // compute distances of nodes from plane or line
576 // ----------------------------------------------
578 computeDistanceOfNodes(coords, normal);
586 for ( int iType = 0; iType < support->getNumberOfTypes(); ++iType) // loop on geom types
588 medGeometryElement type = inTypes[ iType ];
589 TEdgeIterator edges( type );
591 const int* inCells = 0;
592 if ( !support->isOnAllElements() )
593 inCells = support->getNumber( type );
595 int nbInputCells = support->getNumberOfElements( type ); // loop on cells
596 for ( int i = 0; i < nbInputCells; ++i )
598 int oldCell = inCells ? inCells[i] : ++inCell;
599 const int* cellConn = inConn + (inConnIndex[ oldCell-1 ] - 1);
601 // Nodes of new mesh are either coincide with input nodes or lay on
602 // edges cut by plane. If at least one edge of a cell is cut in the middle
603 // then there will be the new cell, if the plane pass only through nodes of
604 // input cell then the new cell is not necessarily created.
606 set<int> oldNodes, newNodes; //!< cut old nodes, new nodes on edges
607 int nbEdgesOnPlane = 0;
608 for ( int iEdge = 0; iEdge < edges.getNbEdges(); ++iEdge ) // loop on cell edges
610 // Analyse edge position in relation to the cutting plane or line
611 const TEdge& edge = edges.getEdge( iEdge, cellConn );
612 double dist1 = _myNodeDistance[ edge.node1()-1 ];
613 double dist2 = _myNodeDistance[ edge.node2()-1 ];
614 bool n1OnPlane = fabs( dist1 ) < tol;
615 bool n2OnPlane = fabs( dist2 ) < tol;
617 oldNodes.insert( edge.node1() );
619 oldNodes.insert( edge.node2() );
620 else if ( !n1OnPlane && dist1 * dist2 < 0 ) {
622 int newNode = cutEdge2newNodeId.size() + oldNode2newNodeId.size() + 1;
623 int node = cutEdge2newNodeId.insert( make_pair( edge, newNode )).first->second;
624 newNodes.insert( node );
626 nbEdgesOnPlane += int( n1OnPlane && n2OnPlane );
628 int nbNodesInNewCell = oldNodes.size() + newNodes.size();
629 if ( nbNodesInNewCell > maxNbNodesPerCell )
630 throw MEDEXCEPTION(STRING(LOC) << "invalid input mesh");
632 if ( nbNodesInNewCell >= minNbNodesPerCell )
634 // Associate new and old cells
635 int newCell = new2oldCells.size() + 1;
636 // detect equal new cells on boundaries of old cells
637 if ( newNodes.empty() && oldNodes.size() == nbEdgesOnPlane + int(meshDim==2)) {
638 pair < map< set<int>, int>::iterator, bool > it_unique =
639 oldNodes2newCell.insert( make_pair( oldNodes, newCell ));
640 if ( !it_unique.second ) { // equal new faces
641 int equalNewCell = it_unique.first->second;
642 new2oldCells[ equalNewCell ].insert( oldCell );
646 set<int>& oldCells = // add a set of old cells to the end of new2oldCells
647 new2oldCells.insert( new2oldCells.end(), make_pair(newCell, set<int>()))->second;
648 oldCells.insert( oldCell );
651 vector< int >& connectivity =
652 nbNodesInNewCell>4 ? newConnByNbNodes[_POLYGON] : newConnByNbNodes[nbNodesInNewCell];
653 // nodes at edge intersection
654 set<int>::iterator n, nEnd;
655 for ( n = newNodes.begin(), nEnd = newNodes.end(); n != nEnd; ++n )
657 connectivity.push_back( *n );
659 // nodes coincident with input nodes
660 for ( n = oldNodes.begin(), nEnd = oldNodes.end(); n != nEnd; ++n )
662 int newNode = cutEdge2newNodeId.size() + oldNode2newNodeId.size() + 1;
663 int node = oldNode2newNodeId.insert( make_pair( *n, newNode )).first->second;
664 connectivity.push_back( node );
666 if ( nbNodesInNewCell>4 )
667 nbNodesPerPolygon.push_back( nbNodesInNewCell );
669 } // loop on cells, cutting thier edges
671 } // loop on geom types of input mesh
678 int nbNodes = cutEdge2newNodeId.size() + oldNode2newNodeId.size();
679 vector< double > resCoords( nbNodes * spaceDim );
681 const double* inCoords = inMesh->getCoordinates(MED_FULL_INTERLACE);
683 // nodes in the middle of edges
684 map< TEdge, int >::iterator edge_node, enEnd = cutEdge2newNodeId.end();
685 for ( edge_node = cutEdge2newNodeId.begin(); edge_node != enEnd; ++edge_node )
687 int newNode = edge_node->second;
688 const TEdge& edge = edge_node->first;
690 double* nodeCoords = & resCoords[ spaceDim * ( newNode-1 )];
691 const double* n1Coords = inCoords + spaceDim * ( edge.node1()-1 );
692 const double* n2Coords = inCoords + spaceDim * ( edge.node2()-1 );
694 double dist1 = _myNodeDistance[ edge.node1()-1 ];
695 double dist2 = _myNodeDistance[ edge.node2()-1 ];
696 double r1 = dist1 / ( dist1 - dist2 );
698 for ( int j = 0 ; j < spaceDim; ++j )
699 nodeCoords[ j ] = ( 1.-r1 ) * n1Coords[ j ] + r1 * n2Coords[ j ];
702 // nodes coincident with input nodes
703 map< int, int >::iterator old_newNode, onEnd = oldNode2newNodeId.end();
704 const size_t size = size_t( sizeof(double)*spaceDim );
705 for ( old_newNode = oldNode2newNodeId.begin(); old_newNode != onEnd; ++old_newNode )
707 double* newCoords = & resCoords[ spaceDim * ( old_newNode->second - 1 )];
708 const double* oldCoords = inCoords + spaceDim * ( old_newNode->first - 1 );
709 memcpy( newCoords, oldCoords, size );
712 // --------------------
713 // Sort nodes of cells
714 // --------------------
716 sortNodes( newConnByNbNodes, &resCoords[0], coords, normal, nbNodesPerPolygon );
722 // count classical types
723 vector< medGeometryElement > types;
724 vector< int > nbCellByType;
725 map< int, vector< int > >::iterator nbNoConn, ncEnd =newConnByNbNodes.end();
726 for ( nbNoConn = newConnByNbNodes.begin(); nbNoConn != ncEnd; ++nbNoConn )
728 int nbNodesPerCell = nbNoConn->first;
729 int connSize = nbNoConn->second.size();
730 if ( nbNodesPerCell >= 2 && nbNodesPerCell <= 4 && connSize > 0 ) {
731 nbCellByType.push_back( connSize / nbNodesPerCell );
732 types.push_back( medGeometryElement( (meshDim-1)*100 + nbNodesPerCell ));
735 if ( types.empty() && newConnByNbNodes[_POLYGON].empty() )
738 MESHING* meshing = new MESHING();
740 meshing->setName(STRING("Cut of ") << inMesh->getName());
741 meshing->setNumberOfTypes( types.size(), MED_CELL );
742 meshing->setCoordinates( spaceDim, nbNodes, & resCoords[0],
743 inMesh->getCoordinatesSystem(), MED_FULL_INTERLACE );
744 meshing->setTypes( &types[0], MED_CELL );
745 meshing->setNumberOfElements( &nbCellByType[0], MED_CELL);
746 for ( int i = 0; i < types.size(); ++i )
747 meshing->setConnectivity( & newConnByNbNodes[ types[i]%100 ].front(), MED_CELL, types[i]);
748 meshing->setMeshDimension( spaceDim /*meshDim-1*/ );
751 if ( !newConnByNbNodes[_POLYGON].empty() )
755 index.reserve( newConnByNbNodes[_POLYGON].size() / 5 );
756 index.push_back( 1 );
757 list<int>::iterator nbNodes = nbNodesPerPolygon.begin(), nnEnd = nbNodesPerPolygon.end();
758 for ( ; nbNodes != nnEnd; ++nbNodes )
759 index.push_back( index.back() + *nbNodes );
761 meshing->setPolygonsConnectivity( & index[0],
762 & newConnByNbNodes[_POLYGON][0],
769 //================================================================================
771 * \brief computes distance of each node from the plane or the line given by point and normal
773 //================================================================================
775 void Extractor::computeDistanceOfNodes(const double* point,
776 const double* normal)
778 const MESH* mesh = _myInputField->getSupport()->getMesh();
779 const double * coord = mesh->getCoordinates(MED_FULL_INTERLACE);
780 const int spaceDim = mesh->getSpaceDimension();
782 _myNodeDistance.resize(mesh->getNumberOfNodes());
784 // compute dot product: normal * Vec(point,node)
785 for ( int i = 0; i < mesh->getNumberOfNodes(); ++i )
787 _myNodeDistance[i] = 0.0;
788 for ( int j = 0; j < spaceDim; ++j, ++coord )
790 _myNodeDistance[i] += normal[j] * (*coord - point[j]);
795 //================================================================================
797 * \brief Orient elements correctly and sort nodes of polygons
798 * \param connByNbNodes - map of nb of nodes per cell to cell connectivity to rearrange
799 * \param nodeCoords - coordinates of nodes of a new mesh in full interlace
800 * \param point - point on plane or line
801 * \param normal - normal to plane or line
802 * \param nbNodesPerPolygon - index of connByNbNodes[_POLYGON] connectivity
804 //================================================================================
806 void Extractor::sortNodes( map< int, vector< int > >& connByNbNodes,
807 const double* nodeCoords,
809 const double* normal,
810 const list<int> & nbNodesPerPolygon)
812 const int spaceDim = _myInputField->getSupport()->getMesh()->getSpaceDimension();
814 if ( !connByNbNodes[2].empty() ) // 1D mesh
816 vector< int > & conn = connByNbNodes[2];
819 // Orient edges along an coordinate axis,
820 // select ordinate to check
821 int ind = (fabs(normal[0]) < fabs(normal[1])) ? 1 : 0;
823 for ( int i = 0; i < conn.size(); i += 2) {
824 const double* p1 = nodeCoords + spaceDim*(conn[i]-1);
825 const double* p2 = nodeCoords + spaceDim*(conn[i+1]-1);
826 if ( p1[ind] > p2[ind] )
827 std::swap( conn[i], conn[i+1] );
832 // Reverse if necessary adjacent edges if they have equal nodes
833 if ( conn.size() > 2 ) {
834 if ( conn[0] == conn[2] || conn[0] == conn[3] )
835 std::swap( conn[0], conn[1] );
837 for ( i = 2; i < conn.size()-2; i += 2) {
838 if ( conn[i-1] == conn[i+1] )
839 std::swap( conn[i], conn[i+1] );
840 else if ( conn[i] == conn[i+2] || conn[i] == conn[i+3] )
841 std::swap( conn[i], conn[i+1] );
843 if ( conn[i+1] == conn[i-1] )
844 std::swap( conn[i], conn[i+1] );
850 // Fix order of nodes
852 // select two ordinates for sorting
853 int i1 = 0, i2 = 1, i3 = 2;
854 if ( fabs( normal[i1] ) > fabs( normal[i3] )) swap( i1, i3 );
855 if ( fabs( normal[i2] ) > fabs( normal[i3] )) swap( i2, i3 );
857 // comparator of nodes
858 TNodeCompare nodeCompare( nodeCoords, i1, i2 );
860 map< int, vector< int > >::iterator nbN_conn = connByNbNodes.begin();
861 for ( ; nbN_conn != connByNbNodes.end(); ++nbN_conn )
863 if ( nbN_conn->second.empty() ) continue;
865 int * conn = & nbN_conn->second[0];
866 int * connEnd = conn + nbN_conn->second.size();
868 int nbNodesPerFace = nbN_conn->first;
869 list<int>::const_iterator nbPolyNodes, npEnd = nbNodesPerPolygon.end();
871 for ( nbPolyNodes = nbNodesPerPolygon.begin(); conn != connEnd; conn += nbNodesPerFace )
873 if ( nbPolyNodes != npEnd )
874 nbNodesPerFace = *nbPolyNodes++;
876 // Sort nodes of polygons and quadrangles
878 if ( nbNodesPerFace > 3 )
881 double bary[2] = { 0., 0. };
882 for ( int i = 0; i < nbNodesPerFace; ++i ) {
883 const double* coord = nodeCoords + spaceDim*(conn[i]-1);
884 bary[0] += coord[i1]; bary[1] += coord[i2];
886 bary[0] /= nbNodesPerFace; bary[1] /= nbNodesPerFace;
887 nodeCompare.setBaryCenter( bary );
890 std::sort( conn, conn + nbNodesPerFace, nodeCompare);
893 // Fix orientation of faces, orient them to have thier normal collinear with plane normal
895 // calculate cross product of two adjacent segments
899 const double* p1 = nodeCoords + spaceDim*(conn[i+0]-1);
900 const double* p2 = nodeCoords + spaceDim*(conn[i+1]-1);
901 const double* p3 = nodeCoords + spaceDim*(conn[i+2]-1);
902 double p2p1[2] = { p1[i1]-p2[i1] , p1[i2]-p2[i2] };
903 double p2p3[2] = { p3[i1]-p2[i1] , p3[i2]-p2[i2] };
904 dot = p2p3[1] * p2p1[0] - p2p3[0] * p2p1[1];
907 while ( dot == 0. && i+2 < nbNodesPerFace );
909 if ( dot * normal[i3] < 0. )
910 std::reverse( conn, conn + nbNodesPerFace );
914 //================================================================================
916 * \brief Makes a 1D mesh by transfixing faces of 3D cells of input mesh by the line
917 * \param coords - give a point to pass through by the line
918 * \param direction - direction of the line
919 * \param new2oldCells - output map of new cells to cut input cell
921 //================================================================================
923 MESH* Extractor::transfixFaces( const double* coords,
924 const double* direction,
925 map<int,set<int> >& new2oldCells)
927 MESH* inMesh = _myInputField->getSupport()->getMesh();
928 TMeshData inMeshData( *inMesh );
929 TLine line( direction, coords );
931 const int nbFaces = inMesh->getNumberOfElements( MED_FACE, MED_ALL_ELEMENTS );
934 // Intersect 1st domain
936 vector< TIntersection*> chains;
937 vector< pair< double, double > > ranges;
938 int nbSegments = 0; // in the future mesh
940 set<int> checkedCells;
941 checkedCells.insert(0); // 0 is returned by getCellsByFace() for boundary faces
944 for ( ; face <= nbFaces; ++face ) {
945 if ( int soleCell = inMeshData.isFreeFace( face ))
946 if ( checkedCells.insert(soleCell).second &&
947 canIntersect( soleCell, inMeshData, line ))
948 if ( TIntersection* chain = intersect( soleCell, inMeshData, line, checkedCells )) {
949 chains.push_back( chain );
950 double min = DBL_MAX, max = -DBL_MAX;
951 chain->getRange( min, max, line._maxDir );
952 ranges.push_back( make_pair( min, max ));
953 nbSegments += chain->size() - 1;
957 if ( chains.empty() )
960 // Intersect the rest domains
962 for ( ; face <= nbFaces; ++face ) {
963 if ( int soleCell = inMeshData.isFreeFace( face ))
964 if ( checkedCells.insert(soleCell).second)
966 // check if at least one node of face is out of ranges of found chains
967 TIter nodes = inMeshData.getFaceNodes( face );
969 while ( nodes.more() && !isOut ) {
970 double coord = inMeshData.getNodeCoord( nodes.next() )[ line._maxDir ];
972 for ( int i = 0; i < ranges.size() && !isIn; ++i ) {
973 const pair< double, double > & minMax = ranges[i];
974 isIn = ( minMax.first < coord && coord < minMax.second );
979 if ( isOut && canIntersect( soleCell, inMeshData, line ))
980 if ( TIntersection* chain = intersect( soleCell, inMeshData, line, checkedCells )) {
981 chains.push_back( chain );
982 double min = DBL_MAX, max = -DBL_MAX;
983 chain->getRange( min, max, line._maxDir );
984 ranges.push_back( make_pair( min, max ));
985 nbSegments += chain->size() - 1;
992 int nbNodes = nbSegments + chains.size();
993 vector< double > resCoords( nbNodes * dim );
994 vector< int > resConn; resConn.reserve( nbSegments * 2 );
996 int iNode = 1, iSeg = 1;
997 double* coord = & resCoords[0];
998 const size_t cooSize = size_t( sizeof(double)*dim );
1000 for ( int i = 0; i < chains.size(); ++i ) {
1001 TIntersection* section = chains[i];
1003 memcpy( coord, section->_point, cooSize );
1005 if ( section->_prevSection ) {
1006 resConn.push_back( iNode++ );
1007 resConn.push_back( iNode );
1008 new2oldCells[ iSeg++ ] = section->_cells;
1010 section = section->_prevSection;
1018 MESHING* meshing = new MESHING();
1020 meshing->setName(STRING("Cut of ") << inMesh->getName());
1021 meshing->setNumberOfTypes( 1, MED_CELL );
1022 //meshing->setMeshDimension( dim );
1023 meshing->setCoordinates( dim, nbNodes, &resCoords[0],
1024 inMesh->getCoordinatesSystem(), MED_FULL_INTERLACE );
1025 meshing->setTypes( &MED_SEG2, MED_CELL );
1026 meshing->setNumberOfElements( &nbSegments, MED_CELL);
1027 meshing->setConnectivity( & resConn[0], MED_CELL, MED_SEG2);
1028 meshing->setMeshDimension( dim );
1033 } // namespace MEDMEM
1036 //================================================================================
1038 * \brief Constructs TEdgeIterator on given classical cell type
1040 //================================================================================
1042 TEdgeIterator::TEdgeIterator(const medGeometryElement type)
1044 static map< medGeometryElement, vector<TEdge>* > _edgesByType;
1045 if ( _edgesByType.empty() ) {
1046 _edges = _edgesByType[ MED_TRIA3 ] = _edgesByType[ MED_TRIA6 ] = new vector<TEdge>();
1047 _edges->reserve( 3 );
1048 _edges->push_back( TEdge( 0, 1 ));
1049 _edges->push_back( TEdge( 1, 2 ));
1050 _edges->push_back( TEdge( 2, 0 ));
1051 _edges = _edgesByType[ MED_QUAD4 ] = _edgesByType[ MED_QUAD8 ] = new vector<TEdge>();
1052 _edges->reserve( 4 );
1053 _edges->push_back( TEdge( 0, 1 ));
1054 _edges->push_back( TEdge( 1, 2 ));
1055 _edges->push_back( TEdge( 2, 3 ));
1056 _edges->push_back( TEdge( 3, 0 ));
1057 _edges = _edgesByType[ MED_TETRA4 ] = _edgesByType[ MED_TETRA10 ] = new vector<TEdge>();
1058 _edges->reserve( 6 );
1059 _edges->push_back( TEdge( 0, 1 ));
1060 _edges->push_back( TEdge( 1, 2 ));
1061 _edges->push_back( TEdge( 2, 0 ));
1062 _edges->push_back( TEdge( 0, 3 ));
1063 _edges->push_back( TEdge( 1, 3 ));
1064 _edges->push_back( TEdge( 2, 3 ));
1065 _edges = _edgesByType[ MED_HEXA8 ] = _edgesByType[ MED_HEXA20 ] = new vector<TEdge>();
1066 _edges->reserve( 12 );
1067 _edges->push_back( TEdge( 0, 1 ));
1068 _edges->push_back( TEdge( 1, 2 ));
1069 _edges->push_back( TEdge( 2, 3 ));
1070 _edges->push_back( TEdge( 3, 0 ));
1071 _edges->push_back( TEdge( 4, 5 ));
1072 _edges->push_back( TEdge( 5, 6 ));
1073 _edges->push_back( TEdge( 6, 7 ));
1074 _edges->push_back( TEdge( 7, 4 ));
1075 _edges->push_back( TEdge( 0, 4 ));
1076 _edges->push_back( TEdge( 1, 5 ));
1077 _edges->push_back( TEdge( 2, 6 ));
1078 _edges->push_back( TEdge( 3, 7 ));
1079 _edges = _edgesByType[ MED_PYRA5 ] = _edgesByType[ MED_PYRA13 ] = new vector<TEdge>();
1080 _edges->reserve( 8 );
1081 _edges->push_back( TEdge( 0, 1 ));
1082 _edges->push_back( TEdge( 1, 2 ));
1083 _edges->push_back( TEdge( 2, 3 ));
1084 _edges->push_back( TEdge( 3, 0 ));
1085 _edges->push_back( TEdge( 0, 4 ));
1086 _edges->push_back( TEdge( 1, 4 ));
1087 _edges->push_back( TEdge( 2, 4 ));
1088 _edges->push_back( TEdge( 3, 4 ));
1089 _edges = _edgesByType[ MED_PENTA6 ] = _edgesByType[ MED_PENTA15 ] = new vector<TEdge>();
1090 _edges->reserve( 9 );
1091 _edges->push_back( TEdge( 0, 1 ));
1092 _edges->push_back( TEdge( 1, 2 ));
1093 _edges->push_back( TEdge( 2, 0 ));
1094 _edges->push_back( TEdge( 3, 4 ));
1095 _edges->push_back( TEdge( 4, 5 ));
1096 _edges->push_back( TEdge( 5, 3 ));
1097 _edges->push_back( TEdge( 0, 4 ));
1098 _edges->push_back( TEdge( 1, 5 ));
1099 _edges->push_back( TEdge( 2, 3 ));
1100 _edgesByType[ MED_NONE ] = 0;
1101 _edgesByType[ MED_POINT1 ] = 0;
1102 _edgesByType[ MED_SEG2 ] = 0;
1103 _edgesByType[ MED_SEG3 ] = 0;
1104 _edgesByType[ MED_POLYGON ] = 0;
1105 _edgesByType[ MED_POLYHEDRA ] = 0;
1106 _edgesByType[ MED_ALL_ELEMENTS ] = 0;
1108 _edges = _edgesByType[type];
1113 //================================================================================
1115 * \brief Transfixes a cell with a line. Returns a head of chain of intersections
1116 * \param cell - cell id to transfixe
1117 * \param meshData - input 3D mesh
1118 * \param line - cutting line
1119 * \param checkedCells - set of cell already tried
1120 * \param prevInter - previosly found intersection. Used to build a chain of
1121 * intersection via recursive call
1123 //================================================================================
1125 TIntersection* intersect(const int cell,
1126 const TMeshData& meshData,
1128 set<int>& checkedCells,
1129 TIntersection* prevInter)
1131 TIntersection* newSection = 0; // section to find
1132 TIntersection* auxSection = 0; // second section used when !prevInter
1133 list< TIntersection > bndSections;// list of intersection on edges
1135 int avoidFace = prevInter ? prevInter->_face : -1;
1137 TIter faces = meshData.getFaces( cell );
1138 while ( faces.more() ) ///////// loop on faces of the cell
1140 int face = abs( faces.next() );
1141 if ( face == avoidFace )
1143 TIter nodes = meshData.getFaceNodes( face );
1148 double faceNormal[3];
1149 bool zeroArea = calcFaceNormal( face, meshData, faceNormal );
1151 continue; // next face
1153 // Is face parallel to line
1154 // -------------------------
1156 double dirDotNorm = dotProduct( line._dir, faceNormal );
1157 const double* pFace0 = meshData.getNodeCoord( nodes[0] );
1158 if ( fabs( dirDotNorm ) < _TOLER )
1160 // line || face, check if the line lays on the face
1162 double lf[3] = { line._coord[0] - pFace0[0],
1163 line._coord[1] - pFace0[1],
1164 line._coord[2] - pFace0[2] };
1165 double lfDotNorm = dotProduct( lf, faceNormal );
1166 if ( fabs( lfDotNorm ) < _TOLER )
1168 // =========================================================
1169 // Line lays on face. Intersect line with edges of the face
1170 // =========================================================
1172 // Calculate distance of nodes from the line
1173 // ------------------------------------------
1174 double lineNormal[3];
1175 crossProduct( faceNormal, line._dir, lineNormal );
1176 vector<double> dist( nodes.size(), 0.0 );
1177 for ( int n = 0; n < nodes.size(); ++n )
1179 const double* p = meshData.getNodeCoord( nodes[n] );
1180 for ( int j = 0; j < 3; ++j )
1181 dist[n] += lineNormal[j] * ( p[j] - line._coord[j] );
1183 // Find intersections
1184 // -------------------
1185 vector<double> pCoords; // intersection coordinates
1186 set<int> pAtNodes; // intersected nodes of the face
1187 list<TEdge> cutEdges; // intersected edges
1188 int nbPoints = 0; // nb intersections
1190 for ( int n = 0; n < nodes.size() && nbPoints < 2; ++n )
1192 int n2 = (n+1) % nodes.size();
1193 double dist1 = dist[ n ];
1194 double dist2 = dist[ n2 ];
1195 bool n1OnLine = fabs( dist1 ) < meshData.tolerance();
1196 bool n2OnLine = fabs( dist2 ) < meshData.tolerance();
1198 pAtNodes.insert( nodes[n] );
1200 pAtNodes.insert( nodes[n2] );
1201 else if ( !n1OnLine && dist1 * dist2 < 0 ) {
1202 const double* p1 = meshData.getNodeCoord( nodes[n] );
1203 const double* p2 = meshData.getNodeCoord( nodes[n2] );
1204 double r1 = dist1 / ( dist1 - dist2 );
1205 for ( int j = 0 ; j < 3; ++j )
1206 pCoords.push_back(( 1.-r1 ) * p1[ j ] + r1 * p2[ j ]);
1207 cutEdges.push_back( TEdge( nodes[n], nodes[n2] ));
1209 nbPoints = cutEdges.size() + pAtNodes.size();
1211 // coords of intersection are stored in pCoords in order:
1212 // first go points on edges, then, points on nodes
1213 if ( nbPoints == 2 && !pAtNodes.empty() ) {
1214 set<int>::iterator n = pAtNodes.begin();
1215 while ( pCoords.size() != 6 ) { // there must be coords of two points
1216 const double* p = meshData.getNodeCoord( *n++ );
1217 for ( int j = 0 ; j < 3; ++j )
1218 pCoords.push_back( p[j] );
1221 // Store intersections
1222 // --------------------
1223 if ( nbPoints == 2 )
1225 vector< TIntersection* > sections(nbPoints);
1226 const double* intCoord = & pCoords[0];
1228 for ( int i = 0; i < nbPoints; ++i, intCoord += 3 )
1230 // Set coords of intersection point
1231 sections[i] = new TIntersection;
1232 sections[i]->_point[0] = intCoord[0];
1233 sections[i]->_point[1] = intCoord[1];
1234 sections[i]->_point[2] = intCoord[2];
1236 // Set intersected cells
1237 if ( cutEdges.empty() ) {
1238 // line can pass by edge shared by several cells
1239 TEdge cutEdge( *pAtNodes.begin(), *pAtNodes.rbegin() );
1240 getCellsSharingEdge( cutEdge, meshData, sections[i]->_cells );
1242 if ( !cutEdges.empty() || sections[i]->_cells.empty() ) {
1243 // line pass by face between two cells
1244 TIter cells = meshData.getCellsByFace( face );
1245 while ( cells.more() )
1246 if ( int elem = cells.next() )
1247 sections[i]->_cells.insert( elem );
1249 // Not to check the face at next search
1250 sections[i]->_face = face;
1252 // Set nodes to start search of next intersection from
1253 if ( !cutEdges.empty() ) {
1254 sections[i]->_startNodes.insert( cutEdges.front().node1() );
1255 sections[i]->_startNodes.insert( cutEdges.front().node2() );
1256 cutEdges.pop_front();
1258 else if ( pAtNodes.size() > 1 ) {
1259 set<int>::iterator p = pAtNodes.begin();
1260 if ( !line.isSame( intCoord, meshData.getNodeCoord( *p )))
1262 sections[i]->_startNodes.insert( *p );
1263 pAtNodes.erase( p );
1266 sections[i]->_startNodes.insert( *pAtNodes.begin() );
1270 // Only one point is needed, exclude already found intersection
1271 if ( line.isSame( prevInter->_point, sections[0]->_point ))
1272 std::swap( sections[0], sections[1] );
1276 newSection = sections[0];
1277 auxSection = sections[1];
1279 auxSection->_cells = newSection->_cells;
1281 bndSections.clear(); // remove already found intersections
1283 } // if ( nbPoints == 2 )
1285 break; // from loop on faces of cell
1287 } // line lays on face
1291 // ==================================
1292 // Line intersects the plane of face
1293 // ==================================
1295 // Find distance of intersection point from line origin
1296 // t = faceNormal * ( pFace0 - line._coord ) / ( faceNormal * line._dir )
1298 double pf0Coord[] = { pFace0[0] - line._coord[0],
1299 pFace0[1] - line._coord[1],
1300 pFace0[2] - line._coord[2] };
1301 double t = dotProduct( faceNormal, pf0Coord ) / dotProduct( faceNormal, line._dir );
1303 // facePlane-line intersection point
1304 double ip[] = { line._coord[0] + line._dir[0] * t,
1305 line._coord[1] + line._dir[1] * t,
1306 line._coord[2] + line._dir[2] * t};
1308 if ( prevInter && line.isSame( ip, prevInter->_point ))
1310 if ( !bndSections.empty() && line.isSame( ip, bndSections.back()._point ))
1313 // Check if intersection point (ip) is inside the face.
1314 // ----------------------------------------------------
1316 // do it in 2d, on the cartesian plane most normal to the face;
1317 // find indices on that plane: i1, i2
1318 int i1 = 0, i2 = 1, i3 = 2;
1319 if ( fabs( faceNormal[i1] ) > fabs( faceNormal[i3] )) swap( i1, i3 );
1320 if ( fabs( faceNormal[i2] ) > fabs( faceNormal[i3] )) swap( i2, i3 );
1321 if ( i2-i1 != 1 && i2 != 0 ) swap ( i1, i2 );
1323 int inside = true, nbOnBoundary = 0;
1325 for ( int n = 0; n < nodes.size() && inside; ++n )
1327 const double* p0 = meshData.getNodeCoord( nodes[n] );
1328 const double* p1 = meshData.getNodeCoord( nodes[ (n+1) % nodes.size() ] );
1330 faceNormal[i3]*((ip[i2] - p0[i2])*(p1[i1] - p0[i1]) - (ip[i1] - p0[i1])*(p1[i2] - p0[i2]));
1331 if ( sign < -DBL_MIN )
1333 else if ( sign < DBL_MIN ) {
1335 cutEdge = TEdge( nodes, n );
1339 // Store intersection point
1340 // -------------------------
1343 TIntersection* section;
1344 if ( !nbOnBoundary )
1345 section = new TIntersection;
1347 if ( bndSections.size() >= 2 )
1348 continue; // go to next face
1349 bndSections.push_back( TIntersection() );
1350 section = & bndSections.back();
1351 // set nodes to start next searching from
1352 if ( nbOnBoundary == 1 ) {
1354 section->_startNodes.insert( cutEdge.node1() );
1355 section->_startNodes.insert( cutEdge.node2() );
1357 else { // node is cut
1358 const double* p1 = meshData.getNodeCoord( cutEdge.node1() );
1359 if ( fabs( ip[i1]-p1[i1] ) < _TOLER && fabs( ip[i2]-p1[i2] ) < _TOLER )
1360 section->_startNodes.insert( cutEdge.node1() );
1362 section->_startNodes.insert( cutEdge.node2() );
1365 section->_point[0] = ip[0];
1366 section->_point[1] = ip[1];
1367 section->_point[2] = ip[2];
1368 section->_face = face;
1369 section->_cells.insert( cell );
1371 if ( !nbOnBoundary )
1374 newSection = section;
1376 auxSection = section;
1377 if ( prevInter || auxSection ) {
1378 bndSections.clear();
1379 break; // from loop on faces
1384 } // loop on faces of cell
1386 // Care of intersections passing through edges
1387 // --------------------------------------------
1389 if ( !bndSections.empty() )
1391 if ( prevInter ) { // boundary section not equal to previous section
1393 newSection = new TIntersection( bndSections.front() );
1396 if ( !newSection ) {
1397 newSection = new TIntersection( bndSections.front() );
1398 bndSections.pop_front();
1400 if ( !auxSection && !bndSections.empty() ) {
1401 auxSection = new TIntersection( bndSections.front() );
1406 // Find the rest of chain starting from the found sections
1407 // --------------------------------------------------------
1409 if ( newSection && ( prevInter || auxSection ))
1411 TIntersection* chain[] = { newSection, auxSection };
1412 int chainLength[] = {0,0};
1413 for ( int i = 0; i < 2; ++i )
1415 TIntersection* section = chain[i];
1416 if ( !section ) continue;
1417 // get cells to try to intersect next
1418 set<int> cellsToCheck;
1419 if ( !section->_startNodes.empty() ) {
1420 if ( section->_startNodes.size() == 1 ) {
1421 TIter cells = meshData.getCellsByNode( *section->_startNodes.begin() );
1422 cellsToCheck.insert( cells.begin(), cells.end() );
1425 TEdge cutEdge( *section->_startNodes.begin(), *section->_startNodes.rbegin() );
1426 getCellsSharingEdge( cutEdge, meshData, cellsToCheck );
1430 TIter cells = meshData.getCellsByFace( section->_face );
1431 cellsToCheck.insert( cells.begin(), cells.end() );
1433 // find the rest intersections
1435 set<int>::iterator elem = cellsToCheck.begin(), elemEnd = cellsToCheck.end();
1436 for ( ; elem != elemEnd && !chain[i]; ++elem ) {
1437 if ( checkedCells.insert( *elem ).second &&
1438 section->_cells.find( *elem ) == section->_cells.end() )
1440 chain[i] = intersect( *elem, meshData, line, checkedCells, section );
1444 chainLength[i] = chain[i]->size();
1447 // Connect just found sections into a chain
1449 newSection->_prevSection = prevInter;
1452 if ( chainLength[0] < chainLength[1] ) {
1453 std::swap( chain[0], chain[1] );
1454 std::swap( newSection, auxSection );
1457 chain[1]->reverse();
1458 newSection->_prevSection = auxSection;
1472 //================================================================================
1474 * \brief Evaluate if the line can intersect a cell
1476 //================================================================================
1478 bool canIntersect(const int cell,
1479 const TMeshData& meshData,
1482 // calculate bnd box of the cell
1483 double min[] = { DBL_MAX,DBL_MAX,DBL_MAX }, max[] = { -DBL_MAX,-DBL_MAX,-DBL_MAX };
1485 TIter cellNodes = meshData.getCellNodes( cell );
1486 for ( int n = 0; n < cellNodes.size(); ++n ) {
1487 const double* node = meshData.getNodeCoord( cellNodes[n] );
1488 for ( int j = 0; j < 3; ++j ) {
1489 if ( node[j] < min[j] ) min[j] = node[j];
1490 if ( node[j] > max[j] ) max[j] = node[j];
1493 double xmin = 0, xmax = 0, ymin = 0, ymax = 0, zmin, zmax;
1494 double parmin, parmax, par1, par2;
1495 bool xToSet, yToSet;
1496 const double infinite = 1e100;
1498 if (fabs(line._dir[0])>0.) {
1499 par1=(min[0]-line._coord[0])/line._dir[0];
1500 par2=(max[0]-line._coord[0])/line._dir[0];
1501 parmin=std::min(par1, par2);
1502 parmax=std::max(par1, par2);
1506 if (line._coord[0]<min[0] || max[0]<line._coord[0]) {
1509 xmin=line._coord[0];
1510 xmax=line._coord[0];
1516 if (fabs(line._dir[1])>0.) {
1517 par1=(min[1]-line._coord[1])/line._dir[1];
1518 par2=(max[1]-line._coord[1])/line._dir[1];
1519 if(parmax < std::min(par1,par2) || parmin > std::max(par1,par2))
1521 parmin=std::max(parmin, std::min(par1,par2));
1522 parmax=std::min(parmax, std::max(par1,par2));
1526 if (line._coord[1]<min[1] || max[1]<line._coord[1]) {
1529 ymin=line._coord[1];
1530 ymax=line._coord[1];
1534 if (fabs(line._dir[2])>0.) {
1535 par1=(min[2]-line._coord[2])/line._dir[2];
1536 par2=(max[2]-line._coord[2])/line._dir[2];
1537 if(parmax < std::min(par1,par2) || parmin > std::max(par1,par2))
1539 parmin=std::max(parmin, std::min(par1,par2));
1540 parmax=std::min(parmax, std::max(par1,par2));
1541 par1=line._coord[2]+parmin*line._dir[2];
1542 par2=line._coord[2]+parmax*line._dir[2];
1543 zmin=std::min(par1, par2);
1544 zmax=std::max(par1, par2);
1547 if (line._coord[2]<min[2] || max[2]<line._coord[2])
1549 zmin=line._coord[2];
1550 zmax=line._coord[2];
1552 if (zmax<min[2] || max[2]<zmin) return false;
1555 par1=line._coord[0]+parmin*line._dir[0];
1556 par2=line._coord[0]+parmax*line._dir[0];
1557 xmin=std::min(par1, par2);
1558 xmax=std::max(par1, par2);
1560 if (xmax<min[0] || max[0]<xmin) return false;
1563 par1=line._coord[1]+parmin*line._dir[1];
1564 par2=line._coord[1]+parmax*line._dir[1];
1565 ymin=std::min(par1, par2);
1566 ymax=std::max(par1, par2);
1568 if (ymax<min[1] || max[1]<ymin) return false;
1572 } // unnamed namespace