STRING(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UC)
SET(${PROJECT_NAME_UC}_MAJOR_VERSION 9)
-SET(${PROJECT_NAME_UC}_MINOR_VERSION 5)
+SET(${PROJECT_NAME_UC}_MINOR_VERSION 6)
SET(${PROJECT_NAME_UC}_PATCH_VERSION 0)
SET(${PROJECT_NAME_UC}_VERSION
${${PROJECT_NAME_UC}_MAJOR_VERSION}.${${PROJECT_NAME_UC}_MINOR_VERSION}.${${PROJECT_NAME_UC}_PATCH_VERSION})
#. run your python code, which creates a 2D mesh,
#. invoke **Compute** command, which computes a 3D mesh.
-.. warning:: **Use Edges to be Created Manually** and **Use Faces to be Created Manually** algorithms should be assigned *before* mesh generation by the Python code.
+ .. warning::
+ * **Use Edges to be Created Manually** and **Use Faces to be Created Manually** algorithms should be assigned *before* mesh generation by the Python code.
+ * Nodes and elements created in your script must be assigned to geometry entities by calling *SetMeshElementOnShape*, *SetNodeOnVertex*, *SetNodeOnEdge* etc. in order to be used by an algorithm of upper dimension.
Consider trying a sample script demonstrating the usage of :ref:`Use Faces to be Created Manually <tui_use_existing_faces>` algorithm for construction of a 2D mesh using Python commands.
{
_error = COMPERR_OK;
_comment.clear();
- list<const SMDS_MeshElement*>::iterator elem = _badInputElements.begin();
- for ( ; elem != _badInputElements.end(); ++elem )
- if ( (*elem)->GetID() < 1 )
- delete *elem;
+ for ( const SMDS_MeshElement* & elem : _badInputElements )
+ if ( !elem->IsNull() && elem->GetID() < 1 )
+ delete elem;
_badInputElements.clear();
_mesh = 0;
SMDS_ElemIteratorPtr eIt = sm->GetElements();
while ( eIt->more() ) addBadInputElement( eIt->next() );
}
+ _mesh = sm->GetParent();
}
}
#define env_sep ':'
#endif
+namespace
+{
+ // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
+ // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
+ struct _Hyp : public SMESH_Hypothesis
+ {
+ void NullifyGen()
+ {
+ _gen = 0;
+ }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Fill a map of shapes with all sub-shape of a sub-mesh
+ */
+ //================================================================================
+
+ TopTools_IndexedMapOfShape * fillAllowed( SMESH_subMesh* sm,
+ const bool toFill,
+ TopTools_IndexedMapOfShape * allowedSub )
+ {
+ if ( !toFill || !allowedSub )
+ {
+ return nullptr;
+ }
+ if ( allowedSub->IsEmpty() )
+ {
+ allowedSub->ReSize( sm->DependsOn().size() + 1 );
+ allowedSub->Add( sm->GetSubShape() );
+ for ( const auto & key_sm : sm->DependsOn() )
+ allowedSub->Add( key_sm.second->GetSubShape() );
+ }
+ return allowedSub;
+ }
+}
+
//=============================================================================
/*!
* Constructor
_compute_canceled = false;
}
-namespace
-{
- // a structure used to nullify SMESH_Gen field of SMESH_Hypothesis,
- // which is needed for SMESH_Hypothesis not deleted before ~SMESH_Gen()
- struct _Hyp : public SMESH_Hypothesis
- {
- void NullifyGen()
- {
- _gen = 0;
- }
- };
-}
-
//=============================================================================
/*!
* Destructor
*/
//=============================================================================
-bool SMESH_Gen::Compute(SMESH_Mesh & aMesh,
- const TopoDS_Shape & aShape,
- const int aFlags /*= COMPACT_MESH*/,
- const ::MeshDimension aDim /*=::MeshDim_3D*/,
- TSetOfInt* aShapesId /*=0*/)
+bool SMESH_Gen::Compute(SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const int aFlags /*= COMPACT_MESH*/,
+ const ::MeshDimension aDim /*=::MeshDim_3D*/,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* anAllowedSubShapes/*=0*/)
{
MEMOSTAT;
bool ret = true;
- SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
+ SMESH_subMesh *sm, *shapeSM = aMesh.GetSubMesh(aShape);
const bool includeSelf = true;
const bool complexShapeFirst = true;
if ( !aMesh.HasShapeToMesh() )
computeEvent = SMESH_subMesh::COMPUTE_NOGEOM; // if several algos and no geometry
+ TopTools_IndexedMapOfShape *allowedSubShapes = anAllowedSubShapes, allowedSub;
+ if ( aShapeOnly && !allowedSubShapes )
+ allowedSubShapes = &allowedSub;
+
if ( anUpward ) // is called from the below code in this method
{
// ===============================================
// Mesh all the sub-shapes starting from vertices
// ===============================================
- smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
+ smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst);
while ( smIt->more() )
{
SMESH_subMesh* smToCompute = smIt->next();
{
if (_compute_canceled)
return false;
+ smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
setCurrentSubMesh( smToCompute );
smToCompute->ComputeStateEngine( computeEvent );
- setCurrentSubMesh( NULL );
+ setCurrentSubMesh( nullptr );
+ smToCompute->SetAllowedSubShapes( nullptr );
}
// we check all the sub-meshes here and detect if any of them failed to compute
TopoDS_Shape algoShape;
int prevShapeDim = -1, aShapeDim;
- smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
+ smIt = shapeSM->getDependsOnIterator(includeSelf, complexShapeFirst);
while ( smIt->more() )
{
SMESH_subMesh* smToCompute = smIt->next();
{
if (_compute_canceled)
return false;
+ smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
setCurrentSubMesh( smToCompute );
smToCompute->ComputeStateEngine( computeEvent );
- setCurrentSubMesh( NULL );
+ setCurrentSubMesh( nullptr );
+ smToCompute->SetAllowedSubShapes( nullptr );
if ( aShapesId )
aShapesId->insert( smToCompute->GetId() );
}
const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
const int aShapeDim = GetShapeDim( aSubShape );
- //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue;
if ( aShapeDim < 1 ) continue;
// check for preview dimension limitations
if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true))
{
if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
+ TopTools_IndexedMapOfShape* localAllowed = allowedSubShapes;
+ if ( localAllowed && localAllowed->IsEmpty() )
+ localAllowed = 0; // prevent fillAllowed() with aSubShape
+
SMESH_Hypothesis::Hypothesis_Status status;
if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
// mesh a lower smToCompute starting from vertices
- Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId );
- // Compute( aMesh, aSubShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId );
+ Compute( aMesh, aSubShape, aFlags | SHAPE_ONLY_UPWARD, aDim, aShapesId, localAllowed );
}
}
}
if (_compute_canceled)
return false;
+ sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes ));
setCurrentSubMesh( sm );
sm->ComputeStateEngine( computeEvent );
setCurrentSubMesh( NULL );
+ sm->SetAllowedSubShapes( nullptr );
if ( aShapesId )
aShapesId->insert( sm->GetId() );
}
// -----------------------------------------------
// mesh the rest sub-shapes starting from vertices
// -----------------------------------------------
- ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId );
+ ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId, allowedSubShapes );
}
MEMOSTAT;
SMESH_MesherHelper aHelper( aMesh );
if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
{
- aHelper.FixQuadraticElements( sm->GetComputeError() );
+ aHelper.FixQuadraticElements( shapeSM->GetComputeError() );
}
}
#include <string>
#include <TopoDS_Shape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
class SMESHDS_Document;
class SMESH_Algo;
* \param aFlags - ComputeFlags. By default compute the whole mesh and compact at the end.
* \param aDim - upper level dimension of the mesh computation (for preview)
* \param aShapesId - list of shapes with computed mesh entities (elements or nodes)
+ * \param anAllowedSubShapes - shapes to mesh only. Mesh all if empty or nullptr
* \retval bool - true if none sub-mesh failed to compute
*/
- bool Compute(::SMESH_Mesh & aMesh,
- const TopoDS_Shape & aShape,
- const int aFlags = COMPACT_MESH,
- const ::MeshDimension aDim=::MeshDim_3D,
- TSetOfInt* aShapesId=0);
+ bool Compute(::SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const int aFlags = COMPACT_MESH,
+ const ::MeshDimension aDim=::MeshDim_3D,
+ TSetOfInt* aShapesId=0,
+ TopTools_IndexedMapOfShape* anAllowedSubShapes=0);
void PrepareCompute(::SMESH_Mesh & aMesh,
const TopoDS_Shape & aShape);
//=======================================================================
//function : IsMoreLocalThanPredicate::IsOk
-//purpose :
+//purpose : Check if aShape is more local than this->_shape
//=======================================================================
bool SMESH_HypoFilter::IsMoreLocalThanPredicate::IsOk(const SMESH_Hypothesis* aHyp,
if ( SMESH_MesherHelper::IsSubShape( aShape, /*mainShape=*/_shape ))
return true;
- if ( aShape.ShapeType() == TopAbs_COMPOUND &&
+ if ( aShape.ShapeType() == TopAbs_COMPOUND &&
!SMESH_MesherHelper::IsSubShape( _shape, /*mainShape=*/aShape)) // issue 0020963
{
- for ( int type = TopAbs_SOLID; type < TopAbs_SHAPE; ++type )
- if ( aHyp->GetDim() == SMESH_Gen::GetShapeDim( TopAbs_ShapeEnum( type )))
- for ( TopExp_Explorer exp( aShape, TopAbs_ShapeEnum( type )); exp.More(); exp.Next())
- if ( SMESH_MesherHelper::IsSubShape( exp.Current(), /*mainShape=*/_shape ))
- return true;
+ // [bos#22320] compound of FACEs is MORE local than compound of SOLIDs
+ TopAbs_ShapeEnum givenType = SMESH_MesherHelper::GetGroupType( _shape );
+ TopAbs_ShapeEnum hypType = SMESH_MesherHelper::GetGroupType( aShape );
+ if ( SMESH_Gen::GetShapeDim( givenType ) > SMESH_Gen::GetShapeDim( hypType ))
+ {
+ for ( int type = TopAbs_SOLID; type < TopAbs_SHAPE; ++type )
+ if ( aHyp->GetDim() == SMESH_Gen::GetShapeDim( TopAbs_ShapeEnum( type )))
+ for ( TopExp_Explorer exp( aShape, TopAbs_ShapeEnum( type )); exp.More(); exp.Next())
+ if ( SMESH_MesherHelper::IsSubShape( exp.Current(), /*mainShape=*/_shape ))
+ return true;
+ }
}
+ // take forced sub-mesh priority into account
if ( _preferableShapes.Contains( aShape ))
return true; // issue 21559, Mesh_6
//=======================================================================
//function : SMESH_HypoFilter
-//purpose :
+//purpose :
//=======================================================================
SMESH_HypoFilter::SMESH_HypoFilter()
SMESH_MesherHelper helper( *GetMesh() );
helper.SetElementsOnShape( true );
- SMDS_ElemIteratorPtr faceIt;
- if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
- else faceIt = SMESHUtils::elemSetIterator( theElems );
+ // get standalone groups of faces
+ vector< SMDS_MeshGroup* > allFaceGroups, faceGroups;
+ for ( SMESHDS_GroupBase* grBase : GetMeshDS()->GetGroups() )
+ if ( SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( grBase ))
+ if ( group->GetType() == SMDSAbs_Face && !group->IsEmpty() )
+ allFaceGroups.push_back( & group->SMDSGroup() );
bool checkUV;
gp_XY uv [9]; uv[8] = gp_XY(0,0);
Handle(Geom_Surface) surface;
TopLoc_Location loc;
+ SMDS_ElemIteratorPtr faceIt;
+ if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
+ else faceIt = SMESHUtils::elemSetIterator( theElems );
+
while ( faceIt->more() )
{
const SMDS_MeshElement* quad = faceIt->next();
myLastCreatedNodes.push_back( nCentral );
}
- // create 4 triangles
-
helper.SetIsQuadratic ( nodes.size() > 4 );
helper.SetIsBiQuadratic( nodes.size() == 9 );
if ( helper.GetIsQuadratic() )
helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
+ // select groups to update
+ faceGroups.clear();
+ for ( SMDS_MeshGroup* group : allFaceGroups )
+ if ( group->Remove( quad ))
+ faceGroups.push_back( group );
+
+ // create 4 triangles
+
GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
for ( int i = 0; i < 4; ++i )
SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
nodes[(i+1)%4],
nCentral );
- ReplaceElemInGroups( tria, quad, GetMeshDS() );
myLastCreatedElems.push_back( tria );
+ for ( SMDS_MeshGroup* group : faceGroups )
+ group->Add( tria );
}
}
}
}
_computeCost = 0; // how costly is to compute this sub-mesh
_realComputeCost = 0;
+ _allowedSubShapes = nullptr;
}
//=============================================================================
if (_father->HasShapeToMesh() ) {
bool subComputed = false, subFailed = false;
if (!algo->OnlyUnaryInput()) {
- if ( event == COMPUTE /*&&
- ( algo->NeedDiscreteBoundary() || algo->SupportSubmeshes() )*/)
- shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
- else
- subComputed = SubMeshesComputed( & subFailed );
+ // --- commented for bos#22320 to compute all sub-shapes at once if possible;
+ // --- in case COMPUTE_SUBMESH, set of sub-shapes is limited
+ // --- by calling SetAllowedSubShapes()
+ // if ( event == COMPUTE )
+ // shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToComput;
+ // else
+ // subComputed = SubMeshesComputed( & subFailed );
+ shape = getCollection( gen, algo, subComputed, subFailed, algo->SubMeshesToCompute());
}
else {
subComputed = SubMeshesComputed();
((SMESHDS_Hypothesis*)hyps.front())->SaveTo( hypStr.Stream() );
hypStr << " ";
}
- cout << _algo->GetName()
- << " " << _father->GetSubMesh( subS.Current() )->GetId()
+ cout << _father->GetSubMesh( subS.Current() )->GetId()
+ << " " << ( ret ? "OK" : "FAIL" )
+ << " " << _algo->GetName()
<< " " << hypStr << endl;
}
#endif
break;
case COMPUTE: // nothing to do
break;
+ case COMPUTE_SUBMESH: // nothing to do
+ break;
case COMPUTE_CANCELED: // nothing to do
break;
case CLEAN:
const TopoDS_Shape& S = subMesh->_subShape;
if ( S.ShapeType() != this->_subShape.ShapeType() )
continue;
+ if ( _allowedSubShapes && !_allowedSubShapes->IsEmpty() && !_allowedSubShapes->Contains( S ))
+ continue;
if ( subMesh == this )
{
aBuilder.Add( aCompound, S );
#include "Utils_SALOME_Exception.hxx"
#include <TopoDS_Shape.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
#include <list>
#include <map>
bool IsMeshComputed() const;
// check if _subMeshDS contains mesh elements unless _alwaysComputed==true
+ /*!
+ * \brief Set sub-shapes that are allowed to compute at once by a multidimensional algo
+ */
+ void SetAllowedSubShapes( const TopTools_IndexedMapOfShape* subShapes )
+ { _allowedSubShapes = subShapes; }
+
/*!
* \brief Allow algo->Compute() if a subshape of lower dim is meshed but
* none mesh entity is bound to it
// mesh several edges as a whole and leave some of them without mesh entities
bool _alwaysComputed;
+ const TopTools_IndexedMapOfShape* _allowedSubShapes; // allowed to be returned by getCollection()
+
};
#endif
{
myDlg = new SMESHGUI_MeshOrderDlg( desktop() );
- myHelpFileName = "constructing_meshes.html#mesh-order-anchor";
+ myHelpFileName = "constructing_meshes.html#submesh-order-anchor";
}
//================================================================================
getEditor().QuadTo4Tri( faces );
TPythonDump() << this << ".QuadTo4Tri( " << theObject << " )";
+ declareMeshModified( /*isReComputeSafe=*/false );
+
SMESH_CATCH( SMESH::throwCorbaException );
}
throw(SALOME::SALOME_Exception)
{
Unexpect aCatch(SALOME_SalomeException);
+
+ const int prevNbMeshEnt = NbNodes() + NbElements();
+
if ( _preMeshInfo )
_preMeshInfo->ForgetOrLoad();
- const int prevNbMeshEnt = _impl->NbNodes() + _impl->GetMeshDS()->NbElements();
-
std::string error;
SMESH_Hypothesis::Hypothesis_Status status = addHypothesis( aSubShape, anHyp, &error );
anErrorText = error.c_str();
Returns:
A list of edge groups and a list of corresponding node groups,
- where the group is a list of IDs of edges or elements, like follows
+ where the group is a list of IDs of edges or nodes, like follows
[[[branch_edges_1],[branch_edges_2]], [[branch_nodes_1],[branch_nodes_2]]].
If a group is closed, the first and last nodes of the group are same.
"""
if ( getBox()->IsOut( point ))
return false;
+ bool ok = false;
+ double dist2, param;
+ distance2 = Precision::Infinite();
+
if ( isLeaf() )
{
for ( size_t i = 0; i < _segments.size(); ++i )
if ( !_segments[i].IsOut( point ) &&
- _segments[i].IsOn( point, distance2, u ))
- return true;
+ _segments[i].IsOn( point, dist2, param ) &&
+ dist2 < distance2 )
+ {
+ distance2 = dist2;
+ u = param;
+ ok = true;
+ }
+ return ok;
}
else
{
for (int i = 0; i < 8; i++)
- if (((CurveProjector*) myChildren[i])->IsOnCurve( point, distance2, u ))
- return true;
+ if (((CurveProjector*) myChildren[i])->IsOnCurve( point, dist2, param ) &&
+ dist2 < distance2 )
+ {
+ distance2 = dist2;
+ u = param;
+ ok = true;
+ }
}
- return false;
+ return ok;
}
-
+
//================================================================================
/*!
* \brief Initialize
_pLast = pl;
_curve = curve;
_length2 = pf.SquareDistance( pl );
+ _line.SetLocation( pf );
+ _line.SetDirection( gp_Vec( pf, pl ));
_chord2 = Max( _line. SquareDistance( curve->Value( uf + 0.25 * ( ul - uf ))),
Max( _line.SquareDistance( curve->Value( uf + 0.5 * ( ul - uf ))),
_line.SquareDistance( curve->Value( uf + 0.75 * ( ul - uf )))));
_chord2 = Max( tol, _chord2 );
_chord = Sqrt( _chord2 );
- _line.SetLocation( pf );
- _line.SetDirection( gp_Vec( pf, pl ));
Bnd_Box bb;
BndLib_Add3dCurve::Add( GeomAdaptor_Curve( curve, uf, ul ), tol, bb );
gp_Vec edge( _pFirst, _pLast );
gp_Vec n1p ( _pFirst, point );
u = ( edge * n1p ) / _length2; // param [0,1] on the edge
- if ( u < 0 )
+ if ( u < 0. )
{
if ( _pFirst.SquareDistance( point ) > _chord2 )
return false;
}
- else if ( u > _chord )
+ else if ( u > 1. )
{
if ( _pLast.SquareDistance( point ) > _chord2 )
return false;
BOTTOM_EDGE = 0, TOP_EDGE, V0_EDGE, V1_EDGE, // edge IDs in face
NB_WALL_FACES = 4 }; //
-namespace {
-
+namespace
+{
+ //=======================================================================
+ /*!
+ * \brief Auxiliary mesh
+ */
+ struct TmpMesh: public SMESH_Mesh
+ {
+ TmpMesh() {
+ _isShapeToMesh = (_id = 0);
+ _myMeshDS = new SMESHDS_Mesh( _id, true );
+ }
+ };
//=======================================================================
/*!
* \brief Quadrangle algorithm
*/
- struct TQuadrangleAlgo : public StdMeshers_Quadrangle_2D
+ class TQuadrangleAlgo : public StdMeshers_Quadrangle_2D
{
+ typedef NCollection_DataMap< TopoDS_Face, FaceQuadStruct::Ptr > TFace2QuadMap;
+ TFace2QuadMap myFace2QuadMap;
+
TQuadrangleAlgo(SMESH_Gen* gen)
: StdMeshers_Quadrangle_2D( gen->GetANewId(), gen)
{
}
- static StdMeshers_Quadrangle_2D* instance( SMESH_Algo* fatherAlgo,
- SMESH_MesherHelper* helper=0)
+ public:
+
+ //================================================================================
+ // Clear data of TQuadrangleAlgo at destruction
+ struct Cleaner
+ {
+ TQuadrangleAlgo* myAlgo;
+
+ Cleaner(TQuadrangleAlgo* algo): myAlgo( algo ){}
+ ~Cleaner() { myAlgo->reset(); }
+ };
+
+ //================================================================================
+ // Return TQuadrangleAlgo singleton
+ static TQuadrangleAlgo* instance( SMESH_Algo* fatherAlgo,
+ SMESH_MesherHelper* helper=0)
{
static TQuadrangleAlgo* algo = new TQuadrangleAlgo( fatherAlgo->GetGen() );
if ( helper &&
return algo;
}
+
+ //================================================================================
+ // Clear collected data
+ void reset()
+ {
+ StdMeshers_Quadrangle_2D::myQuadList.clear();
+ StdMeshers_Quadrangle_2D::myHelper = nullptr;
+ StdMeshers_Quadrangle_2D::myProxyMesh.reset();
+ myFace2QuadMap.Clear();
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return FaceQuadStruct if a given FACE can be meshed by StdMeshers_Quadrangle_2D
+ */
+ FaceQuadStruct::Ptr CheckNbEdges(SMESH_Mesh& theMesh,
+ const TopoDS_Shape& theShape )
+ {
+ const TopoDS_Face& face = TopoDS::Face( theShape );
+ if ( myFace2QuadMap.IsBound( face ))
+ return myFace2QuadMap.Find( face );
+
+ FaceQuadStruct::Ptr & resultQuad = * myFace2QuadMap.Bound( face, FaceQuadStruct::Ptr() );
+
+ FaceQuadStruct::Ptr quad =
+ StdMeshers_Quadrangle_2D::CheckNbEdges( theMesh, face, /*considerMesh=*/false, myHelper );
+ if ( quad )
+ {
+ // check if the quadrangle mesh would be valid
+
+ // check existing 1D mesh
+ // int nbSegments[4], i = 0;
+ // for ( FaceQuadStruct::Side & side : quad->side )
+ // nbSegments[ i++ ] = side.grid->NbSegments();
+ // if ( nbSegments[0] > 0 && nbSegments[2] > 0 && nbSegments[0] != nbSegments[2] ||
+ // nbSegments[1] > 0 && nbSegments[3] > 0 && nbSegments[1] != nbSegments[3] )
+ // return resultQuad;
+
+ int nbEdges = 0;
+ for ( FaceQuadStruct::Side & side : quad->side )
+ nbEdges += side.grid->NbEdges();
+ if ( nbEdges == 4 )
+ return resultQuad = quad;
+
+ TmpMesh mesh;
+ mesh.ShapeToMesh( face );
+ SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
+ SMESH_MesherHelper helper( mesh );
+ helper.SetSubShape( face );
+ helper.SetElementsOnShape( true );
+
+ // create nodes on all VERTEX'es
+ for ( TopExp_Explorer vert( face, TopAbs_VERTEX ); vert.More(); vert.Next() )
+ mesh.GetSubMesh( vert.Current() )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+
+ FaceQuadStruct::Ptr tmpQuad( new FaceQuadStruct() );
+ tmpQuad->side.resize( 4 );
+
+ // divide quad sides into halves at least
+ const SMDS_MeshNode* node;
+ for ( int iDir = 0; iDir < 2; ++iDir )
+ {
+ StdMeshers_FaceSidePtr sides[2] = { quad->side[iDir], quad->side[iDir+2] };
+ std::map< double, const SMDS_MeshNode* > nodes[2];
+ for ( int iS : { 0, 1 } )
+ {
+ node = SMESH_Algo::VertexNode( sides[iS]->FirstVertex(), meshDS );
+ nodes[iS].insert( std::make_pair( 0, node ));
+ double curLen = 0;
+ for ( int iE = 1; iE < sides[iS]->NbEdges(); ++iE )
+ {
+ curLen += sides[iS]->EdgeLength( iE - 1 );
+ double u = curLen / sides[iS]->Length();
+ node = SMESH_Algo::VertexNode( sides[iS]->FirstVertex( iE ), meshDS );
+ nodes[iS ].insert( std::make_pair( u, node ));
+ nodes[1-iS].insert( std::make_pair( u, nullptr ));
+ }
+ nodes[iS].insert( std::make_pair( 0.5, nullptr ));
+ node = SMESH_Algo::VertexNode( sides[iS]->LastVertex(), meshDS );
+ nodes[iS].insert( std::make_pair( 1, node ));
+ }
+
+ for ( int iS : { 0, 1 } )
+ {
+ UVPtStructVec sideNodes;
+ sideNodes.reserve( nodes[ iS ].size() );
+ for ( auto & u_node : nodes[ iS ])
+ {
+ if ( !u_node.second )
+ {
+ gp_Pnt p = sides[iS]->Value3d( u_node.first );
+ u_node.second = meshDS->AddNode( p.X(), p.Y(), p.Z() );
+ TopoDS_Edge edge;
+ double param = sides[iS]->Parameter( u_node.first, edge );
+ meshDS->SetNodeOnEdge( u_node.second, edge, param );
+ }
+ sideNodes.push_back( u_node.second );
+ sideNodes.back().SetUV( helper.GetNodeUV( face, u_node.second ));
+ }
+ tmpQuad->side[ iS ? iDir+2 : iDir ] = StdMeshers_FaceSide::New( sideNodes, face );
+ }
+ }
+ StdMeshers_Quadrangle_2D::myCheckOri = true;
+ StdMeshers_Quadrangle_2D::myQuadList.clear();
+ StdMeshers_Quadrangle_2D::myQuadList.push_back( tmpQuad );
+ StdMeshers_Quadrangle_2D::myHelper = &helper;
+ if ( StdMeshers_Quadrangle_2D::computeQuadDominant( mesh, face, tmpQuad ) &&
+ StdMeshers_Quadrangle_2D::check())
+ {
+ resultQuad = quad;
+ }
+ StdMeshers_Quadrangle_2D::myQuadList.clear();
+ StdMeshers_Quadrangle_2D::myHelper = nullptr;
+ }
+ return resultQuad;
+ }
};
+
//=======================================================================
/*!
* \brief Algorithm projecting 1D mesh
int removeQuasiQuads(list< SMESH_subMesh* >& notQuadSubMesh,
SMESH_MesherHelper* helper,
- StdMeshers_Quadrangle_2D* quadAlgo)
+ TQuadrangleAlgo* quadAlgo)
{
int nbRemoved = 0;
//SMESHDS_Mesh* mesh = notQuadSubMesh.front()->GetFather()->GetMeshDS();
return nbSides;
}
+ //================================================================================
+ /*!
+ * \brief Count EDGEs ignoring degenerated ones
+ */
+ //================================================================================
+
+ int CountEdges( const TopoDS_Face& face )
+ {
+ int nbE = 0;
+ for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
+ if ( !SMESH_Algo::isDegenerated( TopoDS::Edge( edgeExp.Current() )))
+ ++nbE;
+
+ return nbE;
+ }
+
//================================================================================
/*!
* \brief Set/get wire index to FaceQuadStruct
}
#endif
}
+
} // namespace
//=======================================================================
SMESH_MesherHelper helper( theMesh );
myHelper = &helper;
myPrevBottomSM = 0;
+ TQuadrangleAlgo::Cleaner quadCleaner( TQuadrangleAlgo::instance( this ));
int nbSolids = helper.Count( theShape, TopAbs_SOLID, /*skipSame=*/false );
if ( nbSolids < 1 )
// look for meshed FACEs ("source" FACEs) that must be prism bottoms
list< TopoDS_Face > meshedFaces, notQuadMeshedFaces, notQuadFaces;
const bool meshHasQuads = ( theMesh.NbQuadrangles() > 0 );
- //StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this );
for ( int iF = 1; iF <= faceToSolids.Extent(); ++iF )
{
const TopoDS_Face& face = TopoDS::Face( faceToSolids.FindKey( iF ));
}
TopTools_MapOfShape meshedSolids;
+ NCollection_DataMap< TopoDS_Shape, SMESH_subMesh* > meshedFace2AlgoSM;
list< Prism_3D::TPrismTopo > meshedPrism;
list< TopoDS_Face > suspectSourceFaces;
TopTools_ListIteratorOfListOfShape solidIt;
{
prism.Clear();
prism.myBottom = face;
+ if ( meshedFace2AlgoSM.IsBound( face ))
+ prism.myAlgoSM = meshedFace2AlgoSM.Find( face );
if ( !initPrism( prism, solid, selectBottom ) ||
!compute( prism ))
return false;
SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
- if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+ if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ) ||
+ !myHelper->IsStructured( theMesh.GetSubMesh( prism.myTop )))
{
meshedFaces.push_front( prism.myTop );
+ if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() )
+ {
+ meshedFace2AlgoSM.Bind( prism.myTop, prism.myAlgoSM );
+ meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
+ }
}
else
{
solidList.Remove( solidIt );
continue; // already computed prism
}
- if ( myHelper->IsBlock( solid )) {
- solidIt.Next();
- continue; // too trivial
+ if ( myHelper->IsBlock( solid ))
+ {
+ bool isStructBase = true;
+ if ( prismIt->myAlgoSM )
+ isStructBase = ( myHelper->IsSameElemGeometry( prismIt->myAlgoSM->GetSubMeshDS(),
+ SMDSGeom_QUADRANGLE ) &&
+ myHelper->IsStructured(prismIt->myAlgoSM ));
+ if ( isStructBase )
+ {
+ solidIt.Next();
+ continue; // too trivial
+ }
}
// find a source FACE of the SOLID: it's a FACE sharing a bottom EDGE with wFace
const TopoDS_Edge& wEdge = (*wQuad)->side[ QUAD_TOP_SIDE ].grid->Edge(0);
}
prism.Clear();
prism.myBottom = candidateF;
+ prism.myAlgoSM = prismIt->myAlgoSM;
mySetErrorToSM = false;
if ( !myHelper->IsSubShape( candidateF, prismIt->myShape3D ) &&
myHelper ->IsSubShape( candidateF, solid ) &&
!myHelper->GetMesh()->GetSubMesh( candidateF )->IsMeshComputed() &&
initPrism( prism, solid, /*selectBottom=*/false ) &&
!myHelper->GetMesh()->GetSubMesh( prism.myTop )->IsMeshComputed() &&
- !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() &&
- project2dMesh( sourceF, prism.myBottom ))
+ !myHelper->GetMesh()->GetSubMesh( prism.myBottom )->IsMeshComputed() )
{
- mySetErrorToSM = true;
- if ( !compute( prism ))
- return false;
- SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
- if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+ if ( project2dMesh( sourceF, prism.myBottom ))
{
- meshedFaces.push_front( prism.myTop );
- meshedFaces.push_front( prism.myBottom );
- selectBottom = false;
+ mySetErrorToSM = true;
+ if ( !compute( prism ))
+ return false;
+ SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( prism.myTop );
+ if ( !myHelper->IsSameElemGeometry( smDS, SMDSGeom_QUADRANGLE ))
+ {
+ meshedFaces.push_front( prism.myTop );
+ meshedFaces.push_front( prism.myBottom );
+ selectBottom = false;
+ if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() )
+ {
+ meshedFace2AlgoSM.Bind( prism.myTop, prism.myAlgoSM );
+ meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
+ }
+ }
+ meshedPrism.push_back( prism );
+ meshedSolids.Add( solid );
+ }
+ else
+ {
+ meshedFaces.push_back( prism.myBottom );
+ if ( prism.myAlgoSM && prism.myAlgoSM->GetAlgo() )
+ meshedFace2AlgoSM.Bind( prism.myBottom, prism.myAlgoSM );
}
- meshedPrism.push_back( prism );
- meshedSolids.Add( solid );
}
InitComputeError();
}
allSubMeComputed = smIt->next()->IsMeshComputed();
if ( allSubMeComputed )
{
- faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+ faceSM->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH );
if ( !faceSM->IsEmpty() ) {
meshedFaces.push_front( face ); // higher priority
selectBottom = true;
SMESH_Mesh* mesh = myHelper->GetMesh();
- StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
+ TQuadrangleAlgo* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
TopTools_MapOfShape faceMap;
TopTools_IndexedDataMapOfShapeListOfShape edgeToFaces;
{
// find any applicable algorithm assigned to any FACE of the main shape
std::vector< TopoDS_Shape > faces;
- if ( myPrevBottomSM &&
- myPrevBottomSM->GetAlgo()->IsApplicableToShape( thePrism.myBottom, /*all=*/false ))
+ if ( thePrism.myAlgoSM && thePrism.myAlgoSM->GetAlgo() )
+ faces.push_back( thePrism.myAlgoSM->GetSubShape() );
+ if ( myPrevBottomSM && myPrevBottomSM->GetAlgo() )
faces.push_back( myPrevBottomSM->GetSubShape() );
TopExp_Explorer faceIt( mesh->GetShapeToMesh(), TopAbs_FACE );
while ( smIt->more() && subOK )
{
SMESH_subMesh* sub = smIt->next();
- sub->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+ sub->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH );
subOK = sub->IsMeshComputed();
}
if ( !subOK )
}
try {
OCC_CATCH_SIGNALS;
+
+ Hypothesis_Status status;
+ algo->CheckHypothesis( *mesh, faces[i], status );
algo->InitComputeError();
- algo->Compute( *mesh, botSM->GetSubShape() );
+ if ( algo->Compute( *mesh, botSM->GetSubShape() ))
+ {
+ myPrevBottomSM = thePrism.myAlgoSM = mesh->GetSubMesh( faces[i] );
+ break;
+ }
}
catch (...) {
}
}
}
}
+ else
+ {
+ myPrevBottomSM = thePrism.myAlgoSM = botSM;
+ }
if ( botSM->IsEmpty() )
return error( COMPERR_BAD_INPUT_MESH,
TCom( "No mesher defined to compute the base face #")
<< shapeID( thePrism.myBottom ));
- if ( botSM->GetAlgo() )
- myPrevBottomSM = botSM;
-
return true;
}
SMESHDS_Mesh* meshDS = myHelper->GetMeshDS();
DBGOUT( endl << "COMPUTE Prism " << meshDS->ShapeToIndex( thePrism.myShape3D ));
- TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this );
- StdMeshers_Quadrangle_2D* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
+ TProjction1dAlgo* projector1D = TProjction1dAlgo::instance( this );
+ TQuadrangleAlgo* quadAlgo = TQuadrangleAlgo::instance( this, myHelper );
// SMESH_HypoFilter hyp1dFilter( SMESH_HypoFilter::IsAlgo(),/*not=*/true);
// hyp1dFilter.And( SMESH_HypoFilter::HasDim( 1 ));
bool StdMeshers_Prism_3D::project2dMesh(const TopoDS_Face& theSrcFace,
const TopoDS_Face& theTgtFace)
{
+ if ( CountEdges( theSrcFace ) != CountEdges( theTgtFace ))
+ return false;
+
TProjction2dAlgo* projector2D = TProjction2dAlgo::instance( this );
projector2D->myHyp.SetSourceFace( theSrcFace );
bool ok = projector2D->Compute( *myHelper->GetMesh(), theTgtFace );
myBottomEdges.clear();
myNbEdgesInWires.clear();
myWallQuads.clear();
+ myAlgoSM = nullptr;
}
//================================================================================
column = & ( myParamToColumnMap->rbegin()->second );
else
column = & ( myParamToColumnMap->begin()->second );
- if ( column->size() > 0 )
+ if ( column->size() > 1 )
edge = myHelper.GetSubShapeByNode( (*column)[ 1 ], meshDS );
if ( edge.IsNull() || edge.ShapeType() == TopAbs_VERTEX )
node = column->front();
std::list< int > myNbEdgesInWires;
bool myNotQuadOnTop;
+ mutable SMESH_subMesh* myAlgoSM; // sub-mesh with algo which computed myBottom
size_t NbWires() const { return myNbEdgesInWires.size(); }