-// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
-// SMESH SMESH : implementaion of SMESH idl descriptions
+// SMESH SMESH : implementation of SMESH idl descriptions
// File : SMESH_subMesh.cxx
// Author : Paul RASCLE, EDF
// Module : SMESH
#include "SMESH_MesherHelper.hxx"
#include "SMESH_subMeshEventListener.hxx"
-#include <Basics_OCCTVersion.hxx>
-
#include "utilities.h"
-#include "OpUtil.hxx"
#include "Basics_Utils.hxx"
#include <BRep_Builder.hxx>
using namespace std;
+#ifdef _DEBUG_
+// enable printing algo + shape id + hypo used while meshing
+//#define PRINT_WHO_COMPUTE_WHAT
+#endif
+
+//#define PRINT_WHO_COMPUTE_WHAT
//=============================================================================
/*!
* \brief Allocate some memory at construction and release it at destruction.
}
_computeCost = 0; // how costly is to compute this sub-mesh
_realComputeCost = 0;
+ _allowedSubShapes = nullptr;
}
//=============================================================================
if ( !_algo )
{
SMESH_subMesh* me = const_cast< SMESH_subMesh* >( this );
- me->_algo = _father->GetGen()->GetAlgo( me );
+ me->_algo = _father->GetGen()->GetAlgo( me, & me->_algoShape );
}
return _algo;
}
TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
for ( ; exp.More(); exp.Next() )
{
- if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( exp.Current() ))
+ if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( exp.Current() ) )
{
bool computed = (dim > 0) ? smDS->NbElements() : smDS->NbNodes();
if ( computed )
return false;
}
+//================================================================================
+/*!
+ * \brief Check if any upper level sub-shape is not computed.
+ * Used to update a sub-mesh icon
+ */
+//================================================================================
+
+bool SMESH_subMesh::IsComputedPartially() const
+{
+ SMESH_subMeshIteratorPtr smIt = getDependsOnIterator(/*includeSelf=*/true,
+ /*SolidFirst=*/true);
+ bool allComputed = true;
+ TopAbs_ShapeEnum readyType = TopAbs_VERTEX; // max value
+ while ( smIt->more() && allComputed )
+ {
+ SMESH_subMesh* sm = smIt->next();
+
+ if ( sm->GetSubShape().ShapeType() > readyType )
+ break; // lower dimension -> stop
+ if ( sm->GetComputeState() != SMESH_subMesh::NOT_READY )
+ readyType = sm->GetSubShape().ShapeType();
+
+ switch ( sm->GetComputeState() )
+ {
+ case SMESH_subMesh::READY_TO_COMPUTE:
+ case SMESH_subMesh::FAILED_TO_COMPUTE:
+ allComputed = false;// sm->IsMeshComputed();
+ break;
+ case SMESH_subMesh::NOT_READY:
+ case SMESH_subMesh::COMPUTE_OK:
+ continue;
+ }
+ }
+ return !allComputed;
+}
+
//=============================================================================
/*!
* Return true if all sub-meshes have been meshed
*/
//=============================================================================
-const map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn()
+const std::map < int, SMESH_subMesh * >& SMESH_subMesh::DependsOn()
{
if ( _dependenceAnalysed || !_father->HasShapeToMesh() )
return _mapDepend;
//=======================================================================
//function : CanAddHypothesis
//purpose : return true if theHypothesis can be attached to me:
-// its dimention is checked
+// its dimension is checked
//=======================================================================
bool SMESH_subMesh::CanAddHypothesis(const SMESH_Hypothesis* theHypothesis) const
}
//=======================================================================
-//function : IsApplicableHypotesis
-//purpose :
+//function : IsApplicableHypothesis
+//purpose : check if this sub-mesh can be computed using a hypothesis
+//=======================================================================
+
+bool SMESH_subMesh::IsApplicableHypothesis(const SMESH_Hypothesis* theHypothesis) const
+{
+ if ( !_father->HasShapeToMesh() && _subShape.ShapeType() == TopAbs_SOLID )
+ return true; // true for the PseudoShape
+
+ return IsApplicableHypothesis( theHypothesis, _subShape.ShapeType() );
+}
+
+//=======================================================================
+//function : IsApplicableHypothesis
+//purpose : compare shape type and hypothesis type
//=======================================================================
-bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
- const TopAbs_ShapeEnum theShapeType)
+bool SMESH_subMesh::IsApplicableHypothesis(const SMESH_Hypothesis* theHypothesis,
+ const TopAbs_ShapeEnum theShapeType)
{
if ( theHypothesis->GetType() > SMESHDS_Hypothesis::PARAM_ALGO)
{
* \param [in] event - what happens
* \param [in] anHyp - a hypothesis
* \return SMESH_Hypothesis::Hypothesis_Status - a treatment result.
- *
+ *
* Optional description of a problematic situation (if any) can be retrieved
* via GetComputeError().
*/
bool modifiedHyp = (event == MODIF_HYP); // if set to true, force event MODIF_ALGO_STATE
SMESH_Algo* algoRequiringCleaning = 0;
- bool isApplicableHyp = IsApplicableHypotesis( anHyp );
+ bool isApplicableHyp = IsApplicableHypothesis( anHyp );
if (event == ADD_ALGO || event == ADD_FATHER_ALGO)
{
filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+1 ));
filter.Or( SMESH_HypoFilter::HasType( algo->GetType()+2 ));
if ( SMESH_Algo * curAlgo = (SMESH_Algo*)_father->GetHypothesis( this, filter, true ))
- if ( !curAlgo->NeedDiscreteBoundary() )
+ if ( !curAlgo->NeedDiscreteBoundary() && curAlgo != anHyp )
algoRequiringCleaning = curAlgo;
}
}
const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( this, f, true );
if (prevAlgo &&
string( algo->GetName()) != prevAlgo->GetName())
- modifiedHyp = true;
+ {
+ oldAlgoState = NO_ALGO; // force setting event listener (#16648)
+ modifiedHyp = true;
+ }
}
else
setAlgoState(MISSING_HYP);
// detect algorithm hiding
//
- if ( ret == SMESH_Hypothesis::HYP_OK &&
- ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && algo &&
+ if ( ret == SMESH_Hypothesis::HYP_OK &&
+ ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && algo &&
algo->GetName() == anHyp->GetName() )
{
// is algo hidden?
if ( !theAlgo ) return false;
// Suppose that theAlgo is applicable to _subShape, do not check it here
- //if ( !IsApplicableHypotesis( theAlgo )) return false;
+ //if ( !IsApplicableHypothesis( theAlgo )) return false;
// check only algo that doesn't NeedDiscreteBoundary(): because mesh made
// on a sub-shape will be ignored by theAlgo
static void cleanSubMesh( SMESH_subMesh * subMesh )
{
if (subMesh) {
- if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS()) {
+ if (SMESHDS_SubMesh * subMeshDS = subMesh->GetSubMeshDS())
+ {
SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
- SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
- while (ite->more()) {
- const SMDS_MeshElement * elt = ite->next();
- //MESSAGE( " RM elt: "<<elt->GetID()<<" ( "<<elt->NbNodes()<<" )" );
- //meshDS->RemoveElement(elt);
- meshDS->RemoveFreeElement(elt, 0);
- }
-
- SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
- while (itn->more()) {
- const SMDS_MeshNode * node = itn->next();
- //MESSAGE( " RM node: "<<node->GetID());
- if ( node->NbInverseElements() == 0 )
- meshDS->RemoveFreeNode(node, 0);
- else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
- meshDS->RemoveNode(node);
- }
+ smIdType nbElems = subMeshDS->NbElements();
+ if ( nbElems > 0 )
+ for ( SMDS_ElemIteratorPtr ite = subMeshDS->GetElements(); ite->more(); )
+ meshDS->RemoveFreeElement( ite->next(), subMeshDS );
+
+ smIdType nbNodes = subMeshDS->NbNodes();
+ if ( nbNodes > 0 )
+ for ( SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes(); itn->more() ; )
+ {
+ const SMDS_MeshNode * node = itn->next();
+ if ( node->NbInverseElements() == 0 )
+ meshDS->RemoveFreeNode( node, subMeshDS );
+ else // for StdMeshers_CompositeSegment_1D: node in one submesh, edge in another
+ meshDS->RemoveNode( node );
+ }
subMeshDS->Clear();
}
}
else if (( event == COMPUTE || event == COMPUTE_SUBMESH )
&& !_alwaysComputed )
{
+ // LOCK: Adding node to mesh
+ _father->Lock();
const TopoDS_Vertex & V = TopoDS::Vertex( _subShape );
gp_Pnt P = BRep_Tool::Pnt(V);
if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) {
_father->GetMeshDS()->SetNodeOnVertex(n,_Id);
_computeState = COMPUTE_OK;
}
+ _father->Unlock();
+ // UNLOCK
}
if ( event == MODIF_ALGO_STATE )
cleanDependants();
loadDependentMeshes();
ComputeSubMeshStateEngine( SUBMESH_LOADED );
//break;
+ // fall through
case CHECK_COMPUTE_STATE:
if ( IsMeshComputed() )
_computeState = COMPUTE_OK;
_computeState = READY_TO_COMPUTE;
}
break;
+
+ case COMPUTE_NOGEOM: // no geometry; can be several algos
+ if ( !_father->HasShapeToMesh() )
+ {
+ algo = GetAlgo(); // current algo
+ if ( algo )
+ {
+ // apply algos in the order of increasing dimension
+ std::list< const SMESHDS_Hypothesis * > algos = _father->GetHypothesisList( _subShape );
+ for ( int t = SMESHDS_Hypothesis::ALGO_1D; t <= SMESHDS_Hypothesis::ALGO_3D; ++t )
+ {
+ std::list<const SMESHDS_Hypothesis *>::iterator al = algos.begin();
+ for ( ; al != algos.end(); ++al )
+ if ( (*al)->GetType() == t )
+ {
+ _algo = (SMESH_Algo*) *al;
+ _computeState = READY_TO_COMPUTE;
+ if ( !ComputeStateEngine( COMPUTE ))
+ break;
+ }
+ }
+ _algo = algo; // restore
+ }
+ break;
+ }
+ // fall through
case COMPUTE:
case COMPUTE_SUBMESH:
{
algo = GetAlgo();
ASSERT(algo);
- ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
+ if(!_father->IsParallel())
+ ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
+ else
+ ret = true;
if (!ret)
{
MESSAGE("***** verify compute state *****");
break;
}
TopoDS_Shape shape = _subShape;
- algo->SubMeshesToCompute().assign( 1, this );
+ if(!_father->IsParallel())
+ algo->SubMeshesToCompute().assign( 1, this );
// check submeshes needed
- if (_father->HasShapeToMesh() ) {
+ // In parallel there would be no submesh to check
+ if (_father->HasShapeToMesh() && !_father->IsParallel()) {
bool subComputed = false, subFailed = false;
if (!algo->OnlyUnaryInput()) {
- if ( event == COMPUTE /*&&
- ( algo->NeedDiscreteBoundary() || algo->SupportSubmeshes() )*/)
- shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
- else
- subComputed = SubMeshesComputed( & subFailed );
+ // --- commented for bos#22320 to compute all sub-shapes at once if possible;
+ // --- in case COMPUTE_SUBMESH, set of sub-shapes is limited
+ // --- by calling SetAllowedSubShapes()
+ // if ( event == COMPUTE )
+ // shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToComput;
+ // else
+ // subComputed = SubMeshesComputed( & subFailed );
+ shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
}
else {
subComputed = SubMeshesComputed();
}
else
{
+ // TODO: Do switch of compute here instead of within algo
ret = algo->Compute((*_father), shape);
}
// algo can set _computeError of submesh
!algo->isDegenerated( TopoDS::Edge( subS.Current() ))))
ret = false;
}
+#ifdef PRINT_WHO_COMPUTE_WHAT
+ for (subS.ReInit(); subS.More(); subS.Next())
+ {
+ _father->Lock();
+ const std::list <const SMESHDS_Hypothesis *> hyps =
+ _algo->GetUsedHypothesis( *_father, _subShape );
+ _father->Unlock();
+ SMESH_Comment hypStr;
+ if ( !hyps.empty() )
+ {
+ hypStr << hyps.front()->GetName() << " ";
+ ((SMESHDS_Hypothesis*)hyps.front())->SaveTo( hypStr.Stream() );
+ hypStr << " ";
+ }
+ cout << _father->GetSubMesh( subS.Current() )->GetId()
+ << " " << ( ret ? "OK" : "FAIL" )
+ << " " << _algo->GetName()
+ << " " << hypStr << endl;
+ }
+#endif
// Set _computeError
if ( !ret && !isComputeErrorSet )
{
else
updateDependantsState( SUBMESH_COMPUTED );
}
+ // let algo clear its data gathered while algo->Compute()
+ if(!_father->IsParallel())
+ algo->CheckHypothesis((*_father), _subShape, hyp_status);
}
break;
case COMPUTE_CANCELED: // nothing to do
loadDependentMeshes();
ComputeSubMeshStateEngine( SUBMESH_LOADED );
//break;
+ // fall through
case CHECK_COMPUTE_STATE:
if ( IsMeshComputed() )
_computeState = COMPUTE_OK;
break;
case COMPUTE: // nothing to do
break;
+ case COMPUTE_SUBMESH: // nothing to do
+ break;
case COMPUTE_CANCELED: // nothing to do
break;
case CLEAN:
- cleanDependants(); // clean sub-meshes, dependant on this one, with event CLEAN
+ cleanDependants(); // clean sub-meshes, dependent on this one, with event CLEAN
removeSubMeshElementsAndNodes();
_computeState = NOT_READY;
if ( _algoState == HYP_OK )
break;
}
- notifyListenersOnEvent( event, COMPUTE_EVENT );
+ //notifyListenersOnEvent( event, COMPUTE_EVENT );
return ret;
}
bool ret = true;
if (_subShape.ShapeType() == TopAbs_VERTEX) {
- vector<int> aVec(SMDSEntity_Last,0);
+ vector<smIdType> aVec(SMDSEntity_Last,0);
aVec[SMDSEntity_Node] = 1;
aResMap.insert(make_pair(this,aVec));
return ret;
SMESH_subMesh* sm = smIt->next();
int dim = SMESH_Gen::GetShapeDim( sm->GetSubShape() );
if (dim < dimToCheck) break; // the rest subMeshes are all of less dimension
- const vector<int> & nbs = aResMap[ sm ];
+ const vector<smIdType> & nbs = aResMap[ sm ];
subMeshEvaluated = (std::accumulate( nbs.begin(), nbs.end(), 0 ) > 0 );
}
if ( !subMeshEvaluated )
if ( IsMeshComputed() )
{
- vector<int> & nbEntities = aResMap[ this ];
+ vector<smIdType> & nbEntities = aResMap[ this ];
nbEntities.resize( SMDSEntity_Last, 0 );
if ( SMESHDS_SubMesh* sm = GetSubMeshDS() )
{
{
ret = algo->Evaluate((*_father), _subShape, aResMap);
}
- aResMap.insert( make_pair( this,vector<int>(0)));
+ aResMap.insert( make_pair( this,vector<smIdType>(0)));
}
return ret;
//=======================================================================
//function : cleanDependants
-//purpose :
+//purpose :
//=======================================================================
void SMESH_subMesh::cleanDependants()
//=======================================================================
//function : removeSubMeshElementsAndNodes
-//purpose :
+//purpose :
//=======================================================================
void SMESH_subMesh::removeSubMeshElementsAndNodes()
// meshed at once along with _subShape
//=======================================================================
-TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * theGen,
+TopoDS_Shape SMESH_subMesh::getCollection(SMESH_Gen * /*theGen*/,
SMESH_Algo* theAlgo,
bool & theSubComputed,
bool & theSubFailed,
return _subShape;
const bool skipAuxHyps = false;
- list<const SMESHDS_Hypothesis*> aUsedHyp =
+ list<const SMESHDS_Hypothesis*> usedHyps =
theAlgo->GetUsedHypothesis( *_father, _subShape, skipAuxHyps ); // copy
+ std::list < TopoDS_Shape > assiShapes = theAlgo->GetAssignedShapes();
// put in a compound all shapes with the same hypothesis assigned
// and a good ComputeState
const TopoDS_Shape& S = subMesh->_subShape;
if ( S.ShapeType() != this->_subShape.ShapeType() )
continue;
+ if ( _allowedSubShapes && !_allowedSubShapes->IsEmpty() && !_allowedSubShapes->Contains( S ))
+ continue;
if ( subMesh == this )
{
aBuilder.Add( aCompound, S );
{
SMESH_Algo* anAlgo = subMesh->GetAlgo();
if (( anAlgo->IsSameName( *theAlgo )) && // same algo
- ( anAlgo->GetUsedHypothesis( *_father, S, skipAuxHyps ) == aUsedHyp )) // same hyps
+ ( anAlgo->GetUsedHypothesis( *_father, S, skipAuxHyps ) == usedHyps ) && // same hyps
+ ( anAlgo->GetAssignedShapes() == assiShapes ) && // on same sub-shapes
+ ( _algoShape == subMesh->_algoShape ))
{
aBuilder.Add( aCompound, S );
if ( !subMesh->SubMeshesComputed() )
}
}
- return aCompound;
+ return theSubs.size() == 1 ? theSubs[0]->GetSubShape() : aCompound;
}
//=======================================================================
}
//=======================================================================
-//function : CheckConcurentHypothesis
+//function : CheckConcurrentHypothesis
//purpose : check if there are several applicable hypothesis attached to
// ancestors
//=======================================================================
SMESH_Hypothesis::Hypothesis_Status
- SMESH_subMesh::CheckConcurentHypothesis (const int theHypType)
+ SMESH_subMesh::CheckConcurrentHypothesis( SMESH_Hypothesis* theHypothesis)
{
- MESSAGE ("SMESH_subMesh::CheckConcurentHypothesis");
-
// is there local hypothesis on me?
- if ( getSimilarAttached( _subShape, 0, theHypType ) )
+ if ( getSimilarAttached( _subShape, theHypothesis ) )
return SMESH_Hypothesis::HYP_OK;
for (; it.More(); it.Next())
{
const TopoDS_Shape& ancestor = it.Value();
- const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, 0, theHypType );
+ const SMESH_Hypothesis* hyp = getSimilarAttached( ancestor, theHypothesis );
if ( hyp )
{
if ( aPrevWithHyp.IsNull() || aPrevWithHyp.IsSame( ancestor ))
aPrevHyp = hyp;
}
else if ( aPrevWithHyp.ShapeType() == ancestor.ShapeType() && aPrevHyp != hyp )
- return SMESH_Hypothesis::HYP_CONCURENT;
+ return SMESH_Hypothesis::HYP_CONCURRENT;
else
return SMESH_Hypothesis::HYP_OK;
}
* \param listener - the listener to store
* \param data - the listener data to store
* \param where - the submesh to store the listener and it's data
- *
+ *
* It remembers the submesh where it puts the listener in order to delete
* them when HYP_OK algo_state is lost
* After being set, event listener is notified on each event of where submesh.
* \brief Sets an event listener and its data to a submesh
* \param listener - the listener to store
* \param data - the listener data to store
- *
+ *
* After being set, event listener is notified on each event of a submesh.
*/
//================================================================================
_eventListeners.find( listener );
if ( l_d != _eventListeners.end() ) {
EventListenerData* curData = l_d->second;
+ l_d->second = data;
if ( curData && curData != data && curData->IsDeletable() )
delete curData;
- l_d->second = data;
}
else
{
if ( listener->GetName() == l_d->first->GetName() )
{
EventListenerData* curData = l_d->second;
+ l_d->second = 0;
if ( curData && curData != data && curData->IsDeletable() )
delete curData;
if ( l_d->first != listener && l_d->first->IsDeletable() )
//================================================================================
/*!
- * \brief Notify stored event listeners on the occured event
+ * \brief Notify stored event listeners on the occurred event
* \param event - algo_event or compute_event itself
* \param eventType - algo_event or compute_event
* \param hyp - hypothesis, if eventType is algo_event
{
list< OwnListenerData >::iterator d;
for ( d = _ownListeners.begin(); d != _ownListeners.end(); ++d )
- if ( _father != d->mySubMesh->_father )
+ if ( _father != d->mySubMesh->_father &&
+ _father->FindMesh( d->myMeshID ))
d->mySubMesh->_father->Load();
// map< EventListener*, EventListenerData* >::iterator l_d = _eventListeners.begin();
* \brief Do something on a certain event
* \param event - algo_event or compute_event itself
* \param eventType - algo_event or compute_event
- * \param subMesh - the submesh where the event occures
+ * \param subMesh - the submesh where the event occurs
* \param data - listener data stored in the subMesh
* \param hyp - hypothesis, if eventType is algo_event
- *
+ *
* The base implementation translates CLEAN event to the subMesh
* stored in listener data. Also it sends SUBMESH_COMPUTED event in case of
* successful COMPUTE event.
//================================================================================
/*!
- * \brief Return iterator on the submeshes this one depends on
- * \param includeSelf - this submesh to be returned also
- * \param reverse - if true, complex shape submeshes go first
+ * \brief Return iterator on the submeshes this one depends on
+ * \param includeSelf - this submesh to be returned also
+ * \param reverse - if true, complex shape submeshes go first
*/
//================================================================================
SMESH_subMesh* me = const_cast< SMESH_subMesh* >( this );
me->_ancestors.reserve( ancShapes.Extent() );
+ // assure that all sub-meshes exist
+ TopoDS_Shape mainShape = _father->GetShapeToMesh();
+ if ( !mainShape.IsNull() )
+ _father->GetSubMesh( mainShape )->DependsOn();
+
TopTools_MapOfShape map;
-
+
for ( TopTools_ListIteratorOfListOfShape it( ancShapes ); it.More(); it.Next() )
if ( SMESH_subMesh* sm = _father->GetSubMeshContaining( it.Value() ))
if ( map.Add( it.Value() ))