54416: Extrusion 3D algo is not applicable to a prismatic shape

Fix for the case of non-manifold internal faces

+
1) Fix SMESH_Actor for coloring using custom 1D functor
2) Improve some doc images
This commit is contained in:
eap 2019-08-23 16:16:29 +03:00
parent f422debfb5
commit db6f1785f5
9 changed files with 210 additions and 78 deletions

BIN
doc/salome/gui/SMESH/images/hypo_quad_params_1.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -42,14 +42,26 @@ Length from Edges
Quadrangle parameters
#####################
**Quadrangle parameters** is a hypothesis for :ref:`quad_ijk_algo_page`.
Quadrangle parameters dialog includes four tab pages:
- :ref:`Transition <transition_anchor>`
- :ref:`Base vertex <base_vertex_anchor>`
- :ref:`Corner Vertices <corner_vertices_anchor>`
- :ref:`Enforced nodes <enforced_nodes_anchor>`
.. _transition_anchor:
Transition tab
--------------
.. image:: ../images/ hypo_quad_params_dialog.png
:align: center
.. centered::
Quadrangle parameters: Transition
**Quadrangle parameters** is a hypothesis for :ref:`quad_ijk_algo_page`.
**Transition** tab is used to define the algorithm of transition between opposite sides of the face with a different number of segments on them. The following types of transition algorithms are available:
* **Standard** is the default case, when both triangles and quadrangles are possible in the transition area along the finer meshed sides.
@ -70,7 +82,10 @@ Quadrangle parameters
.. centered::
The fastest transition pattern: 3 to 1
**Base vertex** tab allows using Quadrangle: Mapping algorithm for meshing of trilateral faces. In this case it is necessary to select the vertex, which will be used as the forth degenerated side of quadrangle.
.. _base_vertex_anchor:
Base vertex tab
---------------
.. image:: ../images/ hypo_quad_params_dialog_vert.png
:align: center
@ -78,33 +93,41 @@ Quadrangle parameters
.. centered::
Quadrangle parameters: Base Vertex
**Base vertex** tab allows using Quadrangle: Mapping algorithm for meshing of trilateral faces. In this case it is necessary to select the vertex, which will be used as the forth degenerated side of quadrangle.
.. image:: ../images/hypo_quad_params_1.png
:align: center
.. centered::
A face built from 3 edges
A face built from 3 edges and the resulting mesh
.. image:: ../images/ hypo_quad_params_res.png
:align: center
.. centered::
The resulting mesh
This parameter can be also used to mesh a segment of a circular face. Please, consider that there is a limitation on the selection of the vertex for the faces built with the angle > 180 degrees (see the picture).
This parameter can be also used to mesh a segment of a circular face. Please, consider that there is a limitation on the selection of the vertex for the faces built with the angle > 180 degrees (see the picture). In this case, selection of a wrong vertex for the **Base vertex** parameter will generate a wrong mesh. The picture below shows the good (left) and the bad (right) results of meshing.
.. image:: ../images/hypo_quad_params_2.png
:align: center
.. centered::
3/4 of a circular face
3/4 of a circular face and the resulting meshes
In this case, selection of a wrong vertex for the **Base vertex** parameter will generate a wrong mesh. The picture below shows the good (left) and the bad (right) results of meshing.
.. image:: ../images/ hypo_quad_params_res_2.png
.. _corner_vertices_anchor:
Corner Vertices tab
-------------------
.. image:: ../images/hypo_quad_params_dialog_corners.png
:align: center
.. centered::
The resulting meshes
Quadrangle parameters: Corner Vertices
**Corner Vertices** tab page allows specifying vertices that should be used as quadrangle corners. This can be useful for faces with more than four vertices, since in some cases Quadrangle Mapping algorithm chooses corner vertices differently than it is desired. **Quadrangle parameters** hypothesis can be global and define corners for all CAD faces that require it, but be sure that each specified vertex is a corner in all faces the hypothesis will be applied to.
.. _enforced_nodes_anchor:
Enforced nodes tab
------------------
.. image:: ../images/ hypo_quad_params_dialog_enf.png
:align: center

View File

@ -484,7 +484,7 @@
icon-id ="mesh_algo_hexa.png"
group-id="2"
priority="10"
input ="QUAD,TRIA"
input ="EDGE"
output ="HEXA,PENTA,OCTA,POLYHEDRON"
dim ="3">
<python-wrap>

View File

