1 // Copyright (C) 2007-2012 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.
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 : SMESH_Gen.cxx
25 // Author : Paul RASCLE, EDF
31 #include "SMESH_Gen.hxx"
33 #include "SMDS_Mesh.hxx"
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
36 #include "SMESHDS_Document.hxx"
37 #include "SMESH_HypoFilter.hxx"
38 #include "SMESH_MesherHelper.hxx"
39 #include "SMESH_subMesh.hxx"
41 #include "utilities.h"
43 #include "Utils_ExceptHandlers.hxx"
45 #include <TopoDS_Iterator.hxx>
46 #include <LDOMParser.hxx>
56 //=============================================================================
60 //=============================================================================
62 SMESH_Gen::SMESH_Gen()
64 MESSAGE("SMESH_Gen::SMESH_Gen");
67 _segmentation = _nbSegments = 10;
68 SMDS_Mesh::_meshList.clear();
69 MESSAGE(SMDS_Mesh::_meshList.size());
70 _counters = new counters(100);
71 #ifdef WITH_SMESH_CANCEL_COMPUTE
72 _compute_canceled = false;
77 //=============================================================================
81 //=============================================================================
83 SMESH_Gen::~SMESH_Gen()
85 MESSAGE("SMESH_Gen::~SMESH_Gen");
88 //=============================================================================
90 * Creates a mesh in a study.
91 * if (theIsEmbeddedMode) { mesh modification commands are not logged }
93 //=============================================================================
95 SMESH_Mesh* SMESH_Gen::CreateMesh(int theStudyId, bool theIsEmbeddedMode)
96 throw(SALOME_Exception)
98 Unexpect aCatch(SalomeException);
99 MESSAGE("SMESH_Gen::CreateMesh");
101 // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document
102 StudyContextStruct *aStudyContext = GetStudyContext(theStudyId);
104 // create a new SMESH_mesh object
105 SMESH_Mesh *aMesh = new SMESH_Mesh(_localId++,
109 aStudyContext->myDocument);
110 aStudyContext->mapMesh[_localId-1] = aMesh;
115 //=============================================================================
119 //=============================================================================
121 bool SMESH_Gen::Compute(SMESH_Mesh & aMesh,
122 const TopoDS_Shape & aShape,
124 const ::MeshDimension aDim,
125 TSetOfInt* aShapesId)
127 MESSAGE("SMESH_Gen::Compute");
132 SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
134 const bool includeSelf = true;
135 const bool complexShapeFirst = true;
136 const int globalAlgoDim = 100;
138 SMESH_subMeshIteratorPtr smIt;
140 if ( anUpward ) // is called from below code here
142 // -----------------------------------------------
143 // mesh all the sub-shapes starting from vertices
144 // -----------------------------------------------
145 smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
146 while ( smIt->more() )
148 SMESH_subMesh* smToCompute = smIt->next();
150 // do not mesh vertices of a pseudo shape
151 const TopAbs_ShapeEnum aShType = smToCompute->GetSubShape().ShapeType();
152 if ( !aMesh.HasShapeToMesh() && aShType == TopAbs_VERTEX )
155 // check for preview dimension limitations
156 if ( aShapesId && GetShapeDim( aShType ) > (int)aDim )
158 // clear compute state to not show previous compute errors
159 // if preview invoked less dimension less than previous
160 smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
164 if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
166 #ifdef WITH_SMESH_CANCEL_COMPUTE
167 if (_compute_canceled)
169 _sm_current = smToCompute;
171 smToCompute->ComputeStateEngine( SMESH_subMesh::COMPUTE );
172 #ifdef WITH_SMESH_CANCEL_COMPUTE
177 // we check all the submeshes here and detect if any of them failed to compute
178 if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE)
180 else if ( aShapesId )
181 aShapesId->insert( smToCompute->GetId() );
183 //aMesh.GetMeshDS()->Modified();
188 // -----------------------------------------------------------------
189 // apply algos that DO NOT require Discreteized boundaries and DO NOT
190 // support submeshes, starting from the most complex shapes
191 // and collect submeshes with algos that DO support submeshes
192 // -----------------------------------------------------------------
193 list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes;
195 // map to sort sm with same dim algos according to dim of
196 // the shape the algo assigned to (issue 0021217)
197 multimap< int, SMESH_subMesh* > shDim2sm;
198 multimap< int, SMESH_subMesh* >::reverse_iterator shDim2smIt;
199 TopoDS_Shape algoShape;
200 int prevShapeDim = -1;
202 smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
203 while ( smIt->more() )
205 SMESH_subMesh* smToCompute = smIt->next();
206 if ( smToCompute->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE )
209 const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
210 int aShapeDim = GetShapeDim( aSubShape );
211 if ( aShapeDim < 1 ) break;
213 // check for preview dimension limitations
214 if ( aShapesId && aShapeDim > (int)aDim )
217 SMESH_Algo* algo = GetAlgo( aMesh, aSubShape, &algoShape );
218 if ( algo && !algo->NeedDiscreteBoundary() )
220 if ( algo->SupportSubmeshes() )
222 // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
223 // so that more local algos to go first
224 if ( prevShapeDim != aShapeDim )
226 prevShapeDim = aShapeDim;
227 for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
228 if ( shDim2smIt->first == globalAlgoDim )
229 smWithAlgoSupportingSubmeshes.push_back( shDim2smIt->second );
231 smWithAlgoSupportingSubmeshes.push_front( shDim2smIt->second );
234 // add smToCompute to shDim2sm map
235 if ( algoShape.IsSame( aMesh.GetShapeToMesh() ))
237 aShapeDim = globalAlgoDim; // to compute last
241 aShapeDim = GetShapeDim( algoShape );
242 if ( algoShape.ShapeType() == TopAbs_COMPOUND )
244 TopoDS_Iterator it( algoShape );
245 aShapeDim += GetShapeDim( it.Value() );
248 shDim2sm.insert( make_pair( aShapeDim, smToCompute ));
252 #ifdef WITH_SMESH_CANCEL_COMPUTE
253 if (_compute_canceled)
255 _sm_current = smToCompute;
257 smToCompute->ComputeStateEngine( SMESH_subMesh::COMPUTE );
258 #ifdef WITH_SMESH_CANCEL_COMPUTE
262 aShapesId->insert( smToCompute->GetId() );
266 // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
267 for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
268 if ( shDim2smIt->first == globalAlgoDim )
269 smWithAlgoSupportingSubmeshes.push_back( shDim2smIt->second );
271 smWithAlgoSupportingSubmeshes.push_front( shDim2smIt->second );
273 // ------------------------------------------------------------
274 // sort list of submeshes according to mesh order
275 // ------------------------------------------------------------
276 aMesh.SortByMeshOrder( smWithAlgoSupportingSubmeshes );
278 // ------------------------------------------------------------
279 // compute submeshes under shapes with algos that DO NOT require
280 // Discreteized boundaries and DO support submeshes
281 // ------------------------------------------------------------
282 list< SMESH_subMesh* >::iterator subIt, subEnd;
283 subIt = smWithAlgoSupportingSubmeshes.begin();
284 subEnd = smWithAlgoSupportingSubmeshes.end();
285 // start from lower shapes
286 for ( ; subIt != subEnd; ++subIt )
290 // get a shape the algo is assigned to
291 if ( !GetAlgo( aMesh, sm->GetSubShape(), & algoShape ))
292 continue; // strange...
294 // look for more local algos
295 smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
296 while ( smIt->more() )
298 SMESH_subMesh* smToCompute = smIt->next();
300 const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
301 const int aShapeDim = GetShapeDim( aSubShape );
302 //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue;
303 if ( aShapeDim < 1 ) continue;
305 // check for preview dimension limitations
306 if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim )
309 SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
311 .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
312 .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
314 if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( aSubShape, filter, true )) {
315 SMESH_Hypothesis::Hypothesis_Status status;
316 if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
317 // mesh a lower smToCompute starting from vertices
318 Compute( aMesh, aSubShape, /*anUpward=*/true, aDim, aShapesId );
322 // ----------------------------------------------------------
323 // apply the algos that do not require Discreteized boundaries
324 // ----------------------------------------------------------
325 for ( subIt = smWithAlgoSupportingSubmeshes.begin(); subIt != subEnd; ++subIt )
328 if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
330 const TopAbs_ShapeEnum aShType = sm->GetSubShape().ShapeType();
331 // check for preview dimension limitations
332 if ( aShapesId && GetShapeDim( aShType ) > (int)aDim )
335 #ifdef WITH_SMESH_CANCEL_COMPUTE
336 if (_compute_canceled)
340 sm->ComputeStateEngine( SMESH_subMesh::COMPUTE );
341 #ifdef WITH_SMESH_CANCEL_COMPUTE
345 aShapesId->insert( sm->GetId() );
348 // -----------------------------------------------
349 // mesh the rest sub-shapes starting from vertices
350 // -----------------------------------------------
351 ret = Compute( aMesh, aShape, /*anUpward=*/true, aDim, aShapesId );
354 MESSAGE( "VSR - SMESH_Gen::Compute() finished, OK = " << ret);
357 SMESHDS_Mesh *myMesh = aMesh.GetMeshDS();
358 myMesh->adjustStructure();
359 MESSAGE("*** compactMesh after compute");
360 myMesh->compactMesh();
361 //myMesh->adjustStructure();
362 list<int> listind = myMesh->SubMeshIndices();
363 list<int>::iterator it = listind.begin();
365 for(; it != listind.end(); ++it)
367 ::SMESHDS_SubMesh *subMesh = myMesh->MeshElements(*it);
368 total += subMesh->getSize();
370 MESSAGE("total elements and nodes in submesh sets:" << total);
371 MESSAGE("Number of node objects " << SMDS_MeshNode::nbNodes);
372 MESSAGE("Number of cell objects " << SMDS_MeshCell::nbCells);
373 //myMesh->dumpGrid();
374 //aMesh.GetMeshDS()->Modified();
376 // fix quadratic mesh by bending iternal links near concave boundary
377 if ( aShape.IsSame( aMesh.GetShapeToMesh() ) &&
378 !aShapesId ) // not preview
380 SMESH_MesherHelper aHelper( aMesh );
381 if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
383 aHelper.FixQuadraticElements( sm->GetComputeError() );
390 #ifdef WITH_SMESH_CANCEL_COMPUTE
391 //=============================================================================
393 * Prepare Compute a mesh
395 //=============================================================================
396 void SMESH_Gen::PrepareCompute(SMESH_Mesh & aMesh,
397 const TopoDS_Shape & aShape)
399 _compute_canceled = false;
402 //=============================================================================
404 * Cancel Compute a mesh
406 //=============================================================================
407 void SMESH_Gen::CancelCompute(SMESH_Mesh & aMesh,
408 const TopoDS_Shape & aShape)
410 _compute_canceled = true;
413 _sm_current->ComputeStateEngine( SMESH_subMesh::COMPUTE_CANCELED );
418 //=============================================================================
422 //=============================================================================
424 bool SMESH_Gen::Evaluate(SMESH_Mesh & aMesh,
425 const TopoDS_Shape & aShape,
426 MapShapeNbElems& aResMap,
428 TSetOfInt* aShapesId)
430 MESSAGE("SMESH_Gen::Evaluate");
434 SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
436 const bool includeSelf = true;
437 const bool complexShapeFirst = true;
438 SMESH_subMeshIteratorPtr smIt;
440 if ( anUpward ) { // is called from below code here
441 // -----------------------------------------------
442 // mesh all the sub-shapes starting from vertices
443 // -----------------------------------------------
444 smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
445 while ( smIt->more() ) {
446 SMESH_subMesh* smToCompute = smIt->next();
448 // do not mesh vertices of a pseudo shape
449 const TopAbs_ShapeEnum aShType = smToCompute->GetSubShape().ShapeType();
450 //if ( !aMesh.HasShapeToMesh() && aShType == TopAbs_VERTEX )
452 if ( !aMesh.HasShapeToMesh() ) {
453 if( aShType == TopAbs_VERTEX || aShType == TopAbs_WIRE ||
454 aShType == TopAbs_SHELL )
458 smToCompute->Evaluate(aResMap);
460 aShapesId->insert( smToCompute->GetId() );
465 // -----------------------------------------------------------------
466 // apply algos that DO NOT require Discreteized boundaries and DO NOT
467 // support submeshes, starting from the most complex shapes
468 // and collect submeshes with algos that DO support submeshes
469 // -----------------------------------------------------------------
470 list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes;
471 smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
472 while ( smIt->more() ) {
473 SMESH_subMesh* smToCompute = smIt->next();
474 const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
475 const int aShapeDim = GetShapeDim( aSubShape );
476 if ( aShapeDim < 1 ) break;
478 SMESH_Algo* algo = GetAlgo( aMesh, aSubShape );
479 if ( algo && !algo->NeedDiscreteBoundary() ) {
480 if ( algo->SupportSubmeshes() ) {
481 smWithAlgoSupportingSubmeshes.push_front( smToCompute );
484 smToCompute->Evaluate(aResMap);
486 aShapesId->insert( smToCompute->GetId() );
491 // ------------------------------------------------------------
492 // sort list of meshes according to mesh order
493 // ------------------------------------------------------------
494 aMesh.SortByMeshOrder( smWithAlgoSupportingSubmeshes );
496 // ------------------------------------------------------------
497 // compute submeshes under shapes with algos that DO NOT require
498 // Discreteized boundaries and DO support submeshes
499 // ------------------------------------------------------------
500 list< SMESH_subMesh* >::iterator subIt, subEnd;
501 subIt = smWithAlgoSupportingSubmeshes.begin();
502 subEnd = smWithAlgoSupportingSubmeshes.end();
503 // start from lower shapes
504 for ( ; subIt != subEnd; ++subIt ) {
507 // get a shape the algo is assigned to
508 TopoDS_Shape algoShape;
509 if ( !GetAlgo( aMesh, sm->GetSubShape(), & algoShape ))
510 continue; // strange...
512 // look for more local algos
513 smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
514 while ( smIt->more() ) {
515 SMESH_subMesh* smToCompute = smIt->next();
517 const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
518 const int aShapeDim = GetShapeDim( aSubShape );
519 if ( aShapeDim < 1 ) continue;
521 //const TopAbs_ShapeEnum aShType = smToCompute->GetSubShape().ShapeType();
523 SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
525 .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
526 .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));
528 if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( aSubShape, filter, true )) {
529 SMESH_Hypothesis::Hypothesis_Status status;
530 if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
531 // mesh a lower smToCompute starting from vertices
532 Evaluate( aMesh, aSubShape, aResMap, /*anUpward=*/true, aShapesId );
536 // ----------------------------------------------------------
537 // apply the algos that do not require Discreteized boundaries
538 // ----------------------------------------------------------
539 for ( subIt = smWithAlgoSupportingSubmeshes.begin(); subIt != subEnd; ++subIt )
542 sm->Evaluate(aResMap);
544 aShapesId->insert( sm->GetId() );
547 // -----------------------------------------------
548 // mesh the rest sub-shapes starting from vertices
549 // -----------------------------------------------
550 ret = Evaluate( aMesh, aShape, aResMap, /*anUpward=*/true, aShapesId );
553 MESSAGE( "VSR - SMESH_Gen::Evaluate() finished, OK = " << ret);
558 //=======================================================================
559 //function : checkConformIgnoredAlgos
561 //=======================================================================
563 static bool checkConformIgnoredAlgos(SMESH_Mesh& aMesh,
564 SMESH_subMesh* aSubMesh,
565 const SMESH_Algo* aGlobIgnoAlgo,
566 const SMESH_Algo* aLocIgnoAlgo,
568 set<SMESH_subMesh*>& aCheckedMap,
569 list< SMESH_Gen::TAlgoStateError > & theErrors)
572 if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX)
578 const list<const SMESHDS_Hypothesis*>& listHyp =
579 aMesh.GetMeshDS()->GetHypothesis( aSubMesh->GetSubShape() );
580 list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
581 for ( ; it != listHyp.end(); it++)
583 const SMESHDS_Hypothesis * aHyp = *it;
584 if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
587 const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
590 if ( aLocIgnoAlgo ) // algo is hidden by a local algo of upper dim
592 theErrors.push_back( SMESH_Gen::TAlgoStateError() );
593 theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, false );
594 INFOS( "Local <" << algo->GetName() << "> is hidden by local <"
595 << aLocIgnoAlgo->GetName() << ">");
599 bool isGlobal = (aMesh.IsMainShape( aSubMesh->GetSubShape() ));
600 int dim = algo->GetDim();
601 int aMaxGlobIgnoDim = ( aGlobIgnoAlgo ? aGlobIgnoAlgo->GetDim() : -1 );
603 if ( dim < aMaxGlobIgnoDim )
605 // algo is hidden by a global algo
606 theErrors.push_back( SMESH_Gen::TAlgoStateError() );
607 theErrors.back().Set( SMESH_Hypothesis::HYP_HIDDEN_ALGO, algo, true );
608 INFOS( ( isGlobal ? "Global" : "Local" )
609 << " <" << algo->GetName() << "> is hidden by global <"
610 << aGlobIgnoAlgo->GetName() << ">");
612 else if ( !algo->NeedDiscreteBoundary() && !isGlobal)
614 // local algo is not hidden and hides algos on sub-shapes
615 if (checkConform && !aSubMesh->IsConform( algo ))
618 checkConform = false; // no more check conformity
619 INFOS( "ERROR: Local <" << algo->GetName() <<
620 "> would produce not conform mesh: "
621 "<Not Conform Mesh Allowed> hypotesis is missing");
622 theErrors.push_back( SMESH_Gen::TAlgoStateError() );
623 theErrors.back().Set( SMESH_Hypothesis::HYP_NOTCONFORM, algo, false );
626 // sub-algos will be hidden by a local <algo>
627 SMESH_subMeshIteratorPtr revItSub =
628 aSubMesh->getDependsOnIterator( /*includeSelf=*/false, /*complexShapeFirst=*/true);
629 bool checkConform2 = false;
630 while ( revItSub->more() )
632 SMESH_subMesh* sm = revItSub->next();
633 checkConformIgnoredAlgos (aMesh, sm, aGlobIgnoAlgo,
634 algo, checkConform2, aCheckedMap, theErrors);
635 aCheckedMap.insert( sm );
644 //=======================================================================
645 //function : checkMissing
646 //purpose : notify on missing hypothesis
647 // Return false if algo or hipothesis is missing
648 //=======================================================================
650 static bool checkMissing(SMESH_Gen* aGen,
652 SMESH_subMesh* aSubMesh,
653 const int aTopAlgoDim,
655 const bool checkNoAlgo,
656 set<SMESH_subMesh*>& aCheckedMap,
657 list< SMESH_Gen::TAlgoStateError > & theErrors)
659 if ( aSubMesh->GetSubShape().ShapeType() == TopAbs_VERTEX ||
660 aCheckedMap.count( aSubMesh ))
663 //MESSAGE("=====checkMissing");
666 SMESH_Algo* algo = 0;
668 switch (aSubMesh->GetAlgoState())
670 case SMESH_subMesh::NO_ALGO: {
673 // should there be any algo?
674 int shapeDim = SMESH_Gen::GetShapeDim( aSubMesh->GetSubShape() );
675 if (aTopAlgoDim > shapeDim)
677 MESSAGE( "ERROR: " << shapeDim << "D algorithm is missing" );
679 theErrors.push_back( SMESH_Gen::TAlgoStateError() );
680 theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, shapeDim, true );
685 case SMESH_subMesh::MISSING_HYP: {
686 // notify if an algo missing hyp is attached to aSubMesh
687 algo = aGen->GetAlgo( aMesh, aSubMesh->GetSubShape() );
689 bool IsGlobalHypothesis = aGen->IsGlobalHypothesis( algo, aMesh );
690 if (!IsGlobalHypothesis || !globalChecked[ algo->GetDim() ])
692 TAlgoStateErrorName errName = SMESH_Hypothesis::HYP_MISSING;
693 SMESH_Hypothesis::Hypothesis_Status status;
694 algo->CheckHypothesis( aMesh, aSubMesh->GetSubShape(), status );
695 if ( status == SMESH_Hypothesis::HYP_BAD_PARAMETER ) {
696 MESSAGE( "ERROR: hypothesis of " << (IsGlobalHypothesis ? "Global " : "Local ")
697 << "<" << algo->GetName() << "> has a bad parameter value");
699 } else if ( status == SMESH_Hypothesis::HYP_BAD_GEOMETRY ) {
700 MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
701 << "<" << algo->GetName() << "> assigned to mismatching geometry");
704 MESSAGE( "ERROR: " << (IsGlobalHypothesis ? "Global " : "Local ")
705 << "<" << algo->GetName() << "> misses some hypothesis");
707 if (IsGlobalHypothesis)
708 globalChecked[ algo->GetDim() ] = true;
709 theErrors.push_back( SMESH_Gen::TAlgoStateError() );
710 theErrors.back().Set( errName, algo, IsGlobalHypothesis );
715 case SMESH_subMesh::HYP_OK:
716 algo = aSubMesh->GetAlgo();
718 if (!algo->NeedDiscreteBoundary())
720 SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
721 /*complexShapeFirst=*/false);
722 while ( itsub->more() )
723 aCheckedMap.insert( itsub->next() );
729 // do not check under algo that hides sub-algos or
730 // re-start checking NO_ALGO state
732 bool isTopLocalAlgo =
733 ( aTopAlgoDim <= algo->GetDim() && !aGen->IsGlobalHypothesis( algo, aMesh ));
734 if (!algo->NeedDiscreteBoundary() || isTopLocalAlgo)
736 bool checkNoAlgo2 = ( algo->NeedDiscreteBoundary() );
737 SMESH_subMeshIteratorPtr itsub = aSubMesh->getDependsOnIterator( /*includeSelf=*/false,
738 /*complexShapeFirst=*/false);
739 while ( itsub->more() )
741 // sub-meshes should not be checked further more
742 SMESH_subMesh* sm = itsub->next();
746 //check algo on sub-meshes
747 int aTopAlgoDim2 = algo->GetDim();
748 if (!checkMissing (aGen, aMesh, sm, aTopAlgoDim2,
749 globalChecked, checkNoAlgo2, aCheckedMap, theErrors))
752 if (sm->GetAlgoState() == SMESH_subMesh::NO_ALGO )
753 checkNoAlgo2 = false;
756 aCheckedMap.insert( sm );
762 //=======================================================================
763 //function : CheckAlgoState
764 //purpose : notify on bad state of attached algos, return false
765 // if Compute() would fail because of some algo bad state
766 //=======================================================================
768 bool SMESH_Gen::CheckAlgoState(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape)
770 list< TAlgoStateError > errors;
771 return GetAlgoState( aMesh, aShape, errors );
774 //=======================================================================
775 //function : GetAlgoState
776 //purpose : notify on bad state of attached algos, return false
777 // if Compute() would fail because of some algo bad state
778 // theErrors list contains problems description
779 //=======================================================================
781 bool SMESH_Gen::GetAlgoState(SMESH_Mesh& theMesh,
782 const TopoDS_Shape& theShape,
783 list< TAlgoStateError > & theErrors)
785 //MESSAGE("SMESH_Gen::CheckAlgoState");
788 bool hasAlgo = false;
790 SMESH_subMesh* sm = theMesh.GetSubMesh(theShape);
791 const SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
792 TopoDS_Shape mainShape = meshDS->ShapeToMesh();
798 const SMESH_Algo* aGlobAlgoArr[] = {0,0,0,0};
800 const list<const SMESHDS_Hypothesis*>& listHyp = meshDS->GetHypothesis( mainShape );
801 list<const SMESHDS_Hypothesis*>::const_iterator it=listHyp.begin();
802 for ( ; it != listHyp.end(); it++)
804 const SMESHDS_Hypothesis * aHyp = *it;
805 if (aHyp->GetType() == SMESHDS_Hypothesis::PARAM_ALGO)
808 const SMESH_Algo* algo = dynamic_cast<const SMESH_Algo*> (aHyp);
811 int dim = algo->GetDim();
812 aGlobAlgoArr[ dim ] = algo;
817 // --------------------------------------------------------
818 // info on algos that will be ignored because of ones that
819 // don't NeedDiscreteBoundary() attached to super-shapes,
820 // check that a conform mesh will be produced
821 // --------------------------------------------------------
824 // find a global algo possibly hiding sub-algos
826 const SMESH_Algo* aGlobIgnoAlgo = 0;
827 for (dim = 3; dim > 0; dim--)
829 if (aGlobAlgoArr[ dim ] &&
830 !aGlobAlgoArr[ dim ]->NeedDiscreteBoundary())
832 aGlobIgnoAlgo = aGlobAlgoArr[ dim ];
837 set<SMESH_subMesh*> aCheckedSubs;
838 bool checkConform = ( !theMesh.IsNotConformAllowed() );
840 // loop on theShape and its sub-shapes
841 SMESH_subMeshIteratorPtr revItSub = sm->getDependsOnIterator( /*includeSelf=*/true,
842 /*complexShapeFirst=*/true);
843 while ( revItSub->more() )
845 SMESH_subMesh* smToCheck = revItSub->next();
846 if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
849 if ( aCheckedSubs.insert( smToCheck ).second ) // not yet checked
850 if (!checkConformIgnoredAlgos (theMesh, smToCheck, aGlobIgnoAlgo,
851 0, checkConform, aCheckedSubs, theErrors))
854 if ( smToCheck->GetAlgoState() != SMESH_subMesh::NO_ALGO )
858 // ----------------------------------------------------------------
859 // info on missing hypothesis and find out if all needed algos are
861 // ----------------------------------------------------------------
863 //MESSAGE( "---info on missing hypothesis and find out if all needed algos are");
865 // find max dim of global algo
867 for (dim = 3; dim > 0; dim--)
869 if (aGlobAlgoArr[ dim ])
875 bool checkNoAlgo = theMesh.HasShapeToMesh() ? bool( aTopAlgoDim ) : false;
876 bool globalChecked[] = { false, false, false, false };
878 // loop on theShape and its sub-shapes
879 aCheckedSubs.clear();
880 revItSub = sm->getDependsOnIterator( /*includeSelf=*/true, /*complexShapeFirst=*/true);
881 while ( revItSub->more() )
883 SMESH_subMesh* smToCheck = revItSub->next();
884 if ( smToCheck->GetSubShape().ShapeType() == TopAbs_VERTEX)
887 if ( aCheckedSubs.insert( smToCheck ).second ) // not yet checked
888 if (!checkMissing (this, theMesh, smToCheck, aTopAlgoDim,
889 globalChecked, checkNoAlgo, aCheckedSubs, theErrors))
892 if (smToCheck->GetAlgoState() == SMESH_subMesh::NO_ALGO )
899 INFOS( "None algorithm attached" );
900 theErrors.push_back( TAlgoStateError() );
901 theErrors.back().Set( SMESH_Hypothesis::HYP_MISSING, 1, true );
907 //=======================================================================
908 //function : IsGlobalHypothesis
909 //purpose : check if theAlgo is attached to the main shape
910 //=======================================================================
912 bool SMESH_Gen::IsGlobalHypothesis(const SMESH_Hypothesis* theHyp, SMESH_Mesh& aMesh)
914 SMESH_HypoFilter filter( SMESH_HypoFilter::Is( theHyp ));
915 return aMesh.GetHypothesis( aMesh.GetMeshDS()->ShapeToMesh(), filter, false );
918 //================================================================================
920 * \brief Return paths to xml files of plugins
922 //================================================================================
924 std::vector< std::string > SMESH_Gen::GetPluginXMLPaths()
926 // Get paths to xml files of plugins
927 vector< string > xmlPaths;
929 if ( const char* meshersList = getenv("SMESH_MeshersList") )
931 string meshers = meshersList, plugin;
932 string::size_type from = 0, pos;
933 while ( from < meshers.size() )
935 // cut off plugin name
936 pos = meshers.find( ':', from );
937 if ( pos != string::npos )
938 plugin = meshers.substr( from, pos-from );
940 plugin = meshers.substr( from ), pos = meshers.size();
943 // get PLUGIN_ROOT_DIR path
944 string rootDirVar, pluginSubDir = plugin;
945 if ( plugin == "StdMeshers" )
946 rootDirVar = "SMESH", pluginSubDir = "smesh";
948 for ( pos = 0; pos < plugin.size(); ++pos )
949 rootDirVar += toupper( plugin[pos] );
950 rootDirVar += "_ROOT_DIR";
952 const char* rootDir = getenv( rootDirVar.c_str() );
953 if ( !rootDir || strlen(rootDir) == 0 )
955 rootDirVar = plugin + "_ROOT_DIR"; // HexoticPLUGIN_ROOT_DIR
956 rootDir = getenv( rootDirVar.c_str() );
957 if ( !rootDir || strlen(rootDir) == 0 ) continue;
960 // get a separator from rootDir
961 for ( pos = strlen( rootDir )-1; pos >= 0 && sep.empty(); --pos )
962 if ( rootDir[pos] == '/' || rootDir[pos] == '\\' )
968 if (sep.empty() ) sep = "\\";
970 if (sep.empty() ) sep = "/";
973 // get a path to resource file
974 string xmlPath = rootDir;
975 if ( xmlPath[ xmlPath.size()-1 ] != sep[0] )
977 xmlPath += "share" + sep + "salome" + sep + "resources" + sep;
978 for ( pos = 0; pos < pluginSubDir.size(); ++pos )
979 xmlPath += tolower( pluginSubDir[pos] );
980 xmlPath += sep + plugin + ".xml";
983 fileOK = (GetFileAttributes(xmlPath.c_str()) != INVALID_FILE_ATTRIBUTES);
985 fileOK = (access(xmlPath.c_str(), F_OK) == 0);
988 xmlPaths.push_back( xmlPath );
995 //=======================================================================
996 namespace // Access to type of input and output of an algorithm
997 //=======================================================================
1002 set<SMDSAbs_GeometryType> _inElemTypes; // acceptable types of input mesh element
1003 set<SMDSAbs_GeometryType> _outElemTypes; // produced types of mesh elements
1005 bool IsCompatible( const AlgoData& algo2 ) const
1007 if ( _dim > algo2._dim ) return algo2.IsCompatible( *this );
1008 // algo2 is of highter dimension
1009 if ( _outElemTypes.empty() || algo2._inElemTypes.empty() )
1011 bool compatible = true;
1012 set<SMDSAbs_GeometryType>::const_iterator myOutType = _outElemTypes.begin();
1013 for ( ; myOutType != _outElemTypes.end() && compatible; ++myOutType )
1014 compatible = algo2._inElemTypes.count( *myOutType );
1019 //================================================================================
1021 * \brief Return AlgoData of the algorithm
1023 //================================================================================
1025 const AlgoData& getAlgoData( const SMESH_Algo* algo )
1027 static map< string, AlgoData > theDataByName;
1028 if ( theDataByName.empty() )
1030 // Read Plugin.xml files
1031 vector< string > xmlPaths = SMESH_Gen::GetPluginXMLPaths();
1032 LDOMParser xmlParser;
1033 for ( size_t iXML = 0; iXML < xmlPaths.size(); ++iXML )
1035 bool error = xmlParser.parse( xmlPaths[iXML].c_str() );
1038 TCollection_AsciiString data;
1039 INFOS( xmlParser.GetError(data) );
1042 // <algorithm type="Regular_1D"
1045 // output="QUAD,TRIA">
1047 LDOM_Document xmlDoc = xmlParser.getDocument();
1048 LDOM_NodeList algoNodeList = xmlDoc.getElementsByTagName( "algorithm" );
1049 for ( int i = 0; i < algoNodeList.getLength(); ++i )
1051 LDOM_Node algoNode = algoNodeList.item( i );
1052 LDOM_Element& algoElem = (LDOM_Element&) algoNode;
1053 TCollection_AsciiString algoType = algoElem.getAttribute("type");
1054 TCollection_AsciiString input = algoElem.getAttribute("input");
1055 TCollection_AsciiString output = algoElem.getAttribute("output");
1056 TCollection_AsciiString dim = algoElem.getAttribute("dim");
1057 if ( algoType.IsEmpty() ) continue;
1058 AlgoData & data = theDataByName[ algoType.ToCString() ];
1059 data._dim = dim.IntegerValue();
1060 for ( int isInput = 0; isInput < 2; ++isInput )
1062 TCollection_AsciiString& typeStr = isInput ? input : output;
1063 set<SMDSAbs_GeometryType>& typeSet = isInput ? data._inElemTypes : data._outElemTypes;
1065 while ( beg <= typeStr.Length() )
1067 while ( beg < typeStr.Length() && !isalpha( typeStr.Value( beg ) ))
1070 while ( end < typeStr.Length() && isalpha( typeStr.Value( end + 1 ) ))
1074 TCollection_AsciiString typeName = typeStr.SubString( beg, end );
1075 if ( typeName == "EDGE" ) typeSet.insert( SMDSGeom_EDGE );
1076 else if ( typeName == "TRIA" ) typeSet.insert( SMDSGeom_TRIANGLE );
1077 else if ( typeName == "QUAD" ) typeSet.insert( SMDSGeom_QUADRANGLE );
1085 return theDataByName[ algo->GetName() ];
1089 //=============================================================================
1091 * Finds algo to mesh a shape. Optionally returns a shape the found algo is bound to
1093 //=============================================================================
1095 SMESH_Algo *SMESH_Gen::GetAlgo(SMESH_Mesh & aMesh,
1096 const TopoDS_Shape & aShape,
1097 TopoDS_Shape* assignedTo)
1099 SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
1100 filter.And( filter.IsApplicableTo( aShape ));
1102 TopoDS_Shape assignedToShape;
1104 (SMESH_Algo*) aMesh.GetHypothesis( aShape, filter, true, &assignedToShape );
1107 aShape.ShapeType() == TopAbs_FACE &&
1108 !aShape.IsSame( assignedToShape ) &&
1109 SMESH_MesherHelper::NbAncestors( aShape, aMesh, TopAbs_SOLID ) > 1 )
1111 // Issue 0021559. If there is another 2D algo with different types of output
1112 // elements that can be used to mesh aShape, and 3D algos on adjacent SOLIDs
1113 // have different types of input elements, we choose a most appropriate 2D algo.
1115 // try to find a concurrent 2D algo
1116 filter.AndNot( filter.Is( algo ));
1117 TopoDS_Shape assignedToShape2;
1119 (SMESH_Algo*) aMesh.GetHypothesis( aShape, filter, true, &assignedToShape2 );
1120 if ( algo2 && // algo found
1121 !assignedToShape2.IsSame( aMesh.GetShapeToMesh() ) && // algo is local
1122 ( SMESH_MesherHelper::GetGroupType( assignedToShape2 ) == // algo of the same level
1123 SMESH_MesherHelper::GetGroupType( assignedToShape )) &&
1124 aMesh.IsOrderOK( aMesh.GetSubMesh( assignedToShape2 ), // no forced order
1125 aMesh.GetSubMesh( assignedToShape )))
1127 // get algos on the adjacent SOLIDs
1128 filter.Init( filter.IsAlgo() ).And( filter.HasDim( 3 ));
1129 vector< SMESH_Algo* > algos3D;
1130 PShapeIteratorPtr solidIt = SMESH_MesherHelper::GetAncestors( aShape, aMesh,
1132 while ( const TopoDS_Shape* solid = solidIt->next() )
1133 if ( SMESH_Algo* algo3D = (SMESH_Algo*) aMesh.GetHypothesis( *solid, filter, true ))
1135 algos3D.push_back( algo3D );
1136 filter.AndNot( filter.HasName( algo3D->GetName() ));
1138 // check compatibility of algos
1139 if ( algos3D.size() > 1 )
1141 const AlgoData& algoData = getAlgoData( algo );
1142 const AlgoData& algoData2 = getAlgoData( algo2 );
1143 const AlgoData& algoData3d0 = getAlgoData( algos3D[0] );
1144 const AlgoData& algoData3d1 = getAlgoData( algos3D[1] );
1145 if (( algoData2.IsCompatible( algoData3d0 ) &&
1146 algoData2.IsCompatible( algoData3d1 ))
1148 !(algoData.IsCompatible( algoData3d0 ) &&
1149 algoData.IsCompatible( algoData3d1 )))
1155 if ( assignedTo && algo )
1156 * assignedTo = assignedToShape;
1161 //=============================================================================
1163 * Returns StudyContextStruct for a study
1165 //=============================================================================
1167 StudyContextStruct *SMESH_Gen::GetStudyContext(int studyId)
1169 // Get studyContext, create it if it does'nt exist, with a SMESHDS_Document
1171 if (_mapStudyContext.find(studyId) == _mapStudyContext.end())
1173 _mapStudyContext[studyId] = new StudyContextStruct;
1174 _mapStudyContext[studyId]->myDocument = new SMESHDS_Document(studyId);
1176 StudyContextStruct *myStudyContext = _mapStudyContext[studyId];
1177 return myStudyContext;
1180 //================================================================================
1182 * \brief Return shape dimension by TopAbs_ShapeEnum
1184 //================================================================================
1186 int SMESH_Gen::GetShapeDim(const TopAbs_ShapeEnum & aShapeType)
1188 static vector<int> dim;
1191 dim.resize( TopAbs_SHAPE, -1 );
1192 dim[ TopAbs_COMPOUND ] = MeshDim_3D;
1193 dim[ TopAbs_COMPSOLID ] = MeshDim_3D;
1194 dim[ TopAbs_SOLID ] = MeshDim_3D;
1195 dim[ TopAbs_SHELL ] = MeshDim_2D;
1196 dim[ TopAbs_FACE ] = MeshDim_2D;
1197 dim[ TopAbs_WIRE ] = MeshDim_1D;
1198 dim[ TopAbs_EDGE ] = MeshDim_1D;
1199 dim[ TopAbs_VERTEX ] = MeshDim_0D;
1201 return dim[ aShapeType ];
1204 //=============================================================================
1206 * Genarate a new id unique withing this Gen
1208 //=============================================================================
1210 int SMESH_Gen::GetANewId()