[bos #42217][EDF 28921] Horseshoe with bodyfitting.

Intermediate commit - parallel compute is disabled, some unrelated code commented out for debug!
Hexahedron::compute() was splitted to smaller methods.
Added debug output.
SMDS_MeshElement::Print() now is a virtual method, otherwise only parent method was called.
This commit is contained in:
Konstantin Leontev 2024-07-24 18:06:11 +01:00
parent 4b39d980ce
commit 9f7018e42a
6 changed files with 687 additions and 450 deletions

View File

@ -32,7 +32,7 @@
class SMDS_EXPORT SMDS_FaceOfNodes: public SMDS_CellOfNodes class SMDS_EXPORT SMDS_FaceOfNodes: public SMDS_CellOfNodes
{ {
public: public:
void Print(std::ostream & OS) const; virtual void Print(std::ostream & OS) const override;
SMDS_FaceOfNodes(const SMDS_MeshNode* node1, SMDS_FaceOfNodes(const SMDS_MeshNode* node1,
const SMDS_MeshNode* node2, const SMDS_MeshNode* node2,
const SMDS_MeshNode* node3); const SMDS_MeshNode* node3);

View File

@ -142,7 +142,7 @@ public:
SMDS_Mesh* GetMesh() const; SMDS_Mesh* GetMesh() const;
void Print(std::ostream & OS) const; virtual void Print(std::ostream & OS) const;
friend SMDS_EXPORT std::ostream & operator <<(std::ostream & OS, const SMDS_MeshElement *); friend SMDS_EXPORT std::ostream & operator <<(std::ostream & OS, const SMDS_MeshElement *);
friend class SMDS_ElementFactory; friend class SMDS_ElementFactory;

View File

@ -65,7 +65,7 @@ class SMDS_EXPORT SMDS_MeshNode: public SMDS_MeshElement
virtual bool IsMediumNode(const SMDS_MeshNode* /*node*/) const { return false; } virtual bool IsMediumNode(const SMDS_MeshNode* /*node*/) const { return false; }
virtual int NbCornerNodes() const { return 1; } virtual int NbCornerNodes() const { return 1; }
void Print(std::ostream & OS) const; virtual void Print(std::ostream & OS) const override;
private: private:

View File

@ -47,7 +47,7 @@ class SMDS_EXPORT SMDS_PolygonalFaceOfNodes : public SMDS_CellOfNodes
virtual int NbEdges() const; virtual int NbEdges() const;
virtual int NbFaces() const; virtual int NbFaces() const;
virtual void Print (std::ostream & OS) const; virtual void Print (std::ostream & OS) const override;
virtual const SMDS_MeshNode* GetNode(const int ind) const; virtual const SMDS_MeshNode* GetNode(const int ind) const;

View File

@ -62,7 +62,7 @@ class SMDS_EXPORT SMDS_VolumeOfNodes: public SMDS_CellOfNodes
const int nbNodes); const int nbNodes);
~SMDS_VolumeOfNodes(); ~SMDS_VolumeOfNodes();
void Print(std::ostream & OS) const; virtual void Print(std::ostream & OS) const override;
int NbFaces() const; int NbFaces() const;
int NbNodes() const; int NbNodes() const;
int NbEdges() const; int NbEdges() const;

View File

@ -773,6 +773,16 @@ namespace
if ( node ) if ( node )
_node = _intPoint->_node = node; _node = _intPoint->_node = node;
} }
friend std::ostream& operator<<(std::ostream& os, const _Node& node)
{
if (node._node)
node._node->Print(os);
else
os << "mesh node at hexahedron corner is null" << '\n';
return os;
}
}; };
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
struct _Link // link connecting two _Node's struct _Link // link connecting two _Node's
@ -783,6 +793,21 @@ namespace
vector< _Node* > _fIntNodes; // _Node's at _fIntPoints vector< _Node* > _fIntNodes; // _Node's at _fIntPoints
vector< _Link > _splits; vector< _Link > _splits;
_Link(): _faces{ 0, 0 } {} _Link(): _faces{ 0, 0 } {}
friend std::ostream& operator<<(std::ostream& os, const _Link& link)
{
os << "Link:\n";
for (int i = 0; i < 2; ++i)
{
if (link._nodes[i])
os << *link._nodes[i];
else
os << "link node with index " << i << " is null" << '\n';
}
return os;
}
}; };
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
struct _OrientedLink struct _OrientedLink
@ -852,6 +877,16 @@ namespace
} }
} }
} }
friend std::ostream& operator<<(std::ostream& os, const _OrientedLink& link)
{
if (link._link)
os << "Oriented " << *link._link;
else
os << "Oriented link is null" << '\n';
return os;
}
}; };
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
struct _SplitIterator //! set to _hexLinks splits on one side of INTERNAL FACEs struct _SplitIterator //! set to _hexLinks splits on one side of INTERNAL FACEs
@ -1114,6 +1149,26 @@ namespace
TID2Nb::iterator id2nb = id2nbMap.insert( s0 ).first; TID2Nb::iterator id2nb = id2nbMap.insert( s0 ).first;
id2nb->second++; id2nb->second++;
} }
// Called by compute()
//================================================================================
_Face* createPolygon(const SMESH_Block::TShapeID& name);
void closePolygon(
_Face* polygon, _Node* n2, _Node* nFirst, _Face& quad, vector<_Node*>& chainNodes, size_t& nbUsedEdgeNodes, _Face* prevPolyg);
void connectPolygonLinks(
const Solid* solid, _Face* polygon, _Face& quad, vector<_Node*>& chainNodes, std::vector<_OrientedLink>& splits, const bool toCheckSideDivision);
bool collectSplits(std::vector<_OrientedLink>& splits, const _Face& quad, _Face* polygon, int quadIndex);
std::set<TGeomID> getConcaveFaces(const Solid* solid);
std::vector<_Node*> getChainNodes(const Solid* solid, const IsInternalFlag intFlag);
void clearHexUsedInFace();
void clearIntUsedInFace();
void addPolygonsToLinks();
std::vector<_OrientedLink*> getFreeLinks();
int notUsedIntersectionNodesToVInt();
bool createPolygons(const bool hasEdgeIntersections, const IsInternalFlag intFlag);
void setNamesForNoNamePolygons();
bool createVolume(const Solid* solid);
//================================================================================
}; // class Hexahedron }; // class Hexahedron
#ifdef WITH_TBB #ifdef WITH_TBB
@ -2974,23 +3029,20 @@ namespace
//================================================================================ //================================================================================
/*! /*!
* \brief Compute mesh volumes resulted from intersection of the Hexahedron * \brief Collected faces can be used to avoid connecting nodes laying on them
*/ */
bool Hexahedron::compute( const Solid* solid, const IsInternalFlag intFlag ) std::set<TGeomID> Hexahedron::getConcaveFaces(const Solid* solid)
{ {
_polygons.clear(); MESSAGE("Collect concave faces...");
_polygons.reserve( 20 );
for ( int iN = 0; iN < 8; ++iN ) if (!solid->HasConcaveVertex())
_hexNodes[iN]._usedInFace = 0;
if ( intFlag & IS_CUT_BY_INTERNAL_FACE && !_grid->_toAddEdges ) // Issue #19913
preventVolumesOverlapping();
std::set< TGeomID > concaveFaces; // to avoid connecting nodes laying on them
if ( solid->HasConcaveVertex() )
{ {
MESSAGE("There's no concave faces here. Return.");
return {};
}
std::set< TGeomID > concaveFaces;
for ( const E_IntersectPoint* ip : _eIntPoints ) for ( const E_IntersectPoint* ip : _eIntPoints )
{ {
if ( const ConcaveFace* cf = solid->GetConcave( ip->_shapeID )) if ( const ConcaveFace* cf = solid->GetConcave( ip->_shapeID ))
@ -3005,26 +3057,34 @@ namespace
if ( this->hasEdgesAround( cf )) if ( this->hasEdgesAround( cf ))
concaveFaces.insert( cf->_concaveFace ); concaveFaces.insert( cf->_concaveFace );
} }
MESSAGE("Collected concave faces: " << concaveFaces.size());
return concaveFaces;
} }
// Create polygons from quadrangles //================================================================================
// -------------------------------- /*!
* \brief Creates a new polygone with a given name
vector< _OrientedLink > splits; */
vector<_Node*> chainNodes; Hexahedron::_Face* Hexahedron::createPolygon(const SMESH_Block::TShapeID& name)
_Face* coplanarPolyg;
const bool hasEdgeIntersections = !_eIntPoints.empty();
const bool toCheckSideDivision = isImplementEdges() || intFlag & IS_CUT_BY_INTERNAL_FACE;
for ( int iF = 0; iF < 6; ++iF ) // loop on 6 sides of a hexahedron
{ {
_Face& quad = _hexQuads[ iF ] ; MESSAGE("Create a polygon with a name: " << name);
_polygons.resize( _polygons.size() + 1 ); _polygons.resize( _polygons.size() + 1 );
_Face* polygon = &_polygons.back(); _Face* polygon = &_polygons.back();
polygon->_polyLinks.reserve( 20 ); polygon->_polyLinks.reserve( 20 );
polygon->_name = quad._name; polygon->_name = name;
return polygon;
}
//================================================================================
/*!
* \brief Collects split links on 4 sides of a quadrangle.
* Returns false if the quad on FACE is not split.
*/
bool Hexahedron::collectSplits(std::vector<_OrientedLink>& splits, const _Face& quad, _Face* polygon, int quadIndex)
{
MESSAGE("Collect splits...");
splits.clear(); splits.clear();
for ( int iE = 0; iE < 4; ++iE ) // loop on 4 sides of a quadrangle for ( int iE = 0; iE < 4; ++iE ) // loop on 4 sides of a quadrangle
@ -3032,15 +3092,52 @@ namespace
splits.push_back( quad._links[ iE ].ResultLink( iS )); splits.push_back( quad._links[ iE ].ResultLink( iS ));
if ( splits.size() == 4 && if ( splits.size() == 4 &&
isQuadOnFace( iF )) // check if a quad on FACE is not split isQuadOnFace( quadIndex )) // check if a quad on FACE is not split
{ {
MESSAGE("The quad on FACE is not split. Swap splits with polygon links.");
polygon->_links.swap( splits ); polygon->_links.swap( splits );
continue; // goto the next quad return false;
} }
MESSAGE("Collected splits: " << splits.size());
return true;
}
void Hexahedron::closePolygon(
_Face* polygon, _Node* n2, _Node* nFirst, _Face& quad, vector<_Node*>& chainNodes, size_t& nbUsedEdgeNodes, _Face* prevPolyg)
{
MESSAGE("Try to close polygon. Number of used edge nodes: " << nbUsedEdgeNodes);
if ( nFirst == n2 )
return;
if ( !findChain( n2, nFirst, quad, chainNodes ))
{
if ( !closePolygon( polygon, chainNodes ))
if ( !isImplementEdges() )
chainNodes.push_back( nFirst );
}
for ( size_t i = 1; i < chainNodes.size(); ++i )
{
polygon->AddPolyLink( chainNodes[i-1], chainNodes[i], prevPolyg );
nbUsedEdgeNodes += bool( chainNodes[i]->IsUsedInFace( polygon ));
MESSAGE("Added link for nodes:\n" << *chainNodes[i-1] << *chainNodes[i]);
}
MESSAGE("Polygon was closed. Number of used edge nodes: " << nbUsedEdgeNodes);
}
void Hexahedron::connectPolygonLinks(
const Solid* solid, _Face* polygon, _Face& quad, vector<_Node*>& chainNodes, std::vector<_OrientedLink>& splits, const bool toCheckSideDivision)
{
MESSAGE("Connect polygon links...");
const std::set<TGeomID> concaveFaces = getConcaveFaces(solid); // to avoid connecting nodes laying on them
// add splits of links to a polygon and add _polyLinks to make // add splits of links to a polygon and add _polyLinks to make
// polygon's boundary closed // polygon's boundary closed
int nbSplits = splits.size(); int nbSplits = splits.size();
if (( nbSplits == 1 ) && if (( nbSplits == 1 ) &&
( quad._eIntNodes.empty() || ( quad._eIntNodes.empty() ||
@ -3055,6 +3152,7 @@ namespace
size_t nbUsedEdgeNodes = 0; size_t nbUsedEdgeNodes = 0;
_Face* prevPolyg = 0; // polygon previously created from this quad _Face* prevPolyg = 0; // polygon previously created from this quad
MESSAGE("Number of splits: " << nbSplits);
while ( nbSplits > 0 ) while ( nbSplits > 0 )
{ {
size_t iS = 0; size_t iS = 0;
@ -3063,10 +3161,7 @@ namespace
if ( !polygon->_links.empty() ) if ( !polygon->_links.empty() )
{ {
_polygons.resize( _polygons.size() + 1 ); polygon = createPolygon(quad._name);
polygon = &_polygons.back();
polygon->_polyLinks.reserve( 20 );
polygon->_name = quad._name;
} }
polygon->_links.push_back( splits[ iS ] ); polygon->_links.push_back( splits[ iS ] );
splits[ iS++ ]._link = 0; splits[ iS++ ]._link = 0;
@ -3077,15 +3172,18 @@ namespace
for ( ; nFirst != n2 && iS < splits.size(); ++iS ) for ( ; nFirst != n2 && iS < splits.size(); ++iS )
{ {
_OrientedLink& split = splits[ iS ]; _OrientedLink& split = splits[ iS ];
MESSAGE("Current split: " << split);
if ( !split ) continue; if ( !split ) continue;
n1 = split.FirstNode(); n1 = split.FirstNode();
MESSAGE("\n\tnFirst: " << *nFirst << "\tn1: " << *n1 << "\tn2: " << *n2);
if ( n1 == n2 && if ( n1 == n2 &&
n1->_intPoint && n1->_intPoint &&
(( n1->_intPoint->_faceIDs.size() > 1 && toCheckSideDivision ) || (( n1->_intPoint->_faceIDs.size() > 1 && toCheckSideDivision ) ||
( n1->_isInternalFlags ))) ( n1->_isInternalFlags )))
{ {
// n1 is at intersection with EDGE // n1 is at intersection with EDGE
MESSAGE("n1 is at intersection with EDGE");
if ( findChainOnEdge( splits, polygon->_links.back(), split, concaveFaces, if ( findChainOnEdge( splits, polygon->_links.back(), split, concaveFaces,
iS, quad, chainNodes )) iS, quad, chainNodes ))
{ {
@ -3102,6 +3200,7 @@ namespace
else if ( n1 != n2 ) else if ( n1 != n2 )
{ {
// try to connect to intersections with EDGEs // try to connect to intersections with EDGEs
MESSAGE("n1 != n2 -> try to connect to intersections with EDGEs");
if ( quad._eIntNodes.size() > nbUsedEdgeNodes && if ( quad._eIntNodes.size() > nbUsedEdgeNodes &&
findChain( n2, n1, quad, chainNodes )) findChain( n2, n1, quad, chainNodes ))
{ {
@ -3120,6 +3219,7 @@ namespace
// try to connect to a split ending on the same FACE // try to connect to a split ending on the same FACE
else else
{ {
MESSAGE("try to connect to a split ending on the same FACE");
_OrientedLink foundSplit; _OrientedLink foundSplit;
for ( size_t i = iS; i < splits.size() && !foundSplit; ++i ) for ( size_t i = iS; i < splits.size() && !foundSplit; ++i )
if (( foundSplit = splits[ i ]) && if (( foundSplit = splits[ i ]) &&
@ -3131,6 +3231,8 @@ namespace
{ {
foundSplit._link = 0; foundSplit._link = 0;
} }
MESSAGE("Found split: " << foundSplit);
if ( foundSplit ) if ( foundSplit )
{ {
if ( n2 != foundSplit.FirstNode() ) if ( n2 != foundSplit.FirstNode() )
@ -3147,7 +3249,11 @@ namespace
polygon->AddPolyLink( n2, n1, prevPolyg ); polygon->AddPolyLink( n2, n1, prevPolyg );
} }
} }
} // if ( n1 != n2 ) }
else
{
MESSAGE("n1 == n2, split will be added as is");
}// if ( n1 != n2 )
polygon->_links.push_back( split ); polygon->_links.push_back( split );
split._link = 0; split._link = 0;
@ -3156,20 +3262,7 @@ namespace
} // loop on splits } // loop on splits
if ( nFirst != n2 ) // close a polygon closePolygon(polygon, n2, nFirst, quad, chainNodes, nbUsedEdgeNodes, prevPolyg);
{
if ( !findChain( n2, nFirst, quad, chainNodes ))
{
if ( !closePolygon( polygon, chainNodes ))
if ( !isImplementEdges() )
chainNodes.push_back( nFirst );
}
for ( size_t i = 1; i < chainNodes.size(); ++i )
{
polygon->AddPolyLink( chainNodes[i-1], chainNodes[i], prevPolyg );
nbUsedEdgeNodes += bool( chainNodes[i]->IsUsedInFace( polygon ));
}
}
if ( polygon->_links.size() < 3 && nbSplits > 0 ) if ( polygon->_links.size() < 3 && nbSplits > 0 )
{ {
@ -3178,31 +3271,81 @@ namespace
} }
} // while ( nbSplits > 0 ) } // while ( nbSplits > 0 )
MESSAGE("Polygon's links were connected");
}
//================================================================================
/*!
* \brief Collects chain nodes
*/
std::vector<Hexahedron::_Node*> Hexahedron::getChainNodes(const Solid* solid, const IsInternalFlag intFlag)
{
std::vector< _OrientedLink > splits;
std::vector<_Node*> chainNodes;
const bool toCheckSideDivision = isImplementEdges() || intFlag & IS_CUT_BY_INTERNAL_FACE;
for ( int iF = 0; iF < 6; ++iF ) // loop on 6 sides of a hexahedron
{
_Face& quad = _hexQuads[ iF ] ;
_Face* polygon = createPolygon(quad._name);
if (!collectSplits(splits, quad, polygon, iF))
continue; // goto the next quad
connectPolygonLinks(solid, polygon, quad, chainNodes, splits, toCheckSideDivision);
if ( polygon->_links.size() < 3 ) if ( polygon->_links.size() < 3 )
{ {
_polygons.pop_back(); _polygons.pop_back();
} }
} // loop on 6 hexahedron sides } // loop on 6 hexahedron sides
// Create polygons closing holes in a polyhedron return chainNodes;
// ---------------------------------------------- }
// clear _usedInFace //================================================================================
/*!
* \brief Reset used in faces for hex nodes
*/
void Hexahedron::clearHexUsedInFace()
{
for ( int iN = 0; iN < 8; ++iN )
_hexNodes[iN]._usedInFace = 0;
}
//================================================================================
/*!
* \brief Reset used in faces for int nodes
*/
void Hexahedron::clearIntUsedInFace()
{
for ( size_t iN = 0; iN < _intNodes.size(); ++iN ) for ( size_t iN = 0; iN < _intNodes.size(); ++iN )
_intNodes[ iN ]._usedInFace = 0; _intNodes[ iN ]._usedInFace = 0;
}
// add polygons to their links and mark used nodes //================================================================================
for ( size_t iP = 0; iP < _polygons.size(); ++iP ) /*!
* \brief Add polygons to their links and mark used nodes
*/
void Hexahedron::addPolygonsToLinks()
{ {
_Face& polygon = _polygons[ iP ]; for (_Face& polygon : _polygons)
for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
{ {
polygon._links[ iL ].AddFace( &polygon ); for (_OrientedLink& link : polygon._links)
polygon._links[ iL ].FirstNode()->_usedInFace = &polygon; {
link.AddFace( &polygon );
link.FirstNode()->_usedInFace = &polygon;
} }
} }
// find free links }
vector< _OrientedLink* > freeLinks;
//================================================================================
/*!
* \brief Finds free links in polygons
*/
std::vector<Hexahedron::_OrientedLink*> Hexahedron::getFreeLinks()
{
std::vector< _OrientedLink* > freeLinks;
freeLinks.reserve(20); freeLinks.reserve(20);
for ( size_t iP = 0; iP < _polygons.size(); ++iP ) for ( size_t iP = 0; iP < _polygons.size(); ++iP )
{ {
@ -3211,29 +3354,55 @@ namespace
if ( polygon._links[ iL ].NbFaces() < 2 ) if ( polygon._links[ iL ].NbFaces() < 2 )
freeLinks.push_back( & polygon._links[ iL ]); freeLinks.push_back( & polygon._links[ iL ]);
} }
return freeLinks;
}
//================================================================================
/*!
* \brief Put not used intersection nodes to _vIntNodes
*/
int Hexahedron::notUsedIntersectionNodesToVInt()
{
int nbVertexNodes = 0;
// TEMP: the loops below can be commented out for simplified testing
// for ( size_t iN = 0; iN < _vIntNodes.size(); ++iN )
// nbVertexNodes += ( !_vIntNodes[ iN ]->IsUsedInFace() );
// const double tol = 1e-3 * Min( Min( _sideLength[0], _sideLength[1] ), _sideLength[0] );
// for ( size_t iN = _nbFaceIntNodes; iN < _intNodes.size(); ++iN )
// {
// if ( _intNodes[ iN ].IsUsedInFace() ) continue;
// if ( dynamic_cast< const F_IntersectPoint* >( _intNodes[ iN ]._intPoint )) continue;
// _Node* equalNode =
// findEqualNode( _vIntNodes, _intNodes[ iN ].EdgeIntPnt(), tol*tol );
// if ( !equalNode )
// {
// _vIntNodes.push_back( &_intNodes[ iN ]);
// ++nbVertexNodes;
// }
// }
return nbVertexNodes;
}
//================================================================================
/*!
* \brief Creates polygons from free links
*/
bool Hexahedron::createPolygons(const bool hasEdgeIntersections, const IsInternalFlag intFlag)
{
MESSAGE("Create polygons from free links...");
// find free links
vector< _OrientedLink* > freeLinks = getFreeLinks();
int nbFreeLinks = freeLinks.size(); int nbFreeLinks = freeLinks.size();
SCRUTE(nbFreeLinks);
if ( nbFreeLinks == 1 ) return false; if ( nbFreeLinks == 1 ) return false;
// put not used intersection nodes to _vIntNodes // put not used intersection nodes to _vIntNodes
int nbVertexNodes = 0; // nb not used vertex nodes int nbVertexNodes = notUsedIntersectionNodesToVInt();
{
for ( size_t iN = 0; iN < _vIntNodes.size(); ++iN )
nbVertexNodes += ( !_vIntNodes[ iN ]->IsUsedInFace() );
const double tol = 1e-3 * Min( Min( _sideLength[0], _sideLength[1] ), _sideLength[0] );
for ( size_t iN = _nbFaceIntNodes; iN < _intNodes.size(); ++iN )
{
if ( _intNodes[ iN ].IsUsedInFace() ) continue;
if ( dynamic_cast< const F_IntersectPoint* >( _intNodes[ iN ]._intPoint )) continue;
_Node* equalNode =
findEqualNode( _vIntNodes, _intNodes[ iN ].EdgeIntPnt(), tol*tol );
if ( !equalNode )
{
_vIntNodes.push_back( &_intNodes[ iN ]);
++nbVertexNodes;
}
}
}
std::set<TGeomID> usedFaceIDs; std::set<TGeomID> usedFaceIDs;
std::vector< TGeomID > faces; std::vector< TGeomID > faces;
@ -3246,6 +3415,7 @@ namespace
size_t iPolygon = _polygons.size(); size_t iPolygon = _polygons.size();
while ( nbFreeLinks > 0 ) while ( nbFreeLinks > 0 )
{ {
SCRUTE(nbFreeLinks);
if ( iPolygon == _polygons.size() ) if ( iPolygon == _polygons.size() )
{ {
_polygons.resize( _polygons.size() + 1 ); _polygons.resize( _polygons.size() + 1 );
@ -3259,6 +3429,7 @@ namespace
if (( !hasEdgeIntersections ) || if (( !hasEdgeIntersections ) ||
( nbFreeLinks < 4 && nbVertexNodes == 0 )) ( nbFreeLinks < 4 && nbVertexNodes == 0 ))
{ {
MESSAGE("!hasEdgeIntersections || (nbFreeLinks < 4 && nbVertexNodes == 0), get a remaining link to start from...");
// get a remaining link to start from // get a remaining link to start from
for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
if (( curLink = freeLinks[ iL ] )) if (( curLink = freeLinks[ iL ] ))
@ -3282,150 +3453,153 @@ namespace
} }
else // there are intersections with EDGEs else // there are intersections with EDGEs
{ {
MESSAGE("there are intersections with EDGEs...");
// get a remaining link to start from, one lying on minimal nb of FACEs // get a remaining link to start from, one lying on minimal nb of FACEs
{ // {
typedef pair< TGeomID, int > TFaceOfLink; // typedef pair< TGeomID, int > TFaceOfLink;
TFaceOfLink faceOfLink( -1, -1 ); // TFaceOfLink faceOfLink( -1, -1 );
TFaceOfLink facesOfLink[3] = { faceOfLink, faceOfLink, faceOfLink }; // TFaceOfLink facesOfLink[3] = { faceOfLink, faceOfLink, faceOfLink };
for ( size_t iL = 0; iL < freeLinks.size(); ++iL ) // for ( size_t iL = 0; iL < freeLinks.size(); ++iL )
if ( freeLinks[ iL ] ) // if ( freeLinks[ iL ] )
{ // {
faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs ); // faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs );
if ( faces.size() == 1 ) // if ( faces.size() == 1 )
{ // {
faceOfLink = TFaceOfLink( faces[0], iL ); // faceOfLink = TFaceOfLink( faces[0], iL );
if ( !freeLinks[ iL ]->HasEdgeNodes() ) // if ( !freeLinks[ iL ]->HasEdgeNodes() )
break; // break;
facesOfLink[0] = faceOfLink; // facesOfLink[0] = faceOfLink;
} // }
else if ( facesOfLink[0].first < 0 ) // else if ( facesOfLink[0].first < 0 )
{ // {
faceOfLink = TFaceOfLink(( faces.empty() ? -1 : faces[0]), iL ); // faceOfLink = TFaceOfLink(( faces.empty() ? -1 : faces[0]), iL );
facesOfLink[ 1 + faces.empty() ] = faceOfLink; // facesOfLink[ 1 + faces.empty() ] = faceOfLink;
} // }
} // }
for ( int i = 0; faceOfLink.first < 0 && i < 3; ++i ) // for ( int i = 0; faceOfLink.first < 0 && i < 3; ++i )
faceOfLink = facesOfLink[i]; // faceOfLink = facesOfLink[i];
if ( faceOfLink.first < 0 ) // all faces used // if ( faceOfLink.first < 0 ) // all faces used
{ // {
for ( size_t iL = 0; iL < freeLinks.size() && faceOfLink.first < 1; ++iL ) // for ( size_t iL = 0; iL < freeLinks.size() && faceOfLink.first < 1; ++iL )
if (( curLink = freeLinks[ iL ])) // if (( curLink = freeLinks[ iL ]))
{ // {
faceOfLink.first = // faceOfLink.first =
curLink->FirstNode()->IsLinked( curLink->LastNode()->_intPoint ); // curLink->FirstNode()->IsLinked( curLink->LastNode()->_intPoint );
faceOfLink.second = iL; // faceOfLink.second = iL;
} // }
usedFaceIDs.clear(); // usedFaceIDs.clear();
} // }
curFace = faceOfLink.first; // curFace = faceOfLink.first;
curLink = freeLinks[ faceOfLink.second ]; // curLink = freeLinks[ faceOfLink.second ];
freeLinks[ faceOfLink.second ] = 0; // freeLinks[ faceOfLink.second ] = 0;
} // }
usedFaceIDs.insert( curFace ); // usedFaceIDs.insert( curFace );
polygon._links.push_back( *curLink ); // polygon._links.push_back( *curLink );
--nbFreeLinks; // --nbFreeLinks;
// find all links lying on a curFace // find all links lying on a curFace
do // do
{ // {
// go forward from curLink // // go forward from curLink
curNode = curLink->LastNode(); // curNode = curLink->LastNode();
curLink = 0; // curLink = 0;
for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) // for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
if ( freeLinks[ iL ] && // if ( freeLinks[ iL ] &&
freeLinks[ iL ]->FirstNode() == curNode && // freeLinks[ iL ]->FirstNode() == curNode &&
freeLinks[ iL ]->LastNode()->IsOnFace( curFace )) // freeLinks[ iL ]->LastNode()->IsOnFace( curFace ))
{ // {
curLink = freeLinks[ iL ]; // curLink = freeLinks[ iL ];
freeLinks[ iL ] = 0; // freeLinks[ iL ] = 0;
polygon._links.push_back( *curLink ); // polygon._links.push_back( *curLink );
--nbFreeLinks; // --nbFreeLinks;
} // }
} while ( curLink ); // } while ( curLink );
std::reverse( polygon._links.begin(), polygon._links.end() ); // std::reverse( polygon._links.begin(), polygon._links.end() );
curLink = & polygon._links.back(); // curLink = & polygon._links.back();
do // do
{ // {
// go backward from curLink // // go backward from curLink
curNode = curLink->FirstNode(); // curNode = curLink->FirstNode();
curLink = 0; // curLink = 0;
for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL ) // for ( size_t iL = 0; iL < freeLinks.size() && !curLink; ++iL )
if ( freeLinks[ iL ] && // if ( freeLinks[ iL ] &&
freeLinks[ iL ]->LastNode() == curNode && // freeLinks[ iL ]->LastNode() == curNode &&
freeLinks[ iL ]->FirstNode()->IsOnFace( curFace )) // freeLinks[ iL ]->FirstNode()->IsOnFace( curFace ))
{ // {
curLink = freeLinks[ iL ]; // curLink = freeLinks[ iL ];
freeLinks[ iL ] = 0; // freeLinks[ iL ] = 0;
polygon._links.push_back( *curLink ); // polygon._links.push_back( *curLink );
--nbFreeLinks; // --nbFreeLinks;
} // }
} while ( curLink ); // } while ( curLink );
curNode = polygon._links.back().FirstNode(); // curNode = polygon._links.back().FirstNode();
if ( polygon._links[0].LastNode() != curNode ) // if ( polygon._links[0].LastNode() != curNode )
{ // {
if ( nbVertexNodes > 0 ) // if ( nbVertexNodes > 0 )
{ // {
// add links with _vIntNodes if not already used // // add links with _vIntNodes if not already used
chainNodes.clear(); // chainNodes.clear();
for ( size_t iN = 0; iN < _vIntNodes.size(); ++iN ) // for ( size_t iN = 0; iN < _vIntNodes.size(); ++iN )
if ( !_vIntNodes[ iN ]->IsUsedInFace() && // if ( !_vIntNodes[ iN ]->IsUsedInFace() &&
_vIntNodes[ iN ]->IsOnFace( curFace )) // _vIntNodes[ iN ]->IsOnFace( curFace ))
{ // {
_vIntNodes[ iN ]->_usedInFace = &polygon; // _vIntNodes[ iN ]->_usedInFace = &polygon;
chainNodes.push_back( _vIntNodes[ iN ] ); // chainNodes.push_back( _vIntNodes[ iN ] );
} // }
if ( chainNodes.size() > 1 && // if ( chainNodes.size() > 1 &&
curFace != _grid->PseudoIntExtFaceID() ) /////// TODO // curFace != _grid->PseudoIntExtFaceID() ) /////// TODO
{ // {
sortVertexNodes( chainNodes, curNode, curFace ); // sortVertexNodes( chainNodes, curNode, curFace );
} // }
for ( size_t i = 0; i < chainNodes.size(); ++i ) // for ( size_t i = 0; i < chainNodes.size(); ++i )
{ // {
polygon.AddPolyLink( chainNodes[ i ], curNode ); // polygon.AddPolyLink( chainNodes[ i ], curNode );
curNode = chainNodes[ i ]; // curNode = chainNodes[ i ];
freeLinks.push_back( &polygon._links.back() ); // freeLinks.push_back( &polygon._links.back() );
++nbFreeLinks; // ++nbFreeLinks;
} // }
nbVertexNodes -= chainNodes.size(); // nbVertexNodes -= chainNodes.size();
} // }
// if ( polygon._links.size() > 1 ) // // if ( polygon._links.size() > 1 )
{ // {
polygon.AddPolyLink( polygon._links[0].LastNode(), curNode ); // polygon.AddPolyLink( polygon._links[0].LastNode(), curNode );
freeLinks.push_back( &polygon._links.back() ); // freeLinks.push_back( &polygon._links.back() );
++nbFreeLinks; // ++nbFreeLinks;
} // }
} // }
} // if there are intersections with EDGEs } // if there are intersections with EDGEs
if ( polygon._links.size() < 2 || // if ( polygon._links.size() < 2 ||
polygon._links[0].LastNode() != polygon._links.back().FirstNode() ) // polygon._links[0].LastNode() != polygon._links.back().FirstNode() )
{ // {
_polygons.clear(); // _polygons.clear();
break; // closed polygon not found -> invalid polyhedron // break; // closed polygon not found -> invalid polyhedron
} // }
if ( polygon._links.size() == 2 ) if ( polygon._links.size() == 2 )
{ {
if ( freeLinks.back() == &polygon._links.back() ) MESSAGE("polygon._links.size() == 2...");
{ // if ( freeLinks.back() == &polygon._links.back() )
freeLinks.pop_back(); // {
--nbFreeLinks; // freeLinks.pop_back();
} // --nbFreeLinks;
if ( polygon._links.front().NbFaces() > 0 ) // }
polygon._links.back().AddFace( polygon._links.front()._link->_faces[0] ); // if ( polygon._links.front().NbFaces() > 0 )
if ( polygon._links.back().NbFaces() > 0 ) // polygon._links.back().AddFace( polygon._links.front()._link->_faces[0] );
polygon._links.front().AddFace( polygon._links.back()._link->_faces[0] ); // if ( polygon._links.back().NbFaces() > 0 )
// polygon._links.front().AddFace( polygon._links.back()._link->_faces[0] );
if ( iPolygon == _polygons.size()-1 ) // if ( iPolygon == _polygons.size()-1 )
_polygons.pop_back(); // _polygons.pop_back();
} }
else // polygon._links.size() >= 2 else // polygon._links.size() >= 2
{ {
MESSAGE("polygon._links.size() >= 2, add polygon to its links...");
// add polygon to its links // add polygon to its links
for ( size_t iL = 0; iL < polygon._links.size(); ++iL ) for ( size_t iL = 0; iL < polygon._links.size(); ++iL )
{ {
@ -3435,26 +3609,27 @@ namespace
if ( /*hasEdgeIntersections &&*/ iPolygon == _polygons.size() - 1 ) if ( /*hasEdgeIntersections &&*/ iPolygon == _polygons.size() - 1 )
{ {
// check that a polygon does not lie on a hexa side // check that a polygon does not lie on a hexa side
coplanarPolyg = 0; _Face* coplanarPolyg = nullptr;
for ( size_t iL = 0; iL < polygon._links.size() && !coplanarPolyg; ++iL ) // for ( size_t iL = 0; iL < polygon._links.size() && !coplanarPolyg; ++iL )
{ // {
if ( polygon._links[ iL ].NbFaces() < 2 ) // if ( polygon._links[ iL ].NbFaces() < 2 )
continue; // it's a just added free link // continue; // it's a just added free link
// look for a polygon made on a hexa side and sharing // // look for a polygon made on a hexa side and sharing
// two or more haxa links // // two or more haxa links
size_t iL2; // size_t iL2;
coplanarPolyg = polygon._links[ iL ]._link->_faces[0]; // coplanarPolyg = polygon._links[ iL ]._link->_faces[0];
for ( iL2 = iL + 1; iL2 < polygon._links.size(); ++iL2 ) // for ( iL2 = iL + 1; iL2 < polygon._links.size(); ++iL2 )
if ( polygon._links[ iL2 ]._link->_faces[0] == coplanarPolyg && // if ( polygon._links[ iL2 ]._link->_faces[0] == coplanarPolyg &&
!coplanarPolyg->IsPolyLink( polygon._links[ iL ]) && // !coplanarPolyg->IsPolyLink( polygon._links[ iL ]) &&
!coplanarPolyg->IsPolyLink( polygon._links[ iL2 ]) && // !coplanarPolyg->IsPolyLink( polygon._links[ iL2 ]) &&
coplanarPolyg < & _polygons[ nbQuadPolygons ]) // coplanarPolyg < & _polygons[ nbQuadPolygons ])
break; // break;
if ( iL2 == polygon._links.size() ) // if ( iL2 == polygon._links.size() )
coplanarPolyg = 0; // coplanarPolyg = 0;
} // }
if ( coplanarPolyg ) // coplanar polygon found if ( coplanarPolyg ) // coplanar polygon found
{ {
MESSAGE("coplanar polygon found");
freeLinks.resize( freeLinks.size() - polygon._polyLinks.size() ); freeLinks.resize( freeLinks.size() - polygon._polyLinks.size() );
nbFreeLinks -= polygon._polyLinks.size(); nbFreeLinks -= polygon._polyLinks.size();
@ -3531,16 +3706,16 @@ namespace
} // end of case ( polygon._links.size() > 2 ) } // end of case ( polygon._links.size() > 2 )
} // while ( nbFreeLinks > 0 ) } // while ( nbFreeLinks > 0 )
for ( auto & face_ip : tmpAddedFace ) // for ( auto & face_ip : tmpAddedFace )
{ // {
curFace = face_ip.first; // curFace = face_ip.first;
for ( const B_IntersectPoint* ip : face_ip.second ) // for ( const B_IntersectPoint* ip : face_ip.second )
{ // {
auto it = std::find( ip->_faceIDs.begin(), ip->_faceIDs.end(), curFace ); // auto it = std::find( ip->_faceIDs.begin(), ip->_faceIDs.end(), curFace );
if ( it != ip->_faceIDs.end() ) // if ( it != ip->_faceIDs.end() )
ip->_faceIDs.erase( it ); // ip->_faceIDs.erase( it );
} // }
} // }
if ( _polygons.size() < 3 ) if ( _polygons.size() < 3 )
return false; return false;
@ -3548,18 +3723,29 @@ namespace
// check volume size // check volume size
double volSize = 0; double volSize = 0;
_hasTooSmall = ! checkPolyhedronSize( intFlag & IS_CUT_BY_INTERNAL_FACE, volSize ); _hasTooSmall = ! checkPolyhedronSize( intFlag & IS_CUT_BY_INTERNAL_FACE, volSize );
_volumeDefs._size = volSize;
for ( size_t i = 0; i < 8; ++i ) for ( size_t i = 0; i < 8; ++i )
if ( _hexNodes[ i ]._intPoint == &ipTmp ) if ( _hexNodes[ i ]._intPoint == &ipTmp )
_hexNodes[ i ]._intPoint = 0; _hexNodes[ i ]._intPoint = 0;
if ( _hasTooSmall ) return !_hasTooSmall; // too small volume
return false; // too small volume }
/*!
* \brief Sets names for no-name polygons
*/
void Hexahedron::setNamesForNoNamePolygons()
{
MESSAGE("Try to find out names of no-name polygons...");
// Try to find out names of no-name polygons (issue # 19887) // Try to find out names of no-name polygons (issue # 19887)
if ( _grid->IsToRemoveExcessEntities() && _polygons.back()._name == SMESH_Block::ID_NONE ) // TODO: why do we check only last face in vector?
{ if (!_grid->IsToRemoveExcessEntities() || _polygons.back()._name != SMESH_Block::ID_NONE )
return;
MESSAGE("No-name was found! It will be named after grid coordinates.");
gp_XYZ uvwCenter = gp_XYZ uvwCenter =
0.5 * ( _grid->_coords[0][_i] + _grid->_coords[0][_i+1] ) * _grid->_axes[0] + 0.5 * ( _grid->_coords[0][_i] + _grid->_coords[0][_i+1] ) * _grid->_axes[0] +
0.5 * ( _grid->_coords[1][_j] + _grid->_coords[1][_j+1] ) * _grid->_axes[1] + 0.5 * ( _grid->_coords[1][_j] + _grid->_coords[1][_j+1] ) * _grid->_axes[1] +
@ -3586,6 +3772,13 @@ namespace
} }
} }
/*!
* \brief Creates a volume as a classic element (Hexa, Tetra, Penta, Pyra) or non-specific polyhedron
*/
bool Hexahedron::createVolume(const Solid* solid)
{
MESSAGE("Create a volume...");
_volumeDefs._nodes.clear(); _volumeDefs._nodes.clear();
_volumeDefs._quantities.clear(); _volumeDefs._quantities.clear();
_volumeDefs._names.clear(); _volumeDefs._names.clear();
@ -3609,20 +3802,63 @@ namespace
else if ( nbNodes == 5 && nbPolygons == 5 ) isClassicElem = addPyra (); else if ( nbNodes == 5 && nbPolygons == 5 ) isClassicElem = addPyra ();
if ( !isClassicElem ) if ( !isClassicElem )
{ {
MESSAGE("It's not a classic element. Create a volume by polygons and links...");
for ( size_t iF = 0; iF < _polygons.size(); ++iF ) for ( size_t iF = 0; iF < _polygons.size(); ++iF )
{ {
const size_t nbLinks = _polygons[ iF ]._links.size(); const size_t nbLinks = _polygons[ iF ]._links.size();
SCRUTE(nbLinks);
if ( nbLinks < 3 ) continue; if ( nbLinks < 3 ) continue;
_volumeDefs._quantities.push_back( nbLinks ); _volumeDefs._quantities.push_back( nbLinks );
_volumeDefs._names.push_back( _polygons[ iF ]._name ); _volumeDefs._names.push_back( _polygons[ iF ]._name );
SCRUTE(_polygons[ iF ]._name);
for ( size_t iL = 0; iL < nbLinks; ++iL ) for ( size_t iL = 0; iL < nbLinks; ++iL )
_volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() ); _volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() );
} }
} }
_volumeDefs._solidID = solid->ID(); _volumeDefs._solidID = solid->ID();
_volumeDefs._size = volSize;
return !_volumeDefs._nodes.empty(); return !_volumeDefs._nodes.empty();
}
/*!
* \brief Compute mesh volumes resulted from intersection of the Hexahedron
*/
bool Hexahedron::compute( const Solid* solid, const IsInternalFlag intFlag )
{
MESSAGE("Compute solid " << solid->ID() << " with internal flag " << intFlag << " ...");
// Reset polygons
_polygons.clear();
_polygons.reserve( 20 );
clearHexUsedInFace();
// Check volumes
if ( intFlag & IS_CUT_BY_INTERNAL_FACE && !_grid->_toAddEdges ) // Issue #19913
preventVolumesOverlapping();
// Create polygons from quadrangles
// --------------------------------
vector<_Node*> chainNodes = getChainNodes(solid, intFlag);
// TODO: check if we can safely move it inside createPolygons()
const bool hasEdgeIntersections = !_eIntPoints.empty();
// Create polygons closing holes in a polyhedron
// ----------------------------------------------
clearIntUsedInFace();
addPolygonsToLinks();
// Create polygons
if (!createPolygons(hasEdgeIntersections, intFlag))
return false;
// Fix polygons' names
setNamesForNoNamePolygons();
return createVolume(solid);
} }
template<typename Type> template<typename Type>
@ -3651,11 +3887,12 @@ namespace
{ {
// A simple case - just one task executed in one thread. // A simple case - just one task executed in one thread.
// TODO: check if it's faster to do it sequentially // TODO: check if it's faster to do it sequentially
threads.reserve(numTasksTotal); // threads.reserve(numTasksTotal);
for (; it < last; ++it) // for (; it < last; ++it)
{ // {
threads.emplace_back(f, std::ref(*it)); // threads.emplace_back(f, std::ref(*it));
} // }
std::for_each(it, last, f);
} }
else else
{ {
@ -3818,16 +4055,16 @@ namespace
#endif #endif
// simplify polyhedrons // simplify polyhedrons
if ( _grid->IsToRemoveExcessEntities() ) // if ( _grid->IsToRemoveExcessEntities() )
{ // {
for ( size_t i = 0; i < intHexa.size(); ++i ) // for ( size_t i = 0; i < intHexa.size(); ++i )
if ( Hexahedron * hex = intHexa[ i ] ) // if ( Hexahedron * hex = intHexa[ i ] )
hex->removeExcessSideDivision( allHexa ); // hex->removeExcessSideDivision( allHexa );
for ( size_t i = 0; i < intHexa.size(); ++i ) // for ( size_t i = 0; i < intHexa.size(); ++i )
if ( Hexahedron * hex = intHexa[ i ] ) // if ( Hexahedron * hex = intHexa[ i ] )
hex->removeExcessNodes( allHexa ); // hex->removeExcessNodes( allHexa );
} // }
// add volumes // add volumes
for ( size_t i = 0; i < intHexa.size(); ++i ) for ( size_t i = 0; i < intHexa.size(); ++i )