1 // SMESH SMESH : implementaion of SMESH idl descriptions
3 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
24 // File : StdMeshers_Regular_1D.cxx
25 // Moved here from SMESH_Regular_1D.cxx
26 // Author : Paul RASCLE, EDF
30 #include "StdMeshers_CompositeSegment_1D.hxx"
31 #include "StdMeshers_FaceSide.hxx"
32 #include "StdMeshers_AutomaticLength.hxx"
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_HypoFilter.hxx"
37 #include "SMESH_subMesh.hxx"
38 #include "SMESH_subMeshEventListener.hxx"
39 #include "SMESH_Comment.hxx"
41 #include "SMDS_MeshElement.hxx"
42 #include "SMDS_MeshNode.hxx"
44 #include "utilities.h"
46 #include <BRepAdaptor_CompCurve.hxx>
47 #include <BRep_Builder.hxx>
48 #include <GCPnts_AbscissaPoint.hxx>
50 #include <TopExp_Explorer.hxx>
51 #include <TopTools_ListIteratorOfListOfShape.hxx>
52 #include <TopTools_MapOfShape.hxx>
54 #include <TopoDS_Edge.hxx>
55 #include <TopoDS_Vertex.hxx>
56 #include <TopoDS_Wire.hxx>
59 #include <Standard_ErrorHandler.hxx>
60 #include <Standard_Failure.hxx>
62 typedef SMESH_Comment TComm;
69 //================================================================================
71 * \brief Search for an edge conjunct to the given one by the vertex
72 * Return NULL if more than 2 edges share the vertex or edges
73 * continuity is less than C1
75 //================================================================================
77 TopoDS_Edge nextC1Edge(const TopoDS_Edge& edge,
82 TopTools_MapOfShape edgeCounter;
83 edgeCounter.Add( edge );
85 v = forward ? TopExp::LastVertex( edge,1 ) : TopExp::FirstVertex( edge,1 );
86 TopTools_ListIteratorOfListOfShape ancestIt = aMesh.GetAncestors( v );
87 for ( ; ancestIt.More(); ancestIt.Next() )
89 const TopoDS_Shape & ancestor = ancestIt.Value();
90 if ( ancestor.ShapeType() == TopAbs_EDGE && edgeCounter.Add( ancestor ))
91 eNext = TopoDS::Edge( ancestor );
93 if ( edgeCounter.Extent() < 3 && !eNext.IsNull() ) {
94 GeomAbs_Shape cont = SMESH_Algo::Continuity( edge, eNext );
95 if (cont >= GeomAbs_G1) {
96 // care of orientation
99 reverse = ( !v.IsSame( TopExp::FirstVertex( eNext, true )));
101 reverse = ( !v.IsSame( TopExp::LastVertex( eNext, true )));
107 return TopoDS_Edge();
110 //================================================================================
112 * \brief Update submeshes state for all edges and internal vertices,
113 * make them look computed even if none edge or node is set on them
115 //================================================================================
117 void careOfSubMeshes( StdMeshers_FaceSide& side, EventListener* eListener)
119 if ( side.NbEdges() < 2)
121 for ( int iE = 0; iE < side.NbEdges(); ++iE )
123 // set listener and its data
124 EventListenerData * listenerData = new EventListenerData(true);
125 const TopoDS_Edge& edge = side.Edge( iE );
126 SMESH_subMesh * sm = side.GetMesh()->GetSubMesh( edge );
127 sm->SetEventListener( eListener, listenerData, sm );
128 // add edge submesh to the data
129 sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
130 if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) {
131 sm->SetIsAlwaysComputed( true );
132 listenerData->mySubMeshes.push_back( sm );
134 // add internal vertex submesh to the data
137 TopoDS_Vertex V = side.FirstVertex( iE );
138 sm = side.GetMesh()->GetSubMesh( V );
139 sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
140 if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK )
141 sm->SetIsAlwaysComputed( true );
142 listenerData->mySubMeshes.push_back( sm );
147 //================================================================================
149 * \brief Class used to restore nodes on internal vertices of a complex side
150 * when StdMeshers_CompositeSegment_1D algorithm is removed
152 //================================================================================
154 struct VertexNodesRestoringListener : public SMESH_subMeshEventListener
156 VertexNodesRestoringListener():SMESH_subMeshEventListener(0) // won't be deleted by submesh
159 * \brief Restore nodes on internal vertices of a complex side
160 * \param event - algo_event or compute_event itself (of SMESH_subMesh)
161 * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh)
162 * \param subMesh - the submesh where the event occures
163 * \param data - listener data stored in the subMesh
164 * \param hyp - hypothesis, if eventType is algo_event
166 void ProcessEvent(const int event,
168 SMESH_subMesh* subMesh,
169 EventListenerData* data,
170 const SMESH_Hypothesis* /*hyp*/)
172 bool hypRemoved = ( eventType == SMESH_subMesh::ALGO_EVENT &&
173 subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK );
174 if ( hypRemoved && data )
176 list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
177 for ( ; smIt != data->mySubMeshes.end(); ++smIt )
179 if ( SMESH_subMesh* sm = *smIt ) {
180 sm->SetIsAlwaysComputed( false );
181 sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
185 // at study restoration:
186 // check if edge submesh must have _alwaysComputed flag
187 else if ( event == SMESH_subMesh::SUBMESH_RESTORED &&
188 eventType == SMESH_subMesh::COMPUTE_EVENT )
190 if ( !subMesh->GetEventListenerData( this )) { // not yet checked
191 SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
192 if ( meshDS->NbNodes() > 0 ) {
193 // check if there are nodes on all vertices
194 bool hasNodesOnVerext = true;
195 SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
196 while ( hasNodesOnVerext && smIt->more() ) {
197 SMESH_subMesh* sm = smIt->next();
198 hasNodesOnVerext = ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbNodes() );
200 if ( !hasNodesOnVerext ) {
201 // check if an edge is a part of a complex side
203 TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
204 auto_ptr< StdMeshers_FaceSide > side
205 ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(),
206 edge, face, false ));
207 if ( side->NbEdges() > 1 && side->NbSegments() )
208 careOfSubMeshes( *side, this );
214 }; // struct VertexNodesRestoringListener
217 //=============================================================================
221 //=============================================================================
223 StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D(int hypId,
226 :StdMeshers_Regular_1D(hypId, studyId, gen)
228 MESSAGE("StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D");
229 _name = "CompositeSegment_1D";
230 _EventListener = new VertexNodesRestoringListener();
233 //=============================================================================
237 //=============================================================================
239 StdMeshers_CompositeSegment_1D::~StdMeshers_CompositeSegment_1D()
241 delete _EventListener;
244 //=============================================================================
246 * \brief Sets event listener to submeshes if necessary
247 * \param subMesh - submesh where algo is set
249 * This method is called when a submesh gets HYP_OK algo_state.
250 * After being set, event listener is notified on each event of a submesh.
252 //=============================================================================
254 void StdMeshers_CompositeSegment_1D::SetEventListener(SMESH_subMesh* subMesh)
256 subMesh->SetEventListener( _EventListener, 0, subMesh);
257 StdMeshers_Regular_1D::SetEventListener( subMesh );
260 //=============================================================================
262 * \brief Return a face side the edge belongs to
264 //=============================================================================
266 StdMeshers_FaceSide *
267 StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh& aMesh,
268 const TopoDS_Edge& anEdge,
269 const TopoDS_Face& aFace,
270 const bool ignoreMeshed)
272 list< TopoDS_Edge > edges;
273 edges.push_back( anEdge );
275 list <const SMESHDS_Hypothesis *> hypList;
276 SMESH_Algo* theAlgo = aMesh.GetGen()->GetAlgo( aMesh, anEdge );
277 if ( theAlgo ) hypList = theAlgo->GetUsedHypothesis(aMesh, anEdge, false);
278 for ( int forward = 0; forward < 2; ++forward )
280 TopoDS_Edge eNext = nextC1Edge( anEdge, aMesh, forward );
281 while ( !eNext.IsNull() ) {
282 if ( ignoreMeshed ) {
283 // eNext must not have computed mesh
284 if ( SMESHDS_SubMesh* sm = aMesh.GetMeshDS()->MeshElements(eNext) )
285 if ( sm->NbNodes() || sm->NbElements() )
288 // eNext must have same hypotheses
289 SMESH_Algo* algo = aMesh.GetGen()->GetAlgo( aMesh, eNext );
291 string(theAlgo->GetName()) != algo->GetName() ||
292 hypList != algo->GetUsedHypothesis(aMesh, eNext, false))
295 edges.push_back( eNext );
297 edges.push_front( eNext );
298 eNext = nextC1Edge( eNext, aMesh, forward );
301 return new StdMeshers_FaceSide( aFace, edges, &aMesh, true, false );
304 //=============================================================================
308 //=============================================================================
310 bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh & aMesh,
311 const TopoDS_Shape & aShape)
313 TopoDS_Edge edge = TopoDS::Edge( aShape );
314 SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
316 // Get edges to be discretized as a whole
317 TopoDS_Face nullFace;
318 auto_ptr< StdMeshers_FaceSide > side( GetFaceSide(aMesh, edge, nullFace, true ));
319 //side->dump("IN COMPOSITE SEG");
321 if ( side->NbEdges() < 2 )
322 return StdMeshers_Regular_1D::Compute( aMesh, aShape );
324 // update segment lenght computed by StdMeshers_AutomaticLength
325 const list <const SMESHDS_Hypothesis * > & hyps = GetUsedHypothesis(aMesh, aShape);
326 if ( !hyps.empty() ) {
327 StdMeshers_AutomaticLength * autoLenHyp = const_cast<StdMeshers_AutomaticLength *>
328 (dynamic_cast <const StdMeshers_AutomaticLength * >(hyps.front()));
330 _value[ BEG_LENGTH_IND ]= autoLenHyp->GetLength( &aMesh, side->Length() );
333 // Compute node parameters
334 auto_ptr< BRepAdaptor_CompCurve > C3d ( side->GetCurve3d() );
335 double f = C3d->FirstParameter(), l = C3d->LastParameter();
336 list< double > params;
337 if ( !computeInternalParameters ( *C3d, side->Length(), f, l, params, false ))
340 // Redistribute parameters near ends
341 TopoDS_Vertex VFirst = side->FirstVertex();
342 TopoDS_Vertex VLast = side->LastVertex();
343 redistributeNearVertices( aMesh, *C3d, side->Length(), params, VFirst, VLast );
345 params.push_front(f);
347 int nbNodes = params.size();
351 const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
352 const SMDS_MeshNode * nLast = SMESH_Algo::VertexNode( VLast, meshDS );
354 return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
355 <<meshDS->ShapeToIndex(VFirst));
357 return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
358 <<meshDS->ShapeToIndex(VLast));
360 vector<const SMDS_MeshNode*> nodes( nbNodes, (const SMDS_MeshNode*)0 );
361 nodes.front() = nFirst;
362 nodes.back() = nLast;
364 // create internal nodes
365 list< double >::iterator parIt = params.begin();
366 double prevPar = *parIt;
368 for ( int iN = 0; parIt != params.end(); ++iN, ++parIt)
370 if ( !nodes[ iN ] ) {
371 gp_Pnt p = C3d->Value( *parIt );
372 SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
373 C3d->Edge( *parIt, edge, u );
374 meshDS->SetNodeOnEdge( n, edge, u );
375 // cout << "new NODE: par="<<*parIt<<" ePar="<<u<<" e="<<edge.TShape().operator->()
376 // << " " << n << endl;
381 double mPar = ( prevPar + *parIt )/2;
382 if ( _quadraticMesh ) {
383 // create medium node
384 double segLen = GCPnts_AbscissaPoint::Length(*C3d, prevPar, *parIt);
385 GCPnts_AbscissaPoint ruler( *C3d, segLen/2., prevPar );
386 if ( ruler.IsDone() )
387 mPar = ruler.Parameter();
388 gp_Pnt p = C3d->Value( mPar );
389 SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
390 //cout << "new NODE "<< n << endl;
391 meshDS->SetNodeOnEdge( n, edge, u );
392 SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ], n);
393 meshDS->SetMeshElementOnShape(seg, edge);
396 C3d->Edge( mPar, edge, u );
397 SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ]);
398 meshDS->SetMeshElementOnShape(seg, edge);
404 // remove nodes on internal vertices
405 for ( int iE = 1; iE < side->NbEdges(); ++iE )
407 TopoDS_Vertex V = side->FirstVertex( iE );
408 while ( const SMDS_MeshNode * n = SMESH_Algo::VertexNode( V, meshDS ))
409 meshDS->RemoveNode( n );
412 // Update submeshes state for all edges and internal vertices,
413 // make them look computed even if none edge or node is set on them
414 careOfSubMeshes( *side, _EventListener );