@ -1546,6 +1546,7 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation)
myScalarBarActor->VisibilityOn();
}
if ( GetPickable( ))
myPickableActor->VisibilityOn();
if ( GetRepresentation() != ePoint )
@ -1556,7 +1557,8 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation)
if(myEntityMode & eBallElem ){
myBallActor->VisibilityOn();
}
if(myEntityMode & eEdges && GetCellsLabeled() ){ // my1DActor shows labels only
if(myEntityMode & eEdges && ( GetCellsLabeled() || // my1DActor shows labels only
( myControlActor == my1DActor && myControlMode != eNone ))){
my1DActor->VisibilityOn();
}
if(myEntityMode & eFaces ){
@ -1760,6 +1762,12 @@ void SMESH_ActorDef::SetRepresentation (int theMode)
if ( myRepresentation != ePoint )
aReperesent = SMESH_DeviceActor::eInsideframe;
break;
case eCustomControl:
if ( myControlActor == my1DActor )
aProp = aBackProp = my1DProp;
if ( myRepresentation != ePoint )
aReperesent = SMESH_DeviceActor::eInsideframe;
break;
default:;
}
@ -2485,8 +2493,8 @@ void SMESH_ActorDef::UpdateDistribution()
std::vector<int> nbEvents;
std::vector<double> funValues;
SMESH_VisualObjDef::TEntityList elems;
if ( ! dynamic_cast<SMESH_MeshObj*>(myVisualObj.get()))
dynamic_cast<SMESH_VisualObjDef*>(myVisualObj.get())->GetEntities( fun->GetType(), elems );
if ( dynamic_cast<SMESH_SubMeshObj*>(myVisualObj.get()))
dynamic_cast<SMESH_SubMeshObj*>(myVisualObj.get())->GetEntities( fun->GetType(), elems );
std::vector<int> elemIds; elemIds.reserve( elems.size() );
for ( SMESH_VisualObjDef::TEntityList::iterator e = elems.begin(); e != elems.end(); ++e)
elemIds.push_back( (*e)->GetID());
@ -2671,8 +2679,8 @@ SPlot2d_Histogram* SMESH_ActorDef::UpdatePlot2Histogram()
std::vector<int> nbEvents;
std::vector<double> funValues;
SMESH_VisualObjDef::TEntityList elems;
if ( ! dynamic_cast<SMESH_MeshObj*>(myVisualObj.get()))
dynamic_cast<SMESH_VisualObjDef*>(myVisualObj.get())->GetEntities( fun->GetType(), elems );
if ( dynamic_cast<SMESH_SubMeshObj*>(myVisualObj.get()))
dynamic_cast<SMESH_SubMeshObj*>(myVisualObj.get())->GetEntities( fun->GetType(), elems );
std::vector<int> elemIds;
for ( SMESH_VisualObjDef::TEntityList::iterator e = elems.begin(); e != elems.end(); ++e)

View File

@ -5068,7 +5068,7 @@ SMESH::long_array* SMESH_Mesh_i::GetElemFaceNodes(CORBA::Long elemId,
}
//=======================================================================
//function : GetElemFaceNodes
//function : GetFaceNormal
//purpose : Returns three components of normal of given mesh face.
//=======================================================================

View File

@ -2772,18 +2772,49 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
struct EdgeWithNeighbors
{
TopoDS_Edge _edge;
int _iBase; /* index in a WIRE with non-base EDGEs excluded */
int _iL, _iR; /* used to connect edges in a base FACE */
bool _isBase; /* is used in a base FACE */
EdgeWithNeighbors(const TopoDS_Edge& E, int iE, int nbE, int shift, bool isBase ):
_edge( E ), _iBase( iE + shift ),
int _iBase; // index in a WIRE with non-base EDGEs excluded
int _iL, _iR; // used to connect PrismSide's
int _iE; // index in a WIRE
int _iLE, _iRE; // used to connect EdgeWithNeighbors's
bool _isBase; // is used in a base FACE
TopoDS_Vertex _vv[2]; // end VERTEXes
EdgeWithNeighbors(const TopoDS_Edge& E,
int iE, int nbE, int shift,
int iEE, int nbEE, int shiftE,
bool isBase, bool setVV ):
_edge( E ),
_iBase( iE + shift ),
_iL ( SMESH_MesherHelper::WrapIndex( iE-1, Max( 1, nbE )) + shift ),
_iR ( SMESH_MesherHelper::WrapIndex( iE+1, Max( 1, nbE )) + shift ),
_iE ( iEE + shiftE ),
_iLE( SMESH_MesherHelper::WrapIndex( iEE-1, Max( 1, nbEE )) + shiftE ),
_iRE( SMESH_MesherHelper::WrapIndex( iEE+1, Max( 1, nbEE )) + shiftE ),
_isBase( isBase )
{
if ( setVV )
{
Vertex( 0 );
Vertex( 1 );
}
}
EdgeWithNeighbors() {}
bool IsInternal() const { return !_edge.IsNull() && _edge.Orientation() == TopAbs_INTERNAL; }
bool IsConnected( const EdgeWithNeighbors& edge, int iEnd ) const
{
return (( _vv[ iEnd ].IsSame( edge._vv[ 1 - iEnd ])) ||
( IsInternal() && _vv[ iEnd ].IsSame( edge._vv[ iEnd ])));
}
bool IsConnected( const std::vector< EdgeWithNeighbors > & edges, int iEnd ) const
{
int iEdge = iEnd ? _iRE : _iLE;
return iEdge == _iE ? false : IsConnected( edges[ iEdge ], iEnd );
}
const TopoDS_Vertex& Vertex( int iEnd )
{
if ( _vv[ iEnd ].IsNull() )
_vv[ iEnd ] = SMESH_MesherHelper::IthVertex( iEnd, _edge );
return _vv[ iEnd ];
}
};
// PrismSide contains all FACEs linking a bottom EDGE with a top one.
struct PrismSide
@ -2798,8 +2829,8 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
PrismSide *_leftSide; // neighbor sides
PrismSide *_rightSide;
bool _isInternal; // whether this side raises from an INTERNAL EDGE
void SetExcluded() { _leftSide = _rightSide = NULL; }
bool IsExcluded() const { return !_leftSide; }
//void SetExcluded() { _leftSide = _rightSide = NULL; }
//bool IsExcluded() const { return !_leftSide; }
const TopoDS_Edge& Edge( int i ) const
{
return (*_edges)[ i ]._edge;
@ -2810,14 +2841,33 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
if ( E.IsSame( Edge( i ))) return i;
return -1;
}
bool IsSideFace( const TopoDS_Shape& face, const bool checkNeighbors ) const
const TopoDS_Vertex& Vertex( int iE, int iEnd ) const
{
return (*_edges)[ iE ].Vertex( iEnd );
}
bool HasVertex( const TopoDS_Vertex& V ) const
{
for ( size_t i = 0; i < _edges->size(); ++i )
if ( V.IsSame( Vertex( i, 0 ))) return true;
return false;
}
bool IsSideFace( const TopTools_ListOfShape& faces,
const TopoDS_Face& avoidFace,
const bool checkNeighbors ) const
{
TopTools_ListIteratorOfListOfShape faceIt( faces );
for ( ; faceIt.More(); faceIt.Next() )
{
const TopoDS_Shape& face = faceIt.Value();
if ( !face.IsSame( avoidFace ))
{
if ( _faces->Contains( face )) // avoid returning true for a prism top FACE
return ( !_face.IsNull() || !( face.IsSame( _faces->FindKey( _faces->Extent() ))));
}
}
if ( checkNeighbors )
return (( _leftSide && _leftSide->IsSideFace ( face, false )) ||
( _rightSide && _rightSide->IsSideFace( face, false )));
return (( _leftSide && _leftSide->IsSideFace ( faces, avoidFace, false )) ||
( _rightSide && _rightSide->IsSideFace( faces, avoidFace, false )));
return false;
}
@ -2827,20 +2877,39 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
* \brief Return another faces sharing an edge
*/
const TopoDS_Face & getAnotherFace( const TopoDS_Face& face,
const TopoDS_Edge& edge,
TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge)
const TopTools_ListOfShape& faces)
{
TopTools_ListIteratorOfListOfShape faceIt( facesOfEdge.FindFromKey( edge ));
TopTools_ListIteratorOfListOfShape faceIt( faces );
for ( ; faceIt.More(); faceIt.Next() )
if ( !face.IsSame( faceIt.Value() ))
return TopoDS::Face( faceIt.Value() );
return face;
}
//--------------------------------------------------------------------------------
/*!
* \brief Return another faces sharing an edge
*/
const TopoDS_Face & getAnotherFace( const TopoDS_Face& face,
const TopoDS_Edge& edge,
TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge)
{
return getAnotherFace( face, facesOfEdge.FindFromKey( edge ));
}
//--------------------------------------------------------------------------------
/*!
* \brief Return ordered edges of a face
*/
//================================================================================
/*!
* \brief Return ordered edges of a face
* \param [in] face - the face
* \param [out] edges - return edge (edges from which no vertical faces raise excluded)
* \param [in] facesOfEdge - faces of each edge
* \param [in] noHolesAllowed - are multiple wires allowed
*/
//================================================================================
bool getEdges( const TopoDS_Face& face,
vector< EdgeWithNeighbors > & edges,
TopTools_IndexedDataMapOfShapeListOfShape& facesOfEdge,
@ -2856,11 +2925,10 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
if ( nbW > 1 && noHolesAllowed )
return false;
int iE, nbTot = 0, nbBase, iBase;
list< TopoDS_Edge >::iterator e = ee.begin();
list< int >::iterator nbE = nbEdgesInWires.begin();
for ( ; nbE != nbEdgesInWires.end(); ++nbE )
for ( iE = 0; iE < *nbE; ++e, ++iE )
for ( int iE = 0; iE < *nbE; ++e, ++iE )
if ( SMESH_Algo::isDegenerated( *e )) // degenerated EDGE is never used
{
e = --ee.erase( e );
@ -2868,6 +2936,7 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
--iE;
}
int iE, nbTot = 0, iBase, nbBase, nbTotBase = 0;
vector<int> isBase;
edges.clear();
e = ee.begin();
@ -2883,40 +2952,51 @@ namespace // utils used by StdMeshers_Prism_3D::IsApplicable()
}
for ( iBase = 0, iE = 0; iE < *nbE; ++e, ++iE )
{
edges.push_back( EdgeWithNeighbors( *e, iBase, nbBase, nbTot, isBase[ iE ] ));
edges.push_back( EdgeWithNeighbors( *e,
iBase, nbBase, nbTotBase,
iE, *nbE, nbTot,
isBase[ iE ], nbW > 1 ));
iBase += isBase[ iE ];
}
nbTot += nbBase;
nbTot += *nbE;
nbTotBase += nbBase;
}
if ( nbTot == 0 )
if ( nbTotBase == 0 )
return false;
// IPAL53099. Set correct neighbors to INTERNAL EDGEs, which can be connected to
// EDGEs of the outer WIRE but this fact can't be detected by their order.
// IPAL53099, 54416. Set correct neighbors to INTERNAL EDGEs
if ( nbW > 1 )
{
int iFirst = 0, iLast;
for ( nbE = nbEdgesInWires.begin(); nbE != nbEdgesInWires.end(); ++nbE )
{
iLast = iFirst + *nbE - 1;
TopoDS_Vertex vv[2] = { SMESH_MesherHelper::IthVertex( 0, edges[ iFirst ]._edge ),
SMESH_MesherHelper::IthVertex( 1, edges[ iLast ]._edge ) };
bool isConnectOk = ( vv[0].IsSame( vv[1] ));
bool isConnectOk = ( edges[ iFirst ].IsConnected( edges, 0 ) &&
edges[ iFirst ].IsConnected( edges, 1 ));
if ( !isConnectOk )
{
edges[ iFirst ]._iL = edges[ iFirst ]._iBase; // connect to self
edges[ iLast ]._iR = edges[ iLast ]._iBase;
// look for an EDGE of the outer WIREs connected to vv
TopoDS_Vertex v0, v1;
for ( iE = 0; iE < iFirst; ++iE )
for ( iE = iFirst; iE <= iLast; ++iE )
{
v0 = SMESH_MesherHelper::IthVertex( 0, edges[ iE ]._edge );
v1 = SMESH_MesherHelper::IthVertex( 1, edges[ iE ]._edge );
if ( vv[0].IsSame( v0 ) || vv[0].IsSame( v1 ))
edges[ iFirst ]._iL = edges[ iE ]._iBase;
if ( vv[1].IsSame( v0 ) || vv[1].IsSame( v1 ))
edges[ iLast ]._iR = edges[ iE ]._iBase;
if ( !edges[ iE ]._isBase )
continue;
int* iNei[] = { & edges[ iE ]._iL,
& edges[ iE ]._iR };
for ( int iV = 0; iV < 2; ++iV )
{
if ( edges[ iE ].IsConnected( edges, iV ))
continue; // Ok - connected to a neighbor EDGE
// look for a connected EDGE
bool found = false;
for ( int iE2 = 0, nbE = edges.size(); iE2 < nbE && !found; ++iE2 )
if (( iE2 != iE ) &&
( found = edges[ iE ].IsConnected( edges[ iE2 ], iV )))
{
*iNei[ iV ] = edges[ iE2 ]._iBase;
}
if ( !found )
*iNei[ iV ] = edges[ iE ]._iBase; // connect to self
}
}
}
iFirst += *nbE;
@ -3049,11 +3129,11 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
}
bool isOK = true; // ok for a current botF
bool isAdvanced = true; // is new data found in a current loop
bool hasAdvanced = true; // is new data found in a current loop
int nbFoundSideFaces = 0;
for ( int iLoop = 0; isOK && isAdvanced; ++iLoop )
for ( int iLoop = 0; isOK && hasAdvanced; ++iLoop )
{
isAdvanced = false;
hasAdvanced = false;
for ( size_t iS = 0; iS < sides.size() && isOK; ++iS )
{
PrismSide& side = sides[ iS ];
@ -3065,19 +3145,32 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
// find vertical EDGEs --- EDGEs shared with neighbor side FACEs
for ( int is2nd = 0; is2nd < 2 && isOK; ++is2nd ) // 2 adjacent neighbors
{
int di = is2nd ? 1 : -1;
const PrismSide* adjSide = is2nd ? side._rightSide : side._leftSide;
if ( side._isInternal )
{
const TopoDS_Vertex& V = side.Vertex( side._iBotEdge, is2nd );
bool lHasV = side._leftSide ->HasVertex( V );
bool rHasV = side._rightSide->HasVertex( V );
if ( lHasV == rHasV )
adjSide = ( &side == side._leftSide ) ? side._rightSide : side._leftSide;
else
adjSide = ( rHasV ) ? side._rightSide : side._leftSide;
}
int di = is2nd ? 1 : -1;
for ( size_t i = 1; i < side._edges->size(); ++i )
{
int iE = SMESH_MesherHelper::WrapIndex( i*di + side._iBotEdge, side._edges->size());
if ( side._isCheckedEdge[ iE ] ) continue;
const TopoDS_Edge& vertE = side.Edge( iE );
const TopoDS_Shape& neighborF = getAnotherFace( side._face, vertE, facesOfEdge );
bool isEdgeShared = (( adjSide->IsSideFace( neighborF, side._isInternal )) ||
( adjSide == &side && neighborF.IsSame( side._face )) );
const TopTools_ListOfShape& neighborFF = facesOfEdge.FindFromKey( vertE );
bool isEdgeShared = (( adjSide->IsSideFace( neighborFF, side._face,
side._isInternal )) ||
( adjSide == &side &&
side._face.IsSame( getAnotherFace( side._face,
neighborFF ))));
if ( isEdgeShared ) // vertE is shared with adjSide
{
isAdvanced = true;
hasAdvanced = true;
side._isCheckedEdge[ iE ] = true;
side._nbCheckedEdges++;
int nbNotCheckedE = side._edges->size() - side._nbCheckedEdges;
@ -3145,7 +3238,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
const int nbE = side._edges->size();
if ( nbE >= 4 )
{
isAdvanced = true;
hasAdvanced = true;
++nbFoundSideFaces;
side._iBotEdge = side.FindEdge( side._topEdge );
side._isCheckedEdge.clear();
@ -3175,7 +3268,7 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
cerr << "BUG: infinite loop in StdMeshers_Prism_3D::IsApplicable()" << endl;
#endif
}
} // while isAdvanced
} // while hasAdvanced
if ( isOK && sides[0]._faces->Extent() > 1 )
{
@ -3186,12 +3279,20 @@ bool StdMeshers_Prism_3D::IsApplicable(const TopoDS_Shape & shape, bool toCheckA
}
else
{
// check that all face columns end up at the same top face
const TopoDS_Shape& topFace = sides[0]._faces->FindKey( nbFaces );
size_t iS;
for ( iS = 1; iS < sides.size(); ++iS )
if ( ! sides[ iS ]._faces->Contains( topFace ))
break;
prismDetected = ( iS == sides.size() );
if (( prismDetected = ( iS == sides.size() )))
{
// check that bottom and top faces has equal nb of edges
TEdgeWithNeighborsVec& topEdges = faceEdgesVec[ allFaces.FindIndex( topFace )];
if ( topEdges.empty() )
getEdges( TopoDS::Face( topFace ), topEdges, facesOfEdge, /*noHoles=*/false );
prismDetected = ( botEdges.size() == topEdges.size() );
}
}
}
} // loop on allFaces