// 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"
#include "SMESH_Algo.hxx"
#include "SMESH_HypoFilter.hxx"
+#include "SMESH_MesherHelper.hxx"
#include "utilities.h"
#include "OpUtil.hxx"
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
+using namespace std;
+
//=============================================================================
/*!
* default constructor:
*/
//=============================================================================
-SMESH_subMesh::SMESH_subMesh(int Id, SMESH_Mesh * father, SMESHDS_Mesh * meshDS,
- const TopoDS_Shape & aSubShape)
+SMESH_subMesh::SMESH_subMesh(int Id,
+ SMESH_Mesh * father,
+ SMESHDS_Mesh * meshDS,
+ const TopoDS_Shape & aSubShape)
{
_subShape = aSubShape;
_meshDS = meshDS;
_subMeshDS = meshDS->MeshElements(_subShape); // may be null ...
_father = father;
_Id = Id;
- _dependenceAnalysed = false;
+ _dependenceAnalysed = _alwaysComputed = false;
if (_subShape.ShapeType() == TopAbs_VERTEX)
{
SMESHDS_SubMesh * SMESH_subMesh::GetSubMeshDS()
{
- // submesh appears in DS only when a mesher set nodes and elements on it
- if (_subMeshDS==NULL)
- {
- _subMeshDS = _meshDS->MeshElements(_subShape); // may be null ...
-// if (_subMeshDS==NULL)
-// {
-// MESSAGE("problem... subMesh still empty");
-// }
- }
- return _subMeshDS;
+ // submesh appears in DS only when a mesher set nodes and elements on a shape
+ return _subMeshDS ? _subMeshDS : _subMeshDS = _meshDS->MeshElements(_subShape); // may be null
}
//=============================================================================
return 0; // nothing to compute
}
+//================================================================================
+/*!
+ * \brief Allow algo->Compute() if a subshape of lower dim is meshed but
+ * none mesh entity is bound to it (PAL13615, 2nd part)
+ */
+//================================================================================
+
+void SMESH_subMesh::SetIsAlwaysComputed(bool isAlCo)
+{
+ _alwaysComputed = isAlCo;
+ if ( _alwaysComputed )
+ _computeState = COMPUTE_OK;
+ else
+ ComputeStateEngine( CHECK_COMPUTE_STATE );
+}
+
+//=======================================================================
+//function : IsMeshComputed
+//purpose : check if _subMeshDS contains mesh elements
+//=======================================================================
+
+bool SMESH_subMesh::IsMeshComputed() const
+{
+ if ( _alwaysComputed )
+ return true;
+ // algo may bind a submesh not to _subShape, eg 3D algo
+ // sets nodes on SHELL while _subShape may be SOLID
+
+ int dim = SMESH_Gen::GetShapeDim( _subShape );
+ int type = _subShape.ShapeType();
+ for ( ; type <= TopAbs_VERTEX; type++) {
+ if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
+ {
+ TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type );
+ for ( ; exp.More(); exp.Next() )
+ {
+ SMESHDS_SubMesh * smDS = _meshDS->MeshElements( exp.Current() );
+ if ( smDS && ( smDS->NbElements() || smDS->NbNodes()))
+ return true;
+ }
+ }
+ else
+ break;
+ }
+
+ return false;
+}
+
//=============================================================================
/*!
*
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++)
+ // check subMeshes with upper dimension => reverse iteration
+ map < int, SMESH_subMesh * >::const_reverse_iterator itsub;
+ for (itsub = subMeshes.rbegin(); itsub != subMeshes.rend(); itsub++)
{
SMESH_subMesh *sm = (*itsub).second;
+ if ( sm->_alwaysComputed )
+ continue;
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;
+ break; // the rest subMeshes are all of less dimension
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 ||
- (ds && ( ds->GetNodes()->more() || ds->GetElements()->more() )));
+ (ds && ( ds->NbNodes() || ds->NbElements() )));
if (!computeOk)
{
int type = ss.ShapeType();
//=======================================================================
//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_VERTEX:
+ 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:
SMESH_Hypothesis::Hypothesis_Status aux_ret, ret = SMESH_Hypothesis::HYP_OK;
- int dim = SMESH_Gen::GetShapeDim(_subShape);
+ SMESH_Gen* gen =_father->GetGen();
+ SMESH_Algo* algo = 0;
- if (dim < 1)
+ if (_subShape.ShapeType() == TopAbs_VERTEX )
{
- _algoState = HYP_OK;
- if (event == ADD_HYP || event == ADD_ALGO)
- return SMESH_Hypothesis::HYP_BAD_DIM; // do not allow to assign any hyp
- else
- return SMESH_Hypothesis::HYP_OK;
+ if ( anHyp->GetDim() != 0) {
+ if (event == ADD_HYP || event == ADD_ALGO)
+ return SMESH_Hypothesis::HYP_BAD_DIM;
+ else
+ return SMESH_Hypothesis::HYP_OK;
+ }
+ // 0D hypothesis
+ else if ( _algoState == HYP_OK ) { // update default _algoState
+ _algoState = NO_ALGO;
+ algo = gen->GetAlgo(*_father, _subShape);
+ if ( algo ) {
+ _algoState = MISSING_HYP;
+ if ( algo->CheckHypothesis(*_father,_subShape, aux_ret))
+ _algoState = HYP_OK;
+ }
+ }
}
- SMESH_Gen* gen =_father->GetGen();
-// bool ret = false;
int oldAlgoState = _algoState;
- bool modifiedHyp = false; // if set to true, force event MODIF_ALGO_STATE
- // in ComputeStateEngine
+ bool modifiedHyp = (event == MODIF_HYP); // if set to true, force event MODIF_ALGO_STATE
+
+ bool isApplicableHyp = IsApplicableHypotesis( anHyp );
- // ----------------------
- // check mesh conformity
- // ----------------------
- if (event == ADD_ALGO)
+ if (event == ADD_ALGO || event == ADD_FATHER_ALGO)
{
- if (IsApplicableHypotesis( anHyp ) &&
- !_father->IsNotConformAllowed() &&
- !IsConform( static_cast< SMESH_Algo* >( anHyp )))
+ // -------------------------------------------
+ // check if a shape needed by algo is present
+ // -------------------------------------------
+ algo = static_cast< SMESH_Algo* >( anHyp );
+ if ( !_father->HasShapeToMesh() && algo->NeedShape() )
+ return SMESH_Hypothesis::HYP_BAD_GEOMETRY;
+ // ----------------------
+ // check mesh conformity
+ // ----------------------
+ if (isApplicableHyp && !_father->IsNotConformAllowed() && !IsConform( algo ))
return SMESH_Hypothesis::HYP_NOTCONFORM;
}
// ----------------------------------
if (event == ADD_HYP || event == ADD_ALGO)
{
- if ( ! CanAddHypothesis( anHyp ))
+ if ( ! CanAddHypothesis( anHyp )) // check dimension
return SMESH_Hypothesis::HYP_BAD_DIM;
if ( /*!anHyp->IsAuxiliary() &&*/ GetSimilarAttached( _subShape, anHyp ) )
return SMESH_Hypothesis::HYP_ALREADY_EXIST;
// Serve Propagation of 1D hypothesis
+ // NOTE: it is possible to re-implement Propagation using EventListener
if (event == ADD_HYP) {
bool isPropagationOk = true;
bool isPropagationHyp = ( strcmp( "Propagation", anHyp->GetName() ) == 0 );
return SMESH_Hypothesis::HYP_OK; // nothing changes
// Serve Propagation of 1D hypothesis
+ // NOTE: it is possible to re-implement Propagation using EventListener
if (event == REMOVE_HYP)
{
bool isPropagationOk = true;
} // Serve Propagation of 1D hypothesis
else // event == REMOVE_ALGO
{
- SMESH_Algo* algo = dynamic_cast<SMESH_Algo*> (anHyp);
+ algo = dynamic_cast<SMESH_Algo*> (anHyp);
if (!algo->NeedDescretBoundary())
{
// clean all mesh in the tree of the current submesh;
// ------------------
// analyse algo state
// ------------------
- if (!IsApplicableHypotesis( anHyp ))
+ if (!isApplicableHyp)
return ret; // not applicable hypotheses do not change algo state
switch (_algoState)
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 REMOVE_HYP:
- break;
case REMOVE_ALGO:
- 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 ))
}
break;
}
+ case MODIF_HYP: break;
default:
ASSERT(0);
break;
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 MODIF_HYP: // assigned hypothesis value may become good
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 MODIF_HYP: // hypothesis value may become bad
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)
+ // detect algorithm hiding
+ //
+ if ( ret == SMESH_Hypothesis::HYP_OK &&
+ ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) &&
+ algo->GetName() == anHyp->GetName() )
+ {
+ // is algo hidden?
+ SMESH_Gen* gen = _father->GetGen();
+ TopTools_ListIteratorOfListOfShape it( _father->GetAncestors( _subShape ));
+ for ( ; ( ret == SMESH_Hypothesis::HYP_OK && it.More()); it.Next() ) {
+ if ( SMESH_Algo* upperAlgo = gen->GetAlgo( *_father, it.Value() ))
+ if ( !upperAlgo->NeedDescretBoundary() )
+ ret = SMESH_Hypothesis::HYP_HIDDEN_ALGO;
+ }
+ // is algo hiding?
+ if ( ret == SMESH_Hypothesis::HYP_OK && !algo->NeedDescretBoundary() ) {
+ map<int, SMESH_subMesh*>::reverse_iterator i_sm = _mapDepend.rbegin();
+ for ( ; ( ret == SMESH_Hypothesis::HYP_OK && i_sm != _mapDepend.rend()) ; ++i_sm )
+ if ( gen->GetAlgo( *_father, i_sm->second->_subShape ))
+ ret = SMESH_Hypothesis::HYP_HIDING_ALGO;
+ }
+ }
+
+ bool stateChange = ( _algoState != oldAlgoState );
+
+ if ( stateChange && _algoState == HYP_OK ) // hyp becomes OK
+ algo->SetEventListener( this );
+
+ NotifyListenersOnEvent( event, ALGO_EVENT, anHyp );
+
+ if ( stateChange && oldAlgoState == HYP_OK ) { // hyp becomes KO
+ DeleteOwnListeners();
+ if (_subShape.ShapeType() == TopAbs_VERTEX ) {
+ // restore default states
+ _algoState = HYP_OK;
+ _computeState = READY_TO_COMPUTE;
+ }
+ }
+
+ if (stateChange || modifiedHyp)
ComputeStateEngine(MODIF_ALGO_STATE);
return ret;
}
-
//=======================================================================
//function : IsConform
//purpose : check if a conform mesh will be produced by the Algo
bool SMESH_subMesh::IsConform(const SMESH_Algo* theAlgo)
{
// MESSAGE( "SMESH_subMesh::IsConform" );
-
if ( !theAlgo ) return false;
+ // Suppose that theAlgo is applicable to _subShape, do not check it here
+ //if ( !IsApplicableHypotesis( theAlgo )) return false;
+
// check only algo that doesn't NeedDescretBoundary(): because mesh made
// on a sub-shape will be ignored by theAlgo
- if ( theAlgo->NeedDescretBoundary() )
+ if ( theAlgo->NeedDescretBoundary() ||
+ !theAlgo->OnlyUnaryInput() ) // all adjacent shapes will be meshed by this algo?
return true;
SMESH_Gen* gen =_father->GetGen();
// only local algo is to be checked
- if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
+ //if ( gen->IsGlobalHypothesis( theAlgo, *_father ))
+ if ( _subShape.ShapeType() == _father->GetMeshDS()->ShapeToMesh().ShapeType() )
return true;
// check algo attached to adjacent shapes
// check algo attached to smAdjacent
SMESH_Algo * algo = gen->GetAlgo((*_father), adjacent);
if (algo &&
- //algo != theAlgo &&
- !algo->NeedDescretBoundary() /*&&
- !gen->IsGlobalHypothesis( algo, *_father )*/)
+ !algo->NeedDescretBoundary() &&
+ algo->OnlyUnaryInput())
return false; // NOT CONFORM MESH WILL BE PRODUCED
}
}
//SCRUTE(_computeState);
//SCRUTE(event);
- int dim = SMESH_Gen::GetShapeDim(_subShape);
-
- if (dim < 1)
+ if (_subShape.ShapeType() == TopAbs_VERTEX)
{
if ( IsMeshComputed() )
_computeState = COMPUTE_OK;
else
_computeState = READY_TO_COMPUTE;
+ if ( event == MODIF_ALGO_STATE )
+ CleanDependants();
return true;
}
SMESH_Gen *gen = _father->GetGen();
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:
case MODIF_ALGO_STATE:
algo = gen->GetAlgo((*_father), _subShape);
if (algo && !algo->NeedDescretBoundary())
CleanDependsOn(); // clean sub-meshes with event CLEAN
- if (event == MODIF_ALGO_STATE && _algoState == HYP_OK)
- {
+ if ( _algoState == HYP_OK )
_computeState = READY_TO_COMPUTE;
- }
break;
case COMPUTE: // nothing to do
break;
case SUBMESH_COMPUTED: // nothing to do
break;
case SUBMESH_RESTORED:
- ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
+ ComputeSubMeshStateEngine( SUBMESH_RESTORED );
break;
case MESH_ENTITY_REMOVED:
break;
case READY_TO_COMPUTE:
switch (event)
{
- case MODIF_HYP:
case MODIF_ALGO_STATE:
- algo = gen->GetAlgo((*_father), _subShape);
- if (algo && !algo->NeedDescretBoundary())
- CleanDependsOn(); // clean sub-meshes with event CLEAN
- if (event == MODIF_HYP)
- break; // nothing else to do when MODIF_HYP
_computeState = NOT_READY;
+ algo = gen->GetAlgo((*_father), _subShape);
if (algo)
{
- ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
- if (ret)
+ if (!algo->NeedDescretBoundary())
+ CleanDependsOn(); // clean sub-meshes with event CLEAN
+ if ( _algoState == HYP_OK )
_computeState = READY_TO_COMPUTE;
}
break;
{
MESSAGE("***** verify compute state *****");
_computeState = NOT_READY;
+ SetAlgoState(MISSING_HYP);
break;
}
// check submeshes needed
- if (algo->NeedDescretBoundary())
+ if (_father->HasShapeToMesh() && algo->NeedDescretBoundary())
ret = SubMeshesComputed();
if (!ret)
{
#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 ( !_father->HasShapeToMesh() ) // no shape
+ {
+ SMESH_MesherHelper helper( *_father );
+ helper.SetSubShape( _subShape );
+ helper.SetElementsOnShape( true );
+ ret = algo->Compute(*_father, &helper );
+ }
+ else {
+ 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 );
ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
if (ret)
_computeState = READY_TO_COMPUTE;
+ else
+ SetAlgoState(MISSING_HYP);
}
break;
case SUBMESH_COMPUTED: // nothing to do
// check if a mesh is already computed that may
// happen after retrieval from a file
ComputeStateEngine( CHECK_COMPUTE_STATE );
- ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
+ ComputeSubMeshStateEngine( SUBMESH_RESTORED );
+ algo = gen->GetAlgo(*_father, _subShape);
+ if (algo) algo->SubmeshRestored( this );
break;
case MESH_ENTITY_REMOVED:
break;
case COMPUTE_OK:
switch (event)
{
- case MODIF_HYP:
case MODIF_ALGO_STATE:
ComputeStateEngine( CLEAN );
algo = gen->GetAlgo((*_father), _subShape);
CleanDependants(); // clean sub-meshes, dependant on this one, with event CLEAN
RemoveSubMeshElementsAndNodes();
_computeState = NOT_READY;
- algo = gen->GetAlgo((*_father), _subShape);
- if (algo)
- {
- ret = algo->CheckHypothesis((*_father), _subShape, hyp_status);
- if (ret)
- _computeState = READY_TO_COMPUTE;
- }
+ if ( _algoState == HYP_OK )
+ _computeState = READY_TO_COMPUTE;
break;
case SUBMESH_COMPUTED: // nothing to do
break;
case SUBMESH_RESTORED:
ComputeStateEngine( CHECK_COMPUTE_STATE );
- ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
+ ComputeSubMeshStateEngine( SUBMESH_RESTORED );
+ algo = gen->GetAlgo(*_father, _subShape);
+ if (algo) algo->SubmeshRestored( this );
break;
case MESH_ENTITY_REMOVED:
UpdateDependantsState( CHECK_COMPUTE_STATE );
case FAILED_TO_COMPUTE:
switch (event)
{
- case MODIF_HYP:
- if (_algoState == HYP_OK)
- _computeState = READY_TO_COMPUTE;
- else
- _computeState = NOT_READY;
- break;
case MODIF_ALGO_STATE:
if (_algoState == HYP_OK)
_computeState = READY_TO_COMPUTE;
_computeState = NOT_READY;
break;
case SUBMESH_RESTORED:
- ComputeSubMeshStateEngine( CHECK_COMPUTE_STATE );
+ ComputeSubMeshStateEngine( SUBMESH_RESTORED );
break;
case MESH_ENTITY_REMOVED:
break;
break;
}
- //SCRUTE(_computeState);
+ NotifyListenersOnEvent( event, COMPUTE_EVENT );
+
return ret;
}
}
}
-//=======================================================================
-//function : IsMeshComputed
-//purpose : check if _subMeshDS contains mesh elements
-//=======================================================================
-
-bool SMESH_subMesh::IsMeshComputed() const
-{
- // algo may bind a submesh not to _subShape, eg 3D algo
- // sets nodes on SHELL while _subShape may be SOLID
-
- int dim = SMESH_Gen::GetShapeDim( _subShape );
- int type = _subShape.ShapeType();
- for ( ; type <= TopAbs_VERTEX; type++) {
- if ( dim == SMESH_Gen::GetShapeDim( (TopAbs_ShapeEnum) type ))
- {
- 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())) {
- return true;
- }
- }
- }
- else
- break;
- }
-
- return false;
-}
-
-
//=======================================================================
//function : GetCollection
//purpose : return a shape containing all sub-shapes of the MainShape that can be
//=======================================================================
//function : CheckConcurentHypothesis
//purpose : check if there are several applicable hypothesis attached to
-// ansestors
+// ancestors
//=======================================================================
SMESH_Hypothesis::Hypothesis_Status
}
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)
+{
+ map< EventListener*, EventListenerData* >::iterator l_d =
+ myEventListeners.find( listener );
+ if ( l_d != myEventListeners.end() ) {
+ if ( l_d->second && l_d->second->IsDeletable() )
+ delete l_d->second;
+ l_d->second = data;
+ }
+ else
+ 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 && l_d->first->IsDeletable() ) delete l_d->first;
+ if ( l_d->second && 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:;
+ }
+ }
+}