// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
-// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
//
//
// Module : SMESH
// $Header$
-using namespace std;
#include "SMESH_subMesh.hxx"
+
+#include "SMESH_subMeshEventListener.hxx"
#include "SMESH_Gen.hxx"
#include "SMESH_Mesh.hxx"
#include "SMESH_Hypothesis.hxx"
//MESSAGE("SMESH_subMesh::SubMeshesComputed");
const map < int, SMESH_subMesh * >&subMeshes = DependsOn();
+ int myDim = SMESH_Gen::GetShapeDim( _subShape );
+ int dimToCheck = myDim - 1;
bool subMeshesComputed = true;
map < int, SMESH_subMesh * >::const_iterator itsub;
for (itsub = subMeshes.begin(); itsub != subMeshes.end(); itsub++)
{
SMESH_subMesh *sm = (*itsub).second;
+ const TopoDS_Shape & ss = sm->GetSubShape();
+ // MSV 07.04.2006: restrict checking to myDim-1 only. Ex., there is no sense
+ // in checking of existence of edges if the algo needs only faces. Moreover,
+ // degenerated edges may have no submesh, as after computing NETGEN_2D.
+ int dim = SMESH_Gen::GetShapeDim( ss );
+ if (dim < dimToCheck)
+ continue;
SMESHDS_SubMesh * ds = sm->GetSubMeshDS();
// PAL10974.
// There are some tricks with compute states, e.g. Penta_3D leaves
// one face with READY_TO_COMPUTE state in order to be able to
// recompute 3D when a locale triangle hypo changes (see PAL7428).
// So we check if mesh is really present
- //bool computeOk = (sm->GetComputeState() == COMPUTE_OK);
- bool computeOk = ( ds && ( ds->GetNodes()->more() || ds->GetElements()->more() ));
+ bool computeOk = (sm->GetComputeState() == COMPUTE_OK ||
+ (ds && ( ds->GetNodes()->more() || ds->GetElements()->more() )));
if (!computeOk)
{
- const TopoDS_Shape & ss = sm->GetSubShape();
int type = ss.ShapeType();
subMeshesComputed = false;
//=======================================================================
//function : IsApplicableHypotesis
-//purpose :
+//purpose :
//=======================================================================
bool SMESH_subMesh::IsApplicableHypotesis(const SMESH_Hypothesis* theHypothesis,
// hypothesis
switch ( theShapeType ) {
- case TopAbs_EDGE:
- case TopAbs_FACE:
- case TopAbs_SHELL:
+ case TopAbs_EDGE:
+ case TopAbs_FACE:
case TopAbs_SOLID:
return SMESH_Gen::GetShapeDim( theShapeType ) == theHypothesis->GetDim();
+
+ case TopAbs_SHELL:
+ // Special case for algorithms, building 2D mesh on a whole shell.
+ // Before this fix there was a problem after restoring from study,
+ // because in that case algorithm is assigned before hypothesis
+ // (on shell in problem case) and hypothesis is checked on faces
+ // (because it is 2D), where we have NO_ALGO state.
+ // Now 2D hypothesis is also applicable to shells.
+ return (theHypothesis->GetDim() == 2 || theHypothesis->GetDim() == 3);
+
// case TopAbs_WIRE:
// case TopAbs_COMPSOLID:
// case TopAbs_COMPOUND:
return SMESH_Hypothesis::HYP_OK;
}
- SMESH_Gen* gen =_father->GetGen();
-// bool ret = false;
+ SMESH_Gen* gen =_father->GetGen();
+ SMESH_Algo* algo = 0;
int oldAlgoState = _algoState;
bool modifiedHyp = false; // if set to true, force event MODIF_ALGO_STATE
// in ComputeStateEngine
ret = SMESH_Hypothesis::HYP_CONCURENT;
}
} // Serve Propagation of 1D hypothesis
+ else // event == REMOVE_ALGO
+ {
+ algo = dynamic_cast<SMESH_Algo*> (anHyp);
+ if (!algo->NeedDescretBoundary())
+ {
+ // clean all mesh in the tree of the current submesh;
+ // we must perform it now because later
+ // we will have no information about the type of the removed algo
+ CleanDependants();
+ ComputeStateEngine( CLEAN );
+ CleanDependsOn();
+ }
+ }
}
// ------------------
case ADD_HYP:
break;
case ADD_ALGO: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if (algo->CheckHypothesis((*_father),_subShape, aux_ret))
SetAlgoState(HYP_OK);
+ else if ( algo->IsStatusFatal( aux_ret )) {
+ _meshDS->RemoveHypothesis(_subShape, anHyp);
+ ret = aux_ret;
+ }
else
SetAlgoState(MISSING_HYP);
break;
case ADD_FATHER_HYP:
break;
case ADD_FATHER_ALGO: { // Algo just added in father
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo == anHyp ) {
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret))
case REMOVE_FATHER_HYP:
break;
case REMOVE_FATHER_ALGO: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if (algo)
{
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
switch (event)
{
case ADD_HYP: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo->CheckHypothesis((*_father),_subShape, ret ))
SetAlgoState(HYP_OK);
break;
}
case ADD_ALGO: { //already existing algo : on father ?
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))// ignore hyp status
SetAlgoState(HYP_OK);
+ else if ( algo->IsStatusFatal( aux_ret )) {
+ _meshDS->RemoveHypothesis(_subShape, anHyp);
+ ret = aux_ret;
+ }
else
SetAlgoState(MISSING_HYP);
break;
case REMOVE_HYP:
break;
case REMOVE_ALGO: { // perhaps a father algo applies ?
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if (algo == NULL) // no more algo applying on subShape...
{
SetAlgoState(NO_ALGO);
break;
}
case ADD_FATHER_HYP: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
SetAlgoState(HYP_OK);
else
SetAlgoState(MISSING_HYP);
- }
break;
+ }
case ADD_FATHER_ALGO: { // new father algo
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT( algo );
if ( algo == anHyp ) {
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
case REMOVE_FATHER_HYP: // nothing to do
break;
case REMOVE_FATHER_ALGO: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if (algo == NULL) // no more applying algo on father
{
SetAlgoState(NO_ALGO);
switch (event)
{
case ADD_HYP: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if (!algo->CheckHypothesis((*_father),_subShape, ret ))
{
break;
}
case ADD_ALGO: { //already existing algo : on father ?
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
// check if algo changes
SMESH_HypoFilter f;
f.And( SMESH_HypoFilter::IsApplicableTo( _subShape ));
f.AndNot( SMESH_HypoFilter::Is( algo ));
const SMESH_Hypothesis * prevAlgo = _father->GetHypothesis( _subShape, f, true );
- if (prevAlgo &&
+ if (prevAlgo &&
string(algo->GetName()) != string(prevAlgo->GetName()) )
modifiedHyp = true;
}
break;
}
case REMOVE_HYP: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
SetAlgoState(HYP_OK);
break;
}
case REMOVE_ALGO: { // perhaps a father algo applies ?
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if (algo == NULL) // no more algo applying on subShape...
{
SetAlgoState(NO_ALGO);
break;
}
case ADD_FATHER_HYP: { // new father hypothesis ?
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret ))
{
break;
}
case ADD_FATHER_ALGO: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if ( algo == anHyp ) { // a new algo on father
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
// check if algo changes
f.And( SMESH_HypoFilter::IsApplicableTo( _subShape ));
f.AndNot( SMESH_HypoFilter::Is( algo ));
const SMESH_Hypothesis* prevAlgo = _father->GetHypothesis( _subShape, f, true );
- if (prevAlgo &&
+ if (prevAlgo &&
string(algo->GetName()) != string(prevAlgo->GetName()) )
modifiedHyp = true;
}
break;
}
case REMOVE_FATHER_HYP: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
ASSERT(algo);
if ( algo->CheckHypothesis((*_father),_subShape, aux_ret )) {
// is there the same local hyp or maybe a new father algo applied?
break;
}
case REMOVE_FATHER_ALGO: {
- SMESH_Algo* algo = gen->GetAlgo((*_father), _subShape);
+ algo = gen->GetAlgo((*_father), _subShape);
if (algo == NULL) // no more applying algo on father
{
SetAlgoState(NO_ALGO);
break;
}
- if ((_algoState != oldAlgoState) || modifiedHyp)
+ if ( _algoState != oldAlgoState )
+ {
+ if (_algoState == HYP_OK )
+ algo->SetEventListener( this );
+ if ( oldAlgoState == HYP_OK )
+ DeleteOwnListeners();
+ }
+ NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
+
+ if (_algoState != oldAlgoState || modifiedHyp)
ComputeStateEngine(MODIF_ALGO_STATE);
return ret;
void SMESH_subMesh::CleanDependsOn()
{
//MESSAGE("SMESH_subMesh::CleanDependsOn");
- // **** parcourir les ancetres dans l'ordre de dépendance
-
- ComputeStateEngine(CLEAN);
const map < int, SMESH_subMesh * >&dependson = DependsOn();
map < int, SMESH_subMesh * >::const_iterator its;
SMESH_Algo *algo = 0;
bool ret = true;
SMESH_Hypothesis::Hypothesis_Status hyp_status;
+ algo_state oldAlgoState = (algo_state) GetAlgoState();
switch (_computeState)
{
case NOT_READY:
switch (event)
{
- case MODIF_HYP: // nothing to do
- break;
+ case MODIF_HYP:
case MODIF_ALGO_STATE:
- if (_algoState == HYP_OK)
+ algo = gen->GetAlgo((*_father), _subShape);
+ if (algo && !algo->NeedDescretBoundary())
+ CleanDependsOn(); // clean sub-meshes with event CLEAN
+ if (algo)
{
- _computeState = READY_TO_COMPUTE;
+ ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
+ if (ret)
+ _computeState = READY_TO_COMPUTE;
}
+ if ( _computeState == READY_TO_COMPUTE )
+ SetAlgoState(HYP_OK);
+ else
+ SetAlgoState(MISSING_HYP);
break;
case COMPUTE: // nothing to do
break;
case READY_TO_COMPUTE:
switch (event)
{
- case MODIF_HYP: // nothing to do
- break;
+ case MODIF_HYP:
case MODIF_ALGO_STATE:
- _computeState = NOT_READY;
algo = gen->GetAlgo((*_father), _subShape);
+ if (algo && !algo->NeedDescretBoundary())
+ CleanDependsOn(); // clean sub-meshes with event CLEAN
+ _computeState = NOT_READY;
if (algo)
{
ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
- if (ret)
+ if (ret) {
+ SetAlgoState(HYP_OK); // it might be KO if BAD_PARAM_VALUE
_computeState = READY_TO_COMPUTE;
+ }
+ else
+ SetAlgoState(MISSING_HYP);
}
break;
case COMPUTE:
{
MESSAGE("***** verify compute state *****");
_computeState = NOT_READY;
+ SetAlgoState(MISSING_HYP);
break;
}
// check submeshes needed
// compute
CleanDependants();
RemoveSubMeshElementsAndNodes();
- try {
- if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput())
- ret = ApplyToCollection( algo, GetCollection( gen, algo ) );
- else
- ret = algo->Compute((*_father), _subShape);
- }
- catch (Standard_Failure) {
- MESSAGE( "Exception in algo->Compute() ");
- ret = false;
- }
+ {
+ try {
+#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
+ OCC_CATCH_SIGNALS;
+#endif
+ if (!algo->NeedDescretBoundary() && !algo->OnlyUnaryInput())
+ ret = ApplyToCollection( algo, GetCollection( gen, algo ) );
+ else
+ ret = algo->Compute((*_father), _subShape);
+ }
+ catch (Standard_Failure) {
+ MESSAGE( "Exception in algo->Compute() ");
+ ret = false;
+ }
+ }
if (!ret)
{
MESSAGE("problem in algo execution: failed to compute");
+ // release ALGO from responsibilty of partially built mesh
+ RemoveSubMeshElementsAndNodes();
_computeState = FAILED_TO_COMPUTE;
if (!algo->NeedDescretBoundary())
UpdateSubMeshState( FAILED_TO_COMPUTE );
#ifdef _DEBUG_
// Show vertices location of a failed shape
+ cout << algo->GetName() << " failed on shape with the following vertices:" << endl;
TopTools_IndexedMapOfShape vMap;
TopExp::MapShapes( _subShape, TopAbs_VERTEX, vMap );
for ( int iv = 1; iv <= vMap.Extent(); ++iv ) {
ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
if (ret)
_computeState = READY_TO_COMPUTE;
+ else
+ SetAlgoState(MISSING_HYP);
}
break;
case SUBMESH_COMPUTED: // nothing to do
ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
if (ret)
_computeState = READY_TO_COMPUTE;
+ else
+ SetAlgoState(MISSING_HYP);
}
break;
case SUBMESH_COMPUTED: // nothing to do
break;
}
+ if ( _algoState != oldAlgoState || event == MODIF_HYP )
+ {
+ if ( oldAlgoState == HYP_OK )
+ DeleteOwnListeners();
+ if (_algoState == HYP_OK && algo )
+ algo->SetEventListener( this );
+ }
+ NotifyListenersOnEvent( event, COMPUTE_EVENT );
+
//SCRUTE(_computeState);
return ret;
}
TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
for ( ; exp.More(); exp.Next() )
{
- SMESHDS_SubMesh * subMeshDS = _meshDS->MeshElements( exp.Current() );
- if ( subMeshDS != NULL &&
- (subMeshDS->GetElements()->more() || subMeshDS->GetNodes()->more())) {
+ SMESHDS_SubMesh * smDS = _meshDS->MeshElements( exp.Current() );
+ if ( smDS && ( smDS->NbElements() || smDS->NbNodes()))
return true;
- }
}
}
else
}
return SMESH_Hypothesis::HYP_OK;
}
+
+//================================================================================
+/*!
+ * \brief Sets an event listener and its data to a submesh
+ * \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
+ * \param deleteListener - if true then the listener will be deleted as
+ * it is removed from where submesh
+ *
+ * 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.
+ */
+//================================================================================
+
+void SMESH_subMesh::SetEventListener(EventListener* listener,
+ EventListenerData* data,
+ SMESH_subMesh* where)
+{
+ if ( listener && where ) {
+ where->SetEventListener( listener, data );
+ myOwnListeners.push_back( make_pair( where, listener ));
+ }
+}
+
+//================================================================================
+/*!
+ * \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.
+ */
+//================================================================================
+
+void SMESH_subMesh::SetEventListener(EventListener* listener, EventListenerData* data)
+{
+ myEventListeners.insert( make_pair( listener, data ));
+}
+
+//================================================================================
+/*!
+ * \brief Return an event listener data
+ * \param listener - the listener whose data is
+ * \retval EventListenerData* - found data, maybe NULL
+ */
+//================================================================================
+
+EventListenerData* SMESH_subMesh::GetEventListenerData(EventListener* listener) const
+{
+ map< EventListener*, EventListenerData* >::const_iterator l_d =
+ myEventListeners.find( listener );
+ if ( l_d != myEventListeners.end() )
+ return l_d->second;
+ return 0;
+}
+
+//================================================================================
+/*!
+ * \brief Notify stored event listeners on the occured 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 data - listener data stored in the subMesh
+ * \param hyp - hypothesis, if eventType is algo_event
+ */
+//================================================================================
+
+void SMESH_subMesh::NotifyListenersOnEvent( const int event,
+ const event_type eventType,
+ SMESH_Hypothesis* hyp)
+{
+ map< EventListener*, EventListenerData* >::iterator l_d = myEventListeners.begin();
+ for ( ; l_d != myEventListeners.end(); ++l_d )
+ l_d->first->ProcessEvent( event, eventType, this, l_d->second, hyp );
+}
+
+//================================================================================
+/*!
+ * \brief Unregister the listener and delete listener's data
+ * \param listener - the event listener
+ */
+//================================================================================
+
+void SMESH_subMesh::DeleteEventListener(EventListener* listener)
+{
+ map< EventListener*, EventListenerData* >::iterator l_d =
+ myEventListeners.find( listener );
+ if ( l_d != myEventListeners.end() ) {
+ if ( l_d->first->IsDeletable() ) delete l_d->first;
+ if ( l_d->second->IsDeletable() ) delete l_d->second;
+ myEventListeners.erase( l_d );
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Delete event listeners depending on algo of this submesh
+ */
+//================================================================================
+
+void SMESH_subMesh::DeleteOwnListeners()
+{
+ list< pair< SMESH_subMesh*, EventListener* > >::iterator sm_l;
+ for ( sm_l = myOwnListeners.begin(); sm_l != myOwnListeners.end(); ++sm_l)
+ sm_l->first->DeleteEventListener( sm_l->second );
+ myOwnListeners.clear();
+}
+
+//================================================================================
+/*!
+ * \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 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.
+ */
+//================================================================================
+
+void SMESH_subMeshEventListener::ProcessEvent(const int event,
+ const int eventType,
+ SMESH_subMesh* subMesh,
+ EventListenerData* data,
+ SMESH_Hypothesis* /*hyp*/)
+{
+ if ( data && !data->mySubMeshes.empty() &&
+ eventType == SMESH_subMesh::COMPUTE_EVENT)
+ {
+ ASSERT( data->mySubMeshes.front() != subMesh );
+ switch ( event ) {
+ case SMESH_subMesh::CLEAN:
+ data->mySubMeshes.front()->ComputeStateEngine( event );
+ break;
+ case SMESH_subMesh::COMPUTE:
+ if ( subMesh->GetComputeState() == SMESH_subMesh::COMPUTE_OK )
+ data->mySubMeshes.front()->ComputeStateEngine( SMESH_subMesh::SUBMESH_COMPUTED );
+ break;
+ default:;
+ }
+ }
+}