1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 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, or (at your option) any later version.
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
23 // SMESH SMESH : implementaion of SMESH idl descriptions
24 // File : StdMeshers_CompositeSegment_1D.cxx
27 #include "StdMeshers_CompositeSegment_1D.hxx"
29 #include "SMDS_MeshElement.hxx"
30 #include "SMDS_MeshNode.hxx"
31 #include "SMESHDS_Mesh.hxx"
32 #include "SMESH_Comment.hxx"
33 #include "SMESH_Gen.hxx"
34 #include "SMESH_HypoFilter.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_TypeDefs.hxx"
37 #include "SMESH_subMesh.hxx"
38 #include "SMESH_subMeshEventListener.hxx"
39 #include "StdMeshers_AutomaticLength.hxx"
40 #include "StdMeshers_FaceSide.hxx"
42 #include "utilities.h"
44 #include <BRepAdaptor_CompCurve.hxx>
45 #include <BRep_Builder.hxx>
46 #include <GCPnts_AbscissaPoint.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopTools_ListIteratorOfListOfShape.hxx>
50 #include <TopTools_MapOfShape.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Vertex.hxx>
54 #include <TopoDS_Wire.hxx>
57 #include <Standard_ErrorHandler.hxx>
58 #include <Standard_Failure.hxx>
60 typedef SMESH_Comment TComm;
67 void careOfSubMeshes( StdMeshers_FaceSide& side );
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(TopoDS_Edge edge,
81 if (edge.Orientation() > TopAbs_REVERSED) // INTERNAL
82 edge.Orientation( TopAbs_FORWARD );
84 TopTools_MapOfShape edgeCounter;
85 edgeCounter.Add( edge );
86 TopoDS_Vertex v = forward ? TopExp::LastVertex(edge,true) : TopExp::FirstVertex(edge,true);
87 TopTools_ListIteratorOfListOfShape ancestIt = aMesh.GetAncestors( v );
88 for ( ; ancestIt.More(); ancestIt.Next() )
90 const TopoDS_Shape & ancestor = ancestIt.Value();
91 if ( ancestor.ShapeType() == TopAbs_EDGE && edgeCounter.Add( ancestor ))
92 eNext = TopoDS::Edge( ancestor );
94 if ( edgeCounter.Extent() < 3 && !eNext.IsNull() ) {
95 if ( SMESH_Algo::IsContinuous( edge, eNext )) {
96 // care of orientation
97 if (eNext.Orientation() > TopAbs_REVERSED) // INTERNAL
98 eNext.Orientation( TopAbs_FORWARD );
100 forward ? TopExp::FirstVertex(eNext,true) : TopExp::LastVertex(eNext,true);
101 bool reverse = (!v.IsSame(vn));
107 return TopoDS_Edge();
110 //================================================================================
112 * \brief Class used to restore nodes on internal vertices of a complex side
113 * when StdMeshers_CompositeSegment_1D algorithm is removed
115 //================================================================================
117 struct VertexNodesRestoringListener : public SMESH_subMeshEventListener
119 VertexNodesRestoringListener():
120 SMESH_subMeshEventListener(1, // will be deleted by sub-mesh
121 "StdMeshers_CompositeSegment_1D::VertexNodesRestoringListener")
123 static VertexNodesRestoringListener* New() { return new VertexNodesRestoringListener(); }
126 * \brief Restore nodes on internal vertices of a complex side
127 * \param event - algo_event or compute_event itself (of SMESH_subMesh)
128 * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh)
129 * \param subMesh - the submesh where the event occures
130 * \param data - listener data stored in the subMesh
131 * \param hyp - hypothesis, if eventType is algo_event
133 void ProcessEvent(const int event,
135 SMESH_subMesh* subMesh,
136 EventListenerData* data,
137 const SMESH_Hypothesis* /*hyp*/)
139 if ( data && eventType == SMESH_subMesh::ALGO_EVENT )
142 if ( subMesh->GetAlgoState() != SMESH_subMesh::HYP_OK )
145 SMESH_Algo* algo = subMesh->GetAlgo();
146 hypRemoved = ( string( algo->GetName() ) != StdMeshers_CompositeSegment_1D::AlgoName());
150 list<SMESH_subMesh*>::iterator smIt = data->mySubMeshes.begin();
151 for ( ; smIt != data->mySubMeshes.end(); ++smIt )
152 if ( SMESH_subMesh* sm = *smIt ) {
153 sm->SetIsAlwaysComputed( false );
154 sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
158 // at study restoration:
159 // check if edge submesh must have _alwaysComputed flag
160 else if ( event == SMESH_subMesh::SUBMESH_RESTORED &&
161 eventType == SMESH_subMesh::COMPUTE_EVENT )
163 if ( !subMesh->GetEventListenerData( this )) { // not yet checked
164 SMESHDS_Mesh * meshDS = subMesh->GetFather()->GetMeshDS();
165 if ( meshDS->NbNodes() > 0 ) {
166 // check if there are nodes on all vertices
167 bool hasNodesOnVerext = true;
168 SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
169 while ( hasNodesOnVerext && smIt->more() ) {
170 SMESH_subMesh* sm = smIt->next();
171 hasNodesOnVerext = ( sm->GetSubMeshDS() && sm->GetSubMeshDS()->NbNodes() );
173 if ( !hasNodesOnVerext ) {
174 // check if an edge is a part of a complex side
176 TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
177 SMESHUtils::Deleter< StdMeshers_FaceSide > side
178 ( StdMeshers_CompositeSegment_1D::GetFaceSide(*subMesh->GetFather(),
179 edge, face, false ));
180 if ( side->NbEdges() > 1 && side->NbSegments() )
181 careOfSubMeshes( *side );
186 // clean all EDGEs of a complex side if one EDGE is cleaned
187 else if ( event == SMESH_subMesh::CLEAN &&
188 eventType == SMESH_subMesh::COMPUTE_EVENT )
190 SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(/*includeSelf=*/false);
191 while ( smIt->more() ) // loop on VERTEX sub-meshes
193 SMESH_subMesh* sm = smIt->next();
194 if ( sm->IsAlwaysComputed() ) // it's an internal node sub-mesh
195 sm->ComputeStateEngine( SMESH_subMesh::CLEAN );
199 }; // struct VertexNodesRestoringListener
201 //================================================================================
203 * \brief Update submeshes state for all edges and internal vertices,
204 * make them look computed even if none edge or node is set on them
206 //================================================================================
208 void careOfSubMeshes( StdMeshers_FaceSide& side )
210 if ( side.NbEdges() < 2)
212 for ( int iE = 0; iE < side.NbEdges(); ++iE )
214 // set listener and its data
215 EventListenerData * listenerData = new EventListenerData(true);
216 const TopoDS_Edge& edge = side.Edge( iE );
217 SMESH_subMesh * sm = side.GetMesh()->GetSubMesh( edge );
218 sm->SetEventListener( new VertexNodesRestoringListener(), listenerData, sm );
219 // add edge submesh to the data
220 sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
221 if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK ) {
222 sm->SetIsAlwaysComputed( true );
223 listenerData->mySubMeshes.push_back( sm );
225 // add internal vertex submesh to the data
228 TopoDS_Vertex V = side.FirstVertex( iE );
229 sm = side.GetMesh()->GetSubMesh( V );
230 sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
231 if ( sm->GetComputeState() != SMESH_subMesh::COMPUTE_OK )
232 sm->SetIsAlwaysComputed( true );
233 listenerData->mySubMeshes.push_back( sm );
239 //=============================================================================
243 //=============================================================================
245 StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D(int hypId,
248 :StdMeshers_Regular_1D(hypId, studyId, gen)
250 MESSAGE("StdMeshers_CompositeSegment_1D::StdMeshers_CompositeSegment_1D");
254 //=======================================================================
255 //function : AlgoName
256 //purpose : Returns algo type name
257 //=======================================================================
259 std::string StdMeshers_CompositeSegment_1D::AlgoName()
261 return "CompositeSegment_1D";
264 //=============================================================================
266 * \brief Sets event listener to submeshes if necessary
267 * \param subMesh - submesh where algo is set
269 * This method is called when a submesh gets HYP_OK algo_state.
270 * After being set, event listener is notified on each event of a submesh.
272 //=============================================================================
274 void StdMeshers_CompositeSegment_1D::SetEventListener(SMESH_subMesh* subMesh)
276 // issue 0020279. Set "_alwaysComputed" flag to the submeshes of internal
277 // vertices of composite edge in order to avoid creation of vertices on
278 // them for the sake of stability.
280 // check if "_alwaysComputed" is not yet set
281 bool isAlwaysComputed = false;
282 SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
283 while ( !isAlwaysComputed && smIt->more() )
284 isAlwaysComputed = smIt->next()->IsAlwaysComputed();
286 if ( !isAlwaysComputed )
288 // check if an edge is a part of a complex side
290 TopoDS_Edge edge = TopoDS::Edge( subMesh->GetSubShape() );
291 SMESHUtils::Deleter< StdMeshers_FaceSide > side
292 ( StdMeshers_CompositeSegment_1D::GetFaceSide( *subMesh->GetFather(), edge, face, false ));
293 if ( side->NbEdges() > 1 ) { // complex
295 // set _alwaysComputed to vertices
296 for ( int iE = 1; iE < side->NbEdges(); ++iE )
298 TopoDS_Vertex V = side->FirstVertex( iE );
299 SMESH_subMesh* sm = side->GetMesh()->GetSubMesh( V );
300 sm->SetIsAlwaysComputed( true );
304 // set listener that will remove _alwaysComputed from submeshes at algorithm change
305 subMesh->SetEventListener( new VertexNodesRestoringListener(), 0, subMesh );
306 StdMeshers_Regular_1D::SetEventListener( subMesh );
309 //=============================================================================
311 * \brief Return a face side the edge belongs to
313 //=============================================================================
315 StdMeshers_FaceSide *
316 StdMeshers_CompositeSegment_1D::GetFaceSide(SMESH_Mesh& aMesh,
317 const TopoDS_Edge& anEdge,
318 const TopoDS_Face& aFace,
319 const bool ignoreMeshed)
321 list< TopoDS_Edge > edges;
322 if ( anEdge.Orientation() <= TopAbs_REVERSED )
323 edges.push_back( anEdge );
325 edges.push_back( TopoDS::Edge( anEdge.Oriented( TopAbs_FORWARD ))); // PAL21718
327 list <const SMESHDS_Hypothesis *> hypList;
328 SMESH_Algo* theAlgo = aMesh.GetGen()->GetAlgo( aMesh, anEdge );
329 if ( theAlgo ) hypList = theAlgo->GetUsedHypothesis(aMesh, anEdge, false);
330 for ( int forward = 0; forward < 2; ++forward )
332 TopoDS_Edge eNext = nextC1Edge( edges.back(), aMesh, forward );
333 while ( !eNext.IsNull() ) {
334 if ( ignoreMeshed ) {
335 // eNext must not have computed mesh
336 if ( SMESHDS_SubMesh* sm = aMesh.GetMeshDS()->MeshElements(eNext) )
337 if ( sm->NbNodes() || sm->NbElements() )
340 // eNext must have same hypotheses
341 SMESH_Algo* algo = aMesh.GetGen()->GetAlgo( aMesh, eNext );
343 string(theAlgo->GetName()) != algo->GetName() ||
344 hypList != algo->GetUsedHypothesis(aMesh, eNext, false))
346 if ( std::find( edges.begin(), edges.end(), eNext ) != edges.end() )
349 edges.push_back( eNext );
351 edges.push_front( eNext );
352 eNext = nextC1Edge( eNext, aMesh, forward );
355 return new StdMeshers_FaceSide( aFace, edges, &aMesh, true, false );
358 //=============================================================================
362 //=============================================================================
364 bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh & aMesh,
365 const TopoDS_Shape & aShape)
367 TopoDS_Edge edge = TopoDS::Edge( aShape );
368 SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
370 // Get edges to be discretized as a whole
371 TopoDS_Face nullFace;
372 SMESHUtils::Deleter< StdMeshers_FaceSide > side( GetFaceSide(aMesh, edge, nullFace, true ));
373 //side->dump("IN COMPOSITE SEG");
375 if ( side->NbEdges() < 2 )
376 return StdMeshers_Regular_1D::Compute( aMesh, aShape );
378 // update segment lenght computed by StdMeshers_AutomaticLength
379 const list <const SMESHDS_Hypothesis * > & hyps = GetUsedHypothesis(aMesh, aShape);
380 if ( !hyps.empty() ) {
381 StdMeshers_AutomaticLength * autoLenHyp = const_cast<StdMeshers_AutomaticLength *>
382 (dynamic_cast <const StdMeshers_AutomaticLength * >(hyps.front()));
384 _value[ BEG_LENGTH_IND ]= autoLenHyp->GetLength( &aMesh, side->Length() );
387 // Compute node parameters
388 SMESHUtils::Deleter< BRepAdaptor_CompCurve > C3d ( side->GetCurve3d() );
389 double f = C3d->FirstParameter(), l = C3d->LastParameter();
390 list< double > params;
391 if ( !computeInternalParameters ( aMesh, *C3d, side->Length(), f, l, params, false ))
394 // Redistribute parameters near ends
395 TopoDS_Vertex VFirst = side->FirstVertex();
396 TopoDS_Vertex VLast = side->LastVertex();
397 redistributeNearVertices( aMesh, *C3d, side->Length(), params, VFirst, VLast );
399 params.push_front(f);
401 int nbNodes = params.size();
405 // compute and get nodes on extremity VERTEX'es
406 SMESH_subMesh* smVFirst = aMesh.GetSubMesh( VFirst );
407 smVFirst->SetIsAlwaysComputed( false );
408 smVFirst->ComputeStateEngine( SMESH_subMesh::COMPUTE );
410 SMESH_subMesh* smVLast = aMesh.GetSubMesh( VLast );
411 smVLast->SetIsAlwaysComputed( false );
412 smVLast->ComputeStateEngine( SMESH_subMesh::COMPUTE );
414 const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
415 const SMDS_MeshNode * nLast = SMESH_Algo::VertexNode( VLast, meshDS );
417 return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
418 <<meshDS->ShapeToIndex(VFirst));
420 return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ")
421 <<meshDS->ShapeToIndex(VLast));
423 vector<const SMDS_MeshNode*> nodes( nbNodes, (const SMDS_MeshNode*)0 );
424 nodes.front() = nFirst;
425 nodes.back() = nLast;
427 // create internal nodes
428 list< double >::iterator parIt = params.begin();
429 double prevPar = *parIt;
431 for ( int iN = 0; parIt != params.end(); ++iN, ++parIt)
433 if ( !nodes[ iN ] ) {
434 gp_Pnt p = C3d->Value( *parIt );
435 SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
436 C3d->Edge( *parIt, edge, u );
437 meshDS->SetNodeOnEdge( n, edge, u );
438 // cout << "new NODE: par="<<*parIt<<" ePar="<<u<<" e="<<edge.TShape().operator->()
439 // << " " << n << endl;
444 double mPar = ( prevPar + *parIt )/2;
445 if ( _quadraticMesh ) {
446 // create medium node
447 double segLen = GCPnts_AbscissaPoint::Length(*C3d, prevPar, *parIt);
448 GCPnts_AbscissaPoint ruler( *C3d, segLen/2., prevPar );
449 if ( ruler.IsDone() )
450 mPar = ruler.Parameter();
451 gp_Pnt p = C3d->Value( mPar );
452 SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z());
453 //cout << "new NODE "<< n << endl;
454 meshDS->SetNodeOnEdge( n, edge, u );
455 SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ], n);
456 meshDS->SetMeshElementOnShape(seg, edge);
459 C3d->Edge( mPar, edge, u );
460 SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ]);
461 meshDS->SetMeshElementOnShape(seg, edge);
467 // remove nodes on internal vertices
468 for ( int iE = 1; iE < side->NbEdges(); ++iE )
470 TopoDS_Vertex V = side->FirstVertex( iE );
471 while ( const SMDS_MeshNode * n = SMESH_Algo::VertexNode( V, meshDS ))
472 meshDS->RemoveNode( n );
475 // Update submeshes state for all edges and internal vertices,
476 // make them look computed even if none edge or node is set on them
477 careOfSubMeshes( *side );