+namespace
+{
+ // ------------------------------------------------------------------------------
+ /*!
+ * \brief Listener used to mark edges meshed by StdMeshers_RadialQuadrangle_1D2D
+ */
+ class TEdgeMarker : public SMESH_subMeshEventListener
+ {
+ TEdgeMarker(): SMESH_subMeshEventListener(/*isDeletable=*/false) {}
+ public:
+ //!< Return static listener
+ static SMESH_subMeshEventListener* getListener()
+ {
+ static TEdgeMarker theEdgeMarker;
+ return &theEdgeMarker;
+ }
+ //! Clear face sumbesh if something happens on edges
+ void ProcessEvent(const int event,
+ const int eventType,
+ SMESH_subMesh* edgeSubMesh,
+ EventListenerData* data,
+ const SMESH_Hypothesis* /*hyp*/)
+ {
+ if ( data && !data->mySubMeshes.empty() && eventType == SMESH_subMesh::ALGO_EVENT)
+ {
+ ASSERT( data->mySubMeshes.front() != edgeSubMesh );
+ SMESH_subMesh* faceSubMesh = data->mySubMeshes.front();
+ faceSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
+ }
+ }
+ };
+
+ // ------------------------------------------------------------------------------
+ /*!
+ * \brief Mark an edge as computed by StdMeshers_RadialQuadrangle_1D2D
+ */
+ void markEdgeAsComputedByMe(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh)
+ {
+ if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge ))
+ {
+ if ( !edgeSM->GetEventListenerData( TEdgeMarker::getListener() ))
+ faceSubMesh->SetEventListener( TEdgeMarker::getListener(),
+ SMESH_subMeshEventListenerData::MakeData(faceSubMesh),
+ edgeSM);
+ }
+ }
+ // ------------------------------------------------------------------------------
+ /*!
+ * \brief Return true if a radial edge was meshed with StdMeshers_RadialQuadrangle_1D2D with
+ * the same radial distribution
+ */
+// bool isEdgeCompatiballyMeshed(const TopoDS_Edge& edge, SMESH_subMesh* faceSubMesh)
+// {
+// if ( SMESH_subMesh* edgeSM = faceSubMesh->GetFather()->GetSubMeshContaining( edge ))
+// {
+// if ( SMESH_subMeshEventListenerData* otherFaceData =
+// edgeSM->GetEventListenerData( TEdgeMarker::getListener() ))
+// {
+// // compare hypothesis aplied to two disk faces sharing radial edges
+// SMESH_Mesh& mesh = *faceSubMesh->GetFather();
+// SMESH_Algo* radialQuadAlgo = mesh.GetGen()->GetAlgo(mesh, faceSubMesh->GetSubShape() );
+// SMESH_subMesh* otherFaceSubMesh = otherFaceData->mySubMeshes.front();
+// list <const SMESHDS_Hypothesis *> hyps1 =
+// radialQuadAlgo->GetUsedHypothesis( mesh, faceSubMesh->GetSubShape());
+// list <const SMESHDS_Hypothesis *> hyps2 =
+// radialQuadAlgo->GetUsedHypothesis( mesh, otherFaceSubMesh->GetSubShape());
+// if( hyps1.empty() && hyps2.empty() )
+// return true; // defaul hyps
+// if ( hyps1.size() != hyps2.size() )
+// return false;
+// return *hyps1.front() == *hyps2.front();
+// }
+// }
+// return false;
+// }
+
+ //================================================================================
+ /*!
+ * \brief Return base curve of the edge and extremum parameters
+ */
+ //================================================================================
+
+ Handle(Geom_Curve) getCurve(const TopoDS_Edge& edge, double* f=0, double* l=0)
+ {
+ Handle(Geom_Curve) C;
+ if ( !edge.IsNull() )
+ {
+ double first = 0., last = 0.;
+ C = BRep_Tool::Curve(edge, first, last);
+ if ( !C.IsNull() )
+ {
+ Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(C);
+ while( !tc.IsNull() ) {
+ C = tc->BasisCurve();
+ tc = Handle(Geom_TrimmedCurve)::DownCast(C);
+ }
+ if ( f ) *f = first;
+ if ( l ) *l = last;
+ }
+ }
+ return C;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return edges of the face
+ * \retval int - nb of edges
+ */
+ //================================================================================
+
+ int analyseFace(const TopoDS_Shape& face,
+ TopoDS_Edge& CircEdge,
+ TopoDS_Edge& LinEdge1,
+ TopoDS_Edge& LinEdge2)
+ {
+ CircEdge.Nullify(); LinEdge1.Nullify(); LinEdge2.Nullify();
+ int nbe = 0;
+
+ for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next(), ++nbe )
+ {
+ const TopoDS_Edge& E = TopoDS::Edge( exp.Current() );
+ double f,l;
+ Handle(Geom_Curve) C = getCurve(E,&f,&l);
+ if ( !C.IsNull() )
+ {
+ if ( C->IsKind( STANDARD_TYPE(Geom_Circle)))
+ {
+ if ( CircEdge.IsNull() )
+ CircEdge = E;
+ else
+ return 0;
+ }
+ else if ( LinEdge1.IsNull() )
+ LinEdge1 = E;
+ else
+ LinEdge2 = E;
+ }
+ }
+ return nbe;
+ }
+
+//================================================================================
+//================================================================================
+/*!
+ * \brief Class computing layers distribution using data of
+ * StdMeshers_LayerDistribution hypothesis
+ */
+//================================================================================
+//================================================================================
+
+class TNodeDistributor: public StdMeshers_Regular_1D
+{
+ list <const SMESHDS_Hypothesis *> myUsedHyps;
+public:
+ // -----------------------------------------------------------------------------
+ static TNodeDistributor* GetDistributor(SMESH_Mesh& aMesh)
+ {
+ const int myID = -1000;
+ map < int, SMESH_1D_Algo * > & algoMap = aMesh.GetGen()->_map1D_Algo;
+ map < int, SMESH_1D_Algo * >::iterator id_algo = algoMap.find( myID );
+ if ( id_algo == algoMap.end() )
+ return new TNodeDistributor( myID, 0, aMesh.GetGen() );
+ return static_cast< TNodeDistributor* >( id_algo->second );
+ }
+ // -----------------------------------------------------------------------------
+ //! Computes distribution of nodes on a straight line ending at pIn and pOut
+ bool Compute( vector< double > & positions,
+ gp_Pnt pIn,
+ gp_Pnt pOut,
+ SMESH_Mesh& aMesh,
+ const SMESH_Hypothesis* hyp1d)
+ {
+ if ( !hyp1d ) return error( "Invalid LayerDistribution hypothesis");
+
+ double len = pIn.Distance( pOut );
+ if ( len <= DBL_MIN ) return error("Too close points of inner and outer shells");
+
+ myUsedHyps.clear();
+ myUsedHyps.push_back( hyp1d );
+
+ TopoDS_Edge edge = BRepBuilderAPI_MakeEdge( pIn, pOut );
+ SMESH_Hypothesis::Hypothesis_Status aStatus;
+ if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, edge, aStatus ))
+ return error( "StdMeshers_Regular_1D::CheckHypothesis() failed "
+ "with LayerDistribution hypothesis");
+
+ BRepAdaptor_Curve C3D(edge);
+ double f = C3D.FirstParameter(), l = C3D.LastParameter();
+ list< double > params;
+ if ( !StdMeshers_Regular_1D::computeInternalParameters( aMesh, C3D, len, f, l, params, false ))
+ return error("StdMeshers_Regular_1D failed to compute layers distribution");
+
+ positions.clear();
+ positions.reserve( params.size() );
+ for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++)
+ positions.push_back( *itU / len );
+ return true;
+ }
+ // -----------------------------------------------------------------------------
+ //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments
+ bool ComputeCircularEdge(SMESH_Mesh& aMesh,
+ const TopoDS_Edge& anEdge)
+ {
+ _gen->Compute( aMesh, anEdge);
+ SMESH_subMesh *sm = aMesh.GetSubMesh(anEdge);
+ if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK)
+ {
+ // find any 1d hyp assigned (there can be a hyp w/o algo)
+ myUsedHyps = SMESH_Algo::GetUsedHypothesis(aMesh, anEdge, /*ignoreAux=*/true);
+ Hypothesis_Status aStatus;
+ if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, anEdge, aStatus ))
+ {
+ // no valid 1d hyp assigned, use default nb of segments
+ _hypType = NB_SEGMENTS;
+ _ivalue[ DISTR_TYPE_IND ] = StdMeshers_NumberOfSegments::DT_Regular;
+ _ivalue[ NB_SEGMENTS_IND ] = _gen->GetDefaultNbSegments();
+ }
+ return StdMeshers_Regular_1D::Compute( aMesh, anEdge );
+ }
+ return true;
+ }
+ // -----------------------------------------------------------------------------
+ //! Make mesh on an adge using assigned 1d hyp or defaut nb of segments
+ bool EvaluateCircularEdge(SMESH_Mesh& aMesh,
+ const TopoDS_Edge& anEdge,
+ MapShapeNbElems& aResMap)
+ {
+ _gen->Evaluate( aMesh, anEdge, aResMap );
+ if ( aResMap.count( aMesh.GetSubMesh( anEdge )))
+ return true;
+
+ // find any 1d hyp assigned
+ myUsedHyps = SMESH_Algo::GetUsedHypothesis(aMesh, anEdge, /*ignoreAux=*/true);
+ Hypothesis_Status aStatus;
+ if ( !StdMeshers_Regular_1D::CheckHypothesis( aMesh, anEdge, aStatus ))
+ {
+ // no valid 1d hyp assigned, use default nb of segments
+ _hypType = NB_SEGMENTS;
+ _ivalue[ DISTR_TYPE_IND ] = StdMeshers_NumberOfSegments::DT_Regular;
+ _ivalue[ NB_SEGMENTS_IND ] = _gen->GetDefaultNbSegments();
+ }
+ return StdMeshers_Regular_1D::Evaluate( aMesh, anEdge, aResMap );
+ }
+protected:
+ // -----------------------------------------------------------------------------
+ TNodeDistributor( int hypId, int studyId, SMESH_Gen* gen)
+ : StdMeshers_Regular_1D( hypId, studyId, gen)
+ {
+ }
+ // -----------------------------------------------------------------------------
+ virtual const list <const SMESHDS_Hypothesis *> &
+ GetUsedHypothesis(SMESH_Mesh &, const TopoDS_Shape &, const bool)
+ {
+ return myUsedHyps;
+ }
+ // -----------------------------------------------------------------------------
+};
+}
+
+//=======================================================================
+/*!
+ * \brief Allow algo to do something after persistent restoration
+ * \param subMesh - restored submesh
+ *
+ * call markEdgeAsComputedByMe()
+ */
+//=======================================================================
+
+void StdMeshers_RadialQuadrangle_1D2D::SubmeshRestored(SMESH_subMesh* faceSubMesh)
+{
+ if ( !faceSubMesh->IsEmpty() )
+ {
+ TopoDS_Edge CircEdge, LinEdge1, LinEdge2;
+ analyseFace( faceSubMesh->GetSubShape(), CircEdge, LinEdge1, LinEdge2 );
+ if ( !CircEdge.IsNull() ) markEdgeAsComputedByMe( CircEdge, faceSubMesh );
+ if ( !LinEdge1.IsNull() ) markEdgeAsComputedByMe( LinEdge1, faceSubMesh );
+ if ( !LinEdge2.IsNull() ) markEdgeAsComputedByMe( LinEdge2, faceSubMesh );
+ }
+}