From 61a244479959ec4382f2358818f829a45af8e4fb Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 30 Aug 2017 19:38:26 +0300 Subject: [PATCH] Implement MakePolyLine() for ASERIS module Modified sources = master(223c5b7) + new development. --- idl/SMESH_MeshEditor.idl | 46 +- src/SMDS/ObjectPool.hxx | 116 ++- src/SMESH/SMESH_MeshEditor.cxx | 1525 +++++++++++++++++++--------- src/SMESH/SMESH_MeshEditor.hxx | 76 +- src/SMESHGUI/SMESHGUI_MergeDlg.cxx | 10 +- src/SMESHGUI/SMESHGUI_MergeDlg.h | 1 + src/SMESHUtils/SMESH_MeshAlgos.cxx | 506 ++++++--- src/SMESHUtils/SMESH_MeshAlgos.hxx | 29 +- src/SMESHUtils/SMESH_TryCatch.cxx | 6 + src/SMESHUtils/SMESH_TryCatch.hxx | 1 + src/SMESHUtils/SMESH_TypeDefs.hxx | 1 + src/SMESH_I/SMESH_MeshEditor_i.cxx | 151 ++- src/SMESH_I/SMESH_MeshEditor_i.hxx | 30 +- src/SMESH_SWIG/smeshBuilder.py | 909 ++++++++++------- 14 files changed, 2308 insertions(+), 1099 deletions(-) diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 7cbe67bff..199f1bbc1 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -57,6 +57,24 @@ module SMESH }; + // structure used in MakePolyLine() to define a cutting plane + struct PolySegment + { + // point 1: if node1ID2 > 0, then the point is in the middle of a face edge defined + // by two nodes, else it is at node1ID1 + long node1ID1; + long node1ID2; + + // point 2: if node2ID2 > 0, then the point is in the middle of a face edge defined + // by two nodes, else it is at node2ID1 + long node2ID1; + long node2ID2; + + DirStruct vector; // vector on the plane; to use a default plane set vector = (0,0,0) + }; + typedef sequence ListOfPolySegments; + + /*! * This interface makes modifications on the Mesh - removing elements and nodes etc. */ @@ -93,7 +111,7 @@ module SMESH void ClearLastCreated() raises (SALOME::SALOME_Exception); /*! - * \brief Returns description of an error/warning occured during the last operation + * \brief Returns description of an error/warning occurred during the last operation */ ComputeError GetLastError() raises (SALOME::SALOME_Exception); @@ -689,7 +707,8 @@ module SMESH raises (SALOME::SALOME_Exception); void MergeNodes (in array_of_long_array GroupsOfNodes, - in SMESH::ListOfIDSources NodesToKeep) + in SMESH::ListOfIDSources NodesToKeep, + in boolean AvoidMakingHoles) raises (SALOME::SALOME_Exception); /*! @@ -1183,7 +1202,28 @@ module SMESH in GEOM::GEOM_Object theShape, in string groupName, in double_array theNodesCoords, - out array_of_long_array GroupsOfNodes) + out array_of_long_array GroupsOfNodes) + raises (SALOME::SALOME_Exception); + + + /*! + * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of + * the initial mesh. Positions of new nodes are found by cutting the mesh by the + * plane passing through pairs of points specified by each PolySegment structure. + * If there are several paths connecting a pair of points, the shortest path is + * selected by the module. Position of the cutting plane is defined by the two + * points and an optional vector lying on the plane specified by a PolySegment. + * By default the vector is defined by Mesh module as following. A middle point + * of the two given points is computed. The middle point is projected to the mesh. + * The vector goes from the middle point to the projection point. In case of planar + * mesh, the vector is normal to the mesh. + * \param [inout] segments - PolySegment's defining positions of cutting planes. + * Return the used vector which goes from the middle point to its projection. + * \param [in] groupName - optional name of a group where created mesh segments will + * be added. + */ + void MakePolyLine(inout ListOfPolySegments segments, + in string groupName) raises (SALOME::SALOME_Exception); }; }; diff --git a/src/SMDS/ObjectPool.hxx b/src/SMDS/ObjectPool.hxx index 5e5f0d289..ef514b353 100644 --- a/src/SMDS/ObjectPool.hxx +++ b/src/SMDS/ObjectPool.hxx @@ -21,9 +21,10 @@ #define _OBJECTPOOL_HXX_ #include -//#include #include +#include "SMDS_Iterator.hxx" + namespace { // assure deallocation of memory of a vector @@ -33,18 +34,22 @@ namespace } } +template class ObjectPoolIterator; + template class ObjectPool { private: - std::vector _chunkList; + std::vector _chunkList; std::vector _freeList; - int _nextFree; - int _maxAvail; - int _chunkSize; - int _maxOccupied; - int _nbHoles; - int _lastDelChunk; + int _nextFree; // either the 1st hole or last added + int _maxAvail; // nb allocated elements + int _chunkSize; + int _maxOccupied; // max used ID + int _nbHoles; + int _lastDelChunk; + + friend class ObjectPoolIterator; int getNextFree() { @@ -76,16 +81,16 @@ private: } public: - ObjectPool(int nblk) + ObjectPool(int nblk = 1024) { - _chunkSize = nblk; - _nextFree = 0; - _maxAvail = 0; - _maxOccupied = 0; - _nbHoles = 0; + _chunkSize = nblk; + _nextFree = 0; + _maxAvail = 0; + _maxOccupied = -1; + _nbHoles = 0; + _lastDelChunk = 0; _chunkList.clear(); _freeList.clear(); - _lastDelChunk = 0; } virtual ~ObjectPool() @@ -105,16 +110,16 @@ public: _freeList.insert(_freeList.end(), _chunkSize, true); _maxAvail += _chunkSize; _freeList[_nextFree] = false; - obj = newChunk; // &newChunk[0]; + obj = newChunk; } else { int chunkId = _nextFree / _chunkSize; int rank = _nextFree - chunkId * _chunkSize; _freeList[_nextFree] = false; - obj = _chunkList[chunkId] + rank; // &_chunkList[chunkId][rank]; + obj = _chunkList[chunkId] + rank; } - if (_nextFree < _maxOccupied) + if (_nextFree <= _maxOccupied) { _nbHoles-=1; } @@ -122,7 +127,6 @@ public: { _maxOccupied = _nextFree; } - //obj->init(); return obj; } @@ -148,10 +152,10 @@ public: if (toFree < _nextFree) _nextFree = toFree; if (toFree < _maxOccupied) - _nbHoles += 1; + ++_nbHoles; + else + --_maxOccupied; _lastDelChunk = i; - //obj->clean(); - //checkDelete(i); compactage non fait } void clear() @@ -167,6 +171,37 @@ public: clearVector( _freeList ); } + // nb allocated elements + size_t size() const + { + return _freeList.size(); + } + + // nb used elements + size_t nbElements() const + { + return _maxOccupied + 1 - _nbHoles; + } + + // return an element w/o any check + const X* operator[]( size_t i ) const // i < size() + { + int chunkId = i / _chunkSize; + int rank = i - chunkId * _chunkSize; + return _chunkList[ chunkId ] + rank; + } + + // return only being used element + const X* at( size_t i ) const // i < size() + { + if ( i >= size() || _freeList[ i ] ) + return 0; + + int chunkId = i / _chunkSize; + int rank = i - chunkId * _chunkSize; + return _chunkList[ chunkId ] + rank; + } + // void destroy(int toFree) // { // // no control 0<= toFree < _freeList.size() @@ -177,4 +212,41 @@ public: }; +template class ObjectPoolIterator : public SMDS_Iterator +{ + const ObjectPool& _pool; + int _i, _nbFound; +public: + + ObjectPoolIterator( const ObjectPool& pool ) : _pool( pool ), _i( 0 ), _nbFound( 0 ) + { + if ( more() && _pool._freeList[ _i ] == true ) + { + next(); + --_nbFound; + } + } + + virtual bool more() + { + return ( _i <= _pool._maxOccupied && _nbFound < (int)_pool.nbElements() ); + } + + virtual const X* next() + { + const X* x = 0; + if ( more() ) + { + x = _pool[ _i ]; + + ++_nbFound; + + for ( ++_i; _i <= _pool._maxOccupied; ++_i ) + if ( _pool._freeList[ _i ] == false ) + break; + } + return x; + } +}; + #endif diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 056da7050..7b7c1a40e 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -98,6 +98,9 @@ #include #include +#include + +#include "SMESH_TryCatch.hxx" // include after OCCT headers! #define cast2Node(elem) static_cast( elem ) @@ -1168,7 +1171,7 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) * \brief Reorient faces. * \param theFaces - the faces to reorient. If empty the whole mesh is meant * \param theDirection - desired direction of normal of \a theFace - * \param theFace - one of \a theFaces that sould be oriented according to + * \param theFace - one of \a theFaces that should be oriented according to * \a theDirection and whose orientation defines orientation of other faces * \return number of reoriented faces. */ @@ -2398,7 +2401,7 @@ void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems, } else { - // among possible triangles create ones discribed by split method + // among possible triangles create ones described by split method const int* nInd = volTool.GetFaceNodesIndices( iF ); int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); int iCom = 0; // common node of triangle faces to split into @@ -2524,7 +2527,7 @@ void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas, // Fill theFacets starting from facetID of startHex - // facets used for seach of volumes adjacent to already treated ones + // facets used for searching of volumes adjacent to already treated ones typedef pair< TFacetOfElem::iterator, int > TElemFacets; typedef map< TVolumeFaceKey, TElemFacets > TFacetMap; TFacetMap facetsToCheck; @@ -4342,18 +4345,18 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, } } if ( maxRatio <= theTgtAspectRatio ) { - MESSAGE("-- quality achived --"); + //MESSAGE("-- quality achieved --"); break; } if (it+1 == theNbIterations) { - MESSAGE("-- Iteration limit exceeded --"); + //MESSAGE("-- Iteration limit exceeded --"); } } // smoothing iterations - MESSAGE(" Face id: " << *fId << - " Nb iterstions: " << it << - " Displacement: " << maxDisplacement << - " Aspect Ratio " << maxRatio); + // MESSAGE(" Face id: " << *fId << + // " Nb iterstions: " << it << + // " Displacement: " << maxDisplacement << + // " Aspect Ratio " << maxRatio); // --------------------------------------- // new nodes positions are computed, @@ -4568,7 +4571,11 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, std::swap( itNN[0], itNN[1] ); std::swap( prevNod[0], prevNod[1] ); std::swap( nextNod[0], nextNod[1] ); +#if defined(__APPLE__) + std::swap( isSingleNode[0], isSingleNode[1] ); +#else isSingleNode.swap( isSingleNode[0], isSingleNode[1] ); +#endif if ( nbSame > 0 ) sames[0] = 1 - sames[0]; iNotSameNode = 1 - iNotSameNode; @@ -6091,7 +6098,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], aPrms.push_back( aT ); } //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); } else if( aS.ShapeType() == TopAbs_WIRE ) { list< SMESH_subMesh* > LSM; TopTools_SequenceOfShape Edges; @@ -6136,7 +6143,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], } list LPP; //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); + makeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); LLPPs.push_back(LPP); UsedNums.Add(k); // update startN for search following egde @@ -6179,7 +6186,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], return EXTR_BAD_PATH_SHAPE; } - return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, theHasRefPoint, theRefPoint, theMakeGroups); } @@ -6318,7 +6325,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], TopoDS_Edge e = BRepBuilderAPI_MakeEdge( p1, p2 ); list LPP; aPrms.clear(); - MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); + makeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); LLPPs.push_back(LPP); if ( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i ]->GetID(); else startNid = aNodesList[i-1]->GetID(); @@ -6376,7 +6383,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], aPrms.push_back( aT ); } //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + makeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); } else if( aS.ShapeType() == TopAbs_WIRE ) { list< SMESH_subMesh* > LSM; @@ -6435,7 +6442,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], } list LPP; //Extrusion_Error err = - MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP); + makeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP); LLPPs.push_back(LPP); UsedNums.Add(k); // update startN for search following egde @@ -6471,17 +6478,17 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2], return EXTR_BAD_PATH_SHAPE; } - return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + return makeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, theHasRefPoint, theRefPoint, theMakeGroups); } //======================================================================= -//function : MakeEdgePathPoints -//purpose : auxilary for ExtrusionAlongTrack +//function : makeEdgePathPoints +//purpose : auxiliary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, +SMESH_MeshEditor::makeEdgePathPoints(std::list& aPrms, const TopoDS_Edge& aTrackEdge, bool FirstIsStart, list& LPP) @@ -6532,11 +6539,11 @@ SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, //======================================================================= -//function : MakeExtrElements -//purpose : auxilary for ExtrusionAlongTrack +//function : makeExtrElements +//purpose : auxiliary for ExtrusionAlongTrack //======================================================================= SMESH_MeshEditor::Extrusion_Error -SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets[2], +SMESH_MeshEditor::makeExtrElements(TIDSortedElemSet theElemSets[2], list& fullList, const bool theHasAngles, list& theAngles, @@ -6549,7 +6556,7 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets // Angles if( theHasAngles && !theAngles.empty() && theLinearVariation ) - LinearAngleVariation(aNbTP-1, theAngles); + linearAngleVariation(aNbTP-1, theAngles); // fill vector of path points with angles vector aPPs; @@ -6742,11 +6749,11 @@ SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet theElemSets //======================================================================= -//function : LinearAngleVariation +//function : linearAngleVariation //purpose : spread values over nbSteps //======================================================================= -void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, +void SMESH_MeshEditor::linearAngleVariation(const int nbSteps, list& Angles) { int nbAngles = Angles.size(); @@ -7254,7 +7261,7 @@ void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes, } else while ( nIt->more() ) - theNodes.insert( theNodes.end(),nIt->next() ); + theNodes.insert( theNodes.end(), nIt->next() ); } else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes { @@ -7341,16 +7348,18 @@ int SMESH_MeshEditor::SimplifyFace (const vector& faceNod // in all elements. //======================================================================= -void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) +void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes, + const bool theAvoidMakingHoles) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - SMESHDS_Mesh* aMesh = GetMeshDS(); + SMESHDS_Mesh* mesh = GetMeshDS(); TNodeNodeMap nodeNodeMap; // node to replace - new node set elems; // all elements with changed nodes list< int > rmElemIds, rmNodeIds; + vector< ElemFeatures > newElemDefs; // Fill nodeNodeMap and elems @@ -7364,17 +7373,6 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) { const SMDS_MeshNode* nToRemove = *nIt; nodeNodeMap.insert( make_pair( nToRemove, nToKeep )); - if ( nToRemove != nToKeep ) - { - rmNodeIds.push_back( nToRemove->GetID() ); - AddToSameGroups( nToKeep, nToRemove, aMesh ); - // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing - // after MergeNodes() w/o creating node in place of merged ones. - const SMDS_PositionPtr& pos = nToRemove->GetPosition(); - if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) - if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() )) - sm->SetIsAlwaysComputed( true ); - } SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); while ( invElemIt->more() ) { const SMDS_MeshElement* elem = invElemIt->next(); @@ -7382,469 +7380,568 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } } } - // Change element nodes or remove an element - set nodeSet; - vector< const SMDS_MeshNode*> curNodes, uniqueNodes; - vector iRepl; - ElemFeatures elemType; + // Apply recursive replacements (BUG 0020185) + TNodeNodeMap::iterator nnIt = nodeNodeMap.begin(); + for ( ; nnIt != nodeNodeMap.end(); ++nnIt ) + { + const SMDS_MeshNode* nToKeep = nnIt->second; + TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( nToKeep ); + while ( nnIt_i != nodeNodeMap.end() && nnIt_i->second != nnIt->second ) + nToKeep = nnIt_i->second; + nnIt->second = nToKeep; + } + + if ( theAvoidMakingHoles ) + { + // find elements whose topology changes + + vector pbElems; + set::iterator eIt = elems.begin(); + for ( ; eIt != elems.end(); ++eIt ) + { + const SMDS_MeshElement* elem = *eIt; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); + TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); + if ( nnIt != nodeNodeMap.end() && elem->GetNodeIndex( nnIt->second ) >= 0 ) + { + // several nodes of elem stick + pbElems.push_back( elem ); + break; + } + } + } + // exclude from merge nodes causing spoiling element + for ( size_t iLoop = 0; iLoop < pbElems.size(); ++iLoop ) // avoid infinite cycle + { + bool nodesExcluded = false; + for ( size_t i = 0; i < pbElems.size(); ++i ) + { + size_t prevNbMergeNodes = nodeNodeMap.size(); + if ( !applyMerge( pbElems[i], newElemDefs, nodeNodeMap, /*noHoles=*/true ) && + prevNbMergeNodes < nodeNodeMap.size() ) + nodesExcluded = true; + } + if ( !nodesExcluded ) + break; + } + } + + for ( nnIt = nodeNodeMap.begin(); nnIt != nodeNodeMap.end(); ++nnIt ) + { + const SMDS_MeshNode* nToRemove = nnIt->first; + const SMDS_MeshNode* nToKeep = nnIt->second; + if ( nToRemove != nToKeep ) + { + rmNodeIds.push_back( nToRemove->GetID() ); + AddToSameGroups( nToKeep, nToRemove, mesh ); + // set _alwaysComputed to a sub-mesh of VERTEX to enable further mesh computing + // w/o creating node in place of merged ones. + const SMDS_PositionPtr& pos = nToRemove->GetPosition(); + if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX ) + if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() )) + sm->SetIsAlwaysComputed( true ); + } + } + + // Change element nodes or remove an element set::iterator eIt = elems.begin(); for ( ; eIt != elems.end(); eIt++ ) { const SMDS_MeshElement* elem = *eIt; - const int nbNodes = elem->NbNodes(); - const int aShapeId = FindShape( elem ); - SMDSAbs_EntityType entity = elem->GetEntityType(); + SMESHDS_SubMesh* sm = mesh->MeshElements( elem->getshapeId() ); - nodeSet.clear(); - curNodes.resize( nbNodes ); - uniqueNodes.resize( nbNodes ); - iRepl.resize( nbNodes ); - int iUnique = 0, iCur = 0, nbRepl = 0; + bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false ); + if ( !keepElem ) + rmElemIds.push_back( elem->GetID() ); - // get new seq of nodes - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - const SMDS_MeshNode* n = static_cast( itN->next() ); - - TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); - if ( nnIt != nodeNodeMap.end() ) { // n sticks - n = (*nnIt).second; - { ////////// BUG 0020185: begin - bool stopRecur = false; - set nodesRecur; - nodesRecur.insert(n); - while (!stopRecur) { - TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n ); - if ( nnIt_i != nodeNodeMap.end() ) { // n sticks - n = (*nnIt_i).second; - if (!nodesRecur.insert(n).second) { - // error: recursive dependency - stopRecur = true; - } - } - else - stopRecur = true; - } - } ////////// BUG 0020185: end + for ( size_t i = 0; i < newElemDefs.size(); ++i ) + { + if ( i > 0 || !mesh->ChangeElementNodes( elem, + & newElemDefs[i].myNodes[0], + newElemDefs[i].myNodes.size() )) + { + if ( i == 0 ) + { + newElemDefs[i].SetID( elem->GetID() ); + mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); + if ( !keepElem ) rmElemIds.pop_back(); + } + else + { + newElemDefs[i].SetID( -1 ); + } + SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] ); + if ( sm && newElem ) + sm->AddElement( newElem ); + if ( elem != newElem ) + ReplaceElemInGroups( elem, newElem, mesh ); } - curNodes[ iCur ] = n; - bool isUnique = nodeSet.insert( n ).second; - if ( isUnique ) - uniqueNodes[ iUnique++ ] = n; - else - iRepl[ nbRepl++ ] = iCur; - iCur++; } + } + + // Remove bad elements, then equal nodes (order important) + Remove( rmElemIds, /*isNodes=*/false ); + Remove( rmNodeIds, /*isNodes=*/true ); + + return; +} + +//======================================================================= +//function : applyMerge +//purpose : Compute new connectivity of an element after merging nodes +// \param [in] elems - the element +// \param [out] newElemDefs - definition(s) of result element(s) +// \param [inout] nodeNodeMap - nodes to merge +// \param [in] avoidMakingHoles - if true and and the element becomes invalid +// after merging (but not degenerated), removes nodes causing +// the invalidity from \a nodeNodeMap. +// \return bool - true if the element should be removed +//======================================================================= + +bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem, + vector< ElemFeatures >& newElemDefs, + TNodeNodeMap& nodeNodeMap, + const bool avoidMakingHoles ) +{ + bool toRemove = false; // to remove elem + int nbResElems = 1; // nb new elements + + newElemDefs.resize(nbResElems); + newElemDefs[0].Init( elem ); + newElemDefs[0].myNodes.clear(); + + set nodeSet; + vector< const SMDS_MeshNode*> curNodes; + vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes; + vector iRepl; + + const int nbNodes = elem->NbNodes(); + SMDSAbs_EntityType entity = elem->GetEntityType(); + + curNodes.resize( nbNodes ); + uniqueNodes.resize( nbNodes ); + iRepl.resize( nbNodes ); + int iUnique = 0, iCur = 0, nbRepl = 0; - // Analyse element topology after replacement + // Get new seq of nodes + + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) + { + const SMDS_MeshNode* n = static_cast( itN->next() ); + + TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n ); + if ( nnIt != nodeNodeMap.end() ) { + n = (*nnIt).second; + } + curNodes[ iCur ] = n; + bool isUnique = nodeSet.insert( n ).second; + if ( isUnique ) + uniqueNodes[ iUnique++ ] = n; + else + iRepl[ nbRepl++ ] = iCur; + iCur++; + } - bool isOk = true; - int nbUniqueNodes = nodeSet.size(); - if ( nbNodes != nbUniqueNodes ) // some nodes stick + // Analyse element topology after replacement + + int nbUniqueNodes = nodeSet.size(); + if ( nbNodes != nbUniqueNodes ) // some nodes stick + { + toRemove = true; + nbResElems = 0; + + if ( newElemDefs[0].myIsQuad && newElemDefs[0].myType == SMDSAbs_Face && nbNodes > 6 ) { - if ( elem->IsPoly() ) // Polygons and Polyhedral volumes + // if corner nodes stick, remove medium nodes between them from uniqueNodes + int nbCorners = nbNodes / 2; + for ( int iCur = 0; iCur < nbCorners; ++iCur ) { - if ( elem->GetType() == SMDSAbs_Face ) // Polygon + int iNext = ( iCur + 1 ) % nbCorners; + if ( curNodes[ iCur ] == curNodes[ iNext ] ) // corners stick { - elemType.Init( elem ); - const bool isQuad = elemType.myIsQuad; - if ( isQuad ) - SMDS_MeshCell::applyInterlace // interlace medium and corner nodes - ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes ); - - // a polygon can divide into several elements - vector polygons_nodes; - vector quantities; - int nbNew = SimplifyFace( curNodes, polygons_nodes, quantities ); - if (nbNew > 0) + int iMedium = iCur + nbCorners; + vector< const SMDS_MeshNode* >::iterator i = + std::find( uniqueNodes.begin() + nbCorners - nbRepl, + uniqueNodes.end(), + curNodes[ iMedium ]); + if ( i != uniqueNodes.end() ) { - vector face_nodes; - int inode = 0; - for (int iface = 0; iface < nbNew; iface++) - { - int nbNewNodes = quantities[iface]; - face_nodes.assign( polygons_nodes.begin() + inode, - polygons_nodes.begin() + inode + nbNewNodes ); - inode += nbNewNodes; - if ( isQuad ) // check if a result elem is a valid quadratic polygon - { - bool isValid = ( nbNewNodes % 2 == 0 ); - for ( int i = 0; i < nbNewNodes && isValid; ++i ) - isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 )); - elemType.SetQuad( isValid ); - if ( isValid ) // put medium nodes after corners - SMDS_MeshCell::applyInterlaceRev - ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, - nbNewNodes ), face_nodes ); - } - elemType.SetPoly(( nbNewNodes / ( elemType.myIsQuad + 1 ) > 4 )); - - SMDS_MeshElement* newElem = AddElement( face_nodes, elemType.SetID(-1)); - if ( aShapeId ) - aMesh->SetMeshElementOnShape(newElem, aShapeId); - } + --nbUniqueNodes; + for ( ; i+1 != uniqueNodes.end(); ++i ) + *i = *(i+1); } - rmElemIds.push_back(elem->GetID()); + } + } + } - } // Polygon + switch ( entity ) + { + case SMDSEntity_Polygon: + case SMDSEntity_Quad_Polygon: // Polygon + { + ElemFeatures* elemType = & newElemDefs[0]; + const bool isQuad = elemType->myIsQuad; + if ( isQuad ) + SMDS_MeshCell::applyInterlace // interlace medium and corner nodes + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes ); - else if ( elem->GetType() == SMDSAbs_Volume ) // Polyhedral volume - { - if ( nbUniqueNodes < 4 ) { - rmElemIds.push_back(elem->GetID()); - } - else { - // each face has to be analyzed in order to check volume validity - const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem ); - if ( aPolyedre ) - { - int nbFaces = aPolyedre->NbFaces(); + // a polygon can divide into several elements + vector polygons_nodes; + vector quantities; + nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities ); + newElemDefs.resize( nbResElems ); + for ( int inode = 0, iface = 0; iface < nbResElems; iface++ ) + { + ElemFeatures* elemType = & newElemDefs[iface]; + if ( iface ) elemType->Init( elem ); - vector poly_nodes; - vector quantities; - vector faceNodes; + vector& face_nodes = elemType->myNodes; + int nbNewNodes = quantities[iface]; + face_nodes.assign( polygons_nodes.begin() + inode, + polygons_nodes.begin() + inode + nbNewNodes ); + inode += nbNewNodes; + if ( isQuad ) // check if a result elem is a valid quadratic polygon + { + bool isValid = ( nbNewNodes % 2 == 0 ); + for ( int i = 0; i < nbNewNodes && isValid; ++i ) + isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 )); + elemType->SetQuad( isValid ); + if ( isValid ) // put medium nodes after corners + SMDS_MeshCell::applyInterlaceRev + ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, + nbNewNodes ), face_nodes ); + } + elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 )); + } + nbUniqueNodes = newElemDefs[0].myNodes.size(); + break; + } // Polygon - for (int iface = 1; iface <= nbFaces; iface++) - { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - faceNodes.resize( nbFaceNodes ); - for (int inode = 1; inode <= nbFaceNodes; inode++) - { - const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); - if ( nnIt != nodeNodeMap.end() ) // faceNode sticks - faceNode = (*nnIt).second; - faceNodes[inode - 1] = faceNode; - } - SimplifyFace(faceNodes, poly_nodes, quantities); - } + case SMDSEntity_Polyhedra: // Polyhedral volume + { + if ( nbUniqueNodes >= 4 ) + { + // each face has to be analyzed in order to check volume validity + if ( const SMDS_VtkVolume* aPolyedre = dynamic_cast( elem )) + { + int nbFaces = aPolyedre->NbFaces(); - if ( quantities.size() > 3 ) { - // TODO: remove coincident faces - } + vector& poly_nodes = newElemDefs[0].myNodes; + vector & quantities = newElemDefs[0].myPolyhedQuantities; + vector faceNodes; + poly_nodes.clear(); + quantities.clear(); - if ( quantities.size() > 3 ) - { - const SMDS_MeshElement* newElem = - aMesh->AddPolyhedralVolume( poly_nodes, quantities ); - myLastCreatedElems.Append( newElem ); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - rmElemIds.push_back( elem->GetID() ); - } - } - else { - rmElemIds.push_back( elem->GetID() ); + for (int iface = 1; iface <= nbFaces; iface++) + { + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + faceNodes.resize( nbFaceNodes ); + for (int inode = 1; inode <= nbFaceNodes; inode++) + { + const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); + TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); + if ( nnIt != nodeNodeMap.end() ) // faceNode sticks + faceNode = (*nnIt).second; + faceNodes[inode - 1] = faceNode; } + SimplifyFace(faceNodes, poly_nodes, quantities); } - } - else { - } - - continue; - } // poly element - // Regular elements - // TODO not all the possible cases are solved. Find something more generic? - switch ( entity ) { - case SMDSEntity_Edge: //////// EDGE - case SMDSEntity_Triangle: //// TRIANGLE - case SMDSEntity_Quad_Triangle: - case SMDSEntity_Tetra: - case SMDSEntity_Quad_Tetra: // TETRAHEDRON - { - isOk = false; - break; + if ( quantities.size() > 3 ) + { + // TODO: remove coincident faces + nbResElems = 1; + nbUniqueNodes = newElemDefs[0].myNodes.size(); + } + } } - case SMDSEntity_Quad_Edge: + } + break; + + // Regular elements + // TODO not all the possible cases are solved. Find something more generic? + case SMDSEntity_Edge: //////// EDGE + case SMDSEntity_Triangle: //// TRIANGLE + case SMDSEntity_Quad_Triangle: + case SMDSEntity_Tetra: + case SMDSEntity_Quad_Tetra: // TETRAHEDRON + { + break; + } + case SMDSEntity_Quad_Edge: + { + break; + } + case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE + { + if ( nbUniqueNodes < 3 ) + toRemove = true; + else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ]) + toRemove = true; // opposite nodes stick + else + toRemove = false; + break; + } + case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE + { + // 1 5 2 + // +---+---+ + // | | + // 4+ +6 + // | | + // +---+---+ + // 0 7 3 + if ( nbUniqueNodes == 6 && + iRepl[0] < 4 && + ( nbRepl == 1 || iRepl[1] >= 4 )) { - isOk = false; // to linear EDGE ??????? - break; + toRemove = false; } - case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE + break; + } + case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE + { + // 1 5 2 + // +---+---+ + // | | + // 4+ 8+ +6 + // | | + // +---+---+ + // 0 7 3 + if ( nbUniqueNodes == 7 && + iRepl[0] < 4 && + ( nbRepl == 1 || iRepl[1] != 8 )) { - if ( nbUniqueNodes < 3 ) - isOk = false; - else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ]) - isOk = false; // opposite nodes stick - break; + toRemove = false; } - case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE - { - // 1 5 2 - // +---+---+ - // | | - // 4+ +6 - // | | - // +---+---+ - // 0 7 3 - if (( nbUniqueNodes == 6 && nbRepl == 2 ) && - (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) || - ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) || - ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) || - ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] ))) + break; + } + case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON + { + if ( nbUniqueNodes == 4 ) { + // ---------------------------------> tetrahedron + if ( curNodes[3] == curNodes[4] && + curNodes[3] == curNodes[5] ) { + // top nodes stick + toRemove = false; + } + else if ( curNodes[0] == curNodes[1] && + curNodes[0] == curNodes[2] ) { + // bottom nodes stick: set a top before + uniqueNodes[ 3 ] = uniqueNodes [ 0 ]; + uniqueNodes[ 0 ] = curNodes [ 5 ]; + uniqueNodes[ 1 ] = curNodes [ 4 ]; + uniqueNodes[ 2 ] = curNodes [ 3 ]; + toRemove = false; + } + else if (( curNodes[0] == curNodes[3] ) + + ( curNodes[1] == curNodes[4] ) + + ( curNodes[2] == curNodes[5] ) == 2 ) { + // a lateral face turns into a line + toRemove = false; + } + } + else if ( nbUniqueNodes == 5 ) { + // PENTAHEDRON --------------------> pyramid + if ( curNodes[0] == curNodes[3] ) { - isOk = true; - } - break; - } - case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE - { - // 1 5 2 - // +---+---+ - // | | - // 4+ 8+ +6 - // | | - // +---+---+ - // 0 7 3 - if (( nbUniqueNodes == 7 && nbRepl == 2 && iRepl[1] != 8 ) && - (( iRepl[0] == 1 && iRepl[1] == 4 && curNodes[1] == curNodes[0] ) || - ( iRepl[0] == 2 && iRepl[1] == 5 && curNodes[2] == curNodes[1] ) || - ( iRepl[0] == 3 && iRepl[1] == 6 && curNodes[3] == curNodes[2] ) || - ( iRepl[0] == 3 && iRepl[1] == 7 && curNodes[3] == curNodes[0] ))) + uniqueNodes[ 0 ] = curNodes[ 1 ]; + uniqueNodes[ 1 ] = curNodes[ 4 ]; + uniqueNodes[ 2 ] = curNodes[ 5 ]; + uniqueNodes[ 3 ] = curNodes[ 2 ]; + uniqueNodes[ 4 ] = curNodes[ 0 ]; + toRemove = false; + } + if ( curNodes[1] == curNodes[4] ) { - isOk = true; - } - break; - } - case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON - { - isOk = false; - if ( nbUniqueNodes == 4 ) { - // ---------------------------------> tetrahedron - if ( curNodes[3] == curNodes[4] && - curNodes[3] == curNodes[5] ) { - // top nodes stick - isOk = true; - } - else if ( curNodes[0] == curNodes[1] && - curNodes[0] == curNodes[2] ) { - // bottom nodes stick: set a top before - uniqueNodes[ 3 ] = uniqueNodes [ 0 ]; - uniqueNodes[ 0 ] = curNodes [ 5 ]; - uniqueNodes[ 1 ] = curNodes [ 4 ]; - uniqueNodes[ 2 ] = curNodes [ 3 ]; - isOk = true; - } - else if (( curNodes[0] == curNodes[3] ) + - ( curNodes[1] == curNodes[4] ) + - ( curNodes[2] == curNodes[5] ) == 2 ) { - // a lateral face turns into a line - isOk = true; - } - } - else if ( nbUniqueNodes == 5 ) { - // PENTAHEDRON --------------------> pyramid - if ( curNodes[0] == curNodes[3] ) - { - uniqueNodes[ 0 ] = curNodes[ 1 ]; - uniqueNodes[ 1 ] = curNodes[ 4 ]; - uniqueNodes[ 2 ] = curNodes[ 5 ]; - uniqueNodes[ 3 ] = curNodes[ 2 ]; - uniqueNodes[ 4 ] = curNodes[ 0 ]; - isOk = true; - } - if ( curNodes[1] == curNodes[4] ) - { - uniqueNodes[ 0 ] = curNodes[ 0 ]; - uniqueNodes[ 1 ] = curNodes[ 2 ]; - uniqueNodes[ 2 ] = curNodes[ 5 ]; - uniqueNodes[ 3 ] = curNodes[ 3 ]; - uniqueNodes[ 4 ] = curNodes[ 1 ]; - isOk = true; - } - if ( curNodes[2] == curNodes[5] ) - { - uniqueNodes[ 0 ] = curNodes[ 0 ]; - uniqueNodes[ 1 ] = curNodes[ 3 ]; - uniqueNodes[ 2 ] = curNodes[ 4 ]; - uniqueNodes[ 3 ] = curNodes[ 1 ]; - uniqueNodes[ 4 ] = curNodes[ 2 ]; - isOk = true; - } + uniqueNodes[ 0 ] = curNodes[ 0 ]; + uniqueNodes[ 1 ] = curNodes[ 2 ]; + uniqueNodes[ 2 ] = curNodes[ 5 ]; + uniqueNodes[ 3 ] = curNodes[ 3 ]; + uniqueNodes[ 4 ] = curNodes[ 1 ]; + toRemove = false; + } + if ( curNodes[2] == curNodes[5] ) + { + uniqueNodes[ 0 ] = curNodes[ 0 ]; + uniqueNodes[ 1 ] = curNodes[ 3 ]; + uniqueNodes[ 2 ] = curNodes[ 4 ]; + uniqueNodes[ 3 ] = curNodes[ 1 ]; + uniqueNodes[ 4 ] = curNodes[ 2 ]; + toRemove = false; } - break; } - case SMDSEntity_Hexa: - { - //////////////////////////////////// HEXAHEDRON - isOk = false; - SMDS_VolumeTool hexa (elem); - hexa.SetExternalNormal(); - if ( nbUniqueNodes == 4 && nbRepl == 4 ) { - //////////////////////// HEX ---> tetrahedron - for ( int iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { - // one face turns into a point ... - int pickInd = ind[ 0 ]; - int iOppFace = hexa.GetOppFaceIndex( iFace ); - ind = hexa.GetFaceNodesIndices( iOppFace ); - int nbStick = 0; - uniqueNodes.clear(); - for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) { - if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) - nbStick++; - else - uniqueNodes.push_back( curNodes[ind[ iCur ]]); - } - if ( nbStick == 1 ) { - // ... and the opposite one - into a triangle. - // set a top node - uniqueNodes.push_back( curNodes[ pickInd ]); - isOk = true; - } - break; + break; + } + case SMDSEntity_Hexa: + { + //////////////////////////////////// HEXAHEDRON + SMDS_VolumeTool hexa (elem); + hexa.SetExternalNormal(); + if ( nbUniqueNodes == 4 && nbRepl == 4 ) { + //////////////////////// HEX ---> tetrahedron + for ( int iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { + // one face turns into a point ... + int pickInd = ind[ 0 ]; + int iOppFace = hexa.GetOppFaceIndex( iFace ); + ind = hexa.GetFaceNodesIndices( iOppFace ); + int nbStick = 0; + uniqueNodes.clear(); + for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) { + if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) + nbStick++; + else + uniqueNodes.push_back( curNodes[ind[ iCur ]]); + } + if ( nbStick == 1 ) { + // ... and the opposite one - into a triangle. + // set a top node + uniqueNodes.push_back( curNodes[ pickInd ]); + toRemove = false; } - } - } - else if ( nbUniqueNodes == 6 && nbRepl == 2 ) { - //////////////////////// HEX ---> prism - int nbTria = 0, iTria[3]; - const int *ind; // indices of face nodes - // look for triangular faces - for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) { - ind = hexa.GetFaceNodesIndices( iFace ); - TIDSortedNodeSet faceNodes; - for ( iCur = 0; iCur < 4; iCur++ ) - faceNodes.insert( curNodes[ind[iCur]] ); - if ( faceNodes.size() == 3 ) - iTria[ nbTria++ ] = iFace; - } - // check if triangles are opposite - if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] )) - { - // set nodes of the bottom triangle - ind = hexa.GetFaceNodesIndices( iTria[ 0 ]); - vector indB; - for ( iCur = 0; iCur < 4; iCur++ ) - if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1]) - indB.push_back( ind[iCur] ); - if ( !hexa.IsForward() ) - std::swap( indB[0], indB[2] ); - for ( iCur = 0; iCur < 3; iCur++ ) - uniqueNodes[ iCur ] = curNodes[indB[iCur]]; - // set nodes of the top triangle - const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]); - for ( iCur = 0; iCur < 3; ++iCur ) - for ( int j = 0; j < 4; ++j ) - if ( hexa.IsLinked( indB[ iCur ], indT[ j ] )) - { - uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]]; - break; - } - isOk = true; break; } } - else if (nbUniqueNodes == 5 && nbRepl == 3 ) { - //////////////////// HEXAHEDRON ---> pyramid - for ( int iFace = 0; iFace < 6; iFace++ ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && - curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { - // one face turns into a point ... - int iOppFace = hexa.GetOppFaceIndex( iFace ); - ind = hexa.GetFaceNodesIndices( iOppFace ); - uniqueNodes.clear(); - for ( iCur = 0; iCur < 4; iCur++ ) { - if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) - break; - else - uniqueNodes.push_back( curNodes[ind[ iCur ]]); - } - if ( uniqueNodes.size() == 4 ) { - // ... and the opposite one is a quadrangle - // set a top node - const int* indTop = hexa.GetFaceNodesIndices( iFace ); - uniqueNodes.push_back( curNodes[indTop[ 0 ]]); - isOk = true; + } + else if ( nbUniqueNodes == 6 && nbRepl == 2 ) { + //////////////////////// HEX ---> prism + int nbTria = 0, iTria[3]; + const int *ind; // indices of face nodes + // look for triangular faces + for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) { + ind = hexa.GetFaceNodesIndices( iFace ); + TIDSortedNodeSet faceNodes; + for ( iCur = 0; iCur < 4; iCur++ ) + faceNodes.insert( curNodes[ind[iCur]] ); + if ( faceNodes.size() == 3 ) + iTria[ nbTria++ ] = iFace; + } + // check if triangles are opposite + if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] )) + { + // set nodes of the bottom triangle + ind = hexa.GetFaceNodesIndices( iTria[ 0 ]); + vector indB; + for ( iCur = 0; iCur < 4; iCur++ ) + if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1]) + indB.push_back( ind[iCur] ); + if ( !hexa.IsForward() ) + std::swap( indB[0], indB[2] ); + for ( iCur = 0; iCur < 3; iCur++ ) + uniqueNodes[ iCur ] = curNodes[indB[iCur]]; + // set nodes of the top triangle + const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]); + for ( iCur = 0; iCur < 3; ++iCur ) + for ( int j = 0; j < 4; ++j ) + if ( hexa.IsLinked( indB[ iCur ], indT[ j ] )) + { + uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]]; + break; } - break; + toRemove = false; + break; + } + } + else if (nbUniqueNodes == 5 && nbRepl == 3 ) { + //////////////////// HEXAHEDRON ---> pyramid + for ( int iFace = 0; iFace < 6; iFace++ ) { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] && + curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) { + // one face turns into a point ... + int iOppFace = hexa.GetOppFaceIndex( iFace ); + ind = hexa.GetFaceNodesIndices( iOppFace ); + uniqueNodes.clear(); + for ( iCur = 0; iCur < 4; iCur++ ) { + if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] ) + break; + else + uniqueNodes.push_back( curNodes[ind[ iCur ]]); } + if ( uniqueNodes.size() == 4 ) { + // ... and the opposite one is a quadrangle + // set a top node + const int* indTop = hexa.GetFaceNodesIndices( iFace ); + uniqueNodes.push_back( curNodes[indTop[ 0 ]]); + toRemove = false; + } + break; } } + } - if ( !isOk && nbUniqueNodes > 4 ) { - ////////////////// HEXAHEDRON ---> polyhedron - hexa.SetExternalNormal(); - vector poly_nodes; poly_nodes.reserve( 6 * 4 ); - vector quantities; quantities.reserve( 6 ); - for ( int iFace = 0; iFace < 6; iFace++ ) + if ( toRemove && nbUniqueNodes > 4 ) { + ////////////////// HEXAHEDRON ---> polyhedron + hexa.SetExternalNormal(); + vector& poly_nodes = newElemDefs[0].myNodes; + vector & quantities = newElemDefs[0].myPolyhedQuantities; + poly_nodes.reserve( 6 * 4 ); poly_nodes.clear(); + quantities.reserve( 6 ); quantities.clear(); + for ( int iFace = 0; iFace < 6; iFace++ ) + { + const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes + if ( curNodes[ind[0]] == curNodes[ind[2]] || + curNodes[ind[1]] == curNodes[ind[3]] ) { - const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes - if ( curNodes[ind[0]] == curNodes[ind[2]] || - curNodes[ind[1]] == curNodes[ind[3]] ) - { - quantities.clear(); - break; // opposite nodes stick - } - nodeSet.clear(); - for ( iCur = 0; iCur < 4; iCur++ ) - { - if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second ) - poly_nodes.push_back( curNodes[ind[ iCur ]]); - } - if ( nodeSet.size() < 3 ) - poly_nodes.resize( poly_nodes.size() - nodeSet.size() ); - else - quantities.push_back( nodeSet.size() ); + quantities.clear(); + break; // opposite nodes stick } - if ( quantities.size() >= 4 ) + nodeSet.clear(); + for ( iCur = 0; iCur < 4; iCur++ ) { - const SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities ); - myLastCreatedElems.Append( newElem ); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); - rmElemIds.push_back( elem->GetID() ); + if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second ) + poly_nodes.push_back( curNodes[ind[ iCur ]]); } + if ( nodeSet.size() < 3 ) + poly_nodes.resize( poly_nodes.size() - nodeSet.size() ); + else + quantities.push_back( nodeSet.size() ); } - break; - } // case HEXAHEDRON + if ( quantities.size() >= 4 ) + { + nbResElems = 1; + nbUniqueNodes = poly_nodes.size(); + newElemDefs[0].SetPoly(true); + } + } + break; + } // case HEXAHEDRON - default: - isOk = false; - } // switch ( nbNodes ) + default: + toRemove = true; - } // if ( nbNodes != nbUniqueNodes ) // some nodes stick + } // switch ( entity ) - if ( isOk ) // a non-poly elem remains valid after sticking nodes + if ( toRemove && nbResElems == 0 && avoidMakingHoles ) { - if ( nbNodes != nbUniqueNodes || - !aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes )) - { - elemType.Init( elem ).SetID( elem->GetID() ); - - SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0; - aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false); - - uniqueNodes.resize(nbUniqueNodes); - SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType ); - if ( sm && newElem ) - sm->AddElement( newElem ); - if ( elem != newElem ) - ReplaceElemInGroups( elem, newElem, aMesh ); - } - } - else { - // Remove invalid regular element or invalid polygon - rmElemIds.push_back( elem->GetID() ); + // erase from nodeNodeMap nodes whose merge spoils elem + vector< const SMDS_MeshNode* > noMergeNodes; + SMESH_MeshAlgos::DeMerge( elem, curNodes, noMergeNodes ); + for ( size_t i = 0; i < noMergeNodes.size(); ++i ) + nodeNodeMap.erase( noMergeNodes[i] ); } + + } // if ( nbNodes != nbUniqueNodes ) // some nodes stick - } // loop on elements + uniqueNodes.resize( nbUniqueNodes ); - // Remove bad elements, then equal nodes (order important) + if ( !toRemove && nbResElems == 0 ) + nbResElems = 1; - Remove( rmElemIds, false ); - Remove( rmNodeIds, true ); + newElemDefs.resize( nbResElems ); - return; + return !toRemove; } @@ -8235,7 +8332,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, // ------------------------------------------------------------------------- // 1. Since sewing may break if there are volumes to split on the side 2, - // we wont move nodes but just compute new coordinates for them + // we won't move nodes but just compute new coordinates for them typedef map TNodeXYZMap; TNodeXYZMap nBordXYZ; list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ]; @@ -8399,7 +8496,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, } // loop on inverse elements of prevSideNode if ( !sideNode ) { - MESSAGE(" Cant find path by links of the Side 2 "); + MESSAGE(" Can't find path by links of the Side 2 "); return SEW_BAD_SIDE_NODES; } sideNodes.push_back( sideNode ); @@ -9197,7 +9294,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, // remove a linear element GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); - // remove central nodes of biquadratic elements (biquad->quad convertion) + // remove central nodes of biquadratic elements (biquad->quad conversion) if ( hasCentralNodes ) for ( size_t i = nbNodes * 2; i < nodes.size(); ++i ) if ( nodes[i]->NbInverseElements() == 0 ) @@ -9845,7 +9942,7 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // face does not exist SMESHDS_Mesh* aMesh = GetMeshDS(); - // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes + // TODO algorithm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh TIDSortedElemSet faceSet1, faceSet2; set volSet1, volSet2; @@ -11075,9 +11172,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectormyMesh->GetMeshDS(); meshDS->BuildDownWardConnectivity(true); @@ -11100,7 +11197,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector emptySet; emptyMap.clear(); - MESSAGE(".. Number of domains :"< > mutipleNodes; // nodes multi domains with domain order std::map > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains) - MESSAGE(".. Duplication of the nodes"); + //MESSAGE(".. Duplication of the nodes"); for (int idomain = idom0; idomain < nbDomains; idomain++) { itface = faceDomains.begin(); @@ -11312,7 +11409,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector > nodeQuadDomains; std::map mapOfJunctionGroups; - MESSAGE(".. Creation of elements: simple junction"); + //MESSAGE(".. Creation of elements: simple junction"); if (createJointElems) { int idg; @@ -11494,7 +11591,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector >::const_iterator itnod = nodeDomains.begin(); @@ -11669,9 +11766,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& theElems) { - MESSAGE("-------------------------------------------------"); - MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups"); - MESSAGE("-------------------------------------------------"); + // MESSAGE("-------------------------------------------------"); + // MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups"); + // MESSAGE("-------------------------------------------------"); SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); @@ -11833,9 +11930,9 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, std::vector& nodesCoords, std::vector >& listOfListOfNodes) { - MESSAGE("--------------------------------"); - MESSAGE("SMESH_MeshEditor::CreateHoleSkin"); - MESSAGE("--------------------------------"); + // MESSAGE("--------------------------------"); + // MESSAGE("SMESH_MeshEditor::CreateHoleSkin"); + // MESSAGE("--------------------------------"); // --- zone of volumes to remove is given : // 1 either by a geom shape (one or more vertices) and a radius, @@ -11937,7 +12034,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes { - MESSAGE("group of nodes provided"); + //MESSAGE("group of nodes provided"); SMDS_ElemIteratorPtr elemIt = groupDS->GetElements(); while ( elemIt->more() ) { @@ -11959,7 +12056,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, } else if (isNodeCoords) { - MESSAGE("list of nodes coordinates provided"); + //MESSAGE("list of nodes coordinates provided"); size_t i = 0; int k = 0; while ( i < nodesCoords.size()-2 ) @@ -11969,13 +12066,13 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, double z = nodesCoords[i++]; gp_Pnt p = gp_Pnt(x, y ,z); gpnts.push_back(p); - MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z()); + //MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z()); k++; } } else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius { - MESSAGE("no group of nodes provided, using vertices from geom shape, and radius"); + //MESSAGE("no group of nodes provided, using vertices from geom shape, and radius"); TopTools_IndexedMapOfShape vertexMap; TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap ); gp_Pnt p = gp_Pnt(0,0,0); @@ -11987,20 +12084,17 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i )); p = BRep_Tool::Pnt(vertex); gpnts.push_back(p); - MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z()); + //MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z()); } } if (gpnts.size() > 0) { - int nodeId = 0; const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]); - if (startNode) - nodeId = startNode->GetID(); - MESSAGE("nodeId " << nodeId); + //MESSAGE("startNode->nodeId " << nodeId); double radius2 = radius*radius; - MESSAGE("radius2 " << radius2); + //MESSAGE("radius2 " << radius2); // --- volumes on start node @@ -12029,7 +12123,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, { std::set::iterator it = setOfVolToCheck.begin(); int vtkId = *it; - MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + //MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); bool volInside = false; vtkIdType npts = 0; vtkIdType* pts = 0; @@ -12040,7 +12134,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, if (mapOfNodeDistance2.count(pts[i])) { distance2 = mapOfNodeDistance2[pts[i]]; - MESSAGE("point " << pts[i] << " distance2 " << distance2); + //MESSAGE("point " << pts[i] << " distance2 " << distance2); } else { @@ -12058,7 +12152,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, } } mapOfNodeDistance2[pts[i]] = distance2; - MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]); + //MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]); } if (distance2 < radius2) { @@ -12070,7 +12164,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, if (volInside) { setOfInsideVol.insert(vtkId); - MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + //MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); int neighborsVtkIds[NBMAXNEIGHBORS]; int downIds[NBMAXNEIGHBORS]; unsigned char downTypes[NBMAXNEIGHBORS]; @@ -12082,7 +12176,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, else { setOfOutsideVol.insert(vtkId); - MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + //MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); } setOfVolToCheck.erase(vtkId); } @@ -12095,7 +12189,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, std::set setOfVolToReCheck; while (addedInside) { - MESSAGE(" --------------------------- re check"); + //MESSAGE(" --------------------------- re check"); addedInside = false; std::set::iterator itv = setOfInsideVol.begin(); for (; itv != setOfInsideVol.end(); ++itv) @@ -12117,7 +12211,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, int vtkId = *it; if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON) { - MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + //MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); int countInside = 0; int neighborsVtkIds[NBMAXNEIGHBORS]; int downIds[NBMAXNEIGHBORS]; @@ -12126,10 +12220,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, for (int n = 0; n < nbNeighbors; n++) if (setOfInsideVol.count(neighborsVtkIds[n])) countInside++; - MESSAGE("countInside " << countInside); + //MESSAGE("countInside " << countInside); if (countInside > 1) { - MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + //MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); setOfInsideVol.insert(vtkId); sgrp->Add(meshDS->fromVtkToSmds(vtkId)); addedInside = true; @@ -12226,7 +12320,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, for (; itShape != shapeIdToVtkIdSet.end(); ++itShape) { int shapeId = itShape->first; - MESSAGE(" --- Shape ID --- "<< shapeId); + //MESSAGE(" --- Shape ID --- "<< shapeId); shapeIdToEdges[shapeId] = emptyEdges; std::vector nodesEdges; @@ -12235,7 +12329,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, for (; its != itShape->second.end(); ++its) { int vtkId = *its; - MESSAGE(" " << vtkId); + //MESSAGE(" " << vtkId); int neighborsVtkIds[NBMAXNEIGHBORS]; int downIds[NBMAXNEIGHBORS]; unsigned char downTypes[NBMAXNEIGHBORS]; @@ -12256,7 +12350,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId); nodesEdges.push_back(vtkNodeId[0]); nodesEdges.push_back(vtkNodeId[nbNodes-1]); - MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1); + //MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1); } } } @@ -12266,9 +12360,9 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, order.clear(); if (nodesEdges.size() > 0) { - order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1; + order.push_back(nodesEdges[0]); //MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1; nodesEdges[0] = -1; - order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1); + order.push_back(nodesEdges[1]); //MESSAGE(" --- back " << order.back()+1); nodesEdges[1] = -1; // do not reuse this edge bool found = true; while (found) @@ -12287,7 +12381,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, found = false; else { - order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1); + order.push_back(nodesEdges[i-1]); //MESSAGE(" --- back " << order.back()+1); nodesEdges[i-1] = -1; } else // even ==> use the next one @@ -12295,7 +12389,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, found = false; else { - order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1); + order.push_back(nodesEdges[i+1]); //MESSAGE(" --- back " << order.back()+1); nodesEdges[i+1] = -1; } } @@ -12317,7 +12411,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, found = false; else { - order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1); + order.push_front(nodesEdges[i-1]); //MESSAGE(" --- front " << order.front()+1); nodesEdges[i-1] = -1; } else // even ==> use the next one @@ -12325,7 +12419,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, found = false; else { - order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1); + order.push_front(nodesEdges[i+1]); //MESSAGE(" --- front " << order.front()+1); nodesEdges[i+1] = -1; } } @@ -12338,7 +12432,7 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius, for (; itl != order.end(); itl++) { nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1; - MESSAGE(" ordered node " << nodes[nodes.size()-1]); + //MESSAGE(" ordered node " << nodes[nodes.size()-1]); } listOfListOfNodes.push_back(nodes); } @@ -12740,3 +12834,448 @@ void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from, default:; } } + +namespace // utils for MakePolyLine +{ + //================================================================================ + /*! + * \brief Sequence of found points and a current point data + */ + struct Path + { + std::vector< gp_XYZ > myPoints; + double myLength; + + int mySrcPntInd; //!< start point index + const SMDS_MeshElement* myFace; + SMESH_NodeXYZ myNode1; + SMESH_NodeXYZ myNode2; + int myNodeInd1; + int myNodeInd2; + double myDot1; + double myDot2; + TIDSortedElemSet myElemSet, myAvoidSet; + + Path(): myLength(0.0), myFace(0) {} + + bool SetCutAtCorner( const SMESH_NodeXYZ& cornerNode, + const SMDS_MeshElement* face, + const gp_XYZ& plnNorm, + const gp_XYZ& plnOrig ); + + void AddPoint( const gp_XYZ& p ); + + bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig ); + + static void Remove( std::vector< Path > & paths, size_t& i ); + }; + + //================================================================================ + /*! + * \brief Remove a path from a vector + */ + //================================================================================ + + void Path::Remove( std::vector< Path > & paths, size_t& i ) + { + size_t j = paths.size() - 1; // last item to be removed + if ( i < j ) + { + paths[ i ].myPoints.swap( paths[ j ].myPoints ); + paths[ i ].myFace = paths[ j ].myFace; + paths[ i ].myNodeInd1 = paths[ j ].myNodeInd1; + paths[ i ].myNodeInd2 = paths[ j ].myNodeInd2; + paths[ i ].myNode1 = paths[ j ].myNode1; + paths[ i ].myNode2 = paths[ j ].myNode2; + paths[ i ].myLength = paths[ j ].myLength; + } + paths.pop_back(); + --i; + } + + //================================================================================ + /*! + * \brief Store a point that is at a node of a face if the face is intersected by plane. + * Return false if the node is a sole intersection point of the face and the plane + */ + //================================================================================ + + bool Path::SetCutAtCorner( const SMESH_NodeXYZ& cornerNode, + const SMDS_MeshElement* face, + const gp_XYZ& plnNorm, + const gp_XYZ& plnOrig ) + { + if ( face == myFace ) + return false; + myNodeInd1 = face->GetNodeIndex( cornerNode._node ); + myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes(); + int ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes(); + myNode1.Set( face->GetNode( ind3 )); + myNode2.Set( face->GetNode( myNodeInd2 )); + + myDot1 = plnNorm * ( myNode1 - plnOrig ); + myDot2 = plnNorm * ( myNode2 - plnOrig ); + + bool ok = ( myDot1 * myDot2 < 0 ); + if ( !ok && myDot1 * myDot2 == 0 ) + { + ok = ( myDot1 != myDot2 ); + if ( ok && myFace ) + ok = ( myFace->GetNodeIndex( myNode1._node ) < 0 && + myFace->GetNodeIndex( myNode2._node ) < 0 ); + } + if ( ok ) + { + myFace = face; + myDot1 = 0; + AddPoint( cornerNode ); + } + return ok; + } + + //================================================================================ + /*! + * \brief Store a point and update myLength + */ + //================================================================================ + + void Path::AddPoint( const gp_XYZ& p ) + { + if ( !myPoints.empty() ) + myLength += ( p - myPoints.back() ).Modulus(); + else + myLength = 0; + myPoints.push_back( p ); + } + + //================================================================================ + /*! + * \brief Try to find the next point + * \param [in] plnNorm - cutting plane normal + * \param [in] plnOrig - cutting plane origin + */ + //================================================================================ + + bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig ) + { + int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes(); + if ( myNodeInd2 == nodeInd3 ) + nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes(); + + SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 ); + double dot3 = plnNorm * ( node3 - plnOrig ); + + if ( dot3 * myDot1 < 0. ) + { + myNode2 = node3; + myNodeInd2 = nodeInd3; + myDot2 = dot3; + } + else if ( dot3 * myDot2 < 0. ) + { + myNode1 = node3; + myNodeInd1 = nodeInd3; + myDot1 = dot3; + } + else if ( dot3 == 0. ) + { + SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig )) + return true; + return false; + } + else if ( myDot2 == 0. ) + { + SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner() + SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig )) + return true; + return false; + } + + double r = Abs( myDot1 / ( myDot2 - myDot1 )); + AddPoint( myNode1 * ( 1 - r ) + myNode2 * r ); + + myAvoidSet.clear(); + myAvoidSet.insert( myFace ); + myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node, + myElemSet, myAvoidSet, + &myNodeInd1, &myNodeInd2 ); + return myFace; + } + + //================================================================================ + /*! + * \brief Compute a path between two points of PolySegment + */ + struct PolyPathCompute + { + SMESH_MeshEditor::TListOfPolySegments& mySegments; //!< inout PolySegment's + std::vector< Path >& myPaths; //!< path of each of segments to compute + SMESH_Mesh* myMesh; + mutable std::vector< std::string > myErrors; + + PolyPathCompute( SMESH_MeshEditor::TListOfPolySegments& theSegments, + std::vector< Path >& thePaths, + SMESH_Mesh* theMesh): + mySegments( theSegments ), + myPaths( thePaths ), + myMesh( theMesh ), + myErrors( theSegments.size() ) + { + } +#undef SMESH_CAUGHT +#define SMESH_CAUGHT myErrors[i] = + void operator() ( const int i ) const + { + SMESH_TRY; + const_cast< PolyPathCompute* >( this )->Compute( i ); + SMESH_CATCH( SMESH::returnError ); + } +#undef SMESH_CAUGHT + //================================================================================ + /*! + * \brief Compute a path of a given segment + */ + //================================================================================ + + void Compute( const int iSeg ) + { + SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ]; + + // get a cutting plane + + gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] ); + gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] ); + if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] )); + if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] )); + + gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ(); + gp_XYZ plnOrig = SMESH_NodeXYZ( polySeg.myNode1[0] ); + + // find paths connecting the 2 end points of polySeg + + std::vector< Path > paths; paths.reserve(10); + + // initialize paths + + for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points + { + Path path; + path.mySrcPntInd = iP; + size_t nbPaths = paths.size(); + + if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] ) + { + while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ], + polySeg.myNode2[ iP ], + path.myElemSet, + path.myAvoidSet, + &path.myNodeInd1, + &path.myNodeInd2 ))) + { + path.myNode1.Set( polySeg.myNode1[ iP ]); + path.myNode2.Set( polySeg.myNode2[ iP ]); + path.myDot1 = plnNorm * ( path.myNode1 - plnOrig ); + path.myDot2 = plnNorm * ( path.myNode2 - plnOrig ); + path.myPoints.clear(); + path.AddPoint( 0.5 * ( path.myNode1 + path.myNode2 )); + path.myAvoidSet.insert( path.myFace ); + paths.push_back( path ); + } + if ( nbPaths == paths.size() ) + throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1 + << " in a PolySegment " << iSeg ); + } + else // an end point is at node + { + std::set nodes; + SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face); + while ( fIt->more() ) + { + path.myPoints.clear(); + if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig )) + { + if (( path.myDot1 * path.myDot2 != 0 ) || + ( nodes.insert( path.myNode1._node ).second && + nodes.insert( path.myNode2._node ).second )) + paths.push_back( path ); + } + } + } + + // look for a one-segment path + for ( size_t i = 0; i < nbPaths; ++i ) + for ( size_t j = nbPaths; j < paths.size(); ++j ) + if ( paths[i].myFace == paths[j].myFace ) + { + myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] ); + myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] ); + paths.clear(); + } + } + + // extend paths + + myPaths[ iSeg ].myLength = 1e100; + + while ( paths.size() >= 2 ) + { + for ( size_t i = 0; i < paths.size(); ++i ) + { + Path& path = paths[ i ]; + if ( !path.Extend( plnNorm, plnOrig ) || // path reached a mesh boundary + path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others + { + Path::Remove( paths, i ); + continue; + } + + // join paths that reach same point + for ( size_t j = 0; j < paths.size(); ++j ) + { + if ( i != j && + paths[i].myFace == paths[j].myFace && + paths[i].mySrcPntInd != paths[j].mySrcPntInd ) + { + double distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus(); + double fullLength = ( paths[i].myLength + paths[j].myLength + distLast ); + if ( fullLength < myPaths[ iSeg ].myLength ) + { + myPaths[ iSeg ].myLength = fullLength; + std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints; + allPoints.swap( paths[i].myPoints ); + allPoints.insert( allPoints.end(), + paths[j].myPoints.rbegin(), + paths[j].myPoints.rend() ); + } + Path::Remove( paths, i ); + Path::Remove( paths, j ); + } + } + } + if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() ) + throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()")); + } + + return; + + } // PolyPathCompute::Compute() + + }; // struct PolyPathCompute + +} // namespace + +//======================================================================= +//function : MakePolyLine +//purpose : Create a polyline consisting of 1D mesh elements each lying on a 2D element of +// the initial mesh +//======================================================================= + +void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments& theSegments, + SMESHDS_Group* theGroup, + SMESH_ElementSearcher* theSearcher) +{ + std::vector< Path > segPaths( theSegments.size() ); // path of each of segments + + SMESH_ElementSearcher* searcher = theSearcher; + SMESHUtils::Deleter delSearcher; + if ( !searcher ) + { + searcher = SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS() ); + delSearcher._obj = searcher; + } + + // get cutting planes + + std::vector< bool > isVectorOK( theSegments.size(), true ); + + for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg ) + { + PolySegment& polySeg = theSegments[ iSeg ]; + + gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] ); + gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] ); + if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] )); + if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] )); + + gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ(); + + isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits::min() ); + if ( !isVectorOK[ iSeg ]) + { + gp_XYZ pMid = 0.5 * ( p1 + p2 ); + const SMDS_MeshElement* face; + polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face ); + + if ( polySeg.myMidProjPoint.Distance( pMid ) < Precision::Confusion() ) + { + SMESH_MeshAlgos::FaceNormal( face, const_cast< gp_XYZ& >( polySeg.myVector.XYZ() )); + polySeg.myMidProjPoint = pMid + polySeg.myVector.XYZ(); + } + } + } + + // find paths + + PolyPathCompute algo( theSegments, segPaths, myMesh ); + OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 ); + + for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg ) + if ( !algo.myErrors[ iSeg ].empty() ) + throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() ); + + // create an 1D mesh + + const SMDS_MeshNode *n, *nPrev = 0; + SMESHDS_Mesh* mesh = GetMeshDS(); + + for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg ) + { + const Path& path = segPaths[iSeg]; + if ( path.myPoints.size() < 2 ) + continue; + + double tol = path.myLength / path.myPoints.size() / 1000.; + if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol ) + { + nPrev = mesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() ); + myLastCreatedNodes.Append( nPrev ); + } + for ( size_t iP = 1; iP < path.myPoints.size(); ++iP ) + { + n = mesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() ); + myLastCreatedNodes.Append( n ); + + const SMDS_MeshElement* elem = mesh->AddEdge( nPrev, n ); + myLastCreatedElems.Append( elem ); + if ( theGroup ) + theGroup->Add( elem ); + + nPrev = n; + } + + // return a vector + + if ( isVectorOK[ iSeg ]) + { + // find the most distance point of a path + double maxDist = 0; + for ( size_t iP = 1; iP < path.myPoints.size(); ++iP ) + { + double dist = theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] ); + if ( dist > maxDist ) + { + maxDist = dist; + theSegments[iSeg].myMidProjPoint = path.myPoints[iP]; + } + } + } + gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() ); + theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint ); + } + + return; +} diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index 103e4a417..a04f8dac1 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -46,8 +46,10 @@ class SMDS_MeshElement; class SMDS_MeshFace; class SMDS_MeshNode; +class SMESHDS_Group; class SMESHDS_Mesh; class SMESHDS_SubMesh; +class SMESH_ElementSearcher; class SMESH_Group; class SMESH_Mesh; class SMESH_MesherHelper; @@ -83,11 +85,12 @@ public: // -------------------------------------------------------------------------------- struct ElemFeatures //!< Features of element to create { - SMDSAbs_ElementType myType; - bool myIsPoly, myIsQuad; - int myID; - double myBallDiameter; - std::vector myPolyhedQuantities; + SMDSAbs_ElementType myType; + bool myIsPoly, myIsQuad; + int myID; + double myBallDiameter; + std::vector myPolyhedQuantities; + std::vector myNodes; // not managed by ElemFeatures SMESH_EXPORT ElemFeatures( SMDSAbs_ElementType type=SMDSAbs_All, bool isPoly=false, bool isQuad=false ) :myType( type ), myIsPoly(isPoly), myIsQuad(isQuad), myID(-1), myBallDiameter(0) {} @@ -471,7 +474,8 @@ public: // Return list of group of nodes close to each other within theTolerance. // Search among theNodes or in the whole mesh if theNodes is empty. - void MergeNodes (TListOfListOfNodes & theNodeGroups); + void MergeNodes (TListOfListOfNodes & theNodeGroups, + const bool theAvoidMakingHoles = false); // In each group, the cdr of nodes are substituted by the first one // in all elements. @@ -540,7 +544,7 @@ public: // additional nodes are inserted on a link provided that no // volume elements share the splitted link. // The side 2 is a free border if theSide2IsFreeBorder == true. - // Sewing is peformed between the given first, second and last + // Sewing is performed between the given first, second and last // nodes on the sides. // theBorderFirstNode is merged with theSide2FirstNode. // if (!theSide2IsFreeBorder) then theSide2SecondNode gives @@ -705,6 +709,42 @@ public: bool toAddExistingBondary = false, bool aroundElements = false); + + // structure used in MakePolyLine() to define a cutting plane + struct PolySegment + { + // 2 points: if myNode2 != 0, then the point is the middle of a face edge defined + // by two nodes, else it is at myNode1 + const SMDS_MeshNode* myNode1[2]; + const SMDS_MeshNode* myNode2[2]; + + gp_Vec myVector; // vector on the plane; to use a default plane set vector = (0,0,0) + + // point to return coordinates of a middle of the two points, projected to mesh + gp_Pnt myMidProjPoint; + }; + typedef std::vector TListOfPolySegments; + + /*! + * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of + * the initial mesh. Positions of new nodes are found by cutting the mesh by the + * plane passing through pairs of points specified by each PolySegment structure. + * If there are several paths connecting a pair of points, the shortest path is + * selected by the module. Position of the cutting plane is defined by the two + * points and an optional vector lying on the plane specified by a PolySegment. + * By default the vector is defined by Mesh module as following. A middle point + * of the two given points is computed. The middle point is projected to the mesh. + * The vector goes from the middle point to the projection point. In case of planar + * mesh, the vector is normal to the mesh. + * \param [inout] segments - PolySegment's defining positions of cutting planes. + * Return the used vector and position of the middle point. + * \param [in] group - an optional group where created mesh segments will + * be added. + */ + void MakePolyLine( TListOfPolySegments& segments, + SMESHDS_Group* group=0, + SMESH_ElementSearcher* searcher=0); + private: /*! @@ -749,6 +789,20 @@ public: const size_t nbSteps, SMESH_SequenceOfElemPtr& srcElements); + /*! + * \brief Computes new connectivity of an element after merging nodes + * \param [in] elems - the element + * \param [out] newElemDefs - definition(s) of result element(s) + * \param [inout] nodeNodeMap - nodes to merge + * \param [in] avoidMakingHoles - if true and and the element becomes invalid + * after merging (but not degenerated), removes nodes causing + * the invalidity from \a nodeNodeMap. + * \return bool - true if the element should be removed + */ + bool applyMerge( const SMDS_MeshElement* elems, + std::vector< ElemFeatures >& newElemDefs, + TNodeNodeMap& nodeNodeMap, + const bool avoidMakingHoles ); /*! * \brief Create 1D and 2D elements around swept elements * \param mapNewNodes - source nodes and ones generated from them @@ -781,11 +835,11 @@ public: double Angle ()const { return myAngle; } double Parameter ()const { return myPrm; } }; - Extrusion_Error MakeEdgePathPoints(std::list& aPrms, + Extrusion_Error makeEdgePathPoints(std::list& aPrms, const TopoDS_Edge& aTrackEdge, bool aFirstIsStart, std::list& aLPP); - Extrusion_Error MakeExtrElements(TIDSortedElemSet theElements[2], + Extrusion_Error makeExtrElements(TIDSortedElemSet theElements[2], std::list& theFullList, const bool theHasAngles, std::list& theAngles, @@ -793,7 +847,7 @@ public: const bool theHasRefPoint, const gp_Pnt& theRefPoint, const bool theMakeGroups); - static void LinearAngleVariation(const int NbSteps, + static void linearAngleVariation(const int NbSteps, std::list& theAngles); bool doubleNodes( SMESHDS_Mesh* theMeshDS, @@ -812,7 +866,7 @@ private: // Nodes and elements created during last operation SMESH_SequenceOfElemPtr myLastCreatedNodes, myLastCreatedElems; - // Description of error/warning occured during last operation + // Description of error/warning occurred during last operation SMESH_ComputeErrorPtr myError; }; diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx index e5dcf5d12..2aba558af 100644 --- a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx @@ -191,6 +191,9 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction) SeparateCornersAndMedium = new QCheckBox(tr("SEPARATE_CORNERS_AND_MEDIUM"), NodeSpecWidget ); SeparateCornersAndMedium->setEnabled( false ); + AvoidMakingHoles = new QCheckBox(tr("AVOID_MAKING_HOLES"), NodeSpecWidget ); + AvoidMakingHoles->setChecked( false ); + QGridLayout* NodeSpecLayout = new QGridLayout(NodeSpecWidget); NodeSpecLayout->setSpacing(SPACING); NodeSpecLayout->setMargin(0); @@ -198,6 +201,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction) NodeSpecLayout->addWidget(TextLabelTolerance, 0, 0 ); NodeSpecLayout->addWidget(SpinBoxTolerance, 0, 1 ); NodeSpecLayout->addWidget(SeparateCornersAndMedium, 1, 0, 1, 2 ); + NodeSpecLayout->addWidget(AvoidMakingHoles, 2, 0, 1, 2 ); /***************************************************************/ // Exclude groups @@ -585,12 +589,12 @@ bool SMESHGUI_MergeDlg::ClickOnApply() } if( myAction == MERGE_NODES ) - aMeshEditor->MergeNodes (aGroupsOfElements.inout(), nodesToKeep); + aMeshEditor->MergeNodes( aGroupsOfElements.inout(), nodesToKeep, AvoidMakingHoles->isChecked() ); else - aMeshEditor->MergeElements (aGroupsOfElements.inout()); + aMeshEditor->MergeElements( aGroupsOfElements.inout() ); if ( myTypeId == TYPE_AUTO ) { - if (myAction == MERGE_NODES ) + if ( myAction == MERGE_NODES ) SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"), tr("SMESH_MERGED_NODES").arg(QString::number(ListCoincident->count()).toLatin1().data())); else diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.h b/src/SMESHGUI/SMESHGUI_MergeDlg.h index 5e827abc8..6b087b631 100644 --- a/src/SMESHGUI/SMESHGUI_MergeDlg.h +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.h @@ -130,6 +130,7 @@ private: QWidget* NodeSpecWidget; SMESHGUI_SpinBox* SpinBoxTolerance; QCheckBox* SeparateCornersAndMedium; + QCheckBox* AvoidMakingHoles; QGroupBox* GroupCoincident; //QWidget* GroupCoincidentWidget; diff --git a/src/SMESHUtils/SMESH_MeshAlgos.cxx b/src/SMESHUtils/SMESH_MeshAlgos.cxx index 6670e509e..8e03e4e67 100644 --- a/src/SMESHUtils/SMESH_MeshAlgos.cxx +++ b/src/SMESHUtils/SMESH_MeshAlgos.cxx @@ -35,6 +35,8 @@ #include "SMDS_VolumeTool.hxx" #include "SMESH_OctreeNode.hxx" +#include + #include #include #include @@ -228,15 +230,16 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius ); - void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems ); - void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); - void getElementsInSphere ( const gp_XYZ& center, - const double radius, TIDSortedElemSet& foundElems); - size_t getSize() { return std::max( _size, _elements.size() ); } - virtual ~ElementBndBoxTree(); + void prepare(); // !!!call it before calling the following methods!!! + void getElementsNearPoint( const gp_Pnt& point, vector& foundElems ); + void getElementsNearLine ( const gp_Ax1& line, vector& foundElems); + void getElementsInSphere ( const gp_XYZ& center, + const double radius, + vector& foundElems); + ElementBndBoxTree* getLeafAtPoint( const gp_XYZ& point ); protected: - ElementBndBoxTree():_size(0) {} + ElementBndBoxTree() {} SMESH_Octree* newChild() const { return new ElementBndBoxTree; } void buildChildrenData(); Bnd_B3d* buildRootBox(); @@ -245,11 +248,25 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() struct ElementBox : public Bnd_B3d { const SMDS_MeshElement* _element; - int _refCount; // an ElementBox can be included in several tree branches - ElementBox(const SMDS_MeshElement* elem, double tolerance); + bool _isMarked; + void init(const SMDS_MeshElement* elem, double tolerance); }; vector< ElementBox* > _elements; - size_t _size; + + typedef ObjectPool< ElementBox > TElementBoxPool; + + //!< allocator of ElementBox's and SMESH_TreeLimit + struct LimitAndPool : public SMESH_TreeLimit + { + TElementBoxPool _elBoPool; + std::vector< ElementBox* > _markedElems; + LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ) {} + }; + LimitAndPool* getLimitAndPool() const + { + SMESH_TreeLimit* limitAndPool = const_cast< SMESH_TreeLimit* >( myLimit ); + return static_cast< LimitAndPool* >( limitAndPool ); + } }; //================================================================================ @@ -258,32 +275,27 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance) - :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. )) + ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, + SMDSAbs_ElementType elemType, + SMDS_ElemIteratorPtr theElemIt, + double tolerance) + :SMESH_Octree( new LimitAndPool() ) { int nbElems = mesh.GetMeshInfo().NbElements( elemType ); _elements.reserve( nbElems ); + TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool; + SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType ); while ( elemIt->more() ) - _elements.push_back( new ElementBox( elemIt->next(),tolerance )); - + { + ElementBox* eb = elBoPool.getNew(); + eb->init( elemIt->next(), tolerance ); + _elements.push_back( eb ); + } compute(); } - //================================================================================ - /*! - * \brief Destructor - */ - //================================================================================ - - ElementBndBoxTree::~ElementBndBoxTree() - { - for ( size_t i = 0; i < _elements.size(); ++i ) - if ( --_elements[i]->_refCount <= 0 ) - delete _elements[i]; - } - //================================================================================ /*! * \brief Return the maximal box @@ -311,14 +323,10 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() for (int j = 0; j < 8; j++) { if ( !_elements[i]->IsOut( *myChildren[j]->getBox() )) - { - _elements[i]->_refCount++; ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]); - } } - _elements[i]->_refCount--; } - _size = _elements.size(); + //_size = _elements.size(); SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory for (int j = 0; j < 8; j++) @@ -327,33 +335,61 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() if ((int) child->_elements.size() <= MaxNbElemsInLeaf ) child->myIsLeaf = true; - if ( child->_elements.capacity() - child->_elements.size() > 1000 ) + if ( child->isLeaf() && child->_elements.capacity() > child->_elements.size() ) SMESHUtils::CompactVector( child->_elements ); } } + //================================================================================ + /*! + * \brief Un-mark all elements + */ + //================================================================================ + + void ElementBndBoxTree::prepare() + { + // TElementBoxPool& elBoPool = getElementBoxPool(); + // for ( size_t i = 0; i < elBoPool.nbElements(); ++i ) + // const_cast< ElementBox* >( elBoPool[ i ])->_isMarked = false; + } + //================================================================================ /*! * \brief Return elements which can include the point */ //================================================================================ - void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, - TIDSortedElemSet& foundElems) + void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, + vector& foundElems) { if ( getBox()->IsOut( point.XYZ() )) return; if ( isLeaf() ) { + LimitAndPool* pool = getLimitAndPool(); + for ( size_t i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( point.XYZ() )) - foundElems.insert( _elements[i]->_element ); + if ( !_elements[i]->IsOut( point.XYZ() ) && + !_elements[i]->_isMarked ) + { + foundElems.push_back( _elements[i]->_element ); + _elements[i]->_isMarked = true; + pool->_markedElems.push_back( _elements[i] ); + } } else { for (int i = 0; i < 8; i++) ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems ); + + if ( level() == 0 ) + { + LimitAndPool* pool = getLimitAndPool(); + for ( size_t i = 0; i < pool->_markedElems.size(); ++i ) + pool->_markedElems[i]->_isMarked = false; + pool->_markedElems.clear(); + } } } @@ -363,22 +399,37 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, - TIDSortedElemSet& foundElems) + void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, + vector& foundElems) { if ( getBox()->IsOut( line )) return; if ( isLeaf() ) { + LimitAndPool* pool = getLimitAndPool(); + for ( size_t i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( line )) - foundElems.insert( _elements[i]->_element ); + if ( !_elements[i]->IsOut( line ) && + !_elements[i]->_isMarked ) + { + foundElems.push_back( _elements[i]->_element ); + _elements[i]->_isMarked = true; + pool->_markedElems.push_back( _elements[i] ); + } } else { for (int i = 0; i < 8; i++) ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems ); + + if ( level() == 0 ) + { + LimitAndPool* pool = getLimitAndPool(); + for ( size_t i = 0; i < pool->_markedElems.size(); ++i ) + pool->_markedElems[i]->_isMarked = false; + pool->_markedElems.clear(); + } } } @@ -388,24 +439,63 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, - const double radius, - TIDSortedElemSet& foundElems) + void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, + const double radius, + vector& foundElems) { if ( getBox()->IsOut( center, radius )) return; if ( isLeaf() ) { + LimitAndPool* pool = getLimitAndPool(); + for ( size_t i = 0; i < _elements.size(); ++i ) - if ( !_elements[i]->IsOut( center, radius )) - foundElems.insert( _elements[i]->_element ); + if ( !_elements[i]->IsOut( center, radius ) && + !_elements[i]->_isMarked ) + { + foundElems.push_back( _elements[i]->_element ); + _elements[i]->_isMarked = true; + pool->_markedElems.push_back( _elements[i] ); + } } else { for (int i = 0; i < 8; i++) ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems ); + + if ( level() == 0 ) + { + LimitAndPool* pool = getLimitAndPool(); + for ( size_t i = 0; i < pool->_markedElems.size(); ++i ) + pool->_markedElems[i]->_isMarked = false; + pool->_markedElems.clear(); + } + } + } + + //================================================================================ + /*! + * \brief Return a leaf including a point + */ + //================================================================================ + + ElementBndBoxTree* ElementBndBoxTree::getLeafAtPoint( const gp_XYZ& point ) + { + if ( getBox()->IsOut( point )) + return 0; + + if ( isLeaf() ) + { + return this; + } + else + { + for (int i = 0; i < 8; i++) + if ( ElementBndBoxTree* l = ((ElementBndBoxTree*) myChildren[i])->getLeafAtPoint( point )) + return l; } + return 0; } //================================================================================ @@ -414,13 +504,13 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() */ //================================================================================ - ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance) + void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance) { _element = elem; - _refCount = 1; + _isMarked = false; SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); while ( nIt->more() ) - Add( SMESH_TNodeXYZ( nIt->next() )); + Add( SMESH_NodeXYZ( nIt->next() )); Enlarge( tolerance ); } @@ -441,8 +531,8 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher { SMDS_Mesh* _mesh; SMDS_ElemIteratorPtr _meshPartIt; - ElementBndBoxTree* _ebbTree; - int _ebbTreeHeight; + ElementBndBoxTree* _ebbTree [SMDSAbs_NbElementTypes]; + int _ebbTreeHeight[SMDSAbs_NbElementTypes]; SMESH_NodeSearcherImpl* _nodeSearcher; SMDSAbs_ElementType _elementType; double _tolerance; @@ -452,10 +542,21 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, double tol=-1, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) - : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_ebbTreeHeight(-1),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {} + : _mesh(&mesh),_meshPartIt(elemIt),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) + { + for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i ) + { + _ebbTree[i] = NULL; + _ebbTreeHeight[i] = -1; + } + _elementType = SMDSAbs_All; + } virtual ~SMESH_ElementSearcherImpl() { - if ( _ebbTree ) delete _ebbTree; _ebbTree = 0; + for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i ) + { + delete _ebbTree[i]; _ebbTree[i] = NULL; + } if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0; } virtual int FindElementsByPoint(const gp_Pnt& point, @@ -465,13 +566,16 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point, SMDSAbs_ElementType type ); - void GetElementsNearLine( const gp_Ax1& line, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems); - void GetElementsInSphere( const gp_XYZ& center, - const double radius, - SMDSAbs_ElementType type, - vector< const SMDS_MeshElement* >& foundElems); + virtual void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems); + virtual void GetElementsInSphere( const gp_XYZ& center, + const double radius, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems); + virtual gp_XYZ Project(const gp_Pnt& point, + SMDSAbs_ElementType type, + const SMDS_MeshElement** closestElem); double getTolerance(); bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face, const double tolerance, double & param); @@ -482,9 +586,9 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher } int getTreeHeight() { - if ( _ebbTreeHeight < 0 ) - _ebbTreeHeight = _ebbTree->getHeight(); - return _ebbTreeHeight; + if ( _ebbTreeHeight[ _elementType ] < 0 ) + _ebbTreeHeight[ _elementType ] = _ebbTree[ _elementType ]->getHeight(); + return _ebbTreeHeight[ _elementType ]; } struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState()) @@ -528,9 +632,9 @@ double SMESH_ElementSearcherImpl::getTolerance() double boxSize = _nodeSearcher->getTree()->maxSize(); _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/; } - else if ( _ebbTree && meshInfo.NbElements() > 0 ) + else if ( _ebbTree[_elementType] && meshInfo.NbElements() > 0 ) { - double boxSize = _ebbTree->maxSize(); + double boxSize = _ebbTree[_elementType]->maxSize(); _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/; } if ( _tolerance == 0 ) @@ -551,10 +655,9 @@ double SMESH_ElementSearcherImpl::getTolerance() } else { - SMDS_ElemIteratorPtr elemIt = - _mesh->elementsIterator( SMDSAbs_ElementType( complexType )); + SMDS_ElemIteratorPtr elemIt = _mesh->elementsIterator( SMDSAbs_ElementType( complexType )); const SMDS_MeshElement* elem = elemIt->next(); - SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); SMESH_TNodeXYZ n1( nodeIt->next() ); elemSize = 0; while ( nodeIt->more() ) @@ -594,7 +697,7 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& lin anExtCC.Init( lineCurve, edge.Value() ); if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol) { - Quantity_Parameter pl, pe; + Standard_Real pl, pe; anExtCC.LowerDistanceParameters( pl, pe ); param += pl; if ( ++nbInts == 2 ) @@ -679,7 +782,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF outerFace2 = angle2Face.begin()->second; } } - // store the found outer face and add its links to continue seaching from + // store the found outer face and add its links to continue searching from if ( outerFace2 ) { _outerFaces.insert( outerFace2 ); @@ -723,6 +826,7 @@ FindElementsByPoint(const gp_Pnt& point, vector< const SMDS_MeshElement* >& foundElements) { foundElements.clear(); + _elementType = type; double tolerance = getTolerance(); @@ -756,14 +860,17 @@ FindElementsByPoint(const gp_Pnt& point, // ================================================================================= else // elements more complex than 0D { - if ( !_ebbTree || _elementType != type ) + if ( !_ebbTree[type] ) { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance ); + _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance ); } - TIDSortedElemSet suspectElems; - _ebbTree->getElementsNearPoint( point, suspectElems ); - TIDSortedElemSet::iterator elem = suspectElems.begin(); + else + { + _ebbTree[ type ]->prepare(); + } + vector< const SMDS_MeshElement* > suspectElems; + _ebbTree[ type ]->getElementsNearPoint( point, suspectElems ); + vector< const SMDS_MeshElement* >::iterator elem = suspectElems.begin(); for ( ; elem != suspectElems.end(); ++elem ) if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance )) foundElements.push_back( *elem ); @@ -784,35 +891,38 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, SMDSAbs_ElementType type ) { const SMDS_MeshElement* closestElem = 0; + _elementType = type; if ( type == SMDSAbs_Face || type == SMDSAbs_Volume ) { - if ( !_ebbTree || _elementType != type ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); - } - TIDSortedElemSet suspectElems; - _ebbTree->getElementsNearPoint( point, suspectElems ); + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt ); + else + ebbTree->prepare(); - if ( suspectElems.empty() && _ebbTree->maxSize() > 0 ) + vector suspectElems; + ebbTree->getElementsNearPoint( point, suspectElems ); + + if ( suspectElems.empty() && ebbTree->maxSize() > 0 ) { - gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() + - _ebbTree->getBox()->CornerMax() ); + gp_Pnt boxCenter = 0.5 * ( ebbTree->getBox()->CornerMin() + + ebbTree->getBox()->CornerMax() ); double radius = -1; - if ( _ebbTree->getBox()->IsOut( point.XYZ() )) - radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize(); + if ( ebbTree->getBox()->IsOut( point.XYZ() )) + radius = point.Distance( boxCenter ) - 0.5 * ebbTree->maxSize(); if ( radius < 0 ) - radius = _ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2; + radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2; while ( suspectElems.empty() ) { - _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); + ebbTree->prepare(); + ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); radius *= 1.1; } } double minDist = std::numeric_limits::max(); multimap< double, const SMDS_MeshElement* > dist2face; - TIDSortedElemSet::iterator elem = suspectElems.begin(); + vector::iterator elem = suspectElems.begin(); for ( ; elem != suspectElems.end(); ++elem ) { double dist = SMESH_MeshAlgos::GetDistance( *elem, point ); @@ -869,12 +979,16 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) { + _elementType = SMDSAbs_Face; + double tolerance = getTolerance(); - if ( !_ebbTree || _elementType != SMDSAbs_Face ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt ); - } + + ElementBndBoxTree*& ebbTree = _ebbTree[ SMDSAbs_Face ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + else + ebbTree->prepare(); + // Algo: analyse transition of a line starting at the point through mesh boundary; // try three lines parallel to axis of the coordinate system and perform rough // analysis. If solution is not clear perform thorough analysis. @@ -889,13 +1003,14 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) gp_Ax1 lineAxis( point, axisDir[axis]); gp_Lin line ( lineAxis ); - TIDSortedElemSet suspectFaces; // faces possibly intersecting the line - _ebbTree->getElementsNearLine( lineAxis, suspectFaces ); + vector suspectFaces; // faces possibly intersecting the line + if ( axis > 0 ) ebbTree->prepare(); + ebbTree->getElementsNearLine( lineAxis, suspectFaces ); // Intersect faces with the line map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; - TIDSortedElemSet::iterator face = suspectFaces.begin(); + vector::iterator face = suspectFaces.begin(); for ( ; face != suspectFaces.end(); ++face ) { // get face plane @@ -1098,14 +1213,14 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& SMDSAbs_ElementType type, vector< const SMDS_MeshElement* >& foundElems) { - if ( !_ebbTree || _elementType != type ) - { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); - } - TIDSortedElemSet suspectFaces; // elements possibly intersecting the line - _ebbTree->getElementsNearLine( line, suspectFaces ); - foundElems.assign( suspectFaces.begin(), suspectFaces.end()); + _elementType = type; + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + else + ebbTree->prepare(); + + ebbTree->getElementsNearLine( line, foundElems ); } //======================================================================= @@ -1119,14 +1234,63 @@ void SMESH_ElementSearcherImpl::GetElementsInSphere( const gp_XYZ& SMDSAbs_ElementType type, vector< const SMDS_MeshElement* >& foundElems) { - if ( !_ebbTree || _elementType != type ) + _elementType = type; + ElementBndBoxTree*& ebbTree = _ebbTree[ type ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt ); + else + ebbTree->prepare(); + + ebbTree->getElementsInSphere( center, radius, foundElems ); +} + +//======================================================================= +/* + * \brief Return a projection of a given point to a mesh. + * Optionally return the closest element + */ +//======================================================================= + +gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt& point, + SMDSAbs_ElementType type, + const SMDS_MeshElement** closestElem) +{ + _elementType = type; + if ( _mesh->GetMeshInfo().NbElements( _elementType ) == 0 ) + throw SALOME_Exception( LOCALIZED( "No elements of given type in the mesh" )); + + ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ]; + if ( !ebbTree ) + ebbTree = new ElementBndBoxTree( *_mesh, _elementType ); + + gp_XYZ p = point.XYZ(); + ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p ); + const Bnd_B3d* box = ebbLeaf->getBox(); + double radius = ( box->CornerMax() - box->CornerMin() ).Modulus(); + + vector< const SMDS_MeshElement* > elems; + ebbTree->getElementsInSphere( p, radius, elems ); + while ( elems.empty() ) { - if ( _ebbTree ) delete _ebbTree; - _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); + radius *= 1.5; + ebbTree->getElementsInSphere( p, radius, elems ); } - TIDSortedElemSet suspectFaces; // elements possibly intersecting the line - _ebbTree->getElementsInSphere( center, radius, suspectFaces ); - foundElems.assign( suspectFaces.begin(), suspectFaces.end() ); + gp_XYZ proj, bestProj; + const SMDS_MeshElement* elem = 0; + double minDist = 2 * radius; + for ( size_t i = 0; i < elems.size(); ++i ) + { + double d = SMESH_MeshAlgos::GetDistance( elems[i], p, &proj ); + if ( d < minDist ) + { + bestProj = proj; + elem = elems[i]; + minDist = d; + } + } + if ( closestElem ) *closestElem = elem; + + return bestProj; } //======================================================================= @@ -1163,8 +1327,8 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] ); faceNorm += edge1 ^ edge2; } - double normSize = faceNorm.Magnitude(); - if ( normSize <= tol ) + double fNormSize = faceNorm.Magnitude(); + if ( fNormSize <= tol ) { // degenerated face: point is out if it is out of all face edges for ( i = 0; i < nbNodes; ++i ) @@ -1175,7 +1339,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin } return true; } - faceNorm /= normSize; + faceNorm /= fNormSize; // check if the point lays on face plane gp_Vec n2p( xyz[0], point ); @@ -1204,9 +1368,10 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // to find intersections of the ray with the boundary. gp_Vec ray = n2p; gp_Vec plnNorm = ray ^ faceNorm; - normSize = plnNorm.Magnitude(); - if ( normSize <= tol ) return false; // point coincides with the first node - plnNorm /= normSize; + double n2pSize = plnNorm.Magnitude(); + if ( n2pSize <= tol ) return false; // point coincides with the first node + if ( n2pSize * n2pSize > fNormSize * 100 ) return true; // point is very far + plnNorm /= n2pSize; // for each node of the face, compute its signed distance to the cutting plane vector dist( nbNodes + 1); for ( i = 0; i < nbNodes; ++i ) @@ -1252,7 +1417,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin if ( rClosest > 0. && rClosest < 1. ) // not node intersection return out; - // ray pass through a face node; analyze transition through an adjacent edge + // the ray passes through a face node; analyze transition through an adjacent edge gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ]; gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ]; gp_Vec edgeAdjacent( p1, p2 ); @@ -1375,17 +1540,19 @@ namespace //======================================================================= double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem, - const gp_Pnt& point ) + const gp_Pnt& point, + gp_XYZ* closestPnt ) { switch ( elem->GetType() ) { case SMDSAbs_Volume: - return GetDistance( dynamic_cast( elem ), point); + return GetDistance( dynamic_cast( elem ), point, closestPnt ); case SMDSAbs_Face: - return GetDistance( dynamic_cast( elem ), point); + return GetDistance( dynamic_cast( elem ), point, closestPnt ); case SMDSAbs_Edge: - return GetDistance( dynamic_cast( elem ), point); + return GetDistance( dynamic_cast( elem ), point, closestPnt ); case SMDSAbs_Node: + if ( closestPnt ) *closestPnt = SMESH_TNodeXYZ( elem ); return point.Distance( SMESH_TNodeXYZ( elem )); default:; } @@ -1401,9 +1568,10 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem, //======================================================================= double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, - const gp_Pnt& point ) + const gp_Pnt& point, + gp_XYZ* closestPnt ) { - double badDistance = -1; + const double badDistance = -1; if ( !face ) return badDistance; // coordinates of nodes (medium nodes, if any, ignored) @@ -1447,7 +1615,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, trsf.Transforms( tmpPnt ); gp_XY point2D( tmpPnt.X(), tmpPnt.Z() ); - // loop on segments of the face to analyze point position ralative to the face + // loop on edges of the face to analyze point position ralative to the face set< PointPos > pntPosSet; for ( size_t i = 1; i < xy.size(); ++i ) { @@ -1457,31 +1625,40 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, // compute distance PointPos pos = *pntPosSet.begin(); - // cout << "Face " << face->GetID() << " DIST: "; switch ( pos._name ) { - case POS_LEFT: { - // point is most close to a segment - gp_Vec p0p1( point, xyz[ pos._index ] ); - gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector - p1p2.Normalize(); - double projDist = p0p1 * p1p2; // distance projected to the segment - gp_Vec projVec = p1p2 * projDist; - gp_Vec distVec = p0p1 - projVec; - // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID() - // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl; - return distVec.Magnitude(); + case POS_LEFT: + { + // point is most close to an edge + gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]); + gp_Vec n1p ( xyz[ pos._index ], point ); + double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + // projection of the point on the edge + gp_XYZ proj = ( 1. - u ) * xyz[ pos._index ] + u * xyz[ pos._index+1 ]; + if ( closestPnt ) *closestPnt = proj; + return point.Distance( proj ); } - case POS_RIGHT: { + case POS_RIGHT: + { // point is inside the face double distToFacePlane = tmpPnt.Y(); - // cout << distToFacePlane << ", INSIDE " << endl; + if ( closestPnt ) + { + if ( distToFacePlane < std::numeric_limits::min() ) { + *closestPnt = point.XYZ(); + } + else { + tmpPnt.SetY( 0 ); + trsf.Inverted().Transforms( tmpPnt ); + *closestPnt = tmpPnt; + } + } return Abs( distToFacePlane ); } - case POS_VERTEX: { + case POS_VERTEX: + { // point is most close to a node gp_Vec distVec( point, xyz[ pos._index ]); - // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl; return distVec.Magnitude(); } default:; @@ -1495,7 +1672,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face, */ //======================================================================= -double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& point ) +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, + const gp_Pnt& point, + gp_XYZ* closestPnt ) { double dist = Precision::Infinite(); if ( !seg ) return dist; @@ -1514,13 +1693,16 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& poi double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge if ( u <= 0. ) { dist = Min( dist, n1p.SquareMagnitude() ); + if ( closestPnt ) *closestPnt = xyz[i-1]; } else if ( u >= 1. ) { dist = Min( dist, point.SquareDistance( xyz[i] )); + if ( closestPnt ) *closestPnt = xyz[i]; } else { gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge dist = Min( dist, point.SquareDistance( proj )); + if ( closestPnt ) *closestPnt = proj; } } return Sqrt( dist ); @@ -1534,7 +1716,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& poi */ //======================================================================= -double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point ) +double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, + const gp_Pnt& point, + gp_XYZ* closestPnt ) { SMDS_VolumeTool vTool( volume ); vTool.SetExternalNormal(); @@ -1542,6 +1726,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt double n[3], bc[3]; double minDist = 1e100, dist; + gp_XYZ closeP = point.XYZ(); + bool isOut = false; for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) { // skip a facet with normal not "looking at" the point @@ -1558,23 +1744,34 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt case 3: { SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] ); - dist = GetDistance( &tmpFace, point ); + dist = GetDistance( &tmpFace, point, closestPnt ); break; } case 4: { SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]); - dist = GetDistance( &tmpFace, point ); + dist = GetDistance( &tmpFace, point, closestPnt ); break; } default: vector nvec( nodes, nodes + vTool.NbFaceNodes( iF )); SMDS_PolygonalFaceOfNodes tmpFace( nvec ); - dist = GetDistance( &tmpFace, point ); + dist = GetDistance( &tmpFace, point, closestPnt ); } - minDist = Min( minDist, dist ); + if ( dist < minDist ) + { + minDist = dist; + isOut = true; + if ( closestPnt ) closeP = *closestPnt; + } + } + if ( isOut ) + { + if ( closestPnt ) *closestPnt = closeP; + return minDist; } - return minDist; + + return 0; // point is inside the volume } //================================================================================ @@ -1765,3 +1962,12 @@ SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& { return new SMESH_ElementSearcherImpl( mesh, tolerance, elemIt ); } + +// TMP for ASERIS in V8_2_BR -- to remove when merging to master +void SMESH_MeshAlgos::DeMerge(const SMDS_MeshElement* elem, + std::vector< const SMDS_MeshNode* >& newNodes, + std::vector< const SMDS_MeshNode* >& noMergeNodes) +{ +// TMP for ASERIS in V8_2_BR -- to remove when merging to master +} +// TMP for ASERIS in V8_2_BR -- to remove when merging to master diff --git a/src/SMESHUtils/SMESH_MeshAlgos.hxx b/src/SMESHUtils/SMESH_MeshAlgos.hxx index b6c3661b0..22498c0e2 100644 --- a/src/SMESHUtils/SMESH_MeshAlgos.hxx +++ b/src/SMESHUtils/SMESH_MeshAlgos.hxx @@ -100,6 +100,15 @@ struct SMESHUtils_EXPORT SMESH_ElementSearcher * \brief Find out if the given point is out of closed 2D mesh. */ virtual TopAbs_State GetPointState(const gp_Pnt& point) = 0; + + /*! + * \brief Return a projection of a given point to a 2D mesh. + * Optionally return the closest face + */ + virtual gp_XYZ Project(const gp_Pnt& point, + SMDSAbs_ElementType type, + const SMDS_MeshElement** closestFace= 0) = 0; + virtual ~SMESH_ElementSearcher(); }; @@ -112,16 +121,16 @@ namespace SMESH_MeshAlgos bool IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ); SMESHUtils_EXPORT - double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point ); + double GetDistance( const SMDS_MeshElement* elem, const gp_Pnt& point, gp_XYZ* closestPnt = 0 ); SMESHUtils_EXPORT - double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point ); + double GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point, gp_XYZ* closestPnt = 0 ); SMESHUtils_EXPORT - double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point ); + double GetDistance( const SMDS_MeshFace* face, const gp_Pnt& point, gp_XYZ* closestPnt = 0 ); SMESHUtils_EXPORT - double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point ); + double GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point, gp_XYZ* closestPnt = 0 ); SMESHUtils_EXPORT void GetBarycentricCoords( const gp_XY& point, @@ -206,6 +215,16 @@ namespace SMESH_MeshAlgos CoincidentFreeBorders & foundFreeBordes); -} // SMESH_MeshAlgos + /*! + * \brief Find nodes whose merge makes the element invalid + * + * (Implemented in SMESH_DeMerge.cxx) + */ + SMESHUtils_EXPORT + void DeMerge(const SMDS_MeshElement* elem, + std::vector< const SMDS_MeshNode* >& newNodes, + std::vector< const SMDS_MeshNode* >& noMergeNodes); + +} // namespace SMESH_MeshAlgos #endif diff --git a/src/SMESHUtils/SMESH_TryCatch.cxx b/src/SMESHUtils/SMESH_TryCatch.cxx index 1f987213a..71e587caa 100644 --- a/src/SMESHUtils/SMESH_TryCatch.cxx +++ b/src/SMESHUtils/SMESH_TryCatch.cxx @@ -32,6 +32,12 @@ void SMESH::doNothing(const char* txt) { MESSAGE( txt << " " << __FILE__ << ": " << __LINE__ ); } + +const char* SMESH::returnError(const char* txt) +{ + return txt; +} + // ------------------------------------------------------------------ #include "SMESH_ComputeError.hxx" diff --git a/src/SMESHUtils/SMESH_TryCatch.hxx b/src/SMESHUtils/SMESH_TryCatch.hxx index ccdf3b1da..1443c7594 100644 --- a/src/SMESHUtils/SMESH_TryCatch.hxx +++ b/src/SMESHUtils/SMESH_TryCatch.hxx @@ -104,6 +104,7 @@ namespace SMESH { SMESHUtils_EXPORT void throwSalomeEx(const char* txt); SMESHUtils_EXPORT void doNothing(const char* txt); + SMESHUtils_EXPORT const char* returnError(const char* txt); } #endif diff --git a/src/SMESHUtils/SMESH_TypeDefs.hxx b/src/SMESHUtils/SMESH_TypeDefs.hxx index 77c095cc1..c9be990f6 100644 --- a/src/SMESHUtils/SMESH_TypeDefs.hxx +++ b/src/SMESHUtils/SMESH_TypeDefs.hxx @@ -169,6 +169,7 @@ struct SMESH_TNodeXYZ : public gp_XYZ double SquareDistance(const SMDS_MeshNode* n) const { return (SMESH_TNodeXYZ( n )-*this).SquareModulus(); } bool operator==(const SMESH_TNodeXYZ& other) const { return _node == other._node; } }; +typedef SMESH_TNodeXYZ SMESH_NodeXYZ; //-------------------------------------------------- /*! diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index a0c252bd3..7ef2f4633 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -184,7 +184,7 @@ namespace MeshEditor_I { //============================================================================= /*! - * \brief Deleter of theNodeSearcher at any compute event occured + * \brief Deleter of theNodeSearcher at any compute event occurred */ //============================================================================= @@ -467,9 +467,9 @@ void SMESH_MeshEditor_i::initData(bool deleteSearchers) //================================================================================ /*! * \brief Increment mesh modif time and optionally record that the performed - * modification may influence futher mesh re-compute. + * modification may influence further mesh re-compute. * \param [in] isReComputeSafe - true if the modification does not influence - * futher mesh re-compute + * further mesh re-compute */ //================================================================================ @@ -501,7 +501,7 @@ void SMESH_MeshEditor_i::declareMeshModified( bool isReComputeSafe ) * \brief Initialize and return myPreviewMesh * \param previewElements - type of elements to show in preview * - * WARNING: call it once par a method! + * WARNING: call it once per method! */ //================================================================================ @@ -669,7 +669,7 @@ void SMESH_MeshEditor_i::ClearLastCreated() throw (SALOME::SALOME_Exception) //======================================================================= /* - * Returns description of an error/warning occured during the last operation + * Returns description of an error/warning occurred during the last operation * WARNING: ComputeError.code >= 100 and no corresponding enum in IDL API */ //======================================================================= @@ -4159,7 +4159,8 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr theObject, //======================================================================= void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes, - const SMESH::ListOfIDSources& NodesToKeep) + const SMESH::ListOfIDSources& NodesToKeep, + CORBA::Boolean AvoidMakingHoles) throw (SALOME::SALOME_Exception) { SMESH_TRY; @@ -4203,9 +4204,9 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN aTPythonDump << aNodeGroup; } - getEditor().MergeNodes( aListOfListOfNodes ); + getEditor().MergeNodes( aListOfListOfNodes, AvoidMakingHoles ); - aTPythonDump << "], " << NodesToKeep << ")"; + aTPythonDump << "], " << NodesToKeep << ", " << AvoidMakingHoles << ")"; declareMeshModified( /*isReComputeSafe=*/false ); @@ -5117,7 +5118,6 @@ CORBA::Boolean SMESH_MeshEditor_i::ChangeElemNodes(CORBA::Long ide, TPythonDump() << "isDone = " << this << ".ChangeElemNodes( " << ide << ", " << newIDs << " )"; - MESSAGE("ChangeElementNodes"); bool res = getMeshDS()->ChangeElementNodes( elem, & aNodes[0], nbn1+1 ); declareMeshModified( /*isReComputeSafe=*/ !res ); @@ -6280,7 +6280,6 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl throw (SALOME::SALOME_Exception) { SMESH_TRY; - MESSAGE("AffectedElemGroupsInRegion"); SMESH::ListOfGroups_var aListOfGroups = new SMESH::ListOfGroups(); bool isEdgeGroup = false; bool isFaceGroup = false; @@ -6309,7 +6308,6 @@ SMESH_MeshEditor_i::AffectedElemGroupsInRegion( const SMESH::ListOfGroups& theEl if (aResult) { int lg = anAffected.size(); - MESSAGE("lg="<< lg); SMESH::long_array_var volumeIds = new SMESH::long_array; volumeIds->length(lg); SMESH::long_array_var faceIds = new SMESH::long_array; @@ -6658,7 +6656,7 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource, else pyDump << mesh_var << ", "; if ( group_var->_is_nil() ) - pyDump << "_NoneGroup = "; // assignment to None is forbiden + pyDump << "_NoneGroup = "; // assignment to None is forbidden else pyDump << group_var << " = "; pyDump << this << ".MakeBoundaryMesh( " @@ -6722,7 +6720,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim, else groupsOfThisMesh[ nbGroups++ ] = groups[i]; if ( SMESH::DownCast( groups[i] )) - THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM); + THROW_SALOME_CORBA_EXCEPTION("expected a group but received a mesh", SALOME::BAD_PARAM); } groupsOfThisMesh->length( nbGroups ); groupsOfOtherMesh->length( nbGroupsOfOtherMesh ); @@ -6816,7 +6814,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim, else pyDump << mesh_var << ", "; if ( group_var->_is_nil() ) - pyDump << "_NoneGroup = "; // assignment to None is forbiden + pyDump << "_NoneGroup = "; // assignment to None is forbidden else pyDump << group_var << " = "; pyDump << this << ".MakeBoundaryElements( " @@ -6833,3 +6831,128 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim, SMESH_CATCH( SMESH::throwCorbaException ); return 0; } + +//================================================================================ +/*! + * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of + * the initial mesh. Positions of new nodes are found by cutting the mesh by the + * plane passing through pairs of points specified by each PolySegment structure. + * If there are several paths connecting a pair of points, the shortest path is + * selected by the module. Position of the cutting plane is defined by the two + * points and an optional vector lying on the plane specified by a PolySegment. + * By default the vector is defined by Mesh module as following. A middle point + * of the two given points is computed. The middle point is projected to the mesh. + * The vector goes from the middle point to the projection point. In case of planar + * mesh, the vector is normal to the mesh. + * \param [inout] segments - PolySegment's defining positions of cutting planes. + * Return the used vector and position of the middle point. + * \param [in] groupName - optional name of a group where created mesh segments will + * be added. + */ +//================================================================================ + +void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments, + const char* theGroupName) + throw (SALOME::SALOME_Exception) +{ + if ( theSegments.length() == 0 ) + THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM ); + if ( myMesh->NbFaces() == 0 ) + THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM ); + + SMESH_TRY; + initData(/*deleteSearchers=*/false); + + SMESHDS_Group* groupDS = 0; + if ( myIsPreviewMode ) // copy faces to the tmp mesh + { + TPreviewMesh * tmpMesh = getPreviewMesh( SMDSAbs_Edge ); + SMDS_ElemIteratorPtr faceIt = getMeshDS()->elementsIterator( SMDSAbs_Face ); + while ( faceIt->more() ) + tmpMesh->Copy( faceIt->next() ); + } + else if ( theGroupName[0] ) // find/create a group of segments + { + SMESH_Mesh::GroupIteratorPtr grpIt = myMesh->GetGroups(); + while ( !groupDS && grpIt->more() ) + { + SMESH_Group* group = grpIt->next(); + if ( group->GetGroupDS()->GetType() == SMDSAbs_Edge && + strcmp( group->GetName(), theGroupName ) == 0 ) + { + groupDS = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() ); + } + } + if ( !groupDS ) + { + SMESH::SMESH_Group_var groupVar = myMesh_i->CreateGroup( SMESH::EDGE, theGroupName ); + + if ( SMESH_Group_i* groupImpl = SMESH::DownCast( groupVar )) + groupDS = dynamic_cast< SMESHDS_Group* >( groupImpl->GetGroupDS() ); + } + } + + // convert input polySegments + ::SMESH_MeshEditor::TListOfPolySegments segments( theSegments.length() ); + for ( CORBA::ULong i = 0; i < theSegments.length(); ++i ) + { + SMESH::PolySegment& segIn = theSegments[ i ]; + ::SMESH_MeshEditor::PolySegment& segOut = segments[ i ]; + segOut.myNode1[0] = getMeshDS()->FindNode( segIn.node1ID1 ); + segOut.myNode2[0] = getMeshDS()->FindNode( segIn.node1ID2 ); + segOut.myNode1[1] = getMeshDS()->FindNode( segIn.node2ID1 ); + segOut.myNode2[1] = getMeshDS()->FindNode( segIn.node2ID2 ); + segOut.myVector.SetCoord( segIn.vector.PS.x, + segIn.vector.PS.y, + segIn.vector.PS.z ); + if ( !segOut.myNode1[0] ) + THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node1ID1, + SALOME::BAD_PARAM ); + if ( !segOut.myNode1[1] ) + THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node2ID1, + SALOME::BAD_PARAM ); + } + + // get a static ElementSearcher + SMESH::SMESH_IDSource_var idSource = SMESH::SMESH_IDSource::_narrow( myMesh_i->_this() ); + theSearchersDeleter.Set( myMesh, getPartIOR( idSource, SMESH::FACE )); + if ( !theElementSearcher ) + theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() ); + + // compute + getEditor().MakePolyLine( segments, groupDS, theElementSearcher ); + + // return vectors + if ( myIsPreviewMode ) + { + for ( CORBA::ULong i = 0; i < theSegments.length(); ++i ) + { + SMESH::PolySegment& segOut = theSegments[ i ]; + ::SMESH_MeshEditor::PolySegment& segIn = segments[ i ]; + segOut.vector.PS.x = segIn.myVector.X(); + segOut.vector.PS.y = segIn.myVector.Y(); + segOut.vector.PS.z = segIn.myVector.Z(); + } + } + else + { + TPythonDump() << "_segments = []"; + for ( CORBA::ULong i = 0; i < theSegments.length(); ++i ) + { + SMESH::PolySegment& segIn = theSegments[ i ]; + TPythonDump() << "_segments.append( SMESH.PolySegment( " + << segIn.node1ID1 << ", " + << segIn.node1ID2 << ", " + << segIn.node2ID1 << ", " + << segIn.node2ID2 << ", " + << "smeshBuilder.MakeDirStruct( " + << segIn.vector.PS.x << ", " + << segIn.vector.PS.y << ", " + << segIn.vector.PS.z << ")))"; + } + TPythonDump() << this << ".MakePolyLine( _segments, '" << theGroupName << "')"; + } + + SMESH_CATCH( SMESH::throwCorbaException ); + return; +} diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index dd1212d8c..b8cfa0064 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -83,7 +83,7 @@ public: */ void ClearLastCreated() throw (SALOME::SALOME_Exception); /*! - * \brief Returns description of an error/warning occured during the last operation + * \brief Returns description of an error/warning occurred during the last operation */ SMESH::ComputeError* GetLastError() throw (SALOME::SALOME_Exception); @@ -495,7 +495,8 @@ public: CORBA::Boolean SeparateCornersAndMedium) throw (SALOME::SALOME_Exception); void MergeNodes (const SMESH::array_of_long_array& GroupsOfNodes, - const SMESH::ListOfIDSources& NodesToKeep ) + const SMESH::ListOfIDSources& NodesToKeep, + CORBA::Boolean AvoidMakingHoles ) throw (SALOME::SALOME_Exception); void FindEqualElements(SMESH::SMESH_IDSource_ptr Object, SMESH::array_of_long_array_out GroupsOfElementsID) @@ -815,7 +816,7 @@ public: const char* groupName, const SMESH::double_array& theNodesCoords, SMESH::array_of_long_array_out GroupsOfNodes) - throw (SALOME::SALOME_Exception); + throw (SALOME::SALOME_Exception); /*! * \brief Generated skin mesh (containing 2D cells) from 3D mesh @@ -843,7 +844,28 @@ public: SMESH::SMESH_Group_out group) throw (SALOME::SALOME_Exception); -private: //!< private methods + /*! + * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of + * the initial mesh. Positions of new nodes are found by cutting the mesh by the + * plane passing through pairs of points specified by each PolySegment structure. + * If there are several paths connecting a pair of points, the shortest path is + * selected by the module. Position of the cutting plane is defined by the two + * points and an optional vector lying on the plane specified by a PolySegment. + * By default the vector is defined by Mesh module as following. A middle point + * of the two given points is computed. The middle point is projected to the mesh. + * The vector goes from the middle point to the projection point. In case of planar + * mesh, the vector is normal to the mesh. + * \param [inout] segments - PolySegment's defining positions of cutting planes. + * Return the used vector and position of the middle point. + * \param [in] groupName - optional name of a group where created mesh segments will + * be added. + */ + void MakePolyLine(SMESH::ListOfPolySegments& segments, + const char* groupName) + throw (SALOME::SALOME_Exception); + + + private: //!< private methods ::SMESH_MeshEditor& getEditor(); diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index e779c7a7a..0deca2ea8 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -27,6 +27,10 @@ ## @defgroup l1_creating Creating meshes ## @{ ## @defgroup l2_impexp Importing and exporting meshes +## @{ +## @details +## These are methods of class \ref smeshBuilder.smeshBuilder "smeshBuilder" +## @} ## @defgroup l2_construct Constructing meshes ## @defgroup l2_algorithms Defining Algorithms ## @{ @@ -45,8 +49,7 @@ ## @defgroup l3_hypos_additi Additional Hypotheses ## @} -## @defgroup l2_submeshes Constructing submeshes -## @defgroup l2_compounds Building Compounds +## @defgroup l2_submeshes Constructing sub-meshes ## @defgroup l2_editing Editing Meshes ## @} @@ -55,7 +58,6 @@ ## @defgroup l1_grouping Grouping elements ## @{ ## @defgroup l2_grps_create Creating groups -## @defgroup l2_grps_edit Editing groups ## @defgroup l2_grps_operon Using operations on groups ## @defgroup l2_grps_delete Deleting Groups @@ -67,15 +69,13 @@ ## @defgroup l2_modif_edit Modifying nodes and elements ## @defgroup l2_modif_renumber Renumbering nodes and elements ## @defgroup l2_modif_trsf Transforming meshes (Translation, Rotation, Symmetry, Sewing, Merging) -## @defgroup l2_modif_movenode Moving nodes -## @defgroup l2_modif_throughp Mesh through point ## @defgroup l2_modif_unitetri Uniting triangles ## @defgroup l2_modif_cutquadr Cutting elements ## @defgroup l2_modif_changori Changing orientation of elements ## @defgroup l2_modif_smooth Smoothing ## @defgroup l2_modif_extrurev Extrusion and Revolution -## @defgroup l2_modif_patterns Pattern mapping ## @defgroup l2_modif_tofromqu Convert to/from Quadratic Mesh +## @defgroup l2_modif_duplicat Duplication of nodes and elements (to emulate cracks) ## @} ## @defgroup l1_measurements Measurements @@ -91,6 +91,8 @@ import SALOME import SALOMEDS import os +## Private class used to workaround a problem that sometimes isinstance(m, Mesh) returns False +# class MeshMeta(type): def __instancecheck__(cls, inst): """Implement isinstance(inst, cls).""" @@ -104,7 +106,7 @@ class MeshMeta(type): ## @addtogroup l1_auxiliary ## @{ -## Converts an angle from degrees to radians +## Convert an angle from degrees to radians def DegreesToRadians(AngleInDegrees): from math import pi return AngleInDegrees * pi / 180.0 @@ -145,19 +147,19 @@ def ParseParameters(*args): Result.append( hasVariables ) return Result -# Parse parameters converting variables to radians +## Parse parameters while converting variables to radians def ParseAngles(*args): return ParseParameters( *( args + (DegreesToRadians, ))) -# Substitute PointStruct.__init__() to create SMESH.PointStruct using notebook variables. -# Parameters are stored in PointStruct.parameters attribute +## Substitute PointStruct.__init__() to create SMESH.PointStruct using notebook variables. +# Parameters are stored in PointStruct.parameters attribute def __initPointStruct(point,*args): point.x, point.y, point.z, point.parameters,hasVars = ParseParameters(*args) pass SMESH.PointStruct.__init__ = __initPointStruct -# Substitute AxisStruct.__init__() to create SMESH.AxisStruct using notebook variables. -# Parameters are stored in AxisStruct.parameters attribute +## Substitute AxisStruct.__init__() to create SMESH.AxisStruct using notebook variables. +# Parameters are stored in AxisStruct.parameters attribute def __initAxisStruct(ax,*args): if len( args ) != 6: raise RuntimeError,\ @@ -167,6 +169,7 @@ def __initAxisStruct(ax,*args): SMESH.AxisStruct.__init__ = __initAxisStruct smeshPrecisionConfusion = 1.e-07 +## Compare real values using smeshPrecisionConfusion as tolerance def IsEqual(val1, val2, tol=smeshPrecisionConfusion): if abs(val1 - val2) < tol: return True @@ -174,7 +177,7 @@ def IsEqual(val1, val2, tol=smeshPrecisionConfusion): NO_NAME = "NoName" -## Gets object name +## Return object name def GetName(obj): if obj: # object not null @@ -207,7 +210,7 @@ def GetName(obj): pass raise RuntimeError, "Null or invalid object" -## Prints error message if a hypothesis was not assigned. +## Print error message if a hypothesis was not assigned. def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh): if isAlgo: hypType = "algorithm" @@ -271,7 +274,7 @@ def AssureGeomPublished(mesh, geom, name=''): mesh.geompyD.init_geom( mesh.smeshpyD.GetCurrentStudy()) ## get a name if not name and geom.GetShapeType() != geomBuilder.GEOM.COMPOUND: - # for all groups SubShapeName() returns "Compound_-1" + # for all groups SubShapeName() return "Compound_-1" name = mesh.geompyD.SubShapeName(geom, mesh.geom) if not name: name = "%s_%s"%(geom.GetShapeType(), id(geom)%10000) @@ -376,20 +379,22 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): ## Dump component to the Python script # This method overrides IDL function to allow default values for the parameters. + # @ingroup l1_auxiliary def DumpPython(self, theStudy, theIsPublished=True, theIsMultiFile=True): return SMESH._objref_SMESH_Gen.DumpPython(self, theStudy, theIsPublished, theIsMultiFile) ## Set mode of DumpPython(), \a historical or \a snapshot. - # In the \a historical mode, the Python Dump script includes all commands - # performed by SMESH engine. In the \a snapshot mode, commands - # relating to objects removed from the Study are excluded from the script - # as well as commands not influencing the current state of meshes + # In the \a historical mode, the Python Dump script includes all commands + # performed by SMESH engine. In the \a snapshot mode, commands + # relating to objects removed from the Study are excluded from the script + # as well as commands not influencing the current state of meshes + # @ingroup l1_auxiliary def SetDumpPythonHistorical(self, isHistorical): if isHistorical: val = "true" else: val = "false" SMESH._objref_SMESH_Gen.SetOption(self, "historical_python_dump", val) - ## Sets the current study and Geometry component + ## Set the current study and Geometry component # @ingroup l1_auxiliary def init_smesh(self,theStudy,geompyD = None): #print "init_smesh" @@ -398,7 +403,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): global notebook notebook.myStudy = theStudy - ## Creates a mesh. This can be either an empty mesh, possibly having an underlying geometry, + ## Create a mesh. This can be either an empty mesh, possibly having an underlying geometry, # or a mesh wrapping a CORBA mesh given as a parameter. # @param obj either (1) a CORBA mesh (SMESH._objref_SMESH_Mesh) got e.g. by calling # salome.myStudy.FindObjectID("0:1:2:3").GetObject() or @@ -412,15 +417,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): obj,name = name,obj return Mesh(self,self.geompyD,obj,name) - ## Returns a long value from enumeration - # @ingroup l1_controls + ## Return a long value from enumeration + # @ingroup l1_auxiliary def EnumToLong(self,theItem): return theItem._v - ## Returns a string representation of the color. + ## Return a string representation of the color. # To be used with filters. # @param c color value (SALOMEDS.Color) - # @ingroup l1_controls + # @ingroup l1_auxiliary def ColorToString(self,c): val = "" if isinstance(c, SALOMEDS.Color): @@ -431,7 +436,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): raise ValueError, "Color value should be of string or SALOMEDS.Color type" return val - ## Gets PointStruct from vertex + ## Get PointStruct from vertex # @param theVertex a GEOM object(vertex) # @return SMESH.PointStruct # @ingroup l1_auxiliary @@ -439,7 +444,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): [x, y, z] = self.geompyD.PointCoordinates(theVertex) return PointStruct(x,y,z) - ## Gets DirStruct from vector + ## Get DirStruct from vector # @param theVector a GEOM object(vector) # @return SMESH.DirStruct # @ingroup l1_auxiliary @@ -454,7 +459,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): dirst = DirStruct(pnt) return dirst - ## Makes DirStruct from a triplet + ## Make DirStruct from a triplet # @param x,y,z vector components # @return SMESH.DirStruct # @ingroup l1_auxiliary @@ -497,7 +502,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # From SMESH_Gen interface: # ------------------------ - ## Sets the given name to the object + ## Set the given name to the object # @param obj the object to rename # @param name a new object name # @ingroup l1_auxiliary @@ -509,17 +514,17 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): ior = salome.orb.object_to_string(obj) SMESH._objref_SMESH_Gen.SetName(self, ior, name) - ## Sets the current mode + ## Set the current mode # @ingroup l1_auxiliary def SetEmbeddedMode( self,theMode ): SMESH._objref_SMESH_Gen.SetEmbeddedMode(self,theMode) - ## Gets the current mode + ## Get the current mode # @ingroup l1_auxiliary def IsEmbeddedMode(self): return SMESH._objref_SMESH_Gen.IsEmbeddedMode(self) - ## Sets the current study. Calling SetCurrentStudy( None ) allows to + ## Set the current study. Calling SetCurrentStudy( None ) allows to # switch OFF automatic pubilishing in the Study of mesh objects. # @ingroup l1_auxiliary def SetCurrentStudy( self, theStudy, geompyD = None ): @@ -542,12 +547,12 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): pass pass - ## Gets the current study + ## Get the current study # @ingroup l1_auxiliary def GetCurrentStudy(self): return SMESH._objref_SMESH_Gen.GetCurrentStudy(self) - ## Creates a Mesh object importing data from the given UNV file + ## Create a Mesh object importing data from the given UNV file # @return an instance of Mesh class # @ingroup l2_impexp def CreateMeshesFromUNV( self,theFileName ): @@ -555,7 +560,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMesh = Mesh(self, self.geompyD, aSmeshMesh) return aMesh - ## Creates a Mesh object(s) importing data from the given MED file + ## Create a Mesh object(s) importing data from the given MED file # @return a tuple ( list of Mesh class instances, SMESH.DriverMED_ReadStatus ) # @ingroup l2_impexp def CreateMeshesFromMED( self,theFileName ): @@ -563,7 +568,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] return aMeshes, aStatus - ## Creates a Mesh object(s) importing data from the given SAUV file + ## Create a Mesh object(s) importing data from the given SAUV file # @return a tuple ( list of Mesh class instances, SMESH.DriverMED_ReadStatus ) # @ingroup l2_impexp def CreateMeshesFromSAUV( self,theFileName ): @@ -571,7 +576,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] return aMeshes, aStatus - ## Creates a Mesh object importing data from the given STL file + ## Create a Mesh object importing data from the given STL file # @return an instance of Mesh class # @ingroup l2_impexp def CreateMeshesFromSTL( self, theFileName ): @@ -579,7 +584,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMesh = Mesh(self, self.geompyD, aSmeshMesh) return aMesh - ## Creates Mesh objects importing data from the given CGNS file + ## Create Mesh objects importing data from the given CGNS file # @return a tuple ( list of Mesh class instances, SMESH.DriverMED_ReadStatus ) # @ingroup l2_impexp def CreateMeshesFromCGNS( self, theFileName ): @@ -587,7 +592,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] return aMeshes, aStatus - ## Creates a Mesh object importing data from the given GMF file. + ## Create a Mesh object importing data from the given GMF file. # GMF files must have .mesh extension for the ASCII format and .meshb for # the binary format. # @return [ an instance of Mesh class, SMESH.ComputeError ] @@ -608,7 +613,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # @param allGroups forces creation of groups corresponding to every input mesh # @param name name of a new mesh # @return an instance of Mesh class - # @ingroup l2_compounds + # @ingroup l1_creating def Concatenate( self, meshes, uniteIdenticalGroups, mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False, name = ""): @@ -635,29 +640,30 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # @param toCopyGroups to create in the new mesh groups the copied elements belongs to # @param toKeepIDs to preserve order of the copied elements or not # @return an instance of Mesh class + # @ingroup l1_creating def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): if (isinstance( meshPart, Mesh )): meshPart = meshPart.GetMesh() mesh = SMESH._objref_SMESH_Gen.CopyMesh( self,meshPart,meshName,toCopyGroups,toKeepIDs ) return Mesh(self, self.geompyD, mesh) - ## From SMESH_Gen interface + ## Return IDs of sub-shapes # @return the list of integer values # @ingroup l1_auxiliary def GetSubShapesId( self, theMainObject, theListOfSubObjects ): return SMESH._objref_SMESH_Gen.GetSubShapesId(self,theMainObject, theListOfSubObjects) - ## From SMESH_Gen interface. Creates a pattern + ## Create a pattern mapper. # @return an instance of SMESH_Pattern # # Example of Patterns usage - # @ingroup l2_modif_patterns + # @ingroup l1_modifying def GetPattern(self): return SMESH._objref_SMESH_Gen.GetPattern(self) - ## Sets number of segments per diagonal of boundary box of geometry by which - # default segment length of appropriate 1D hypotheses is defined. - # Default value is 10 + ## Set number of segments per diagonal of boundary box of geometry, by which + # default segment length of appropriate 1D hypotheses is defined in GUI. + # Default value is 10. # @ingroup l1_auxiliary def SetBoundaryBoxSegmentation(self, nbSegments): SMESH._objref_SMESH_Gen.SetBoundaryBoxSegmentation(self,nbSegments) @@ -665,7 +671,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # Filtering. Auxiliary functions: # ------------------------------ - ## Creates an empty criterion + ## Create an empty criterion # @return SMESH.Filter.Criterion # @ingroup l1_controls def GetEmptyCriterion(self): @@ -682,7 +688,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return Filter.Criterion(Type, Compare, Threshold, ThresholdStr, ThresholdID, UnaryOp, BinaryOp, Tolerance, TypeOfElement, Precision) - ## Creates a criterion by the given parameters + ## Create a criterion by the given parameters # \n Criterion structures allow to define complex filters by combining them with logical operations (AND / OR) (see example below) # @param elementType the type of elements(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) # @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.) @@ -870,7 +876,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return aCriterion - ## Creates a filter with the given parameters + ## Create a filter with the given parameters # @param elementType the type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) # @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.) # Type SMESH.FunctorType._items in the Python Console to see all values. @@ -904,7 +910,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aFilterMgr.UnRegister() return aFilter - ## Creates a filter from criteria + ## Create a filter from criteria # @param criteria a list of criteria # @param binOp binary operator used when binary operator of criteria is undefined # @return SMESH_Filter @@ -921,7 +927,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aFilterMgr.UnRegister() return aFilter - ## Creates a numerical functor by its type + ## Create a numerical functor by its type # @param theCriterion functor type - an item of SMESH.FunctorType enumeration. # Type SMESH.FunctorType._items in the Python Console to see all items. # Note that not all items correspond to numerical functors. @@ -969,7 +975,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aFilterMgr.UnRegister() return functor - ## Creates hypothesis + ## Create hypothesis # @param theHType mesh hypothesis type (string) # @param theLibName mesh plug-in library name # @return created hypothesis instance @@ -990,7 +996,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return hyp - ## Gets the mesh statistic + ## Get the mesh statistic # @return dictionary "element type" - "count of elements" # @ingroup l1_meshinfo def GetMeshInfo(self, obj): @@ -1203,7 +1209,7 @@ def New( study, instance=None): # It has a set of methods to build a mesh on the given geometry, including the definition of sub-meshes. # It also has methods to define groups of mesh elements, to modify a mesh (by addition of # new nodes and elements and by changing the existing entities), to get information -# about a mesh and to export a mesh into different formats. +# about a mesh and to export a mesh in different formats. class Mesh: __metaclass__ = MeshMeta @@ -1213,7 +1219,7 @@ class Mesh: ## Constructor # - # Creates a mesh on the shape \a obj (or an empty mesh if \a obj is equal to 0) and + # Create a mesh on the shape \a obj (or an empty mesh if \a obj is equal to 0) and # sets the GUI name of this mesh to \a name. # @param smeshpyD an instance of smeshBuilder class # @param geompyD an instance of geomBuilder class @@ -1275,7 +1281,7 @@ class Mesh: pass pass - ## Initializes the Mesh object from an instance of SMESH_Mesh interface + ## Initialize the Mesh object from an instance of SMESH_Mesh interface # @param theMesh a SMESH_Mesh object # @ingroup l2_construct def SetMesh(self, theMesh): @@ -1287,60 +1293,76 @@ class Mesh: self.geom = self.mesh.GetShapeToMesh() pass - ## Returns the mesh, that is an instance of SMESH_Mesh interface + ## Return the mesh, that is an instance of SMESH_Mesh interface # @return a SMESH_Mesh object # @ingroup l2_construct def GetMesh(self): return self.mesh - ## Gets the name of the mesh + ## Get the name of the mesh # @return the name of the mesh as a string # @ingroup l2_construct def GetName(self): name = GetName(self.GetMesh()) return name - ## Sets a name to the mesh + ## Set a name to the mesh # @param name a new name of the mesh # @ingroup l2_construct def SetName(self, name): self.smeshpyD.SetName(self.GetMesh(), name) - ## Gets the subMesh object associated to a \a theSubObject geometrical object. - # The subMesh object gives access to the IDs of nodes and elements. + ## Get a sub-mesh object associated to a \a geom geometrical object. # @param geom a geometrical object (shape) - # @param name a name for the submesh - # @return an object of type SMESH_SubMesh, representing a part of mesh, which lies on the given shape + # @param name a name for the sub-mesh in the Object Browser + # @return an object of type SMESH.SMESH_subMesh, representing a part of mesh, + # which lies on the given shape + # + # The sub-mesh object gives access to the IDs of nodes and elements. + # The sub-mesh object has the following methods: + # - SMESH.SMESH_subMesh.GetNumberOfElements() + # - SMESH.SMESH_subMesh.GetNumberOfNodes( all ) + # - SMESH.SMESH_subMesh.GetElementsId() + # - SMESH.SMESH_subMesh.GetElementsByType( ElementType ) + # - SMESH.SMESH_subMesh.GetNodesId() + # - SMESH.SMESH_subMesh.GetSubShape() + # - SMESH.SMESH_subMesh.GetFather() + # - SMESH.SMESH_subMesh.GetId() + # @note A sub-mesh is implicitly created when a sub-shape is specified at + # creating an algorithm, for example: algo1D = mesh.Segment(geom=Edge_1) + # creates a sub-mesh on @c Edge_1 and assign Wire Discretization algorithm to it. + # The created sub-mesh can be retrieved from the algorithm: + # submesh = algo1D.GetSubMesh() # @ingroup l2_submeshes def GetSubMesh(self, geom, name): AssureGeomPublished( self, geom, name ) submesh = self.mesh.GetSubMesh( geom, name ) return submesh - ## Returns the shape associated to the mesh + ## Return the shape associated to the mesh # @return a GEOM_Object # @ingroup l2_construct def GetShape(self): return self.geom - ## Associates the given shape to the mesh (entails the recreation of the mesh) + ## Associate the given shape to the mesh (entails the recreation of the mesh) # @param geom the shape to be meshed (GEOM_Object) # @ingroup l2_construct def SetShape(self, geom): self.mesh = self.smeshpyD.CreateMesh(geom) - ## Loads mesh from the study after opening the study + ## Load mesh from the study after opening the study def Load(self): self.mesh.Load() - ## Returns true if the hypotheses are defined well + ## Return true if the hypotheses are defined well # @param theSubObject a sub-shape of a mesh shape # @return True or False # @ingroup l2_construct def IsReadyToCompute(self, theSubObject): return self.smeshpyD.IsReadyToCompute(self.mesh, theSubObject) - ## Returns errors of hypotheses definition. + ## Return errors of hypotheses definition. # The list of errors is empty if everything is OK. # @param theSubObject a sub-shape of a mesh shape # @return a list of errors @@ -1348,20 +1370,20 @@ class Mesh: def GetAlgoState(self, theSubObject): return self.smeshpyD.GetAlgoState(self.mesh, theSubObject) - ## Returns a geometrical object on which the given element was built. + ## Return a geometrical object on which the given element was built. # The returned geometrical object, if not nil, is either found in the # study or published by this method with the given name # @param theElementID the id of the mesh element # @param theGeomName the user-defined name of the geometrical object # @return GEOM::GEOM_Object instance - # @ingroup l2_construct + # @ingroup l1_meshinfo def GetGeometryByMeshElement(self, theElementID, theGeomName): return self.smeshpyD.GetGeometryByMeshElement( self.mesh, theElementID, theGeomName ) - ## Returns the mesh dimension depending on the dimension of the underlying shape + ## Return the mesh dimension depending on the dimension of the underlying shape # or, if the mesh is not based on any shape, basing on deimension of elements # @return mesh dimension as an integer value [0,3] - # @ingroup l1_auxiliary + # @ingroup l1_meshinfo def MeshDimension(self): if self.mesh.HasShapeToMesh(): shells = self.geompyD.SubShapeAllIDs( self.geom, self.geompyD.ShapeType["SOLID"] ) @@ -1379,10 +1401,11 @@ class Mesh: if self.NbEdges() > 0: return 1 return 0 - ## Evaluates size of prospective mesh on a shape + ## Evaluate size of prospective mesh on a shape # @return a list where i-th element is a number of elements of i-th SMESH.EntityType # To know predicted number of e.g. edges, inquire it this way # Evaluate()[ EnumToLong( Entity_Edge )] + # @ingroup l2_construct def Evaluate(self, geom=0): if geom == 0 or not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object): if self.geom == 0: @@ -1392,7 +1415,7 @@ class Mesh: return self.smeshpyD.Evaluate(self.mesh, geom) - ## Computes the mesh and returns the status of the computation + ## Compute the mesh and return the status of the computation # @param geom geomtrical shape on which mesh data should be computed # @param discardModifs if True and the mesh has been edited since # a last total re-compute and that may prevent successful partial re-compute, @@ -1446,7 +1469,7 @@ class Mesh: errText = "code %s" % -err.code if errText: errText += ". " errText += err.comment - if allReasons != "":allReasons += "\n" + if allReasons: allReasons += "\n" if ok: allReasons += '- "%s"%s - %s' %(err.algoName, shapeText, errText) else: @@ -1484,7 +1507,7 @@ class Mesh: reason = ("For unknown reason. " "Developer, revise Mesh.Compute() implementation in smeshBuilder.py!") pass - if allReasons != "":allReasons += "\n" + if allReasons: allReasons += "\n" allReasons += "- " + reason pass if not ok or allReasons != "": @@ -1506,6 +1529,7 @@ class Mesh: return ok ## Return a list of error messages (SMESH.ComputeError) of the last Compute() + # @ingroup l2_construct def GetComputeErrors(self, shape=0 ): if shape == 0: shape = self.mesh.GetShapeToMesh() @@ -1518,6 +1542,7 @@ class Mesh: # - FACE #3 (not published sub-shape) # - sub-shape #3 (invalid sub-shape ID) # - #3 (error in this function) + # @ingroup l1_auxiliary def GetSubShapeName(self, subShapeID ): if not self.mesh.HasShapeToMesh(): return "" @@ -1560,6 +1585,7 @@ class Mesh: # error of an algorithm # @param publish if @c True, the returned groups will be published in the study # @return a list of GEOM groups each named after a failed algorithm + # @ingroup l2_construct def GetFailedShapes(self, publish=False): algo2shapes = {} @@ -1604,13 +1630,13 @@ class Mesh: def GetMeshOrder(self): return self.mesh.GetMeshOrder() - ## Set order in which concurrent sub-meshes sould be meshed + ## Set order in which concurrent sub-meshes should be meshed # @param submeshes list of lists of sub-meshes # @ingroup l2_construct def SetMeshOrder(self, submeshes): return self.mesh.SetMeshOrder(submeshes) - ## Removes all nodes and elements + ## Remove all nodes and elements generated on geometry. Imported elements remain. # @param refresh if @c True, Object browser is automatically updated (when running in GUI) # @ingroup l2_construct def Clear(self, refresh=False): @@ -1622,10 +1648,10 @@ class Mesh: smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) if refresh: salome.sg.updateObjBrowser(True) - ## Removes all nodes and elements of indicated shape + ## Remove all nodes and elements of indicated shape # @param refresh if @c True, Object browser is automatically updated (when running in GUI) # @param geomId the ID of a sub-shape to remove elements on - # @ingroup l2_construct + # @ingroup l2_submeshes def ClearSubMesh(self, geomId, refresh=False): self.mesh.ClearSubMesh(geomId) if salome.sg.hasDesktop(): @@ -1634,7 +1660,7 @@ class Mesh: smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) if refresh: salome.sg.updateObjBrowser(True) - ## Computes a tetrahedral mesh using AutomaticLength + MEFISTO + Tetrahedron + ## Compute a tetrahedral mesh using AutomaticLength + MEFISTO + Tetrahedron # @param fineness [0.0,1.0] defines mesh fineness # @return True or False # @ingroup l3_algos_basic @@ -1651,7 +1677,7 @@ class Mesh: pass return self.Compute() - ## Computes an hexahedral mesh using AutomaticLength + Quadrangle + Hexahedron + ## Compute an hexahedral mesh using AutomaticLength + Quadrangle + Hexahedron # @param fineness [0.0, 1.0] defines mesh fineness # @return True or False # @ingroup l3_algos_basic @@ -1668,11 +1694,11 @@ class Mesh: pass return self.Compute() - ## Assigns a hypothesis + ## Assign a hypothesis # @param hyp a hypothesis to assign # @param geom a subhape of mesh geometry # @return SMESH.Hypothesis_Status - # @ingroup l2_hypotheses + # @ingroup l2_editing def AddHypothesis(self, hyp, geom=0): if isinstance( hyp, geomBuilder.GEOM._objref_GEOM_Object ): hyp, geom = geom, hyp @@ -1710,7 +1736,7 @@ class Mesh: # @param hyp a hypothesis to check # @param geom a subhape of mesh geometry # @return True of False - # @ingroup l2_hypotheses + # @ingroup l2_editing def IsUsedHypothesis(self, hyp, geom): if not hyp: # or not geom return False @@ -1723,11 +1749,11 @@ class Mesh: return True return False - ## Unassigns a hypothesis + ## Unassign a hypothesis # @param hyp a hypothesis to unassign # @param geom a sub-shape of mesh geometry # @return SMESH.Hypothesis_Status - # @ingroup l2_hypotheses + # @ingroup l2_editing def RemoveHypothesis(self, hyp, geom=0): if not hyp: return None @@ -1745,15 +1771,15 @@ class Mesh: print "WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName ) return None - ## Gets the list of hypotheses added on a geometry + ## Get the list of hypotheses added on a geometry # @param geom a sub-shape of mesh geometry # @return the sequence of SMESH_Hypothesis - # @ingroup l2_hypotheses + # @ingroup l2_editing def GetHypothesisList(self, geom): return self.mesh.GetHypothesisList( geom ) - ## Removes all global hypotheses - # @ingroup l2_hypotheses + ## Remove all global hypotheses + # @ingroup l2_editing def RemoveGlobalHypotheses(self): current_hyps = self.mesh.GetHypothesisList( self.geom ) for hyp in current_hyps: @@ -1761,27 +1787,29 @@ class Mesh: pass pass - ## Exports the mesh in a file in MED format and chooses the \a version of MED format + ## Export the mesh in a file in MED format ## allowing to overwrite the file if it exists or add the exported data to its contents # @param f is the file name # @param auto_groups boolean parameter for creating/not creating # the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; - # the typical use is auto_groups=false. - # @param version MED format version(MED_V2_1 or MED_V2_2) + # the typical use is auto_groups=False. + # @param version MED format version (MED_V2_1 or MED_V2_2, + # the latter meaning any current version). The parameter is + # obsolete since MED_V2_1 is no longer supported. # @param overwrite boolean parameter for overwriting/not overwriting the file # @param meshPart a part of mesh (group, sub-mesh) to export instead of the mesh - # @param autoDimension: if @c True (default), a space dimension of a MED mesh can be either + # @param autoDimension if @c True (default), a space dimension of a MED mesh can be either # - 1D if all mesh nodes lie on OX coordinate axis, or # - 2D if all mesh nodes lie on XOY coordinate plane, or - # - 3D in the rest cases. + # - 3D in the rest cases.
# If @a autoDimension is @c False, the space dimension is always 3. - # @param fields : list of GEOM fields defined on the shape to mesh. - # @param geomAssocFields : each character of this string means a need to export a + # @param fields list of GEOM fields defined on the shape to mesh. + # @param geomAssocFields each character of this string means a need to export a # corresponding field; correspondence between fields and characters is following: - # - 'v' stands for _vertices_ field; - # - 'e' stands for _edges_ field; - # - 'f' stands for _faces_ field; - # - 's' stands for _solids_ field. + # - 'v' stands for "_vertices _" field; + # - 'e' stands for "_edges _" field; + # - 'f' stands for "_faces _" field; + # - 's' stands for "_solids _" field. # @ingroup l2_impexp def ExportMED(self, f, auto_groups=0, version=MED_V2_2, overwrite=1, meshPart=None, autoDimension=True, fields=[], geomAssocFields=''): @@ -1795,7 +1823,7 @@ class Mesh: else: self.mesh.ExportToMEDX(f, auto_groups, version, overwrite, autoDimension) - ## Exports the mesh in a file in SAUV format + ## Export the mesh in a file in SAUV format # @param f is the file name # @param auto_groups boolean parameter for creating/not creating # the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; @@ -1804,7 +1832,7 @@ class Mesh: def ExportSAUV(self, f, auto_groups=0): self.mesh.ExportSAUV(f, auto_groups) - ## Exports the mesh in a file in DAT format + ## Export the mesh in a file in DAT format # @param f the file name # @param meshPart a part of mesh (group, sub-mesh) to export instead of the mesh # @ingroup l2_impexp @@ -1818,7 +1846,7 @@ class Mesh: else: self.mesh.ExportDAT(f) - ## Exports the mesh in a file in UNV format + ## Export the mesh in a file in UNV format # @param f the file name # @param meshPart a part of mesh (group, sub-mesh) to export instead of the mesh # @ingroup l2_impexp @@ -1847,12 +1875,15 @@ class Mesh: else: self.mesh.ExportSTL(f, ascii) - ## Exports the mesh in a file in CGNS format + ## Export the mesh in a file in CGNS format # @param f is the file name # @param overwrite boolean parameter for overwriting/not overwriting the file # @param meshPart a part of mesh (group, sub-mesh) to export instead of the mesh + # @param groupElemsByType if true all elements of same entity type are exported at ones, + # else elements are exported in order of their IDs which can cause creation + # of multiple cgns sections # @ingroup l2_impexp - def ExportCGNS(self, f, overwrite=1, meshPart=None): + def ExportCGNS(self, f, overwrite=1, meshPart=None, groupElemsByType=False): unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) @@ -1861,9 +1892,9 @@ class Mesh: meshPart = meshPart.mesh elif not meshPart: meshPart = self.mesh - self.mesh.ExportCGNS(meshPart, f, overwrite) + self.mesh.ExportCGNS(meshPart, f, overwrite, groupElemsByType) - ## Exports the mesh in a file in GMF format. + ## Export the mesh in a file in GMF format. # GMF files must have .mesh extension for the ASCII format and .meshb for # the bynary format. Other extensions are not allowed. # @param f is the file name @@ -1880,28 +1911,29 @@ class Mesh: meshPart = self.mesh self.mesh.ExportGMF(meshPart, f, True) - ## Deprecated, used only for compatibility! Please, use ExportToMEDX() method instead. - # Exports the mesh in a file in MED format and chooses the \a version of MED format - ## allowing to overwrite the file if it exists or add the exported data to its contents + ## Deprecated, used only for compatibility! Please, use ExportMED() method instead. + # Export the mesh in a file in MED format + # allowing to overwrite the file if it exists or add the exported data to its contents # @param f the file name - # @param version values are SMESH.MED_V2_1, SMESH.MED_V2_2 + # @param version MED format version (MED_V2_1 or MED_V2_2, + # the latter meaning any current version). The parameter is + # obsolete since MED_V2_1 is no longer supported. # @param opt boolean parameter for creating/not creating # the groups Group_On_All_Nodes, Group_On_All_Faces, ... # @param overwrite boolean parameter for overwriting/not overwriting the file - # @param autoDimension: if @c True (default), a space dimension of a MED mesh can be either + # @param autoDimension if @c True (default), a space dimension of a MED mesh can be either # - 1D if all mesh nodes lie on OX coordinate axis, or # - 2D if all mesh nodes lie on XOY coordinate plane, or - # - 3D in the rest cases. - # + # - 3D in the rest cases.
# If @a autoDimension is @c False, the space dimension is always 3. # @ingroup l2_impexp - def ExportToMED(self, f, version, opt=0, overwrite=1, autoDimension=True): + def ExportToMED(self, f, version=MED_V2_2, opt=0, overwrite=1, autoDimension=True): self.mesh.ExportToMEDX(f, opt, version, overwrite, autoDimension) # Operations with groups: # ---------------------- - ## Creates an empty mesh group + ## Create an empty mesh group # @param elementType the type of elements in the group; either of # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) # @param name the name of the mesh group @@ -1910,7 +1942,7 @@ class Mesh: def CreateEmptyGroup(self, elementType, name): return self.mesh.CreateGroup(elementType, name) - ## Creates a mesh group based on the geometric object \a grp + ## Create a mesh group based on the geometric object \a grp # and gives a \a name, \n if this parameter is not defined # the name is the same as the geometric group name \n # Note: Works like GroupOnGeom(). @@ -1921,7 +1953,7 @@ class Mesh: def Group(self, grp, name=""): return self.GroupOnGeom(grp, name) - ## Creates a mesh group based on the geometrical object \a grp + ## Create a mesh group based on the geometrical object \a grp # and gives a \a name, \n if this parameter is not defined # the name is the same as the geometrical group name # @param grp a geometrical group, a vertex, an edge, a face or a solid @@ -1960,7 +1992,7 @@ class Mesh: "_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape) return typ - ## Creates a mesh group with given \a name based on the \a filter which + ## Create a mesh group with given \a name based on the \a filter which ## is a special type of group dynamically updating it's contents during ## mesh modification # @param typ the type of elements in the group; either of @@ -1972,7 +2004,7 @@ class Mesh: def GroupOnFilter(self, typ, name, filter): return self.mesh.CreateGroupFromFilter(typ, name, filter) - ## Creates a mesh group by the given ids of elements + ## Create a mesh group by the given ids of elements # @param groupName the name of the mesh group # @param elementType the type of elements in the group; either of # (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). @@ -1981,6 +2013,8 @@ class Mesh: # @ingroup l2_grps_create def MakeGroupByIds(self, groupName, elementType, elemIDs): group = self.mesh.CreateGroup(elementType, groupName) + if isinstance( elemIDs, Mesh ): + elemIDs = elemIDs.GetMesh() if hasattr( elemIDs, "GetIDs" ): if hasattr( elemIDs, "SetMesh" ): elemIDs.SetMesh( self.GetMesh() ) @@ -1989,7 +2023,7 @@ class Mesh: group.Add(elemIDs) return group - ## Creates a mesh group by the given conditions + ## Create a mesh group by the given conditions # @param groupName the name of the mesh group # @param elementType the type of elements(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) # @param CritType the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.) @@ -2014,7 +2048,7 @@ class Mesh: group = self.MakeGroupByCriterion(groupName, aCriterion) return group - ## Creates a mesh group by the given criterion + ## Create a mesh group by the given criterion # @param groupName the name of the mesh group # @param Criterion the instance of Criterion class # @return SMESH_GroupOnFilter @@ -2022,7 +2056,7 @@ class Mesh: def MakeGroupByCriterion(self, groupName, Criterion): return self.MakeGroupByCriteria( groupName, [Criterion] ) - ## Creates a mesh group by the given criteria (list of criteria) + ## Create a mesh group by the given criteria (list of criteria) # @param groupName the name of the mesh group # @param theCriteria the list of criteria # @param binOp binary operator used when binary operator of criteria is undefined @@ -2033,7 +2067,7 @@ class Mesh: group = self.MakeGroupByFilter(groupName, aFilter) return group - ## Creates a mesh group by the given filter + ## Create a mesh group by the given filter # @param groupName the name of the mesh group # @param theFilter the instance of Filter class # @return SMESH_GroupOnFilter @@ -2045,17 +2079,17 @@ class Mesh: group = self.GroupOnFilter( theFilter.GetElementType(), groupName, theFilter ) return group - ## Removes a group + ## Remove a group # @ingroup l2_grps_delete def RemoveGroup(self, group): self.mesh.RemoveGroup(group) - ## Removes a group with its contents + ## Remove a group with its contents # @ingroup l2_grps_delete def RemoveGroupWithContents(self, group): self.mesh.RemoveGroupWithContents(group) - ## Gets the list of groups existing in the mesh in the order + ## Get the list of groups existing in the mesh in the order # of creation (starting from the oldest one) # @param elemType type of elements the groups contain; either of # (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); @@ -2074,13 +2108,13 @@ class Mesh: pass return typedGroups - ## Gets the number of groups existing in the mesh + ## Get the number of groups existing in the mesh # @return the quantity of groups as an integer value # @ingroup l2_grps_create def NbGroups(self): return self.mesh.NbGroups() - ## Gets the list of names of groups existing in the mesh + ## Get the list of names of groups existing in the mesh # @return list of strings # @ingroup l2_grps_create def GetGroupNames(self): @@ -2090,7 +2124,7 @@ class Mesh: names.append(group.GetName()) return names - ## Finds groups by name and type + ## Find groups by name and type # @param name name of the group of interest # @param elemType type of elements the groups contain; either of # (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME); @@ -2109,7 +2143,7 @@ class Mesh: groups.append( group ) return groups - ## Produces a union of two groups. + ## Produce a union of two groups. # A new group is created. All mesh elements that are # present in the initial groups are added to the new one # @return an instance of SMESH_Group @@ -2117,7 +2151,7 @@ class Mesh: def UnionGroups(self, group1, group2, name): return self.mesh.UnionGroups(group1, group2, name) - ## Produces a union list of groups. + ## Produce a union list of groups. # New group is created. All mesh elements that are present in # initial groups are added to the new one # @return an instance of SMESH_Group @@ -2125,7 +2159,7 @@ class Mesh: def UnionListOfGroups(self, groups, name): return self.mesh.UnionListOfGroups(groups, name) - ## Prodices an intersection of two groups. + ## Prodice an intersection of two groups. # A new group is created. All mesh elements that are common # for the two initial groups are added to the new one. # @return an instance of SMESH_Group @@ -2133,7 +2167,7 @@ class Mesh: def IntersectGroups(self, group1, group2, name): return self.mesh.IntersectGroups(group1, group2, name) - ## Produces an intersection of groups. + ## Produce an intersection of groups. # New group is created. All mesh elements that are present in all # initial groups simultaneously are added to the new one # @return an instance of SMESH_Group @@ -2141,7 +2175,7 @@ class Mesh: def IntersectListOfGroups(self, groups, name): return self.mesh.IntersectListOfGroups(groups, name) - ## Produces a cut of two groups. + ## Produce a cut of two groups. # A new group is created. All mesh elements that are present in # the main group but are not present in the tool group are added to the new one # @return an instance of SMESH_Group @@ -2149,7 +2183,7 @@ class Mesh: def CutGroups(self, main_group, tool_group, name): return self.mesh.CutGroups(main_group, tool_group, name) - ## Produces a cut of groups. + ## Produce a cut of groups. # A new group is created. All mesh elements that are present in main groups # but do not present in tool groups are added to the new one # @return an instance of SMESH_Group @@ -2185,14 +2219,14 @@ class Mesh: ## Convert group on geom into standalone group - # @ingroup l2_grps_edit + # @ingroup l2_grps_operon def ConvertToStandalone(self, group): return self.mesh.ConvertToStandalone(group) # Get some info about mesh: # ------------------------ - ## Returns the log of nodes and elements added or removed + ## Return the log of nodes and elements added or removed # since the previous clear of the log. # @param clearAfterGet log is emptied after Get (safe if concurrents access) # @return list of log_block structures: @@ -2204,25 +2238,27 @@ class Mesh: def GetLog(self, clearAfterGet): return self.mesh.GetLog(clearAfterGet) - ## Clears the log of nodes and elements added or removed since the previous + ## Clear the log of nodes and elements added or removed since the previous # clear. Must be used immediately after GetLog if clearAfterGet is false. # @ingroup l1_auxiliary def ClearLog(self): self.mesh.ClearLog() - ## Toggles auto color mode on the object. + ## Toggle auto color mode on the object. # @param theAutoColor the flag which toggles auto color mode. - # @ingroup l1_auxiliary + # + # If switched on, a default color of a new group in Create Group dialog is chosen randomly. + # @ingroup l1_grouping def SetAutoColor(self, theAutoColor): self.mesh.SetAutoColor(theAutoColor) - ## Gets flag of object auto color mode. + ## Get flag of object auto color mode. # @return True or False - # @ingroup l1_auxiliary + # @ingroup l1_grouping def GetAutoColor(self): return self.mesh.GetAutoColor() - ## Gets the internal ID + ## Get the internal ID # @return integer value, which is the internal Id of the mesh # @ingroup l1_auxiliary def GetId(self): @@ -2234,14 +2270,14 @@ class Mesh: def GetStudyId(self): return self.mesh.GetStudyId() - ## Checks the group names for duplications. + ## Check the group names for duplications. # Consider the maximum group name length stored in MED file. # @return True or False - # @ingroup l1_auxiliary + # @ingroup l1_grouping def HasDuplicatedGroupNamesMED(self): return self.mesh.HasDuplicatedGroupNamesMED() - ## Obtains the mesh editor tool + ## Obtain the mesh editor tool # @return an instance of SMESH_MeshEditor # @ingroup l1_modifying def GetMeshEditor(self): @@ -2268,44 +2304,44 @@ class Mesh: # Get informations about mesh contents: # ------------------------------------ - ## Gets the mesh stattistic + ## Get the mesh stattistic # @return dictionary type element - count of elements # @ingroup l1_meshinfo def GetMeshInfo(self, obj = None): if not obj: obj = self.mesh return self.smeshpyD.GetMeshInfo(obj) - ## Returns the number of nodes in the mesh + ## Return the number of nodes in the mesh # @return an integer value # @ingroup l1_meshinfo def NbNodes(self): return self.mesh.NbNodes() - ## Returns the number of elements in the mesh + ## Return the number of elements in the mesh # @return an integer value # @ingroup l1_meshinfo def NbElements(self): return self.mesh.NbElements() - ## Returns the number of 0d elements in the mesh + ## Return the number of 0d elements in the mesh # @return an integer value # @ingroup l1_meshinfo def Nb0DElements(self): return self.mesh.Nb0DElements() - ## Returns the number of ball discrete elements in the mesh + ## Return the number of ball discrete elements in the mesh # @return an integer value # @ingroup l1_meshinfo def NbBalls(self): return self.mesh.NbBalls() - ## Returns the number of edges in the mesh + ## Return the number of edges in the mesh # @return an integer value # @ingroup l1_meshinfo def NbEdges(self): return self.mesh.NbEdges() - ## Returns the number of edges with the given order in the mesh + ## Return the number of edges with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2313,13 +2349,13 @@ class Mesh: def NbEdgesOfOrder(self, elementOrder): return self.mesh.NbEdgesOfOrder(elementOrder) - ## Returns the number of faces in the mesh + ## Return the number of faces in the mesh # @return an integer value # @ingroup l1_meshinfo def NbFaces(self): return self.mesh.NbFaces() - ## Returns the number of faces with the given order in the mesh + ## Return the number of faces with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2327,13 +2363,13 @@ class Mesh: def NbFacesOfOrder(self, elementOrder): return self.mesh.NbFacesOfOrder(elementOrder) - ## Returns the number of triangles in the mesh + ## Return the number of triangles in the mesh # @return an integer value # @ingroup l1_meshinfo def NbTriangles(self): return self.mesh.NbTriangles() - ## Returns the number of triangles with the given order in the mesh + ## Return the number of triangles with the given order in the mesh # @param elementOrder is the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2341,19 +2377,19 @@ class Mesh: def NbTrianglesOfOrder(self, elementOrder): return self.mesh.NbTrianglesOfOrder(elementOrder) - ## Returns the number of biquadratic triangles in the mesh + ## Return the number of biquadratic triangles in the mesh # @return an integer value # @ingroup l1_meshinfo def NbBiQuadTriangles(self): return self.mesh.NbBiQuadTriangles() - ## Returns the number of quadrangles in the mesh + ## Return the number of quadrangles in the mesh # @return an integer value # @ingroup l1_meshinfo def NbQuadrangles(self): return self.mesh.NbQuadrangles() - ## Returns the number of quadrangles with the given order in the mesh + ## Return the number of quadrangles with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2361,13 +2397,13 @@ class Mesh: def NbQuadranglesOfOrder(self, elementOrder): return self.mesh.NbQuadranglesOfOrder(elementOrder) - ## Returns the number of biquadratic quadrangles in the mesh + ## Return the number of biquadratic quadrangles in the mesh # @return an integer value # @ingroup l1_meshinfo def NbBiQuadQuadrangles(self): return self.mesh.NbBiQuadQuadrangles() - ## Returns the number of polygons of given order in the mesh + ## Return the number of polygons of given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2375,13 +2411,13 @@ class Mesh: def NbPolygons(self, elementOrder = SMESH.ORDER_ANY): return self.mesh.NbPolygonsOfOrder(elementOrder) - ## Returns the number of volumes in the mesh + ## Return the number of volumes in the mesh # @return an integer value # @ingroup l1_meshinfo def NbVolumes(self): return self.mesh.NbVolumes() - ## Returns the number of volumes with the given order in the mesh + ## Return the number of volumes with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2389,13 +2425,13 @@ class Mesh: def NbVolumesOfOrder(self, elementOrder): return self.mesh.NbVolumesOfOrder(elementOrder) - ## Returns the number of tetrahedrons in the mesh + ## Return the number of tetrahedrons in the mesh # @return an integer value # @ingroup l1_meshinfo def NbTetras(self): return self.mesh.NbTetras() - ## Returns the number of tetrahedrons with the given order in the mesh + ## Return the number of tetrahedrons with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2403,13 +2439,13 @@ class Mesh: def NbTetrasOfOrder(self, elementOrder): return self.mesh.NbTetrasOfOrder(elementOrder) - ## Returns the number of hexahedrons in the mesh + ## Return the number of hexahedrons in the mesh # @return an integer value # @ingroup l1_meshinfo def NbHexas(self): return self.mesh.NbHexas() - ## Returns the number of hexahedrons with the given order in the mesh + ## Return the number of hexahedrons with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2417,19 +2453,19 @@ class Mesh: def NbHexasOfOrder(self, elementOrder): return self.mesh.NbHexasOfOrder(elementOrder) - ## Returns the number of triquadratic hexahedrons in the mesh + ## Return the number of triquadratic hexahedrons in the mesh # @return an integer value # @ingroup l1_meshinfo def NbTriQuadraticHexas(self): return self.mesh.NbTriQuadraticHexas() - ## Returns the number of pyramids in the mesh + ## Return the number of pyramids in the mesh # @return an integer value # @ingroup l1_meshinfo def NbPyramids(self): return self.mesh.NbPyramids() - ## Returns the number of pyramids with the given order in the mesh + ## Return the number of pyramids with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2437,13 +2473,13 @@ class Mesh: def NbPyramidsOfOrder(self, elementOrder): return self.mesh.NbPyramidsOfOrder(elementOrder) - ## Returns the number of prisms in the mesh + ## Return the number of prisms in the mesh # @return an integer value # @ingroup l1_meshinfo def NbPrisms(self): return self.mesh.NbPrisms() - ## Returns the number of prisms with the given order in the mesh + ## Return the number of prisms with the given order in the mesh # @param elementOrder the order of elements: # SMESH.ORDER_ANY, SMESH.ORDER_LINEAR or SMESH.ORDER_QUADRATIC # @return an integer value @@ -2451,31 +2487,31 @@ class Mesh: def NbPrismsOfOrder(self, elementOrder): return self.mesh.NbPrismsOfOrder(elementOrder) - ## Returns the number of hexagonal prisms in the mesh + ## Return the number of hexagonal prisms in the mesh # @return an integer value # @ingroup l1_meshinfo def NbHexagonalPrisms(self): return self.mesh.NbHexagonalPrisms() - ## Returns the number of polyhedrons in the mesh + ## Return the number of polyhedrons in the mesh # @return an integer value # @ingroup l1_meshinfo def NbPolyhedrons(self): return self.mesh.NbPolyhedrons() - ## Returns the number of submeshes in the mesh + ## Return the number of submeshes in the mesh # @return an integer value # @ingroup l1_meshinfo def NbSubMesh(self): return self.mesh.NbSubMesh() - ## Returns the list of mesh elements IDs + ## Return the list of mesh elements IDs # @return the list of integer values # @ingroup l1_meshinfo def GetElementsId(self): return self.mesh.GetElementsId() - ## Returns the list of IDs of mesh elements with the given type + ## Return the list of IDs of mesh elements with the given type # @param elementType the required type of elements, either of # (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) # @return list of integer values @@ -2483,7 +2519,7 @@ class Mesh: def GetElementsByType(self, elementType): return self.mesh.GetElementsByType(elementType) - ## Returns the list of mesh nodes IDs + ## Return the list of mesh nodes IDs # @return the list of integer values # @ingroup l1_meshinfo def GetNodesId(self): @@ -2492,28 +2528,28 @@ class Mesh: # Get the information about mesh elements: # ------------------------------------ - ## Returns the type of mesh element + ## Return the type of mesh element # @return the value from SMESH::ElementType enumeration # Type SMESH.ElementType._items in the Python Console to see all possible values. # @ingroup l1_meshinfo def GetElementType(self, id, iselem=True): return self.mesh.GetElementType(id, iselem) - ## Returns the geometric type of mesh element + ## Return the geometric type of mesh element # @return the value from SMESH::EntityType enumeration # Type SMESH.EntityType._items in the Python Console to see all possible values. # @ingroup l1_meshinfo def GetElementGeomType(self, id): return self.mesh.GetElementGeomType(id) - ## Returns the shape type of mesh element + ## Return the shape type of mesh element # @return the value from SMESH::GeometryType enumeration. # Type SMESH.GeometryType._items in the Python Console to see all possible values. # @ingroup l1_meshinfo def GetElementShape(self, id): return self.mesh.GetElementShape(id) - ## Returns the list of submesh elements IDs + ## Return the list of submesh elements IDs # @param Shape a geom object(sub-shape) # Shape must be the sub-shape of a ShapeToMesh() # @return the list of integer values @@ -2525,7 +2561,7 @@ class Mesh: ShapeID = Shape return self.mesh.GetSubMeshElementsId(ShapeID) - ## Returns the list of submesh nodes IDs + ## Return the list of submesh nodes IDs # @param Shape a geom object(sub-shape) # Shape must be the sub-shape of a ShapeToMesh() # @param all If true, gives all nodes of submesh elements, otherwise gives only submesh nodes @@ -2538,7 +2574,7 @@ class Mesh: ShapeID = Shape return self.mesh.GetSubMeshNodesId(ShapeID, all) - ## Returns type of elements on given shape + ## Return type of elements on given shape # @param Shape a geom object(sub-shape) # Shape must be a sub-shape of a ShapeToMesh() # @return element type @@ -2550,7 +2586,7 @@ class Mesh: ShapeID = Shape return self.mesh.GetSubMeshElementType(ShapeID) - ## Gets the mesh description + ## Get the mesh description # @return string value # @ingroup l1_meshinfo def Dump(self): @@ -2560,72 +2596,72 @@ class Mesh: # Get the information about nodes and elements of a mesh by its IDs: # ----------------------------------------------------------- - ## Gets XYZ coordinates of a node - # \n If there is no nodes for the given ID - returns an empty list + ## Get XYZ coordinates of a node + # \n If there is no nodes for the given ID - return an empty list # @return a list of double precision values # @ingroup l1_meshinfo def GetNodeXYZ(self, id): return self.mesh.GetNodeXYZ(id) - ## Returns list of IDs of inverse elements for the given node - # \n If there is no node for the given ID - returns an empty list + ## Return list of IDs of inverse elements for the given node + # \n If there is no node for the given ID - return an empty list # @return a list of integer values # @ingroup l1_meshinfo def GetNodeInverseElements(self, id): return self.mesh.GetNodeInverseElements(id) - ## @brief Returns the position of a node on the shape + ## Return the position of a node on the shape # @return SMESH::NodePosition # @ingroup l1_meshinfo def GetNodePosition(self,NodeID): return self.mesh.GetNodePosition(NodeID) - ## @brief Returns the position of an element on the shape + ## Return the position of an element on the shape # @return SMESH::ElementPosition # @ingroup l1_meshinfo def GetElementPosition(self,ElemID): return self.mesh.GetElementPosition(ElemID) - ## Returns the ID of the shape, on which the given node was generated. + ## Return the ID of the shape, on which the given node was generated. # @return an integer value > 0 or -1 if there is no node for the given # ID or the node is not assigned to any geometry # @ingroup l1_meshinfo def GetShapeID(self, id): return self.mesh.GetShapeID(id) - ## Returns the ID of the shape, on which the given element was generated. + ## Return the ID of the shape, on which the given element was generated. # @return an integer value > 0 or -1 if there is no element for the given # ID or the element is not assigned to any geometry # @ingroup l1_meshinfo def GetShapeIDForElem(self,id): return self.mesh.GetShapeIDForElem(id) - ## Returns the number of nodes of the given element + ## Return the number of nodes of the given element # @return an integer value > 0 or -1 if there is no element for the given ID # @ingroup l1_meshinfo def GetElemNbNodes(self, id): return self.mesh.GetElemNbNodes(id) - ## Returns the node ID the given (zero based) index for the given element - # \n If there is no element for the given ID - returns -1 - # \n If there is no node for the given index - returns -2 + ## Return the node ID the given (zero based) index for the given element + # \n If there is no element for the given ID - return -1 + # \n If there is no node for the given index - return -2 # @return an integer value # @ingroup l1_meshinfo def GetElemNode(self, id, index): return self.mesh.GetElemNode(id, index) - ## Returns the IDs of nodes of the given element + ## Return the IDs of nodes of the given element # @return a list of integer values # @ingroup l1_meshinfo def GetElemNodes(self, id): return self.mesh.GetElemNodes(id) - ## Returns true if the given node is the medium node in the given quadratic element + ## Return true if the given node is the medium node in the given quadratic element # @ingroup l1_meshinfo def IsMediumNode(self, elementID, nodeID): return self.mesh.IsMediumNode(elementID, nodeID) - ## Returns true if the given node is the medium node in one of quadratic elements + ## Return true if the given node is the medium node in one of quadratic elements # @param nodeID ID of the node # @param elementType the type of elements to check a state of the node, either of # (SMESH.ALL, SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) @@ -2633,55 +2669,60 @@ class Mesh: def IsMediumNodeOfAnyElem(self, nodeID, elementType = SMESH.ALL ): return self.mesh.IsMediumNodeOfAnyElem(nodeID, elementType) - ## Returns the number of edges for the given element + ## Return the number of edges for the given element # @ingroup l1_meshinfo def ElemNbEdges(self, id): return self.mesh.ElemNbEdges(id) - ## Returns the number of faces for the given element + ## Return the number of faces for the given element # @ingroup l1_meshinfo def ElemNbFaces(self, id): return self.mesh.ElemNbFaces(id) - ## Returns nodes of given face (counted from zero) for given volumic element. + ## Return nodes of given face (counted from zero) for given volumic element. # @ingroup l1_meshinfo def GetElemFaceNodes(self,elemId, faceIndex): return self.mesh.GetElemFaceNodes(elemId, faceIndex) - ## Returns three components of normal of given mesh face + ## Return three components of normal of given mesh face # (or an empty array in KO case) # @ingroup l1_meshinfo def GetFaceNormal(self, faceId, normalized=False): return self.mesh.GetFaceNormal(faceId,normalized) - ## Returns an element based on all given nodes. + ## Return an element based on all given nodes. # @ingroup l1_meshinfo - def FindElementByNodes(self,nodes): + def FindElementByNodes(self, nodes): return self.mesh.FindElementByNodes(nodes) - ## Returns true if the given element is a polygon + ## Return elements including all given nodes. + # @ingroup l1_meshinfo + def GetElementsByNodes(self, nodes, elemType=SMESH.ALL): + return self.mesh.GetElementsByNodes( nodes, elemType ) + + ## Return true if the given element is a polygon # @ingroup l1_meshinfo def IsPoly(self, id): return self.mesh.IsPoly(id) - ## Returns true if the given element is quadratic + ## Return true if the given element is quadratic # @ingroup l1_meshinfo def IsQuadratic(self, id): return self.mesh.IsQuadratic(id) - ## Returns diameter of a ball discrete element or zero in case of an invalid \a id + ## Return diameter of a ball discrete element or zero in case of an invalid \a id # @ingroup l1_meshinfo def GetBallDiameter(self, id): return self.mesh.GetBallDiameter(id) - ## Returns XYZ coordinates of the barycenter of the given element - # \n If there is no element for the given ID - returns an empty list + ## Return XYZ coordinates of the barycenter of the given element + # \n If there is no element for the given ID - return an empty list # @return a list of three double values # @ingroup l1_meshinfo def BaryCenter(self, id): return self.mesh.BaryCenter(id) - ## Passes mesh elements through the given filter and return IDs of fitting elements + ## Pass mesh elements through the given filter and return IDs of fitting elements # @param theFilter SMESH_Filter # @return a list of ids # @ingroup l1_controls @@ -2689,10 +2730,13 @@ class Mesh: theFilter.SetMesh( self.mesh ) return theFilter.GetIDs() - ## Verifies whether a 2D mesh element has free edges (edges connected to one face only)\n - # Returns a list of special structures (borders). + # Get mesh measurements information: + # ------------------------------------ + + ## Verify whether a 2D mesh element has free edges (edges connected to one face only)\n + # Return a list of special structures (borders). # @return a list of SMESH.FreeEdges.Border structure: edge id and ids of two its nodes. - # @ingroup l1_controls + # @ingroup l1_measurements def GetFreeBorders(self): aFilterMgr = self.smeshpyD.CreateFilterManager() aPredicate = aFilterMgr.CreateFreeEdges() @@ -2701,10 +2745,6 @@ class Mesh: aFilterMgr.UnRegister() return aBorders - - # Get mesh measurements information: - # ------------------------------------ - ## Get minimum distance between two nodes, elements or distance to the origin # @param id1 first node/element id # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) @@ -2712,6 +2752,7 @@ class Mesh: # @param isElem2 @c True if @a id2 is element id, @c False if it is node id # @return minimum distance value # @sa GetMinDistance() + # @ingroup l1_measurements def MinDistance(self, id1, id2=0, isElem1=False, isElem2=False): aMeasure = self.GetMinDistance(id1, id2, isElem1, isElem2) return aMeasure.value @@ -2723,6 +2764,7 @@ class Mesh: # @param isElem2 @c True if @a id2 is element id, @c False if it is node id # @return Measure structure # @sa MinDistance() + # @ingroup l1_measurements def GetMinDistance(self, id1, id2=0, isElem1=False, isElem2=False): if isElem1: id1 = self.editor.MakeIDSource([id1], SMESH.FACE) @@ -2748,6 +2790,7 @@ class Mesh: # @c False specifies that @a objects are nodes # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) # @sa GetBoundingBox() + # @ingroup l1_measurements def BoundingBox(self, objects=None, isElem=False): result = self.GetBoundingBox(objects, isElem) if result is None: @@ -2762,6 +2805,7 @@ class Mesh: # @c False specifies that @a objects are nodes # @return Measure structure # @sa BoundingBox() + # @ingroup l1_measurements def GetBoundingBox(self, IDs=None, isElem=False): if IDs is None: IDs = [self.mesh] @@ -2796,21 +2840,21 @@ class Mesh: # Mesh edition (SMESH_MeshEditor functionality): # --------------------------------------------- - ## Removes the elements from the mesh by ids + ## Remove the elements from the mesh by ids # @param IDsOfElements is a list of ids of elements to remove # @return True or False # @ingroup l2_modif_del def RemoveElements(self, IDsOfElements): return self.editor.RemoveElements(IDsOfElements) - ## Removes nodes from mesh by ids + ## Remove nodes from mesh by ids # @param IDsOfNodes is a list of ids of nodes to remove # @return True or False # @ingroup l2_modif_del def RemoveNodes(self, IDsOfNodes): return self.editor.RemoveNodes(IDsOfNodes) - ## Removes all orphan (free) nodes from mesh + ## Remove all orphan (free) nodes from mesh # @return number of the removed nodes # @ingroup l2_modif_del def RemoveOrphanNodes(self): @@ -2824,7 +2868,7 @@ class Mesh: if hasVars: self.mesh.SetParameters(Parameters) return self.editor.AddNode( x, y, z) - ## Creates a 0D element on a node with given number. + ## Create a 0D element on a node with given number. # @param IDOfNode the ID of node for creation of the element. # @param DuplicateElements to add one more 0D element to a node or not # @return the Id of the new 0D element @@ -2853,7 +2897,7 @@ class Mesh: unRegister.set( theObject ) return self.editor.Create0DElementsOnAllNodes( theObject, theGroupName, DuplicateElements ) - ## Creates a ball element on a node with given ID. + ## Create a ball element on a node with given ID. # @param IDOfNode the ID of node for creation of the element. # @param diameter the bal diameter. # @return the Id of the new ball element @@ -2861,7 +2905,7 @@ class Mesh: def AddBall(self, IDOfNode, diameter): return self.editor.AddBall( IDOfNode, diameter ) - ## Creates a linear or quadratic edge (this is determined + ## Create a linear or quadratic edge (this is determined # by the number of given nodes). # @param IDsOfNodes the list of node IDs for creation of the element. # The order of nodes in this list should correspond to the description @@ -2872,7 +2916,7 @@ class Mesh: def AddEdge(self, IDsOfNodes): return self.editor.AddEdge(IDsOfNodes) - ## Creates a linear or quadratic face (this is determined + ## Create a linear or quadratic face (this is determined # by the number of given nodes). # @param IDsOfNodes the list of node IDs for creation of the element. # The order of nodes in this list should correspond to the description @@ -2883,14 +2927,14 @@ class Mesh: def AddFace(self, IDsOfNodes): return self.editor.AddFace(IDsOfNodes) - ## Adds a polygonal face to the mesh by the list of node IDs + ## Add a polygonal face to the mesh by the list of node IDs # @param IdsOfNodes the list of node IDs for creation of the element. # @return the Id of the new face # @ingroup l2_modif_add def AddPolygonalFace(self, IdsOfNodes): return self.editor.AddPolygonalFace(IdsOfNodes) - ## Adds a quadratic polygonal face to the mesh by the list of node IDs + ## Add a quadratic polygonal face to the mesh by the list of node IDs # @param IdsOfNodes the list of node IDs for creation of the element; # corner nodes follow first. # @return the Id of the new face @@ -2898,7 +2942,7 @@ class Mesh: def AddQuadPolygonalFace(self, IdsOfNodes): return self.editor.AddQuadPolygonalFace(IdsOfNodes) - ## Creates both simple and quadratic volume (this is determined + ## Create both simple and quadratic volume (this is determined # by the number of given nodes). # @param IDsOfNodes the list of node IDs for creation of the element. # The order of nodes in this list should correspond to the description @@ -2909,7 +2953,7 @@ class Mesh: def AddVolume(self, IDsOfNodes): return self.editor.AddVolume(IDsOfNodes) - ## Creates a volume of many faces, giving nodes for each face. + ## Create a volume of many faces, giving nodes for each face. # @param IdsOfNodes the list of node IDs for volume creation face by face. # @param Quantities the list of integer values, Quantities[i] # gives the quantity of nodes in face number i. @@ -2918,7 +2962,7 @@ class Mesh: def AddPolyhedralVolume (self, IdsOfNodes, Quantities): return self.editor.AddPolyhedralVolume(IdsOfNodes, Quantities) - ## Creates a volume of many faces, giving the IDs of the existing faces. + ## Create a volume of many faces, giving the IDs of the existing faces. # @param IdsOfFaces the list of face IDs for volume creation. # # Note: The created volume will refer only to the nodes @@ -3014,43 +3058,43 @@ class Mesh: return True - ## Moves the node with the given id + ## Move the node with the given id # @param NodeID the id of the node # @param x a new X coordinate # @param y a new Y coordinate # @param z a new Z coordinate # @return True if succeed else False - # @ingroup l2_modif_movenode + # @ingroup l2_modif_edit def MoveNode(self, NodeID, x, y, z): x,y,z,Parameters,hasVars = ParseParameters(x,y,z) if hasVars: self.mesh.SetParameters(Parameters) return self.editor.MoveNode(NodeID, x, y, z) - ## Finds the node closest to a point and moves it to a point location + ## Find the node closest to a point and moves it to a point location # @param x the X coordinate of a point # @param y the Y coordinate of a point # @param z the Z coordinate of a point # @param NodeID if specified (>0), the node with this ID is moved, # otherwise, the node closest to point (@a x,@a y,@a z) is moved # @return the ID of a node - # @ingroup l2_modif_throughp + # @ingroup l2_modif_edit def MoveClosestNodeToPoint(self, x, y, z, NodeID): x,y,z,Parameters,hasVars = ParseParameters(x,y,z) if hasVars: self.mesh.SetParameters(Parameters) return self.editor.MoveClosestNodeToPoint(x, y, z, NodeID) - ## Finds the node closest to a point + ## Find the node closest to a point # @param x the X coordinate of a point # @param y the Y coordinate of a point # @param z the Z coordinate of a point # @return the ID of a node - # @ingroup l2_modif_throughp + # @ingroup l1_meshinfo def FindNodeClosestTo(self, x, y, z): #preview = self.mesh.GetMeshEditPreviewer() #return preview.MoveClosestNodeToPoint(x, y, z, -1) return self.editor.FindNodeClosestTo(x, y, z) - ## Finds the elements where a point lays IN or ON + ## Find the elements where a point lays IN or ON # @param x the X coordinate of a point # @param y the Y coordinate of a point # @param z the Z coordinate of a point @@ -3059,7 +3103,7 @@ class Mesh: # means elements of any type excluding nodes, discrete and 0D elements. # @param meshPart a part of mesh (group, sub-mesh) to search within # @return list of IDs of found elements - # @ingroup l2_modif_throughp + # @ingroup l1_meshinfo def FindElementsByPoint(self, x, y, z, elementType = SMESH.ALL, meshPart=None): if meshPart: return self.editor.FindAmongElementsByPoint( meshPart, x, y, z, elementType ); @@ -3069,19 +3113,20 @@ class Mesh: ## Return point state in a closed 2D mesh in terms of TopAbs_State enumeration: # 0-IN, 1-OUT, 2-ON, 3-UNKNOWN # UNKNOWN state means that either mesh is wrong or the analysis fails. + # @ingroup l1_meshinfo def GetPointState(self, x, y, z): return self.editor.GetPointState(x, y, z) - ## Finds the node closest to a point and moves it to a point location + ## Find the node closest to a point and moves it to a point location # @param x the X coordinate of a point # @param y the Y coordinate of a point # @param z the Z coordinate of a point # @return the ID of a moved node - # @ingroup l2_modif_throughp + # @ingroup l2_modif_edit def MeshToPassThroughAPoint(self, x, y, z): return self.editor.MoveClosestNodeToPoint(x, y, z, -1) - ## Replaces two neighbour triangles sharing Node1-Node2 link + ## Replace two neighbour triangles sharing Node1-Node2 link # with the triangles built on the same 4 nodes but having other common link. # @param NodeID1 the ID of the first node # @param NodeID2 the ID of the second node @@ -3090,7 +3135,7 @@ class Mesh: def InverseDiag(self, NodeID1, NodeID2): return self.editor.InverseDiag(NodeID1, NodeID2) - ## Replaces two neighbour triangles sharing Node1-Node2 link + ## Replace two neighbour triangles sharing Node1-Node2 link # with a quadrangle built on the same 4 nodes. # @param NodeID1 the ID of the first node # @param NodeID2 the ID of the second node @@ -3099,7 +3144,7 @@ class Mesh: def DeleteDiag(self, NodeID1, NodeID2): return self.editor.DeleteDiag(NodeID1, NodeID2) - ## Reorients elements by ids + ## Reorient elements by ids # @param IDsOfElements if undefined reorients all mesh elements # @return True if succeed else False # @ingroup l2_modif_changori @@ -3108,7 +3153,7 @@ class Mesh: IDsOfElements = self.GetElementsId() return self.editor.Reorient(IDsOfElements) - ## Reorients all elements of the object + ## Reorient all elements of the object # @param theObject mesh, submesh or group # @return True if succeed else False # @ingroup l2_modif_changori @@ -3185,7 +3230,7 @@ class Mesh: unRegister.set( the3DObject ) return self.editor.Reorient2DBy3D( the2DObject, the3DObject, theOutsideNormal ) - ## Fuses the neighbouring triangles into quadrangles. + ## Fuse the neighbouring triangles into quadrangles. # @param IDsOfElements The triangles to be fused. # @param theCriterion a numerical functor, in terms of enum SMESH.FunctorType, used to # applied to possible quadrangles to choose a neighbour to fuse with. @@ -3204,7 +3249,7 @@ class Mesh: Functor = self.smeshpyD.GetFunctor(theCriterion) return self.editor.TriToQuad(IDsOfElements, Functor, MaxAngle) - ## Fuses the neighbouring triangles of the object into quadrangles + ## Fuse the neighbouring triangles of the object into quadrangles # @param theObject is mesh, submesh or group # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, # applied to possible quadrangles to choose a neighbour to fuse with. @@ -3222,7 +3267,7 @@ class Mesh: Functor = self.smeshpyD.GetFunctor(theCriterion) return self.editor.TriToQuadObject(theObject, Functor, MaxAngle) - ## Splits quadrangles into triangles. + ## Split quadrangles into triangles. # @param IDsOfElements the faces to be splitted. # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to # choose a diagonal for splitting. If @a theCriterion is None, which is a default @@ -3239,7 +3284,7 @@ class Mesh: Functor = self.smeshpyD.GetFunctor(theCriterion) return self.editor.QuadToTri(IDsOfElements, Functor) - ## Splits quadrangles into triangles. + ## Split quadrangles into triangles. # @param theObject the object from which the list of elements is taken, # this is mesh, submesh or group # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to @@ -3257,7 +3302,7 @@ class Mesh: Functor = self.smeshpyD.GetFunctor(theCriterion) return self.editor.QuadToTriObject(theObject, Functor) - ## Splits each of given quadrangles into 4 triangles. A node is added at the center of + ## Split each of given quadrangles into 4 triangles. A node is added at the center of # a quadrangle. # @param theElements the faces to be splitted. This can be either mesh, sub-mesh, # group or a list of face IDs. By default all quadrangles are split @@ -3273,7 +3318,7 @@ class Mesh: unRegister.set( theElements ) return self.editor.QuadTo4Tri( theElements ) - ## Splits quadrangles into triangles. + ## Split quadrangles into triangles. # @param IDsOfElements the faces to be splitted # @param Diag13 is used to choose a diagonal for splitting. # @return TRUE in case of success, FALSE otherwise. @@ -3283,7 +3328,7 @@ class Mesh: IDsOfElements = self.GetElementsId() return self.editor.SplitQuad(IDsOfElements, Diag13) - ## Splits quadrangles into triangles. + ## Split quadrangles into triangles. # @param theObject the object from which the list of elements is taken, # this is mesh, submesh or group # @param Diag13 is used to choose a diagonal for splitting. @@ -3294,7 +3339,7 @@ class Mesh: theObject = theObject.GetMesh() return self.editor.SplitQuadObject(theObject, Diag13) - ## Finds a better splitting of the given quadrangle. + ## Find a better splitting of the given quadrangle. # @param IDOfQuad the ID of the quadrangle to be splitted. # @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to # choose a diagonal for splitting. @@ -3306,7 +3351,7 @@ class Mesh: def BestSplit (self, IDOfQuad, theCriterion): return self.editor.BestSplit(IDOfQuad, self.smeshpyD.GetFunctor(theCriterion)) - ## Splits volumic elements into tetrahedrons + ## Split volumic elements into tetrahedrons # @param elems either a list of elements or a mesh or a group or a submesh or a filter # @param method flags passing splitting method: # smesh.Hex_5Tet, smesh.Hex_6Tet, smesh.Hex_24Tet. @@ -3344,7 +3389,7 @@ class Mesh: elems = [elems] self.editor.SplitBiQuadraticIntoLinear( elems ) - ## Splits hexahedra into prisms + ## Split hexahedra into prisms # @param elems either a list of elements or a mesh or a group or a submesh or a filter # @param startHexPoint a point used to find a hexahedron for which @a facetNormal # gives a normal vector defining facets to split into triangles. @@ -3385,9 +3430,9 @@ class Mesh: self.editor.SplitHexahedraIntoPrisms(elems, startHexPoint, facetNormal, method, allDomains) - ## Splits quadrangle faces near triangular facets of volumes + ## Split quadrangle faces near triangular facets of volumes # - # @ingroup l1_auxiliary + # @ingroup l2_modif_cutquadr def SplitQuadsNearTriangularFacets(self): faces_array = self.GetElementsByType(SMESH.FACE) for face_id in faces_array: @@ -3425,7 +3470,7 @@ class Mesh: # key-point will be mapped into theNode001-th node of each volume. # The (0,0,0) key-point of the used pattern corresponds to a non-split corner. # @return TRUE in case of success, FALSE otherwise. - # @ingroup l1_auxiliary + # @ingroup l2_modif_cutquadr def SplitHexaToTetras (self, theObject, theNode000, theNode001): # Pattern: 5.---------.6 # /|#* /| @@ -3483,7 +3528,7 @@ class Mesh: # will be mapped into the theNode001-th node of each volume. # Edge (0,0,0)-(0,0,1) of used pattern connects two not split corners. # @return TRUE in case of success, FALSE otherwise. - # @ingroup l1_auxiliary + # @ingroup l2_modif_cutquadr def SplitHexaToPrisms (self, theObject, theNode000, theNode001): # Pattern: 5.---------.6 # /|# /| @@ -3522,12 +3567,12 @@ class Mesh: isDone = pattern.MakeMesh(self.mesh, False, False) if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode() - # Splits quafrangle faces near triangular facets of volumes + # Split quafrangle faces near triangular facets of volumes self.SplitQuadsNearTriangularFacets() return isDone - ## Smoothes elements + ## Smooth elements # @param IDsOfElements the list if ids of elements to smooth # @param IDsOfFixedNodes the list of ids of fixed nodes. # Note that nodes built on edges and boundary nodes are always fixed. @@ -3546,7 +3591,7 @@ class Mesh: return self.editor.Smooth(IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations, MaxAspectRatio, Method) - ## Smoothes elements which belong to the given object + ## Smooth elements which belong to the given object # @param theObject the object to smooth # @param IDsOfFixedNodes the list of ids of fixed nodes. # Note that nodes built on edges and boundary nodes are always fixed. @@ -3563,7 +3608,7 @@ class Mesh: return self.editor.SmoothObject(theObject, IDsOfFixedNodes, MaxNbOfIterations, MaxAspectRatio, Method) - ## Parametrically smoothes the given elements + ## Parametrically smooth the given elements # @param IDsOfElements the list if ids of elements to smooth # @param IDsOfFixedNodes the list of ids of fixed nodes. # Note that nodes built on edges and boundary nodes are always fixed. @@ -3582,7 +3627,7 @@ class Mesh: return self.editor.SmoothParametric(IDsOfElements, IDsOfFixedNodes, MaxNbOfIterations, MaxAspectRatio, Method) - ## Parametrically smoothes the elements which belong to the given object + ## Parametrically smooth the elements which belong to the given object # @param theObject the object to smooth # @param IDsOfFixedNodes the list of ids of fixed nodes. # Note that nodes built on edges and boundary nodes are always fixed. @@ -3599,13 +3644,14 @@ class Mesh: return self.editor.SmoothParametricObject(theObject, IDsOfFixedNodes, MaxNbOfIterations, MaxAspectRatio, Method) - ## Converts the mesh to quadratic or bi-quadratic, deletes old elements, replacing + ## Convert the mesh to quadratic or bi-quadratic, deletes old elements, replacing # them with quadratic with the same id. # @param theForce3d new node creation method: # 0 - the medium node lies at the geometrical entity from which the mesh element is built # 1 - the medium node lies at the middle of the line segments connecting two nodes of a mesh element # @param theSubMesh a group or a sub-mesh to convert; WARNING: in this case the mesh can become not conformal # @param theToBiQuad If True, converts the mesh to bi-quadratic + # @return SMESH.ComputeError which can hold a warning # @ingroup l2_modif_tofromqu def ConvertToQuadratic(self, theForce3d=False, theSubMesh=None, theToBiQuad=False): if isinstance( theSubMesh, Mesh ): @@ -3620,8 +3666,9 @@ class Mesh: error = self.editor.GetLastError() if error and error.comment: print error.comment + return error - ## Converts the mesh from quadratic to ordinary, + ## Convert the mesh from quadratic to ordinary, # deletes old quadratic elements, \n replacing # them with ordinary mesh elements with the same id. # @param theSubMesh a group or a sub-mesh to convert; WARNING: in this case the mesh can become not conformal @@ -3632,19 +3679,19 @@ class Mesh: else: return self.editor.ConvertFromQuadratic() - ## Creates 2D mesh as skin on boundary faces of a 3D mesh + ## Create 2D mesh as skin on boundary faces of a 3D mesh # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_add def Make2DMeshFrom3D(self): return self.editor.Make2DMeshFrom3D() - ## Creates missing boundary elements + ## Create missing boundary elements # @param elements - elements whose boundary is to be checked: # mesh, group, sub-mesh or list of elements # if elements is mesh, it must be the mesh whose MakeBoundaryMesh() is called # @param dimension - defines type of boundary elements to create, either of # { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D } - # SMESH.BND_1DFROM3D creates mesh edges on all borders of free facets of 3D cells + # SMESH.BND_1DFROM3D create mesh edges on all borders of free facets of 3D cells # @param groupName - a name of group to store created boundary elements in, # "" means not to create the group # @param meshName - a name of new mesh to store created boundary elements in, @@ -3654,7 +3701,7 @@ class Mesh: # @param toCopyExistingBondary - if true, not only new but also pre-existing # boundary elements will be copied into the new mesh # @return tuple (mesh, group) where boundary elements were added to - # @ingroup l2_modif_edit + # @ingroup l2_modif_add def MakeBoundaryMesh(self, elements, dimension=SMESH.BND_2DFROM3D, groupName="", meshName="", toCopyElements=False, toCopyExistingBondary=False): unRegister = genObjUnRegister() @@ -3671,7 +3718,7 @@ class Mesh: return mesh, group ## - # @brief Creates missing boundary elements around either the whole mesh or + # @brief Create missing boundary elements around either the whole mesh or # groups of elements # @param dimension - defines type of boundary elements to create, either of # { SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D } @@ -3687,6 +3734,7 @@ class Mesh: # mesh - the mesh where elements were added to # group - the group of boundary elements or None # + # @ingroup l2_modif_add def MakeBoundaryElements(self, dimension=SMESH.BND_2DFROM3D, groupName="", meshName="", toCopyAll=False, groups=[]): nb, mesh, group = self.editor.MakeBoundaryElements(dimension,groupName,meshName, @@ -3718,7 +3766,7 @@ class Mesh: arg = [arg] return arg - ## Generates new elements by rotation of the given elements and nodes around the axis + ## Generate new elements by rotation of the given elements and nodes around the axis # @param nodes - nodes to revolve: a list including ids, groups, sub-meshes or a mesh # @param edges - edges to revolve: a list including ids, groups, sub-meshes or a mesh # @param faces - faces to revolve: a list including ids, groups, sub-meshes or a mesh @@ -3754,7 +3802,7 @@ class Mesh: Axis, AngleInRadians, NbOfSteps, Tolerance, MakeGroups) - ## Generates new elements by rotation of the elements around the axis + ## Generate new elements by rotation of the elements around the axis # @param IDsOfElements the list of ids of elements to sweep # @param Axis the axis of rotation, AxisStruct or line(geom object) # @param AngleInRadians the angle of Rotation (in radians) or a name of variable which defines angle in degrees @@ -3771,7 +3819,7 @@ class Mesh: AngleInRadians, NbOfSteps, Tolerance, MakeGroups, TotalAngle) - ## Generates new elements by rotation of the elements of object around the axis + ## Generate new elements by rotation of the elements of object around the axis # @param theObject object which elements should be sweeped. # It can be a mesh, a sub mesh or a group. # @param Axis the axis of rotation, AxisStruct or line(geom object) @@ -3789,7 +3837,7 @@ class Mesh: AngleInRadians, NbOfSteps, Tolerance, MakeGroups, TotalAngle ) - ## Generates new elements by rotation of the elements of object around the axis + ## Generate new elements by rotation of the elements of object around the axis # @param theObject object which elements should be sweeped. # It can be a mesh, a sub mesh or a group. # @param Axis the axis of rotation, AxisStruct or line(geom object) @@ -3807,7 +3855,7 @@ class Mesh: AngleInRadians, NbOfSteps, Tolerance, MakeGroups, TotalAngle) - ## Generates new elements by rotation of the elements of object around the axis + ## Generate new elements by rotation of the elements of object around the axis # @param theObject object which elements should be sweeped. # It can be a mesh, a sub mesh or a group. # @param Axis the axis of rotation, AxisStruct or line(geom object) @@ -3824,7 +3872,7 @@ class Mesh: return self.RotationSweepObjects([],[],theObject, Axis, AngleInRadians, NbOfSteps, Tolerance, MakeGroups, TotalAngle) - ## Generates new elements by extrusion of the given elements and nodes + ## Generate new elements by extrusion of the given elements and nodes # @param nodes nodes to extrude: a list including ids, groups, sub-meshes or a mesh # @param edges edges to extrude: a list including ids, groups, sub-meshes or a mesh # @param faces faces to extrude: a list including ids, groups, sub-meshes or a mesh @@ -3844,6 +3892,7 @@ class Mesh: # - a GEOM point # @return the list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion example def ExtrusionSweepObjects(self, nodes, edges, faces, StepVector, NbOfSteps, MakeGroups=False, scaleFactors=[], linearVariation=False, basePoint=[] ): unRegister = genObjUnRegister() @@ -3874,7 +3923,7 @@ class Mesh: MakeGroups) - ## Generates new elements by extrusion of the elements with given ids + ## Generate new elements by extrusion of the elements with given ids # @param IDsOfElements the list of ids of elements or nodes for extrusion # @param StepVector vector or DirStruct or 3 vector components, defining # the direction and value of extrusion for one step (the total extrusion @@ -3884,13 +3933,14 @@ class Mesh: # @param IsNodes is True if elements with given ids are nodes # @return the list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion example def ExtrusionSweep(self, IDsOfElements, StepVector, NbOfSteps, MakeGroups=False, IsNodes = False): n,e,f = [],[],[] if IsNodes: n = IDsOfElements else : e,f, = IDsOfElements,IDsOfElements return self.ExtrusionSweepObjects(n,e,f, StepVector, NbOfSteps, MakeGroups) - ## Generates new elements by extrusion along the normal to a discretized surface or wire + ## Generate new elements by extrusion along the normal to a discretized surface or wire # @param Elements elements to extrude - a list including ids, groups, sub-meshes or a mesh. # Only faces can be extruded so far. A sub-mesh should be a sub-mesh on geom faces. # @param StepSize length of one extrusion step (the total extrusion @@ -3910,6 +3960,7 @@ class Mesh: # @return the list of created groups (SMESH_GroupBase) if \a MakeGroups=True, # empty list otherwise. # @ingroup l2_modif_extrurev + # @ref tui_extrusion example def ExtrusionByNormal(self, Elements, StepSize, NbOfSteps, ByAverageNormal=False, UseInputElemsOnly=True, MakeGroups=False, Dim = 2): unRegister = genObjUnRegister() @@ -3928,7 +3979,7 @@ class Mesh: return self.editor.ExtrusionByNormal(Elements, StepSize, NbOfSteps, ByAverageNormal, UseInputElemsOnly, MakeGroups, Dim) - ## Generates new elements by extrusion of the elements or nodes which belong to the object + ## Generate new elements by extrusion of the elements or nodes which belong to the object # @param theObject the object whose elements or nodes should be processed. # It can be a mesh, a sub-mesh or a group. # @param StepVector vector or DirStruct or 3 vector components, defining @@ -3939,13 +3990,14 @@ class Mesh: # @param IsNodes is True if elements to extrude are nodes # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion example def ExtrusionSweepObject(self, theObject, StepVector, NbOfSteps, MakeGroups=False, IsNodes=False): n,e,f = [],[],[] if IsNodes: n = theObject else : e,f, = theObject,theObject return self.ExtrusionSweepObjects(n,e,f, StepVector, NbOfSteps, MakeGroups) - ## Generates new elements by extrusion of edges which belong to the object + ## Generate new elements by extrusion of edges which belong to the object # @param theObject object whose 1D elements should be processed. # It can be a mesh, a sub-mesh or a group. # @param StepVector vector or DirStruct or 3 vector components, defining @@ -3955,10 +4007,11 @@ class Mesh: # @param MakeGroups to generate new groups from existing ones # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion example def ExtrusionSweepObject1D(self, theObject, StepVector, NbOfSteps, MakeGroups=False): return self.ExtrusionSweepObjects([],theObject,[], StepVector, NbOfSteps, MakeGroups) - ## Generates new elements by extrusion of faces which belong to the object + ## Generate new elements by extrusion of faces which belong to the object # @param theObject object whose 2D elements should be processed. # It can be a mesh, a sub-mesh or a group. # @param StepVector vector or DirStruct or 3 vector components, defining @@ -3968,10 +4021,11 @@ class Mesh: # @param MakeGroups forces the generation of new groups from existing ones # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion example def ExtrusionSweepObject2D(self, theObject, StepVector, NbOfSteps, MakeGroups=False): return self.ExtrusionSweepObjects([],[],theObject, StepVector, NbOfSteps, MakeGroups) - ## Generates new elements by extrusion of the elements with given ids + ## Generate new elements by extrusion of the elements with given ids # @param IDsOfElements is ids of elements # @param StepVector vector or DirStruct or 3 vector components, defining # the direction and value of extrusion for one step (the total extrusion @@ -3992,7 +4046,7 @@ class Mesh: return self.editor.AdvancedExtrusion(IDsOfElements, StepVector, NbOfSteps, ExtrFlags, SewTolerance, MakeGroups) - ## Generates new elements by extrusion of the given elements and nodes along the path. + ## Generate new elements by extrusion of the given elements and nodes along the path. # The path of extrusion must be a meshed edge. # @param Nodes nodes to extrude: a list including ids, groups, sub-meshes or a mesh # @param Edges edges to extrude: a list including ids, groups, sub-meshes or a mesh @@ -4012,6 +4066,7 @@ class Mesh: # @param MakeGroups forces the generation of new groups from existing ones # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error # @ingroup l2_modif_extrurev + # @ref tui_extrusion_along_path example def ExtrusionAlongPathObjects(self, Nodes, Edges, Faces, PathMesh, PathShape=None, NodeStart=1, HasAngles=False, Angles=[], LinearVariation=False, HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False): @@ -4035,7 +4090,7 @@ class Mesh: HasAngles, Angles, LinearVariation, HasRefPoint, RefPoint, MakeGroups) - ## Generates new elements by extrusion of the given elements + ## Generate new elements by extrusion of the given elements # The path of extrusion must be a meshed edge. # @param Base mesh or group, or sub-mesh, or list of ids of elements for extrusion # @param Path - 1D mesh or 1D sub-mesh, along which proceeds the extrusion @@ -4055,6 +4110,7 @@ class Mesh: # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error if MakeGroups=True, # only SMESH::Extrusion_Error otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion_along_path example def ExtrusionAlongPathX(self, Base, Path, NodeStart, HasAngles=False, Angles=[], LinearVariation=False, HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False, @@ -4069,7 +4125,7 @@ class Mesh: if MakeGroups: return gr,er return er - ## Generates new elements by extrusion of the given elements + ## Generate new elements by extrusion of the given elements # The path of extrusion must be a meshed edge. # @param IDsOfElements ids of elements # @param PathMesh mesh containing a 1D sub-mesh on the edge, along which proceeds the extrusion @@ -4087,6 +4143,7 @@ class Mesh: # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error if MakeGroups=True, # only SMESH::Extrusion_Error otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion_along_path example def ExtrusionAlongPath(self, IDsOfElements, PathMesh, PathShape, NodeStart, HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[], MakeGroups=False, LinearVariation=False): @@ -4098,7 +4155,7 @@ class Mesh: if MakeGroups: return gr,er return er - ## Generates new elements by extrusion of the elements which belong to the object + ## Generate new elements by extrusion of the elements which belong to the object # The path of extrusion must be a meshed edge. # @param theObject the object whose elements should be processed. # It can be a mesh, a sub-mesh or a group. @@ -4117,6 +4174,7 @@ class Mesh: # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error if MakeGroups=True, # only SMESH::Extrusion_Error otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion_along_path example def ExtrusionAlongPathObject(self, theObject, PathMesh, PathShape, NodeStart, HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[], MakeGroups=False, LinearVariation=False): @@ -4127,7 +4185,7 @@ class Mesh: if MakeGroups: return gr,er return er - ## Generates new elements by extrusion of mesh segments which belong to the object + ## Generate new elements by extrusion of mesh segments which belong to the object # The path of extrusion must be a meshed edge. # @param theObject the object whose 1D elements should be processed. # It can be a mesh, a sub-mesh or a group. @@ -4146,6 +4204,7 @@ class Mesh: # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error if MakeGroups=True, # only SMESH::Extrusion_Error otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion_along_path example def ExtrusionAlongPathObject1D(self, theObject, PathMesh, PathShape, NodeStart, HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[], MakeGroups=False, LinearVariation=False): @@ -4156,7 +4215,7 @@ class Mesh: if MakeGroups: return gr,er return er - ## Generates new elements by extrusion of faces which belong to the object + ## Generate new elements by extrusion of faces which belong to the object # The path of extrusion must be a meshed edge. # @param theObject the object whose 2D elements should be processed. # It can be a mesh, a sub-mesh or a group. @@ -4175,6 +4234,7 @@ class Mesh: # @return list of created groups (SMESH_GroupBase) and SMESH::Extrusion_Error if MakeGroups=True, # only SMESH::Extrusion_Error otherwise # @ingroup l2_modif_extrurev + # @ref tui_extrusion_along_path example def ExtrusionAlongPathObject2D(self, theObject, PathMesh, PathShape, NodeStart, HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[], MakeGroups=False, LinearVariation=False): @@ -4185,7 +4245,7 @@ class Mesh: if MakeGroups: return gr,er return er - ## Creates a symmetrical copy of mesh elements + ## Create a symmetrical copy of mesh elements # @param IDsOfElements list of elements ids # @param Mirror is AxisStruct or geom object(point, line, plane) # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE @@ -4207,7 +4267,7 @@ class Mesh: self.editor.Mirror(IDsOfElements, Mirror, theMirrorType, Copy) return [] - ## Creates a new mesh by a symmetrical copy of mesh elements + ## Create a new mesh by a symmetrical copy of mesh elements # @param IDsOfElements the list of elements ids # @param Mirror is AxisStruct or geom object (point, line, plane) # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE @@ -4228,7 +4288,7 @@ class Mesh: MakeGroups, NewMeshName) return Mesh(self.smeshpyD,self.geompyD,mesh) - ## Creates a symmetrical copy of the object + ## Create a symmetrical copy of the object # @param theObject mesh, submesh or group # @param Mirror AxisStruct or geom object (point, line, plane) # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE @@ -4250,7 +4310,7 @@ class Mesh: self.editor.MirrorObject(theObject, Mirror, theMirrorType, Copy) return [] - ## Creates a new mesh by a symmetrical copy of the object + ## Create a new mesh by a symmetrical copy of the object # @param theObject mesh, submesh or group # @param Mirror AxisStruct or geom object (point, line, plane) # @param theMirrorType smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE @@ -4271,7 +4331,7 @@ class Mesh: MakeGroups, NewMeshName) return Mesh( self.smeshpyD,self.geompyD,mesh ) - ## Translates the elements + ## Translate the elements # @param IDsOfElements list of elements ids # @param Vector the direction of translation (DirStruct or vector or 3 vector components) # @param Copy allows copying the translated elements @@ -4291,7 +4351,7 @@ class Mesh: self.editor.Translate(IDsOfElements, Vector, Copy) return [] - ## Creates a new mesh of translated elements + ## Create a new mesh of translated elements # @param IDsOfElements list of elements ids # @param Vector the direction of translation (DirStruct or vector or 3 vector components) # @param MakeGroups forces the generation of new groups from existing ones @@ -4309,7 +4369,7 @@ class Mesh: mesh = self.editor.TranslateMakeMesh(IDsOfElements, Vector, MakeGroups, NewMeshName) return Mesh ( self.smeshpyD, self.geompyD, mesh ) - ## Translates the object + ## Translate the object # @param theObject the object to translate (mesh, submesh, or group) # @param Vector direction of translation (DirStruct or geom vector or 3 vector components) # @param Copy allows copying the translated elements @@ -4329,7 +4389,7 @@ class Mesh: self.editor.TranslateObject(theObject, Vector, Copy) return [] - ## Creates a new mesh from the translated object + ## Create a new mesh from the translated object # @param theObject the object to translate (mesh, submesh, or group) # @param Vector the direction of translation (DirStruct or geom vector or 3 vector components) # @param MakeGroups forces the generation of new groups from existing ones @@ -4349,7 +4409,7 @@ class Mesh: - ## Scales the object + ## Scale the object # @param theObject - the object to translate (mesh, submesh, or group) # @param thePoint - base point for scale (SMESH.PointStruct or list of 3 coordinates) # @param theScaleFact - list of 1-3 scale factors for axises @@ -4379,7 +4439,7 @@ class Mesh: self.editor.Scale(theObject, thePoint, theScaleFact, Copy) return [] - ## Creates a new mesh from the translated object + ## Create a new mesh from the translated object # @param theObject - the object to translate (mesh, submesh, or group) # @param thePoint - base point for scale (SMESH.PointStruct or list of 3 coordinates) # @param theScaleFact - list of 1-3 scale factors for axises @@ -4407,7 +4467,7 @@ class Mesh: - ## Rotates the elements + ## Rotate the elements # @param IDsOfElements list of elements ids # @param Axis the axis of rotation (AxisStruct or geom line) # @param AngleInRadians the angle of rotation (in radians) or a name of variable which defines angle in degrees @@ -4428,7 +4488,7 @@ class Mesh: self.editor.Rotate(IDsOfElements, Axis, AngleInRadians, Copy) return [] - ## Creates a new mesh of rotated elements + ## Create a new mesh of rotated elements # @param IDsOfElements list of element ids # @param Axis the axis of rotation (AxisStruct or geom line) # @param AngleInRadians the angle of rotation (in radians) or a name of variable which defines angle in degrees @@ -4448,7 +4508,7 @@ class Mesh: MakeGroups, NewMeshName) return Mesh( self.smeshpyD, self.geompyD, mesh ) - ## Rotates the object + ## Rotate the object # @param theObject the object to rotate( mesh, submesh, or group) # @param Axis the axis of rotation (AxisStruct or geom line) # @param AngleInRadians the angle of rotation (in radians) or a name of variable which defines angle in degrees @@ -4469,7 +4529,7 @@ class Mesh: self.editor.RotateObject(theObject, Axis, AngleInRadians, Copy) return [] - ## Creates a new mesh from the rotated object + ## Create a new mesh from the rotated object # @param theObject the object to rotate (mesh, submesh, or group) # @param Axis the axis of rotation (AxisStruct or geom line) # @param AngleInRadians the angle of rotation (in radians) or a name of variable which defines angle in degrees @@ -4489,7 +4549,7 @@ class Mesh: self.mesh.SetParameters(Parameters) return Mesh( self.smeshpyD, self.geompyD, mesh ) - ## Finds groups of adjacent nodes within Tolerance. + ## Find groups of adjacent nodes within Tolerance. # @param Tolerance the value of tolerance # @param SeparateCornerAndMediumNodes if @c True, in quadratic mesh puts # corner and medium nodes in separate groups thus preventing @@ -4499,7 +4559,7 @@ class Mesh: def FindCoincidentNodes (self, Tolerance, SeparateCornerAndMediumNodes=False): return self.editor.FindCoincidentNodes( Tolerance, SeparateCornerAndMediumNodes ) - ## Finds groups of ajacent nodes within Tolerance. + ## Find groups of ajacent nodes within Tolerance. # @param Tolerance the value of tolerance # @param SubMeshOrGroup SubMesh, Group or Filter # @param exceptNodes list of either SubMeshes, Groups or node IDs to exclude from search @@ -4521,19 +4581,21 @@ class Mesh: return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance, exceptNodes, SeparateCornerAndMediumNodes) - ## Merges nodes + ## Merge nodes # @param GroupsOfNodes a list of groups of nodes IDs for merging # (e.g. [[1,12,13],[25,4]], then nodes 12, 13 and 4 will be removed and replaced # by nodes 1 and 25 correspondingly in all elements and groups # @param NodesToKeep nodes to keep in the mesh: a list of groups, sub-meshes or node IDs. # If @a NodesToKeep does not include a node to keep for some group to merge, # then the first node in the group is kept. + # @param AvoidMakingHoles prevent merging nodes which cause removal of elements becoming + # invalid # @ingroup l2_modif_trsf - def MergeNodes (self, GroupsOfNodes, NodesToKeep=[]): + def MergeNodes (self, GroupsOfNodes, NodesToKeep=[], AvoidMakingHoles=False): # NodesToKeep are converted to SMESH_IDSource in meshEditor.MergeNodes() - self.editor.MergeNodes(GroupsOfNodes,NodesToKeep) + self.editor.MergeNodes( GroupsOfNodes, NodesToKeep, AvoidMakingHoles ) - ## Finds the elements built on the same nodes. + ## Find the elements built on the same nodes. # @param MeshOrSubMeshOrGroup Mesh or SubMesh, or Group of elements for searching # @return the list of groups of equal elements IDs (e.g. [[1,12,13],[4,25]]) # @ingroup l2_modif_trsf @@ -4544,7 +4606,7 @@ class Mesh: MeshOrSubMeshOrGroup = MeshOrSubMeshOrGroup.GetMesh() return self.editor.FindEqualElements( MeshOrSubMeshOrGroup ) - ## Merges elements in each given group. + ## Merge elements in each given group. # @param GroupsOfElementsID a list of groups of elements IDs for merging # (e.g. [[1,12,13],[25,4]], then elements 12, 13 and 4 will be removed and # replaced by elements 1 and 25 in all groups) @@ -4552,12 +4614,12 @@ class Mesh: def MergeElements(self, GroupsOfElementsID): self.editor.MergeElements(GroupsOfElementsID) - ## Leaves one element and removes all other elements built on the same nodes. + ## Leave one element and remove all other elements built on the same nodes. # @ingroup l2_modif_trsf def MergeEqualElements(self): self.editor.MergeEqualElements() - ## Returns groups of FreeBorder's coincident within the given tolerance. + ## Return groups of FreeBorder's coincident within the given tolerance. # @param tolerance the tolerance. If the tolerance <= 0.0 then one tenth of an average # size of elements adjacent to free borders being compared is used. # @return SMESH.CoincidentFreeBorders structure @@ -4603,7 +4665,7 @@ class Mesh: return self.editor.SewCoincidentFreeBorders( freeBorders, createPolygons, createPolyhedra ) - ## Sews free borders + ## Sew free borders # @return SMESH::Sew_Error # @ingroup l2_modif_trsf def SewFreeBorders (self, FirstNodeID1, SecondNodeID1, LastNodeID1, @@ -4613,7 +4675,7 @@ class Mesh: FirstNodeID2, SecondNodeID2, LastNodeID2, CreatePolygons, CreatePolyedrs) - ## Sews conform free borders + ## Sew conform free borders # @return SMESH::Sew_Error # @ingroup l2_modif_trsf def SewConformFreeBorders (self, FirstNodeID1, SecondNodeID1, LastNodeID1, @@ -4621,7 +4683,7 @@ class Mesh: return self.editor.SewConformFreeBorders(FirstNodeID1, SecondNodeID1, LastNodeID1, FirstNodeID2, SecondNodeID2) - ## Sews border to side + ## Sew border to side # @return SMESH::Sew_Error # @ingroup l2_modif_trsf def SewBorderToSide (self, FirstNodeIDOnFreeBorder, SecondNodeIDOnFreeBorder, LastNodeIDOnFreeBorder, @@ -4629,7 +4691,7 @@ class Mesh: return self.editor.SewBorderToSide(FirstNodeIDOnFreeBorder, SecondNodeIDOnFreeBorder, LastNodeIDOnFreeBorder, FirstNodeIDOnSide, LastNodeIDOnSide, CreatePolygons, CreatePolyedrs) - ## Sews two sides of a mesh. The nodes belonging to Side1 are + ## Sew two sides of a mesh. The nodes belonging to Side1 are # merged with the nodes of elements of Side2. # The number of elements in theSide1 and in theSide2 must be # equal and they should have similar nodal connectivity. @@ -4644,36 +4706,36 @@ class Mesh: NodeID1OfSide1ToMerge, NodeID1OfSide2ToMerge, NodeID2OfSide1ToMerge, NodeID2OfSide2ToMerge) - ## Sets new nodes for the given element. + ## Set new nodes for the given element. # @param ide the element id # @param newIDs nodes ids - # @return If the number of nodes does not correspond to the type of element - returns false + # @return If the number of nodes does not correspond to the type of element - return false # @ingroup l2_modif_edit def ChangeElemNodes(self, ide, newIDs): return self.editor.ChangeElemNodes(ide, newIDs) ## If during the last operation of MeshEditor some nodes were - # created, this method returns the list of their IDs, \n - # if new nodes were not created - returns empty list + # created, this method return the list of their IDs, \n + # if new nodes were not created - return empty list # @return the list of integer values (can be empty) - # @ingroup l1_auxiliary + # @ingroup l2_modif_add def GetLastCreatedNodes(self): return self.editor.GetLastCreatedNodes() ## If during the last operation of MeshEditor some elements were - # created this method returns the list of their IDs, \n - # if new elements were not created - returns empty list + # created this method return the list of their IDs, \n + # if new elements were not created - return empty list # @return the list of integer values (can be empty) - # @ingroup l1_auxiliary + # @ingroup l2_modif_add def GetLastCreatedElems(self): return self.editor.GetLastCreatedElems() - ## Clears sequences of nodes and elements created by mesh edition oparations - # @ingroup l1_auxiliary + ## Forget what nodes and elements were created by the last mesh edition operation + # @ingroup l2_modif_add def ClearLastCreated(self): self.editor.ClearLastCreated() - ## Creates duplicates of given elements, i.e. creates new elements based on the + ## Create duplicates of given elements, i.e. create new elements based on the # same nodes as the given ones. # @param theElements - container of elements to duplicate. It can be a Mesh, # sub-mesh, group, filter or a list of element IDs. If \a theElements is @@ -4684,7 +4746,7 @@ class Mesh: # If \a theGroupName is empty, new elements are not added # in any group. # @return a group where the new elements are added. None if theGroupName == "". - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleElements(self, theElements, theGroupName=""): unRegister = genObjUnRegister() if isinstance( theElements, Mesh ): @@ -4694,62 +4756,62 @@ class Mesh: unRegister.set( theElements ) return self.editor.DoubleElements(theElements, theGroupName) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # @param theNodes identifiers of nodes to be doubled # @param theModifiedElems identifiers of elements to be updated by the new (doubled) # nodes. If list of element identifiers is empty then nodes are doubled but # they not assigned to elements # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodes(self, theNodes, theModifiedElems): return self.editor.DoubleNodes(theNodes, theModifiedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theNodeId identifiers of node to be doubled # @param theModifiedElems identifiers of elements to be updated # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNode(self, theNodeId, theModifiedElems): return self.editor.DoubleNode(theNodeId, theModifiedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theNodes group of nodes to be doubled # @param theModifiedElems group of elements to be updated. # @param theMakeGroup forces the generation of a group containing new nodes. # @return TRUE or a created group if operation has been completed successfully, # FALSE or None otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeGroup(self, theNodes, theModifiedElems, theMakeGroup=False): if theMakeGroup: return self.editor.DoubleNodeGroupNew(theNodes, theModifiedElems) return self.editor.DoubleNodeGroup(theNodes, theModifiedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theNodes list of groups of nodes to be doubled # @param theModifiedElems list of groups of elements to be updated. # @param theMakeGroup forces the generation of a group containing new nodes. # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeGroups(self, theNodes, theModifiedElems, theMakeGroup=False): if theMakeGroup: return self.editor.DoubleNodeGroupsNew(theNodes, theModifiedElems) return self.editor.DoubleNodeGroups(theNodes, theModifiedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # @param theElems - the list of elements (edges or faces) to be replicated # The nodes for duplication could be found from these elements # @param theNodesNot - list of nodes to NOT replicate # @param theAffectedElems - the list of elements (cells and edges) to which the # replicated nodes should be associated to. # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeElem(self, theElems, theNodesNot, theAffectedElems): return self.editor.DoubleNodeElem(theElems, theNodesNot, theAffectedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # @param theElems - the list of elements (edges or faces) to be replicated # The nodes for duplication could be found from these elements # @param theNodesNot - list of nodes to NOT replicate @@ -4757,11 +4819,11 @@ class Mesh: # located on or inside shape). # The replicated nodes should be associated to affected elements. # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeElemInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemInRegion(theElems, theNodesNot, theShape) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theElems - group of of elements (edges or faces) to be replicated # @param theNodesNot - group of nodes not to replicated @@ -4771,7 +4833,7 @@ class Mesh: # @param theMakeNodeGroup forces the generation of a group containing new nodes. # @return TRUE or created groups (one or two) if operation has been completed successfully, # FALSE or None otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeElemGroup(self, theElems, theNodesNot, theAffectedElems, theMakeGroup=False, theMakeNodeGroup=False): if theMakeGroup or theMakeNodeGroup: @@ -4784,18 +4846,18 @@ class Mesh: return twoGroups[ int(theMakeNodeGroup) ] return self.editor.DoubleNodeElemGroup(theElems, theNodesNot, theAffectedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theElems - group of of elements (edges or faces) to be replicated # @param theNodesNot - group of nodes not to replicated # @param theShape - shape to detect affected elements (element which geometric center # located on or inside shape). # The replicated nodes should be associated to affected elements. - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeElemGroupInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemGroupInRegion(theElems, theNodesNot, theShape) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theElems - list of groups of elements (edges or faces) to be replicated # @param theNodesNot - list of groups of nodes not to replicated @@ -4805,7 +4867,7 @@ class Mesh: # @param theMakeNodeGroup forces the generation of a group containing new nodes. # @return TRUE or created groups (one or two) if operation has been completed successfully, # FALSE or None otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeElemGroups(self, theElems, theNodesNot, theAffectedElems, theMakeGroup=False, theMakeNodeGroup=False): if theMakeGroup or theMakeNodeGroup: @@ -4818,7 +4880,7 @@ class Mesh: return twoGroups[ int(theMakeNodeGroup) ] return self.editor.DoubleNodeElemGroups(theElems, theNodesNot, theAffectedElems) - ## Creates a hole in a mesh by doubling the nodes of some particular elements + ## Create a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theElems - list of groups of elements (edges or faces) to be replicated # @param theNodesNot - list of groups of nodes not to replicated @@ -4826,7 +4888,7 @@ class Mesh: # located on or inside shape). # The replicated nodes should be associated to affected elements. # @return TRUE if operation has been completed successfully, FALSE otherwise - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def DoubleNodeElemGroupsInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemGroupsInRegion(theElems, theNodesNot, theShape) @@ -4838,30 +4900,32 @@ class Mesh: # located on or inside shape). # The replicated nodes should be associated to affected elements. # @return groups of affected elements - # @ingroup l2_modif_edit + # @ingroup l2_modif_duplicat def AffectedElemGroupsInRegion(self, theElems, theNodesNot, theShape): return self.editor.AffectedElemGroupsInRegion(theElems, theNodesNot, theShape) ## Double nodes on shared faces between groups of volumes and create flat elements on demand. - # The list of groups must describe a partition of the mesh volumes. - # The nodes of the internal faces at the boundaries of the groups are doubled. - # In option, the internal faces are replaced by flat elements. - # Triangles are transformed in prisms, and quadrangles in hexahedrons. - # @param theDomains - list of groups of volumes - # @param createJointElems - if TRUE, create the elements - # @param onAllBoundaries - if TRUE, the nodes and elements are also created on - # the boundary between \a theDomains and the rest mesh - # @return TRUE if operation has been completed successfully, FALSE otherwise + # The list of groups must describe a partition of the mesh volumes. + # The nodes of the internal faces at the boundaries of the groups are doubled. + # In option, the internal faces are replaced by flat elements. + # Triangles are transformed in prisms, and quadrangles in hexahedrons. + # @param theDomains - list of groups of volumes + # @param createJointElems - if TRUE, create the elements + # @param onAllBoundaries - if TRUE, the nodes and elements are also created on + # the boundary between \a theDomains and the rest mesh + # @return TRUE if operation has been completed successfully, FALSE otherwise + # @ingroup l2_modif_duplicat def DoubleNodesOnGroupBoundaries(self, theDomains, createJointElems, onAllBoundaries=False ): return self.editor.DoubleNodesOnGroupBoundaries( theDomains, createJointElems, onAllBoundaries ) ## Double nodes on some external faces and create flat elements. - # Flat elements are mainly used by some types of mechanic calculations. - # - # Each group of the list must be constituted of faces. - # Triangles are transformed in prisms, and quadrangles in hexahedrons. - # @param theGroupsOfFaces - list of groups of faces - # @return TRUE if operation has been completed successfully, FALSE otherwise + # Flat elements are mainly used by some types of mechanic calculations. + # + # Each group of the list must be constituted of faces. + # Triangles are transformed in prisms, and quadrangles in hexahedrons. + # @param theGroupsOfFaces - list of groups of faces + # @return TRUE if operation has been completed successfully, FALSE otherwise + # @ingroup l2_modif_duplicat def CreateFlatElementsOnFacesGroups(self, theGroupsOfFaces ): return self.editor.CreateFlatElementsOnFacesGroups( theGroupsOfFaces ) @@ -4870,6 +4934,32 @@ class Mesh: def CreateHoleSkin(self, radius, theShape, groupName, theNodesCoords): return self.editor.CreateHoleSkin( radius, theShape, groupName, theNodesCoords ) + ## Create a polyline consisting of 1D mesh elements each lying on a 2D element of + # the initial mesh. Positions of new nodes are found by cutting the mesh by the + # plane passing through pairs of points specified by each PolySegment structure. + # If there are several paths connecting a pair of points, the shortest path is + # selected by the module. Position of the cutting plane is defined by the two + # points and an optional vector lying on the plane specified by a PolySegment. + # By default the vector is defined by Mesh module as following. A middle point + # of the two given points is computed. The middle point is projected to the mesh. + # The vector goes from the middle point to the projection point. In case of planar + # mesh, the vector is normal to the mesh. + # @param segments - PolySegment's defining positions of cutting planes. + # Return the used vector which goes from the middle point to its projection. + # @param groupName - optional name of a group where created mesh segments will + # be added. + # @ingroup l2_modif_duplicat + def MakePolyLine(self, segments, groupName='', isPreview=False ): + editor = self.editor + if isPreview: + editor = self.mesh.GetMeshEditPreviewer() + segmentsRes = editor.MakePolyLine( segments, groupName ) + for i, seg in enumerate( segmentsRes ): + segments[i].vector = seg.vector + if isPreview: + return editor.GetPreviewData() + return None + def _getFunctor(self, funcType ): fn = self.functors[ funcType._v ] if not fn: @@ -4878,12 +4968,13 @@ class Mesh: self.functors[ funcType._v ] = fn return fn - ## Returns value of a functor for a given element + ## Return value of a functor for a given element # @param funcType an item of SMESH.FunctorType enum # Type "SMESH.FunctorType._items" in the Python Console to see all items. # @param elemId element or node ID # @param isElem @a elemId is ID of element or node # @return the functor value or zero in case of invalid arguments + # @ingroup l1_measurements def FunctorValue(self, funcType, elemId, isElem=True): fn = self._getFunctor( funcType ) if fn.GetElementType() == self.GetElementType(elemId, isElem): @@ -5006,7 +5097,7 @@ class Mesh: pass # end of Mesh class -## Class used to compensate change of CORBA API of SMESH_Mesh for backward compatibility +## Private class used to compensate change of CORBA API of SMESH_Mesh for backward compatibility # with old dump scripts which call SMESH_Mesh directly and not via smeshBuilder.Mesh # class meshProxy(SMESH._objref_SMESH_Mesh): @@ -5023,7 +5114,7 @@ class meshProxy(SMESH._objref_SMESH_Mesh): omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy) -## Class wrapping SMESH_SubMesh in order to add Compute() +## Private class wrapping SMESH.SMESH_SubMesh in order to add Compute() # class submeshProxy(SMESH._objref_SMESH_subMesh): def __init__(self): @@ -5033,10 +5124,13 @@ class submeshProxy(SMESH._objref_SMESH_subMesh): new = self.__class__() return new - ## Computes the sub-mesh and returns the status of the computation + ## Compute the sub-mesh and return the status of the computation # @param refresh if @c True, Object browser is automatically updated (when running in GUI) # @return True or False - # @ingroup l2_construct + # + # This is a method of SMESH.SMESH_submesh that can be obtained via Mesh.GetSubMesh() or + # @ref smesh_algorithm.Mesh_Algorithm.GetSubMesh() "Mesh_Algorithm.GetSubMesh()". + # @ingroup l2_submeshes def Compute(self,refresh=False): if not self.mesh: self.mesh = Mesh( smeshBuilder(), None, self.GetMesh()) @@ -5055,8 +5149,9 @@ class submeshProxy(SMESH._objref_SMESH_subMesh): omniORB.registerObjref(SMESH._objref_SMESH_subMesh._NP_RepositoryId, submeshProxy) -## Class used to compensate change of CORBA API of SMESH_MeshEditor for backward compatibility -# with old dump scripts which call SMESH_MeshEditor directly and not via smeshBuilder.Mesh +## Private class used to compensate change of CORBA API of SMESH_MeshEditor for backward +# compatibility with old dump scripts which call SMESH_MeshEditor directly and not via +# smeshBuilder.Mesh # class meshEditor(SMESH._objref_SMESH_MeshEditor): def __init__(self): @@ -5080,21 +5175,23 @@ class meshEditor(SMESH._objref_SMESH_MeshEditor): def FindCoincidentNodesOnPart(self,*args): # a 3d arg added (SeparateCornerAndMediumNodes) if len( args ) == 2: args += False, return SMESH._objref_SMESH_MeshEditor.FindCoincidentNodesOnPart( self, *args ) - def MergeNodes(self,*args): # a 2nd arg added (NodesToKeep) + def MergeNodes(self,*args): # 2 args added (NodesToKeep,AvoidMakingHoles) if len( args ) == 1: - return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], [] ) + return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], [], False ) NodesToKeep = args[1] + AvoidMakingHoles = args[2] if len( args ) == 3 else False unRegister = genObjUnRegister() if NodesToKeep: if isinstance( NodesToKeep, list ) and isinstance( NodesToKeep[0], int ): NodesToKeep = self.MakeIDSource( NodesToKeep, SMESH.NODE ) if not isinstance( NodesToKeep, list ): NodesToKeep = [ NodesToKeep ] - return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], NodesToKeep ) + return SMESH._objref_SMESH_MeshEditor.MergeNodes( self, args[0], NodesToKeep, AvoidMakingHoles ) pass omniORB.registerObjref(SMESH._objref_SMESH_MeshEditor._NP_RepositoryId, meshEditor) -## Helper class for wrapping of SMESH.SMESH_Pattern CORBA class +## Private class wrapping SMESH.SMESH_Pattern CORBA class in order to treat Notebook +# variables in some methods # class Pattern(SMESH._objref_SMESH_Pattern): @@ -5128,12 +5225,13 @@ omniORB.registerObjref(SMESH._objref_SMESH_Pattern._NP_RepositoryId, Pattern) ## Private class used to bind methods creating algorithms to the class Mesh # class algoCreator: - def __init__(self): + def __init__(self, method): self.mesh = None self.defaultAlgoType = "" self.algoTypeToClass = {} + self.method = method - # Stores a python class of algorithm + # Store a python class of algorithm def add(self, algoClass): if type( algoClass ).__name__ == 'classobj' and \ hasattr( algoClass, "algoType"): @@ -5143,27 +5241,50 @@ class algoCreator: self.defaultAlgoType = algoClass.algoType #print "Add",algoClass.algoType, "dflt",self.defaultAlgoType - # creates a copy of self and assign mesh to the copy + # Create a copy of self and assign mesh to the copy def copy(self, mesh): - other = algoCreator() + other = algoCreator( self.method ) other.defaultAlgoType = self.defaultAlgoType - other.algoTypeToClass = self.algoTypeToClass + other.algoTypeToClass = self.algoTypeToClass other.mesh = mesh return other - # creates an instance of algorithm + # Create an instance of algorithm def __call__(self,algo="",geom=0,*args): - algoType = self.defaultAlgoType - for arg in args + (algo,geom): - if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ): - geom = arg - if isinstance( arg, str ) and arg: + algoType = "" + shape = 0 + if isinstance( algo, str ): + algoType = algo + elif ( isinstance( algo, geomBuilder.GEOM._objref_GEOM_Object ) and \ + not isinstance( geom, geomBuilder.GEOM._objref_GEOM_Object )): + shape = algo + elif algo: + args += (algo,) + + if isinstance( geom, geomBuilder.GEOM._objref_GEOM_Object ): + shape = geom + elif not algoType and isinstance( geom, str ): + algoType = geom + elif geom: + args += (geom,) + for arg in args: + if isinstance( arg, geomBuilder.GEOM._objref_GEOM_Object ) and not shape: + shape = arg + elif isinstance( arg, str ) and not algoType: algoType = arg + else: + import traceback, sys + msg = "Warning. Unexpected argument in mesh.%s() ---> %s" % ( self.method, arg ) + sys.stderr.write( msg + '\n' ) + tb = traceback.extract_stack(None,2) + traceback.print_list( [tb[0]] ) + if not algoType: + algoType = self.defaultAlgoType if not algoType and self.algoTypeToClass: algoType = self.algoTypeToClass.keys()[0] if self.algoTypeToClass.has_key( algoType ): #print "Create algo",algoType - return self.algoTypeToClass[ algoType ]( self.mesh, geom ) + return self.algoTypeToClass[ algoType ]( self.mesh, shape ) raise RuntimeError, "No class found for algo type %s" % algoType return None @@ -5198,7 +5319,7 @@ class hypMethodWrapper: return result pass -## A helper class that call UnRegister() of SALOME.GenericObj'es stored in it +## A helper class that calls UnRegister() of SALOME.GenericObj'es stored in it # class genObjUnRegister: @@ -5245,7 +5366,7 @@ for pluginName in os.environ[ "SMESH_MeshersList" ].split( ":" ): if type( algo ).__name__ == 'classobj' and hasattr( algo, "meshMethod" ): #print " meshMethod:" , str(algo.meshMethod) if not hasattr( Mesh, algo.meshMethod ): - setattr( Mesh, algo.meshMethod, algoCreator() ) + setattr( Mesh, algo.meshMethod, algoCreator( algo.meshMethod )) pass getattr( Mesh, algo.meshMethod ).add( algo ) pass -- 2.39.2