const TGeomID theUndefID = 1e+9;
+ const std::string debugSepLine = "\n===========================================\n";
+
//=============================================================================
// Definitions of internal utils
// --------------------------------------------------------------------------
_node = _intPoint->_node = node;
}
+ void clear()
+ {
+ _node = nullptr;
+ _boundaryCornerNode = nullptr;
+ _intPoint = nullptr;
+ _usedInFace = nullptr;
+ _isInternalFlags = IS_NOT_INTERNAL;
+ }
+
friend std::ostream& operator<<(std::ostream& os, const _Node& node)
{
if (node._node)
- node._node->Print(os);
+ node._node->Print(os); // mesh node at hexahedron corner
+ else if (node._intPoint && node._intPoint->_node)
+ node._intPoint->_node->Print(os); // intersection point
else
- os << "mesh node at hexahedron corner is null" << '\n';
+ os << "mesh node is null" << '\n';
return os;
}
// --------------------------------------------------------------------------------
struct _Link // link connecting two _Node's
{
- _Node* _nodes[2];
- _Face* _faces[2]; // polygons sharing a link
+ static const std::size_t arrSize = 2;
+
+ _Node* _nodes[arrSize];
+ _Face* _faces[arrSize]; // polygons sharing a link
vector< const F_IntersectPoint* > _fIntPoints; // GridLine intersections with FACEs
vector< _Node* > _fIntNodes; // _Node's at _fIntPoints
vector< _Link > _splits;
_Link(): _faces{ 0, 0 } {}
+ void clear()
+ {
+ for (std::size_t i = 0; i < arrSize; ++i)
+ {
+ if (_nodes[i])
+ _nodes[i]->clear();
+ }
+
+ _fIntPoints.clear();
+ _fIntNodes.clear();
+ _splits.clear();
+ }
+
friend std::ostream& operator<<(std::ostream& os, const _Link& link)
{
os << "Link:\n";
- for (int i = 0; i < 2; ++i)
+ for (std::size_t i = 0; i < arrSize; ++i)
{
if (link._nodes[i])
os << *link._nodes[i];
os << "link node with index " << i << " is null" << '\n';
}
+ os << "_fIntPoints: " << link._fIntPoints.size() << '\n';
+ os << "_fIntNodes: " << link._fIntNodes.size() << '\n';
+ os << "_splits: " << link._splits.size() << '\n';
+
return os;
}
};
_polyLinks.push_back( l );
_links.push_back( _OrientedLink( &_polyLinks.back() ));
}
+
+ friend std::ostream& operator<<(std::ostream& os, const _Face& face)
+ {
+ os << "Face " << face._name << '\n';
+
+ os << "Links on GridLines: \n";
+ for (const auto& link : face._links)
+ {
+ os << link;
+ }
+
+ os << "Links added to close a polygonal face: \n";
+ for (const auto& link : face._polyLinks)
+ {
+ os << link;
+ }
+
+ os << "Nodes at intersection with EDGEs: \n";
+ for (const auto node : face._eIntNodes)
+ {
+ if (node)
+ {
+ os << *node;
+ }
+ }
+
+ return os;
+ }
};
// --------------------------------------------------------------------------------
struct _volumeDef // holder of nodes of a volume mesh element
};
// topology of a hexahedron
- _Node _hexNodes [8];
- _Link _hexLinks [12];
- _Face _hexQuads [6];
+ static const std::size_t HEX_NODES_NUM = 8;
+ static const std::size_t HEX_LINKS_NUM = 12;
+ static const std::size_t HEX_QUADS_NUM = 6;
+ _Node _hexNodes [HEX_NODES_NUM];
+ _Link _hexLinks [HEX_LINKS_NUM];
+ _Face _hexQuads [HEX_QUADS_NUM];
// faces resulted from hexahedron intersection
vector< _Face > _polygons;
Hexahedron(const Hexahedron& other, size_t i, size_t j, size_t k, int cellID );
void init( size_t i, size_t j, size_t k, const Solid* solid=0 );
void init( size_t i );
+ void clearNodesLinkedToNull(const Solid* solid, SMESH_MesherHelper& helper);
+ bool isSplittedLink(const Solid* solid, SMESH_MesherHelper& helper, const Hexahedron::_Link& linkIn) const;
void setIJK( size_t i );
bool compute( const Solid* solid, const IsInternalFlag intFlag );
size_t getSolids( TGeomID ids[] );
init( _i, _j, _k );
}
+ //================================================================================
+ /*!
+ * \brief Clear nodes linked to null by not splitted links
+ */
+ void Hexahedron::clearNodesLinkedToNull(const Solid* solid, SMESH_MesherHelper& helper)
+ {
+ for (std::size_t i = 0; i < HEX_LINKS_NUM; ++i)
+ {
+ _Link& link = _hexLinks[i];
+
+ if (isSplittedLink(solid, helper, link))
+ continue;
+
+ // Links where both nodes are valid should have itself as a split.
+ // Check if we have at least one null node here for a chance if we have
+ // some unexpected edge case.
+ _Node* n1 = link._nodes[0];
+ _Node* n2 = link._nodes[1];
+
+ assert(!n1->_node || !n2->_node);
+ if (!n1->_node || !n2->_node)
+ {
+ link.clear();
+ }
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Returns true if the link will be splitted on the Hexaedron initialization
+ */
+ bool Hexahedron::isSplittedLink(const Solid* solid, SMESH_MesherHelper& helper, const Hexahedron::_Link& linkIn) const
+ {
+ _Link split;
+ std::vector<_Node> intNodes;
+
+ _Link link = linkIn;
+ link._fIntNodes.clear();
+ link._fIntNodes.reserve( link._fIntPoints.size() );
+
+ for ( size_t i = 0; i < link._fIntPoints.size(); ++i )
+ if ( solid->ContainsAny( link._fIntPoints[i]->_faceIDs ))
+ {
+ intNodes.push_back( _Node( 0, link._fIntPoints[i] ));
+ link._fIntNodes.push_back( & intNodes.back() );
+ }
+
+ link._splits.clear();
+ split._nodes[ 0 ] = link._nodes[0];
+ bool isOut = ( ! link._nodes[0]->Node() );
+ bool checkTransition;
+ for ( size_t i = 0; i < link._fIntNodes.size(); ++i )
+ {
+ const bool isGridNode = ( ! link._fIntNodes[i]->Node() );
+ if ( !isGridNode ) // intersection non-coincident with a grid node
+ {
+ if ( split._nodes[ 0 ]->Node() && !isOut )
+ {
+ return true;
+ }
+ split._nodes[ 0 ] = link._fIntNodes[i];
+ checkTransition = true;
+ }
+ else // FACE intersection coincident with a grid node (at link ends)
+ {
+ checkTransition = ( i == 0 && link._nodes[0]->Node() );
+ }
+ if ( checkTransition )
+ {
+ const vector< TGeomID >& faceIDs = link._fIntNodes[i]->_intPoint->_faceIDs;
+ if ( _grid->IsInternal( faceIDs.back() ))
+ isOut = false;
+ else if ( faceIDs.size() > 1 || _eIntPoints.size() > 0 )
+ isOut = isOutPoint( link, i, helper, solid );
+ else
+ {
+ bool okTransi = _grid->IsCorrectTransition( faceIDs[0], solid );
+ switch ( link._fIntNodes[i]->FaceIntPnt()->_transition ) {
+ case Trans_OUT: isOut = okTransi; break;
+ case Trans_IN : isOut = !okTransi; break;
+ default:
+ isOut = isOutPoint( link, i, helper, solid );
+ }
+ }
+ }
+ }
+ if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
//================================================================================
/*!
* \brief Initializes its data by given grid cell nodes and intersections
*/
void Hexahedron::init( size_t i, size_t j, size_t k, const Solid* solid )
{
+ MESSAGE(debugSepLine << "START Hexahedron::init()" << debugSepLine);
+
_i = i; _j = j; _k = k;
bool isCompute = solid;
// this method can be called in parallel, so use own helper
SMESH_MesherHelper helper( *_grid->_helper->GetMesh() );
+ clearNodesLinkedToNull(solid, helper);
+
// Create sub-links (_Link::_splits) by splitting links with _Link::_fIntPoints
// ---------------------------------------------------------------
_Link split;
}
}
}
- return;
+ MESSAGE(debugSepLine << "END Hexahedron::init()" << debugSepLine);
} // init( _i, _j, _k )
//================================================================================
*/
bool Hexahedron::collectSplits(std::vector<_OrientedLink>& splits, const _Face& quad, _Face* polygon, int quadIndex)
{
- MESSAGE("Collect splits...");
+ MESSAGE(debugSepLine << "START Collect splits..." << debugSepLine);
splits.clear();
for ( int iE = 0; iE < 4; ++iE ) // loop on 4 sides of a quadrangle
for ( size_t iS = 0; iS < quad._links[ iE ].NbResultLinks(); ++iS )
+ {
splits.push_back( quad._links[ iE ].ResultLink( iS ));
+ // SCRUTE(splits.back());
+ }
if ( splits.size() == 4 &&
isQuadOnFace( quadIndex )) // check if a quad on FACE is not split
{
- MESSAGE("The quad on FACE is not split. Swap splits with polygon links.");
+ MESSAGE(debugSepLine << "END. The quad on FACE is not split. Swap splits with polygon links." << debugSepLine);
polygon->_links.swap( splits );
return false;
}
- MESSAGE("Collected splits: " << splits.size());
+ MESSAGE(debugSepLine << "Collected splits: " << splits.size() << debugSepLine);
return true;
}
void Hexahedron::connectPolygonLinks(
const Solid* solid, _Face* polygon, _Face& quad, vector<_Node*>& chainNodes, std::vector<_OrientedLink>& splits, const bool toCheckSideDivision)
{
- MESSAGE("Connect polygon links...");
+ MESSAGE(debugSepLine << "START connectPolygonLinks()..." << debugSepLine);
const std::set<TGeomID> concaveFaces = getConcaveFaces(solid); // to avoid connecting nodes laying on them
polygon = createPolygon(quad._name);
}
polygon->_links.push_back( splits[ iS ] );
+ MESSAGE("Split link was added to a polygon: " << splits[iS]);
splits[ iS++ ]._link = 0;
--nbSplits;
else if ( n1 != n2 )
{
// try to connect to intersections with EDGEs
- MESSAGE("n1 != n2 -> try to connect to intersections with EDGEs");
+ MESSAGE("n1 != n2...");
if ( quad._eIntNodes.size() > nbUsedEdgeNodes &&
findChain( n2, n1, quad, chainNodes ))
{
+ MESSAGE("try to connect to intersections with EDGEs");
for ( size_t i = 1; i < chainNodes.size(); ++i )
{
polygon->AddPolyLink( chainNodes[i-1], chainNodes[i] );
{
if ( n2 != foundSplit.FirstNode() )
{
+ MESSAGE("Add link n2 -> foundSplit.FirstNode()");
polygon->AddPolyLink( n2, foundSplit.FirstNode() );
n2 = foundSplit.FirstNode();
}
}
} // while ( nbSplits > 0 )
- MESSAGE("Polygon's links were connected");
+ MESSAGE(debugSepLine << "END connectPolygonLinks(): " << *polygon << debugSepLine);
}
//================================================================================
*/
std::vector<Hexahedron::_Node*> Hexahedron::getChainNodes(const Solid* solid, const IsInternalFlag intFlag)
{
+ MESSAGE(debugSepLine << "START Get chain nodes..." << debugSepLine);
+
std::vector< _OrientedLink > splits;
std::vector<_Node*> chainNodes;
{
_Face& quad = _hexQuads[ iF ] ;
_Face* polygon = createPolygon(quad._name);
+ SCRUTE(quad);
if (!collectSplits(splits, quad, polygon, iF))
continue; // goto the next quad
}
} // loop on 6 hexahedron sides
+ MESSAGE(debugSepLine << "END Collected " << chainNodes.size() << " chain nodes" << debugSepLine);
return chainNodes;
}
*/
void Hexahedron::addPolygonsToLinks()
{
+ MESSAGE(debugSepLine << "START addPolygonsToLinks()..." << debugSepLine);
for (_Face& polygon : _polygons)
{
+ // MESSAGE("START add polygon to its links : " << polygon << debugSepLine);
for (_OrientedLink& link : polygon._links)
{
link.AddFace( &polygon );
link.FirstNode()->_usedInFace = &polygon;
}
}
+ MESSAGE(debugSepLine << "END addPolygonsToLinks()" << debugSepLine);
}
//================================================================================
*/
bool Hexahedron::createPolygons(const bool hasEdgeIntersections, const IsInternalFlag intFlag)
{
- MESSAGE("Create polygons from free links...");
+ MESSAGE(debugSepLine << "START createPolygons()..." << debugSepLine);
// find free links
vector< _OrientedLink* > freeLinks = getFreeLinks();
std::vector< TGeomID > faces;
TGeomID curFace = 0;
const size_t nbQuadPolygons = _polygons.size();
+ SCRUTE(nbQuadPolygons);
E_IntersectPoint ipTmp;
std::map< TGeomID, std::vector< const B_IntersectPoint* > > tmpAddedFace; // face added to _intPoint
_polygons[ iPolygon ]._links.reserve( 20 );
}
_Face& polygon = _polygons[ iPolygon ];
+ SCRUTE(polygon);
_OrientedLink* curLink = 0;
_Node* curNode;
polygon._links.push_back( *curLink );
}
} while ( curLink );
+ SCRUTE(polygon);
}
else // there are intersections with EDGEs
{
{
polygon._links[ iL ].AddFace( &polygon );
polygon._links[ iL ].Reverse();
+ SCRUTE(polygon);
}
if ( /*hasEdgeIntersections &&*/ iPolygon == _polygons.size() - 1 )
{
if ( _hexNodes[ i ]._intPoint == &ipTmp )
_hexNodes[ i ]._intPoint = 0;
+ MESSAGE(debugSepLine << "END createPolygons()" << debugSepLine);
return !_hasTooSmall; // too small volume
}
*/
bool Hexahedron::createVolume(const Solid* solid)
{
- MESSAGE("Create a volume...");
+ MESSAGE(debugSepLine << "START createVolume()" << debugSepLine);
_volumeDefs._nodes.clear();
_volumeDefs._quantities.clear();
// create a classic cell if possible
int nbPolygons = 0;
+ SCRUTE(_polygons.size());
for ( size_t iF = 0; iF < _polygons.size(); ++iF )
nbPolygons += (_polygons[ iF ]._links.size() > 2 );
+ SCRUTE(nbPolygons);
+
//const int nbNodes = _nbCornerNodes + nbIntersections;
int nbNodes = 0;
for ( size_t i = 0; i < 8; ++i )
for ( size_t i = 0; i < _intNodes.size(); ++i )
nbNodes += _intNodes[ i ].IsUsedInFace();
+ SCRUTE(nbNodes);
bool isClassicElem = false;
if ( nbNodes == 8 && nbPolygons == 6 ) isClassicElem = addHexa();
else if ( nbNodes == 4 && nbPolygons == 4 ) isClassicElem = addTetra();
for ( size_t iF = 0; iF < _polygons.size(); ++iF )
{
const size_t nbLinks = _polygons[ iF ]._links.size();
- SCRUTE(nbLinks);
if ( nbLinks < 3 ) continue;
_volumeDefs._quantities.push_back( nbLinks );
_volumeDefs._names.push_back( _polygons[ iF ]._name );
- SCRUTE(_polygons[ iF ]._name);
for ( size_t iL = 0; iL < nbLinks; ++iL )
_volumeDefs._nodes.push_back( _polygons[ iF ]._links[ iL ].FirstNode() );
+
+ // SCRUTE(_polygons[ iF ]);
}
}
_volumeDefs._solidID = solid->ID();
+ MESSAGE(debugSepLine << "END createVolume()" << debugSepLine);
return !_volumeDefs._nodes.empty();
}
*/
bool Hexahedron::compute( const Solid* solid, const IsInternalFlag intFlag )
{
- MESSAGE("Compute solid " << solid->ID() << " with internal flag " << intFlag << " ...");
+ MESSAGE(debugSepLine << "START Compute solid " << solid->ID() << " ..." << debugSepLine);
// Reset polygons
_polygons.clear();
// Fix polygons' names
setNamesForNoNamePolygons();
- return createVolume(solid);
+ const bool isVolumeCreated = createVolume(solid);
+ SCRUTE(isVolumeCreated);
+ MESSAGE(debugSepLine << "END Compute solid " << solid->ID() << debugSepLine);
+
+ return isVolumeCreated;
}
template<typename Type>