-// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#include "SMESH_subMeshEventListener.hxx"
#include "StdMeshers_FaceSide.hxx"
#include "StdMeshers_ProjectionUtils.hxx"
+#include "StdMeshers_Quadrangle_2D.hxx"
#include "StdMeshers_ViscousLayers2D.hxx"
+#include <Basics_OCCTVersion.hxx>
+
+#if OCC_VERSION_LARGE < 0x07070000
#include <Adaptor3d_HSurface.hxx>
+#else
+#include <Adaptor3d_Surface.hxx>
+#endif
+
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Curve2d.hxx>
#include <BRepAdaptor_Surface.hxx>
-//#include <BRepLProp_CLProps.hxx>
#include <BRepLProp_SLProps.hxx>
#include <BRepOffsetAPI_MakeOffsetShape.hxx>
#include <BRep_Tool.hxx>
#include <unordered_map>
#ifdef _DEBUG_
-//#define __myDEBUG
+#ifndef WIN32
+#define __myDEBUG
+#endif
//#define __NOT_INVALIDATE_BAD_SMOOTH
//#define __NODES_AT_POS
#endif
struct _LayerEdge;
struct _EdgesOnShape;
struct _Smoother1D;
+ struct _Mapper2D;
typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge;
//--------------------------------------------------------------------------------
const TopoDS_Face& F,
_EdgesOnShape& eos,
SMESH_MesherHelper& helper );
+ bool UpdatePositionOnSWOL( SMDS_MeshNode* n,
+ double tol,
+ _EdgesOnShape& eos,
+ SMESH_MesherHelper& helper );
void SetDataByNeighbors( const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
const _EdgesOnShape& eos,
bool IsOnFace() const { return ( _nodes[0]->GetPosition()->GetDim() == 2 ); }
int BaseShapeDim() const { return _nodes[0]->GetPosition()->GetDim(); }
gp_XYZ Copy( _LayerEdge& other, _EdgesOnShape& eos, SMESH_MesherHelper& helper );
- void SetCosin( double cosin );
+ double SetCosin( double cosin );
void SetNormal( const gp_XYZ& n ) { _normal = n; }
void SetMaxLen( double l ) { _maxLen = l; }
int NbSteps() const { return _pos.size() - 1; } // nb inlation steps
bool ToCreateGroup() const { return !_groupName.empty(); }
const std::string& GetGroupName() const { return _groupName; }
+ double Get1stLayerThickness( double realThickness = 0.) const
+ {
+ const double T = ( realThickness > 0 ) ? realThickness : GetTotalThickness();
+ const double f = GetStretchFactor();
+ const int N = GetNumberLayers();
+ const double fPowN = pow( f, N );
+ double h0;
+ if ( fPowN - 1 <= numeric_limits<double>::min() )
+ h0 = T / N;
+ else
+ h0 = T * ( f - 1 )/( fPowN - 1 );
+ return h0;
+ }
+
bool UseSurfaceNormal() const
{ return _method == StdMeshers_ViscousLayers::SURF_OFFSET_SMOOTH; }
bool ToSmooth() const
Handle(ShapeAnalysis_Surface) _offsetSurf;
_LayerEdge* _edgeForOffset;
+ double _offsetValue;
+ _Mapper2D* _mapper2D;
_SolidData* _data; // parent SOLID
{ return std::find( _eosC1.begin(), _eosC1.end(), other ) != _eosC1.end(); }
bool GetNormal( const SMDS_MeshElement* face, gp_Vec& norm );
_SolidData& GetData() const { return *_data; }
+ char ShapeTypeLetter() const
+ { switch ( ShapeType() ) { case TopAbs_FACE: return 'F'; case TopAbs_EDGE: return 'E';
+ case TopAbs_VERTEX: return 'V'; default: return 'S'; }}
- _EdgesOnShape(): _shapeID(-1), _subMesh(0), _toSmooth(false), _edgeSmoother(0) {}
+ _EdgesOnShape(): _shapeID(-1), _subMesh(0), _toSmooth(false), _edgeSmoother(0), _mapper2D(0) {}
~_EdgesOnShape();
};
const StdMeshers_ViscousLayers* hyp,
const TopoDS_Shape& hypShape,
set<TGeomID>& ignoreFaces);
- void makeEdgesOnShape();
+ int makeEdgesOnShape();
bool makeLayer(_SolidData& data);
void setShapeData( _EdgesOnShape& eos, SMESH_subMesh* sm, _SolidData& data );
bool setEdgeData( _LayerEdge& edge, _EdgesOnShape& eos,
void offPointsToPython() const; // debug
};
+
+ //--------------------------------------------------------------------------------
+ /*!
+ * \brief Compute positions of nodes of 2D structured mesh using TFI
+ */
+ class _Mapper2D
+ {
+ FaceQuadStruct _quadPoints;
+
+ UVPtStruct& uvPnt( size_t i, size_t j ) { return _quadPoints.UVPt( i, j ); }
+
+ public:
+ _Mapper2D( const TParam2ColumnMap & param2ColumnMap, const TNode2Edge& n2eMap );
+ bool ComputeNodePositions();
+ };
+
//--------------------------------------------------------------------------------
/*!
* \brief Class of temporary mesh face.
namespace VISCOUS_3D
{
- gp_XYZ getEdgeDir( const TopoDS_Edge& E, const TopoDS_Vertex& fromV )
+ gp_XYZ getEdgeDir( const TopoDS_Edge& E, const TopoDS_Vertex& fromV,
+ const double h0, bool* isRegularEdge = nullptr )
{
gp_Vec dir;
double f,l;
Handle(Geom_Curve) c = BRep_Tool::Curve( E, f, l );
if ( c.IsNull() ) return gp_XYZ( Precision::Infinite(), 1e100, 1e100 );
- gp_Pnt p = BRep_Tool::Pnt( fromV );
- double distF = p.SquareDistance( c->Value( f ));
- double distL = p.SquareDistance( c->Value( l ));
+ gp_Pnt p = BRep_Tool::Pnt( fromV );
+ gp_Pnt pf = c->Value( f ), pl = c->Value( l );
+ double distF = p.SquareDistance( pf );
+ double distL = p.SquareDistance( pl );
c->D1(( distF < distL ? f : l), p, dir );
if ( distL < distF ) dir.Reverse();
+ bool isDifficult = false;
+ if ( dir.SquareMagnitude() < h0 * h0 ) // check dir orientation
+ {
+ gp_Pnt& pClose = distF < distL ? pf : pl;
+ gp_Pnt& pFar = distF < distL ? pl : pf;
+ gp_Pnt pMid = 0.9 * pClose.XYZ() + 0.1 * pFar.XYZ();
+ gp_Vec vMid( p, pMid );
+ double dot = vMid * dir;
+ double cos2 = dot * dot / dir.SquareMagnitude() / vMid.SquareMagnitude();
+ if ( cos2 < 0.7 * 0.7 || dot < 0 ) // large angle between dir and vMid
+ {
+ double uClose = distF < distL ? f : l;
+ double uFar = distF < distL ? l : f;
+ double r = h0 / SMESH_Algo::EdgeLength( E );
+ double uMid = ( 1 - r ) * uClose + r * uFar;
+ pMid = c->Value( uMid );
+ dir = gp_Vec( p, pMid );
+ isDifficult = true;
+ }
+ }
+ if ( isRegularEdge )
+ *isRegularEdge = !isDifficult;
+
return dir.XYZ();
}
//--------------------------------------------------------------------------------
}
//--------------------------------------------------------------------------------
gp_XYZ getFaceDir( const TopoDS_Face& F, const TopoDS_Vertex& fromV,
- const SMDS_MeshNode* node, SMESH_MesherHelper& helper, bool& ok,
- double* cosin=0);
+ const SMDS_MeshNode* node, SMESH_MesherHelper& helper, bool& ok/*,
+ double* cosin=0*/);
//--------------------------------------------------------------------------------
gp_XYZ getFaceDir( const TopoDS_Face& F, const TopoDS_Edge& fromE,
const SMDS_MeshNode* node, SMESH_MesherHelper& helper, bool& ok)
//--------------------------------------------------------------------------------
gp_XYZ getFaceDir( const TopoDS_Face& F, const TopoDS_Vertex& fromV,
const SMDS_MeshNode* node, SMESH_MesherHelper& helper,
- bool& ok, double* cosin)
+ bool& ok/*, double* cosin*/)
{
TopoDS_Face faceFrw = F;
faceFrw.Orientation( TopAbs_FORWARD );
ok = true;
for ( size_t i = 0; i < nbEdges && ok; ++i )
{
- edgeDir[i] = getEdgeDir( edges[i], fromV );
+ edgeDir[i] = getEdgeDir( edges[i], fromV, 0.1 * SMESH_Algo::EdgeLength( edges[i] ));
double size2 = edgeDir[i].SquareModulus();
if (( ok = size2 > numeric_limits<double>::min() ))
edgeDir[i] /= sqrt( size2 );
if ( angle < 0 )
dir.Reverse();
}
- if ( cosin ) {
- double angle = gp_Vec( edgeDir[0] ).Angle( dir );
- *cosin = Cos( angle );
- }
+ // if ( cosin ) {
+ // double angle = faceNormal.Angle( dir );
+ // *cosin = Cos( angle );
+ // }
}
else if ( nbEdges == 1 )
{
dir = getFaceDir( faceFrw, edges[ edges[0].IsNull() ], node, helper, ok );
- if ( cosin ) *cosin = 1.;
+ //if ( cosin ) *cosin = 1.;
}
else
{
//case GeomAbs_SurfaceOfExtrusion:
case GeomAbs_OffsetSurface:
{
+#if OCC_VERSION_LARGE < 0x07070000
Handle(Adaptor3d_HSurface) base = surface.BasisSurface();
return getRovolutionAxis( base->Surface(), axis );
+#else
+ Handle(Adaptor3d_Surface) base = surface.BasisSurface();
+ return getRovolutionAxis( *base, axis );
+#endif
}
default: return false;
}
//--------------------------------------------------------------------------------
// DEBUG. Dump intermediate node positions into a python script
- // HOWTO use: run python commands written in a console to see
- // construction steps of viscous layers
+ // HOWTO use: run python commands written in a console and defined in /tmp/viscous.py
+ // to see construction steps of viscous layers
#ifdef __myDEBUG
ostream* py;
int theNbPyFunc;
if ( _ViscousListener::GetSolidMesh( _mesh, exp.Current(), /*toCreate=*/false))
return SMESH_ComputeErrorPtr(); // everything already computed
- PyDump debugDump( theMesh );
- _pyDump = &debugDump;
-
// TODO: ignore already computed SOLIDs
if ( !findSolidsWithLayers())
return _error;
if ( !findFacesWithLayers() )
return _error;
- // for ( size_t i = 0; i < _sdVec.size(); ++i )
- // {
- // if ( ! makeLayer( _sdVec[ i ])) // create _LayerEdge's
- // return _error;
- // }
-
- makeEdgesOnShape();
+ if ( !makeEdgesOnShape() )
+ return _error;
findPeriodicFaces();
+ PyDump debugDump( theMesh );
+ _pyDump = &debugDump;
+
+
for ( size_t i = 0; i < _sdVec.size(); ++i )
{
size_t iSD = 0;
!_sdVec[iSD]._solid.IsNull() &&
!_sdVec[iSD]._done )
break;
+ if ( iSD == _sdVec.size() )
+ break; // all done
if ( ! makeLayer(_sdVec[iSD]) ) // create _LayerEdge's
return _error;
break;
}
default:
- return error("Not yet supported case", _sdVec[i]._index);
+ std::ostringstream msg;
+ msg << "Not yet supported case: vertex bounded by ";
+ msg << facesWOL.size();
+ msg << " faces without layer at coordinates (";
+ TopoDS_Vertex v = TopoDS::Vertex(vertex);
+ gp_Pnt p = BRep_Tool::Pnt(v);
+ msg << p.X() << ", " << p.Y() << ", " << p.Z() << ")";
+ return error(msg.str().c_str(), _sdVec[i]._index);
}
}
}
// Create temporary faces and _LayerEdge's
+ debugMsg( "######################" );
dumpFunction(SMESH_Comment("makeLayers_")<<data._index);
vector< _EdgesOnShape >& edgesByGeom = data._edgesOnShape;
nbDegenNodes++;
}
}
- TNode2Edge::iterator n2e = data._n2eMap.insert( make_pair( n, (_LayerEdge*)0 )).first;
+ TNode2Edge::iterator n2e = data._n2eMap.insert({ n, nullptr }).first;
if ( !(*n2e).second )
{
// add a _LayerEdge
if ( !setEdgeData( *edge, edgesByGeom[ shapeID ], helper, data ))
return false;
- if ( edge->_nodes.size() < 2 )
- edge->Block( data );
- //data._noShrinkShapes.insert( shapeID );
+ if ( edge->_nodes.size() < 2 && !noShrink )
+ edge->Block( data ); // a sole node is moved only if noShrink
}
dumpMove(edge->_nodes.back());
- if ( edge->_cosin > faceMaxCosin )
+ if ( edge->_cosin > faceMaxCosin && edge->_nodes.size() > 1 )
{
faceMaxCosin = edge->_cosin;
maxCosinEdge = edge;
if (( n2e = data._n2eMap.find( *node )) != data._n2eMap.end() )
edge->_neibors.push_back( n2e->second );
}
+
+ // Fix uv of nodes on periodic FACEs (bos #20643)
+
+ if ( eos.ShapeType() != TopAbs_EDGE ||
+ eos.SWOLType() != TopAbs_FACE ||
+ eos.size() == 0 )
+ continue;
+
+ const TopoDS_Face& F = TopoDS::Face( eos._sWOL );
+ SMESH_MesherHelper faceHelper( *_mesh );
+ faceHelper.SetSubShape( F );
+ faceHelper.ToFixNodeParameters( true );
+ if ( faceHelper.GetPeriodicIndex() == 0 )
+ continue;
+
+ SMESHDS_SubMesh* smDS = getMeshDS()->MeshElements( F );
+ if ( !smDS || smDS->GetNodes() == 0 )
+ continue;
+
+ bool toCheck = true;
+ const double tol = 2 * helper.MaxTolerance( F );
+ for ( SMDS_NodeIteratorPtr nIt = smDS->GetNodes(); nIt->more(); )
+ {
+ const SMDS_MeshNode* node = nIt->next();
+ gp_XY uvNew( Precision::Infinite(), 0 );
+ if ( toCheck )
+ {
+ toCheck = false;
+ gp_XY uv = faceHelper.GetNodeUV( F, node );
+ if ( ! faceHelper.CheckNodeUV( F, node, uvNew, tol, /*force=*/true ))
+ break; // projection on F failed
+ if (( uv - uvNew ).Modulus() < Precision::Confusion() )
+ break; // current uv is OK
+ }
+ faceHelper.CheckNodeUV( F, node, uvNew, tol, /*force=*/true );
+ }
}
data._epsilon = 1e-7;
cnvFace._face = F;
cnvFace._normalsFixed = false;
cnvFace._isTooCurved = false;
+ cnvFace._normalsFixedOnBorders = false;
double maxCurvature = cnvFace.GetMaxCurvature( data, eof, surfProp, helper );
if ( maxCurvature > 0 )
if ( SMESH_Algo::isDegenerated( E ) || !edgesOfSmooFaces.Contains( E ))
continue;
- double tgtThick = eos._hyp.GetTotalThickness();
+ double tgtThick = eos._hyp.GetTotalThickness(), h0 = eos._hyp.Get1stLayerThickness();
for ( TopoDS_Iterator vIt( E ); vIt.More() && !eos._toSmooth; vIt.Next() )
{
TGeomID iV = getMeshDS()->ShapeToIndex( vIt.Value() );
vector<_LayerEdge*>& eV = edgesByGeom[ iV ]._edges;
if ( eV.empty() || eV[0]->Is( _LayerEdge::MULTI_NORMAL )) continue;
- gp_Vec eDir = getEdgeDir( E, TopoDS::Vertex( vIt.Value() ));
+ gp_Vec eDir = getEdgeDir( E, TopoDS::Vertex( vIt.Value() ), h0 );
double angle = eDir.Angle( eV[0]->_normal );
double cosin = Cos( angle );
double cosinAbs = Abs( cosin );
{
_EdgesOnShape* eoe = data.GetShapeEdges( *e );
if ( !eoe ) continue; // other solid
- gp_XYZ eDir = getEdgeDir( TopoDS::Edge( *e ), V );
+ gp_XYZ eDir = getEdgeDir( TopoDS::Edge( *e ), V, eoe->_hyp.Get1stLayerThickness() );
if ( !Precision::IsInfinite( eDir.X() ))
dirOfEdges.push_back( make_pair( eoe, eDir.Normalized() ));
}
*/
//================================================================================
-void _ViscousBuilder::makeEdgesOnShape()
+int _ViscousBuilder::makeEdgesOnShape()
{
const int nbShapes = getMeshDS()->MaxShapeIndex();
+ int nbSolidsWL = 0;
for ( size_t i = 0; i < _sdVec.size(); ++i )
{
edgesByGeom.resize( nbShapes+1 );
// set data of _EdgesOnShape's
+ int nbShapesWL = 0;
if ( SMESH_subMesh* sm = _mesh->GetSubMesh( data._solid ))
{
SMESH_subMeshIteratorPtr smIt = sm->getDependsOnIterator(/*includeSelf=*/false);
continue;
setShapeData( edgesByGeom[ sm->GetId() ], sm, data );
+
+ nbShapesWL += ( sm->GetSubShape().ShapeType() == TopAbs_FACE );
}
}
+ if ( nbShapesWL == 0 ) // no shapes with layers in a SOLID
+ {
+ data._done = true;
+ SMESHUtils::FreeVector( edgesByGeom );
+ }
+ else
+ {
+ ++nbSolidsWL;
+ }
}
+ return nbSolidsWL;
}
//================================================================================
eos._shape.Orientation( helper.GetSubShapeOri( data._solid, eos._shape ));
eos._toSmooth = false;
eos._data = &data;
+ eos._mapper2D = nullptr;
// set _SWOL
map< TGeomID, TopoDS_Shape >::const_iterator s2s =
_EdgesOnShape::~_EdgesOnShape()
{
delete _edgeSmoother;
+ delete _mapper2D;
}
//================================================================================
if ( eos.SWOLType() == TopAbs_EDGE )
{
// inflate from VERTEX along EDGE
- edge._normal = getEdgeDir( TopoDS::Edge( eos._sWOL ), TopoDS::Vertex( eos._shape ));
+ edge._normal = getEdgeDir( TopoDS::Edge( eos._sWOL ), TopoDS::Vertex( eos._shape ),
+ eos._hyp.Get1stLayerThickness(), &eos._isRegularSWOL );
}
else if ( eos.ShapeType() == TopAbs_VERTEX )
{
// inflate from VERTEX along FACE
edge._normal = getFaceDir( TopoDS::Face( eos._sWOL ), TopoDS::Vertex( eos._shape ),
- node, helper, normOK, &edge._cosin);
+ node, helper, normOK/*, &edge._cosin*/);
}
else
{
break;
}
case TopAbs_VERTEX: {
+ TopoDS_Vertex V = TopoDS::Vertex( eos._shape );
+ gp_Vec inFaceDir = getFaceDir( face2Norm[0].first , V, node, helper, normOK );
+ double angle = inFaceDir.Angle( edge._normal ); // [0,PI]
+ edge._cosin = Cos( angle );
if ( fromVonF )
- {
- getFaceDir( TopoDS::Face( eos._sWOL ), TopoDS::Vertex( eos._shape ),
- node, helper, normOK, &edge._cosin );
- }
- else if ( eos.SWOLType() != TopAbs_FACE ) // else _cosin is set by getFaceDir()
- {
- TopoDS_Vertex V = TopoDS::Vertex( eos._shape );
- gp_Vec inFaceDir = getFaceDir( F, V, node, helper, normOK );
- double angle = inFaceDir.Angle( edge._normal ); // [0,PI]
- edge._cosin = Cos( angle );
- if ( totalNbFaces > 2 || helper.IsSeamShape( node->getshapeId() ))
- for ( int iF = 1; iF < totalNbFaces; ++iF )
- {
- F = face2Norm[ iF ].first;
- inFaceDir = getFaceDir( F, V, node, helper, normOK=true );
- if ( normOK ) {
- double angle = inFaceDir.Angle( edge._normal );
- double cosin = Cos( angle );
- if ( Abs( cosin ) > Abs( edge._cosin ))
- edge._cosin = cosin;
+ totalNbFaces--;
+ if ( totalNbFaces > 1 || helper.IsSeamShape( node->getshapeId() ))
+ for ( int iF = 1; iF < totalNbFaces; ++iF )
+ {
+ F = face2Norm[ iF ].first;
+ inFaceDir = getFaceDir( F, V, node, helper, normOK=true );
+ if ( normOK ) {
+ if ( onShrinkShape )
+ {
+ gp_Vec faceNorm = getFaceNormal( node, F, helper, normOK );
+ if ( !normOK ) continue;
+ if ( helper.GetSubShapeOri( data._solid, F ) != TopAbs_REVERSED )
+ faceNorm.Reverse();
+ angle = 0.5 * M_PI - faceNorm.Angle( edge._normal );
+ if ( inFaceDir * edge._normal < 0 )
+ angle = M_PI - angle;
+ }
+ else
+ {
+ angle = inFaceDir.Angle( edge._normal );
}
+ double cosin = Cos( angle );
+ if ( Abs( cosin ) > Abs( edge._cosin ))
+ edge._cosin = cosin;
}
- }
+ }
break;
}
default:
// Set the rest data
// --------------------
- edge.SetCosin( edge._cosin ); // to update edge._lenFactor
+ double realLenFactor = edge.SetCosin( edge._cosin ); // to update edge._lenFactor
+ // if ( realLenFactor > 3 )
+ // {
+ // edge._cosin = 1;
+ // if ( onShrinkShape )
+ // {
+ // edge.Set( _LayerEdge::RISKY_SWOL );
+ // edge._lenFactor = 2;
+ // }
+ // else
+ // {
+ // edge._lenFactor = 1;
+ // }
+ // }
if ( onShrinkShape )
{
getMeshDS()->SetNodeOnFace( tgtNode, TopoDS::Face( eos._sWOL ), uv.X(), uv.Y() );
}
- if ( edge._nodes.size() > 1 )
+ //if ( edge._nodes.size() > 1 ) -- allow RISKY_SWOL on noShrink shape
{
// check if an angle between a FACE with layers and SWOL is sharp,
// else the edge should not inflate
geomNorm.Reverse(); // inside the SOLID
if ( geomNorm * edge._normal < -0.001 )
{
- getMeshDS()->RemoveFreeNode( tgtNode, 0, /*fromGroups=*/false );
- edge._nodes.resize( 1 );
+ if ( edge._nodes.size() > 1 )
+ {
+ getMeshDS()->RemoveFreeNode( tgtNode, 0, /*fromGroups=*/false );
+ edge._nodes.resize( 1 );
+ }
}
- else if ( edge._lenFactor > 3 )
+ else if ( realLenFactor > 3 ) /// -- moved to SetCosin()
+ //else if ( edge._lenFactor > 3 )
{
edge._lenFactor = 2;
edge.Set( _LayerEdge::RISKY_SWOL );
// parallel planes - intersection is an offset of the common EDGE
gp_Pnt p = BRep_Tool::Pnt( V );
linePos = 0.5 * (( p.XYZ() + n1 ) + ( p.XYZ() + n2 ));
- lineDir = getEdgeDir( E, V );
+ lineDir = getEdgeDir( E, V, 0.1 * SMESH_Algo::EdgeLength( E ));
}
else
{
*/
//================================================================================
-void _LayerEdge::SetCosin( double cosin )
+double _LayerEdge::SetCosin( double cosin )
{
_cosin = cosin;
cosin = Abs( _cosin );
- //_lenFactor = ( cosin < 1.-1e-12 ) ? Min( 2., 1./sqrt(1-cosin*cosin )) : 1.0;
- _lenFactor = ( cosin < 1.-1e-12 ) ? 1./sqrt(1-cosin*cosin ) : 1.0;
+ //_lenFactor = ( cosin < 1.-1e-12 ) ? 1./sqrt(1-cosin*cosin ) : 1.0;
+ double realLenFactor;
+ if ( cosin < 1.-1e-12 )
+ {
+ _lenFactor = realLenFactor = 1./sqrt(1-cosin*cosin );
+ }
+ else
+ {
+ _lenFactor = 1;
+ realLenFactor = Precision::Infinite();
+ }
+
+ return realLenFactor;
}
//================================================================================
void _ViscousBuilder::makeGroupOfLE()
{
-#ifdef _DEBUG_
+ if (!SALOME::VerbosityActivated())
+ return;
+
for ( size_t i = 0 ; i < _sdVec.size(); ++i )
{
if ( _sdVec[i]._n2eMap.empty() ) continue;
<< "'%s-%s' % (faceId1+1, faceId2))");
dumpFunctionEnd();
}
-#endif
}
//================================================================================
double thinkness = eos._hyp.GetTotalThickness();
for ( size_t i = 0; i < eos._edges.size(); ++i )
{
- if ( eos._edges[i]->Is( _LayerEdge::BLOCKED )) continue;
+ if ( eos._edges[i]->_nodes.size() < 2 ) continue;
eos._edges[i]->SetMaxLen( thinkness );
eos._edges[i]->FindIntersection( *searcher, intersecDist, data._epsilon, eos, &face );
if ( intersecDist > 0 && face )
if ( eos._edges[i]->_nodes.size() > 1 )
avgThick += Min( 1., eos._edges[i]->_len / shapeTgtThick );
else
- avgThick += shapeTgtThick;
+ avgThick += 1;
nbActiveEdges += ( ! eos._edges[i]->Is( _LayerEdge::BLOCKED ));
}
}
for ( size_t iEOS = 0; iEOS < eosC1.size(); ++iEOS )
{
isConcaveFace[ iEOS ] = data._concaveFaces.count( eosC1[ iEOS ]->_shapeID );
- vector< _LayerEdge* > & edges = eosC1[ iEOS ]->_edges;
- for ( size_t i = 0; i < edges.size(); ++i )
- if ( edges[i]->Is( _LayerEdge::MOVED ) ||
- edges[i]->Is( _LayerEdge::NEAR_BOUNDARY ))
- movedEdges.push_back( edges[i] );
+ if ( eosC1[ iEOS ]->_mapper2D )
+ {
+ // compute node position by boundary node position in structured mesh
+ dumpFunction(SMESH_Comment("map2dS")<<data._index<<"_Fa"<<eos._shapeID
+ <<"_InfStep"<<infStep);
+
+ eosC1[ iEOS ]->_mapper2D->ComputeNodePositions();
+
+ for ( _LayerEdge* le : eosC1[ iEOS ]->_edges )
+ le->_pos.back() = SMESH_NodeXYZ( le->_nodes.back() );
+
+ dumpFunctionEnd();
+ }
+ else
+ {
+ for ( _LayerEdge* le : eosC1[ iEOS ]->_edges )
+ if ( le->Is( _LayerEdge::MOVED ) ||
+ le->Is( _LayerEdge::NEAR_BOUNDARY ))
+ movedEdges.push_back( le );
+ }
makeOffsetSurface( *eosC1[ iEOS ], helper );
}
int step = 0, stepLimit = 5, nbBad = 0;
while (( ++step <= stepLimit ) || improved )
{
- dumpFunction(SMESH_Comment("smooth")<<data._index<<"_Fa"<<sInd
- <<"_InfStep"<<infStep<<"_"<<step); // debug
int oldBadNb = nbBad;
badEdges.clear();
#ifdef INCREMENTAL_SMOOTH
+ // smooth moved only
+ if ( !movedEdges.empty() )
+ dumpFunction(SMESH_Comment("smooth")<<data._index<<"_Fa"<<sInd
+ <<"_InfStep"<<infStep<<"_"<<step); // debug
bool findBest = false; // ( step == stepLimit );
for ( size_t i = 0; i < movedEdges.size(); ++i )
{
badEdges.push_back( movedEdges[i] );
}
#else
+ // smooth all
+ dumpFunction(SMESH_Comment("smooth")<<data._index<<"_Fa"<<sInd
+ <<"_InfStep"<<infStep<<"_"<<step); // debug
bool findBest = ( step == stepLimit || isConcaveFace[ iEOS ]);
for ( size_t iEOS = 0; iEOS < eosC1.size(); ++iEOS )
{
+ if ( eosC1[ iEOS ]->_mapper2D )
+ continue;
vector< _LayerEdge* > & edges = eosC1[ iEOS ]->_edges;
for ( size_t i = 0; i < edges.size(); ++i )
{
} // smoothing steps
- // project -- to prevent intersections or fix bad simplices
+ // project -- to prevent intersections or to fix bad simplices
for ( size_t iEOS = 0; iEOS < eosC1.size(); ++iEOS )
{
if ( ! eosC1[ iEOS ]->_eosConcaVer.empty() || nbBad > 0 )
- putOnOffsetSurface( *eosC1[ iEOS ], infStep, eosC1 );
+ putOnOffsetSurface( *eosC1[ iEOS ], -infStep, eosC1 );
}
//if ( !badEdges.empty() )
continue;
// ignore intersection with intFace of an adjacent FACE
- if ( dist > 0.1 * eos._edges[i]->_len )
+ if ( dist > 0.01 * eos._edges[i]->_len )
{
bool toIgnore = false;
if ( eos._toSmooth )
// intersection not ignored
- if ( toBlockInfaltion &&
- dist < ( eos._edges[i]->_len * theThickToIntersection ))
+ double minDist = 0;
+ if ( eos._edges[i]->_maxLen < 0.99 * eos._hyp.GetTotalThickness() ) // limited length
+ minDist = eos._edges[i]->_len * theThickToIntersection;
+
+ if ( toBlockInfaltion && dist < minDist )
{
if ( is1stBlocked ) { is1stBlocked = false; // debug
dumpFunction(SMESH_Comment("blockIntersected") <<data._index<<"_InfStep"<<infStep);
// find offset
gp_Pnt tgtP = SMESH_TNodeXYZ( eos._edgeForOffset->_nodes.back() );
/*gp_Pnt2d uv=*/baseSurface->ValueOfUV( tgtP, Precision::Confusion() );
- double offset = baseSurface->Gap();
+ eos._offsetValue = baseSurface->Gap();
eos._offsetSurf.Nullify();
try
{
BRepOffsetAPI_MakeOffsetShape offsetMaker;
- offsetMaker.PerformByJoin( eos._shape, -offset, Precision::Confusion() );
+ offsetMaker.PerformByJoin( eos._shape, -eos._offsetValue, Precision::Confusion() );
if ( !offsetMaker.IsDone() ) return;
TopExp_Explorer fExp( offsetMaker.Shape(), TopAbs_FACE );
return;
double preci = BRep_Tool::Tolerance( TopoDS::Face( eof->_shape )), vol;
+ bool neighborHasRiskySWOL = false;
for ( size_t i = 0; i < eos._edges.size(); ++i )
{
_LayerEdge* edge = eos._edges[i];
if ( !edge->Is( _LayerEdge::UPD_NORMAL_CONV ))
continue;
}
+ else if ( moveAll == _LayerEdge::RISKY_SWOL )
+ {
+ if ( !edge->Is( _LayerEdge::RISKY_SWOL ) ||
+ edge->_cosin < 0 )
+ continue;
+ }
else if ( !moveAll && !edge->Is( _LayerEdge::MOVED ))
continue;
int nbBlockedAround = 0;
for ( size_t iN = 0; iN < edge->_neibors.size(); ++iN )
+ {
nbBlockedAround += edge->_neibors[iN]->Is( _LayerEdge::BLOCKED );
+ if ( edge->_neibors[iN]->Is( _LayerEdge::RISKY_SWOL ) &&
+ edge->_neibors[iN]->_cosin > 0 )
+ neighborHasRiskySWOL = true;
+ }
if ( nbBlockedAround > 1 )
continue;
{
edge->_normal = ( newP - prevP ).Normalized();
}
+ // if ( edge->_len < eof->_offsetValue )
+ // edge->_len = eof->_offsetValue;
+
+ if ( !eos._sWOL.IsNull() ) // RISKY_SWOL
+ {
+ double change = eof->_offsetSurf->Gap() / eof->_offsetValue;
+ if (( newP - tgtP.XYZ() ) * edge->_normal < 0 )
+ change = 1 - change;
+ else
+ change = 1 + change;
+ gp_XYZ shitfVec = tgtP.XYZ() - SMESH_NodeXYZ( edge->_nodes[0] );
+ gp_XYZ newShiftVec = shitfVec * change;
+ double shift = edge->_normal * shitfVec;
+ double newShift = edge->_normal * newShiftVec;
+ newP = tgtP.XYZ() + edge->_normal * ( newShift - shift );
+
+ uv = eof->_offsetSurf->NextValueOfUV( edge->_curvature->_uv, newP, preci );
+ if ( eof->_offsetSurf->Gap() < edge->_len )
+ {
+ edge->_curvature->_uv = uv;
+ newP = eof->_offsetSurf->Value( uv ).XYZ();
+ }
+ n->setXYZ( newP.X(), newP.Y(), newP.Z());
+ if ( !edge->UpdatePositionOnSWOL( n, /*tol=*/10 * edge->_len / ( edge->NbSteps() + 1 ),
+ eos, eos.GetData().GetHelper() ))
+ {
+ debugMsg("UpdatePositionOnSWOL fails in putOnOffsetSurface()" );
+ }
+ }
}
}
-
-
-#ifdef _DEBUG_
- // dumpMove() for debug
- size_t i = 0;
- for ( ; i < eos._edges.size(); ++i )
- if ( eos._edges[i]->Is( _LayerEdge::MARKED ))
- break;
- if ( i < eos._edges.size() )
+ if (SALOME::VerbosityActivated())
{
- dumpFunction(SMESH_Comment("putOnOffsetSurface_S") << eos._shapeID
- << "_InfStep" << infStep << "_" << smooStep );
+ // dumpMove() for debug
+ size_t i = 0;
for ( ; i < eos._edges.size(); ++i )
+ if ( eos._edges[i]->Is( _LayerEdge::MARKED ))
+ break;
+ if ( i < eos._edges.size() )
{
- if ( eos._edges[i]->Is( _LayerEdge::MARKED )) {
- dumpMove( eos._edges[i]->_nodes.back() );
+ dumpFunction(SMESH_Comment("putOnOffsetSurface_") << eos.ShapeTypeLetter() << eos._shapeID
+ << "_InfStep" << infStep << "_" << Abs( smooStep ));
+ for ( ; i < eos._edges.size(); ++i )
+ {
+ if ( eos._edges[i]->Is( _LayerEdge::MARKED )) {
+ dumpMove( eos._edges[i]->_nodes.back() );
+ }
}
+ dumpFunctionEnd();
}
- dumpFunctionEnd();
}
-#endif
_ConvexFace* cnvFace;
if ( moveAll != _LayerEdge::UPD_NORMAL_CONV &&
SMESH_subMeshIteratorPtr smIt = eos._subMesh->getDependsOnIterator(/*includeSelf=*/false);
while ( smIt->more() )
{
- SMESH_subMesh* sm = smIt->next();
+ SMESH_subMesh* sm = smIt->next();
_EdgesOnShape* subEOS = eos.GetData().GetShapeEdges( sm->GetId() );
if ( !subEOS->_sWOL.IsNull() ) continue;
if ( std::find( eosC1.begin(), eosC1.end(), subEOS ) != eosC1.end() ) continue;
}
cnvFace->_normalsFixedOnBorders = true;
}
+
+
+ // bos #20643
+ // negative smooStep means "final step", where we don't treat RISKY_SWOL edges
+ // as edges based on FACE are a bit late comparing with them
+ if ( smooStep >= 0 &&
+ neighborHasRiskySWOL &&
+ moveAll != _LayerEdge::RISKY_SWOL &&
+ eos.ShapeType() == TopAbs_FACE )
+ {
+ // put on the surface nodes built on FACE boundaries
+ SMESH_subMeshIteratorPtr smIt = eos._subMesh->getDependsOnIterator(/*includeSelf=*/false);
+ while ( smIt->more() )
+ {
+ SMESH_subMesh* sm = smIt->next();
+ _EdgesOnShape* subEOS = eos.GetData().GetShapeEdges( sm->GetId() );
+ if ( subEOS->_sWOL.IsNull() ) continue;
+ if ( std::find( eosC1.begin(), eosC1.end(), subEOS ) != eosC1.end() ) continue;
+
+ putOnOffsetSurface( *subEOS, infStep, eosC1, smooStep, _LayerEdge::RISKY_SWOL );
+ }
+ }
}
//================================================================================
tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
dumpMove( tgtNode );
- SMDS_FacePositionPtr pos = tgtNode->GetPosition();
- pos->SetUParameter( newUV.X() );
- pos->SetVParameter( newUV.Y() );
+ if ( SMDS_FacePositionPtr pos = tgtNode->GetPosition() ) // NULL if F is noShrink
+ {
+ pos->SetUParameter( newUV.X() );
+ pos->SetVParameter( newUV.Y() );
+ }
gp_XYZ newUV0( newUV.X(), newUV.Y(), 0 );
tgtNode->setXYZ( newPos.X(), newPos.Y(), newPos.Z() );
dumpMove( tgtNode );
- SMDS_FacePositionPtr pos = tgtNode->GetPosition();
- pos->SetUParameter( newUV.X() );
- pos->SetVParameter( newUV.Y() );
-
+ if ( SMDS_FacePositionPtr pos = tgtNode->GetPosition() ) // NULL if F is noShrink
+ {
+ pos->SetUParameter( newUV.X() );
+ pos->SetVParameter( newUV.Y() );
+ }
_eos[i]->Set( _LayerEdge::SMOOTHED ); // to check in refine() (IPAL54237)
}
}
_edgeDir[1] = getEdgeDir( E, leOnV[1]->_nodes[0], data.GetHelper() );
_leOnV[0]._cosin = Abs( leOnV[0]->_cosin );
_leOnV[1]._cosin = Abs( leOnV[1]->_cosin );
+ _leOnV[0]._flags = _leOnV[1]._flags = 0;
if ( _eos._sWOL.IsNull() ) // 3D
for ( int iEnd = 0; iEnd < 2; ++iEnd )
_leOnV[iEnd]._cosin = Abs( _edgeDir[iEnd].Normalized() * leOnV[iEnd]->_normal );
// divide E to have offset segments with low deflection
BRepAdaptor_Curve c3dAdaptor( E );
- const double curDeflect = 0.1; //0.01; // Curvature deflection == |p1p2]*sin(p1p2,p1pM)
+ const double curDeflect = 0.1; //0.01; // Curvature deflection == |p1p2|*sin(p1p2,p1pM)
const double angDeflect = 0.1; //0.09; // Angular deflection == sin(p1pM,pMp2)
GCPnts_TangentialDeflection discret(c3dAdaptor, angDeflect, curDeflect);
if ( discret.NbPoints() <= 2 )
// if ( size == 0 ) // MULTI_NORMAL _LayerEdge
// return gp_XYZ( 1e-100, 1e-100, 1e-100 );
+ if ( size < 1e-5 ) // normal || edgeDir (almost) at inflation along EDGE (bos #20643)
+ {
+ const _LayerEdge* le = _eos._edges[ _eos._edges.size() / 2 ];
+ const gp_XYZ& leNorm = le->_normal;
+
+ cross = leNorm ^ edgeDir;
+ norm = edgeDir ^ cross;
+ size = norm.Modulus();
+ }
+
return norm / size;
}
eos->_edgeForOffset = 0;
double maxCosin = -1;
+ //bool hasNoShrink = false;
for ( TopExp_Explorer eExp( eos->_shape, TopAbs_EDGE ); eExp.More(); eExp.Next() )
{
_EdgesOnShape* eoe = GetShapeEdges( eExp.Current() );
if ( !eoe || eoe->_edges.empty() ) continue;
+ // if ( eos->GetData()._noShrinkShapes.count( eoe->_shapeID ))
+ // hasNoShrink = true;
+
vector<_LayerEdge*>& eE = eoe->_edges;
_LayerEdge* e = eE[ eE.size() / 2 ];
- if ( e->_cosin > maxCosin )
+ if ( !e->Is( _LayerEdge::RISKY_SWOL ) && e->_cosin > maxCosin )
{
eos->_edgeForOffset = e;
maxCosin = e->_cosin;
}
+
+ if ( !eoe->_sWOL.IsNull() )
+ for ( _LayerEdge* le : eoe->_edges )
+ if ( le->Is( _LayerEdge::RISKY_SWOL ) && e->_cosin > 0 )
+ {
+ // make _neibors on FACE be smoothed after le->Is( BLOCKED )
+ for ( _LayerEdge* neibor : le->_neibors )
+ {
+ int shapeDim = neibor->BaseShapeDim();
+ if ( shapeDim == 2 )
+ neibor->Set( _LayerEdge::NEAR_BOUNDARY ); // on FACE
+ else if ( shapeDim == 0 )
+ neibor->Set( _LayerEdge::RISKY_SWOL ); // on VERTEX
+
+ if ( !neibor->_curvature )
+ {
+ gp_XY uv = helper.GetNodeUV( F, neibor->_nodes[0] );
+ neibor->_curvature = _Factory::NewCurvature();
+ neibor->_curvature->_r = 0;
+ neibor->_curvature->_k = 0;
+ neibor->_curvature->_h2lenRatio = 0;
+ neibor->_curvature->_uv = uv;
+ }
+ }
+ }
+ } // loop on EDGEs
+
+ // Try to initialize _Mapper2D
+
+ // if ( hasNoShrink )
+ // return;
+
+ SMDS_ElemIteratorPtr fIt = eos->_subMesh->GetSubMeshDS()->GetElements();
+ if ( !fIt->more() || fIt->next()->NbCornerNodes() != 4 )
+ return;
+
+ // get EDGEs of quadrangle bottom
+ std::list< TopoDS_Edge > edges;
+ std::list< int > nbEdgesInWire;
+ int nbWire = SMESH_Block::GetOrderedEdges( F, edges, nbEdgesInWire );
+ if ( nbWire != 1 || nbEdgesInWire.front() < 4 )
+ return;
+ const SMDS_MeshNode* node;
+ while ( true ) // make edges start at a corner VERTEX
+ {
+ node = SMESH_Algo::VertexNode( helper.IthVertex( 0, edges.front() ), helper.GetMeshDS() );
+ if ( node && helper.IsCornerOfStructure( node, eos->_subMesh->GetSubMeshDS(), helper ))
+ break;
+ edges.pop_front();
+ if ( edges.empty() )
+ return;
+ }
+ std::list< TopoDS_Edge >::iterator edgeIt = edges.begin();
+ while ( true ) // make edges finish at a corner VERTEX
+ {
+ node = SMESH_Algo::VertexNode( helper.IthVertex( 1, *edgeIt ), helper.GetMeshDS() );
+ ++edgeIt;
+ if ( node && helper.IsCornerOfStructure( node, eos->_subMesh->GetSubMeshDS(), helper ))
+ {
+ edges.erase( edgeIt, edges.end() );
+ break;
+ }
+ if ( edgeIt == edges.end() )
+ return;
}
- }
+
+ // get structure of nodes
+ TParam2ColumnMap param2ColumnMap;
+ if ( !helper.LoadNodeColumns( param2ColumnMap, F, edges, helper.GetMeshDS() ))
+ return;
+
+ eos->_mapper2D = new _Mapper2D( param2ColumnMap, eos->GetData()._n2eMap );
+
+ } // if eos is of curved FACE
+
+ return;
}
//================================================================================
PShapeIteratorPtr eIt = helper.GetAncestors( V, *_mesh, TopAbs_EDGE, &eos->_sWOL );
while ( const TopoDS_Shape* E = eIt->next() )
{
- gp_Vec edgeDir = getEdgeDir( TopoDS::Edge( *E ), TopoDS::Vertex( V ));
+ gp_Vec edgeDir = getEdgeDir( TopoDS::Edge( *E ), TopoDS::Vertex( V ),
+ eos->_hyp.Get1stLayerThickness() );
double angle = edgeDir.Angle( newEdge._normal ); // [0,PI]
if ( angle < M_PI / 2 )
shapesToSmooth.insert( data.GetShapeEdges( *E ));
Block( eos.GetData() );
}
const double lenDelta = len - _len;
+ // if ( lenDelta < 0 )
+ // return;
if ( lenDelta < len * 1e-3 )
{
Block( eos.GetData() );
_pos.push_back( newXYZ );
if ( !eos._sWOL.IsNull() )
- {
- double distXYZ[4];
- bool uvOK = false;
- if ( eos.SWOLType() == TopAbs_EDGE )
- {
- double u = Precision::Infinite(); // to force projection w/o distance check
- uvOK = helper.CheckNodeU( TopoDS::Edge( eos._sWOL ), n, u,
- /*tol=*/2*lenDelta, /*force=*/true, distXYZ );
- _pos.back().SetCoord( u, 0, 0 );
- if ( _nodes.size() > 1 && uvOK )
- {
- SMDS_EdgePositionPtr pos = n->GetPosition();
- pos->SetUParameter( u );
- }
- }
- else // TopAbs_FACE
- {
- gp_XY uv( Precision::Infinite(), 0 );
- uvOK = helper.CheckNodeUV( TopoDS::Face( eos._sWOL ), n, uv,
- /*tol=*/2*lenDelta, /*force=*/true, distXYZ );
- _pos.back().SetCoord( uv.X(), uv.Y(), 0 );
- if ( _nodes.size() > 1 && uvOK )
- {
- SMDS_FacePositionPtr pos = n->GetPosition();
- pos->SetUParameter( uv.X() );
- pos->SetVParameter( uv.Y() );
- }
- }
- if ( uvOK )
- {
- n->setXYZ( distXYZ[1], distXYZ[2], distXYZ[3]);
- }
- else
+ if ( !UpdatePositionOnSWOL( n, 2*lenDelta, eos, helper ))
{
n->setXYZ( oldXYZ.X(), oldXYZ.Y(), oldXYZ.Z() );
_pos.pop_back();
Block( eos.GetData() );
return;
}
- }
_len = len;
{
for ( size_t i = 0; i < _neibors.size(); ++i )
//if ( _len > _neibors[i]->GetSmooLen() )
- _neibors[i]->Set( MOVED );
+ _neibors[i]->Set( MOVED );
Set( MOVED );
}
dumpMove( n ); //debug
}
+
+//================================================================================
+/*!
+ * \brief Update last position on SWOL by projecting node on SWOL
+*/
+//================================================================================
+
+bool _LayerEdge::UpdatePositionOnSWOL( SMDS_MeshNode* n,
+ double tol,
+ _EdgesOnShape& eos,
+ SMESH_MesherHelper& helper )
+{
+ double distXYZ[4];
+ bool uvOK = false;
+ if ( eos.SWOLType() == TopAbs_EDGE )
+ {
+ double u = Precision::Infinite(); // to force projection w/o distance check
+ uvOK = helper.CheckNodeU( TopoDS::Edge( eos._sWOL ), n, u, tol, /*force=*/true, distXYZ );
+ _pos.back().SetCoord( u, 0, 0 );
+ if ( _nodes.size() > 1 && uvOK )
+ {
+ SMDS_EdgePositionPtr pos = n->GetPosition();
+ pos->SetUParameter( u );
+ }
+ }
+ else // TopAbs_FACE
+ {
+ gp_XY uv( Precision::Infinite(), 0 );
+ uvOK = helper.CheckNodeUV( TopoDS::Face( eos._sWOL ), n, uv, tol, /*force=*/true, distXYZ );
+ _pos.back().SetCoord( uv.X(), uv.Y(), 0 );
+ if ( _nodes.size() > 1 && uvOK )
+ {
+ SMDS_FacePositionPtr pos = n->GetPosition();
+ pos->SetUParameter( uv.X() );
+ pos->SetVParameter( uv.Y() );
+ }
+ }
+ if ( uvOK )
+ {
+ n->setXYZ( distXYZ[1], distXYZ[2], distXYZ[3]);
+ }
+ return uvOK;
+}
+
//================================================================================
/*!
* \brief Set BLOCKED flag and propagate limited _maxLen to _neibors
segLen[j] = segLen[j-1] + (edge._pos[j-1] - edge._pos[j] ).Modulus();
}
}
- else if ( !surface.IsNull() ) // SWOL surface with singularities
+ else // SWOL is surface with singularities or irregularly parametrized curve
{
pos3D.resize( edge._pos.size() );
- for ( size_t j = 0; j < edge._pos.size(); ++j )
- pos3D[j] = surface->Value( edge._pos[j].X(), edge._pos[j].Y() ).XYZ();
+
+ if ( !surface.IsNull() )
+ for ( size_t j = 0; j < edge._pos.size(); ++j )
+ pos3D[j] = surface->Value( edge._pos[j].X(), edge._pos[j].Y() ).XYZ();
+ else if ( !curve.IsNull() )
+ for ( size_t j = 0; j < edge._pos.size(); ++j )
+ pos3D[j] = curve->Value( edge._pos[j].X() ).XYZ();
for ( size_t j = 1; j < edge._pos.size(); ++j )
segLen[j] = segLen[j-1] + ( pos3D[j-1] - pos3D[j] ).Modulus();
if ( n2eMap && (( n2e = n2eMap->find( edge._nodes[0] )) != n2eMap->end() ))
{
edgeOnSameNode = n2e->second;
- useExistingPos = ( edgeOnSameNode->_len < edge._len );
+ useExistingPos = ( edgeOnSameNode->_len < edge._len ||
+ segLen[0] == segLen.back() ); // too short inflation step (bos #20643)
const gp_XYZ& otherTgtPos = edgeOnSameNode->_pos.back();
SMDS_PositionPtr lastPos = tgtNode->GetPosition();
if ( isOnEdge )
fpos->SetVParameter( otherTgtPos.Y() );
}
}
- // calculate height of the first layer
- double h0;
- const double T = segLen.back(); //data._hyp.GetTotalThickness();
- const double f = eos._hyp.GetStretchFactor();
- const int N = eos._hyp.GetNumberLayers();
- const double fPowN = pow( f, N );
- if ( fPowN - 1 <= numeric_limits<double>::min() )
- h0 = T / N;
- else
- h0 = T * ( f - 1 )/( fPowN - 1 );
-
- const double zeroLen = std::numeric_limits<double>::min();
// create intermediate nodes
- double hSum = 0, hi = h0/f;
+ const double h0 = eos._hyp.Get1stLayerThickness( segLen.back() );
+ const double zeroLen = std::numeric_limits<double>::min();
+ double hSum = 0, hi = h0/eos._hyp.GetStretchFactor();
size_t iSeg = 1;
for ( size_t iStep = 1; iStep < edge._nodes.size(); ++iStep )
{
// compute an intermediate position
- hi *= f;
+ hi *= eos._hyp.GetStretchFactor();
hSum += hi;
while ( hSum > segLen[iSeg] && iSeg < segLen.size()-1 )
++iSeg;
std::vector< SMESH_NodeXYZ > _nodes;
TopAbs_ShapeEnum _vertSWOLType[2]; // shrink part includes VERTEXes
AverageHyp* _vertHyp[2];
+ double _edgeWOLLen[2]; // length of wol EDGE
+ double _tol; // to compare _edgeWOLLen's
BndPart():
_isShrink(0), _isReverse(0), _nbSegments(0), _hyp(0),
- _vertSWOLType{ TopAbs_WIRE, TopAbs_WIRE }, _vertHyp{ 0, 0 }
+ _vertSWOLType{ TopAbs_WIRE, TopAbs_WIRE }, _vertHyp{ 0, 0 }, _edgeWOLLen{ 0., 0.}
{}
+ bool IsEqualLengthEWOL( const BndPart& other ) const
+ {
+ return ( std::abs( _edgeWOLLen[0] - other._edgeWOLLen[0] ) < _tol &&
+ std::abs( _edgeWOLLen[1] - other._edgeWOLLen[1] ) < _tol );
+ }
+
bool operator==( const BndPart& other ) const
{
return ( _isShrink == other._isShrink &&
(( !_isShrink ) ||
( *_hyp == *other._hyp &&
vertHyp1() == other.vertHyp1() &&
- vertHyp2() == other.vertHyp2() ))
+ vertHyp2() == other.vertHyp2() &&
+ IsEqualLengthEWOL( other )))
);
}
bool CanAppend( const BndPart& other )
bool hasCommonNode = ( _nodes.back()->GetID() == other._nodes.front()->GetID() );
_nodes.insert( _nodes.end(), other._nodes.begin() + hasCommonNode, other._nodes.end() );
_vertSWOLType[1] = other._vertSWOLType[1];
- if ( _isShrink )
- _vertHyp[1] = other._vertHyp[1];
+ if ( _isShrink ) {
+ _vertHyp[1] = other._vertHyp[1];
+ _edgeWOLLen[1] = other._edgeWOLLen[1];
+ }
}
- const SMDS_MeshNode* Node(size_t i) const
+ const SMDS_MeshNode* Node(size_t i) const
{
return _nodes[ _isReverse ? ( _nodes.size() - 1 - i ) : i ]._node;
}
SMESH_subMesh* _subMesh;
_SolidData* _data1;
_SolidData* _data2;
- //bool _isPeriodic;
std::list< BndPart > _boundary;
int _boundarySize, _nbBoundaryParts;
void Init( SMESH_subMesh* sm, _SolidData* sd1, _SolidData* sd2 )
{
- _subMesh = sm; _data1 = sd1; _data2 = sd2; //_isPeriodic = false;
+ _subMesh = sm; _data1 = sd1; _data2 = sd2;
}
bool IsSame( const TopoDS_Face& face ) const
{
if ( !periodic._trsf.Solve( srcPnts, tgtPnts )) {
continue;
}
- double tol = std::numeric_limits<double>::max();
+ double tol = std::numeric_limits<double>::max(); // tolerance by segment size
for ( size_t i = 1; i < srcPnts.size(); ++i ) {
tol = Min( tol, ( srcPnts[i-1] - srcPnts[i] ).SquareModulus() );
}
tol = 0.01 * Sqrt( tol );
+ for ( BndPart& boundary : _boundary ) { // tolerance by VL thickness
+ if ( boundary._isShrink )
+ tol = Min( tol, boundary._hyp->Get1stLayerThickness() / 50. );
+ }
bool nodeCoincide = true;
TNodeNodeMap::iterator n2n = periodic._nnMap.begin();
for ( ; n2n != periodic._nnMap.end() && nodeCoincide; ++n2n )
SMESH_NodeXYZ nSrc = n2n->first;
SMESH_NodeXYZ nTgt = n2n->second;
gp_XYZ pTgt = periodic._trsf.Transform( nSrc );
- nodeCoincide = (( pTgt - nTgt ).SquareModulus() < tol );
+ nodeCoincide = (( pTgt - nTgt ).SquareModulus() < tol * tol );
}
if ( nodeCoincide )
return true;
for ( int iE = 0; iE < nbEdgesInWire.front(); ++iE )
{
BndPart bndPart;
+
+ std::vector<const SMDS_MeshNode*> nodes = fSide.GetOrderedNodes( iE );
+ bndPart._nodes.assign( nodes.begin(), nodes.end() );
+ bndPart._nbSegments = bndPart._nodes.size() - 1;
+
_EdgesOnShape* eos = _data1->GetShapeEdges( fSide.EdgeID( iE ));
bndPart._isShrink = ( eos->SWOLType() == TopAbs_FACE );
bndPart._vertSWOLType[iV] = eov[iV]->SWOLType();
}
}
+ bndPart._edgeWOLLen[0] = fSide.EdgeLength( iE - 1 );
+ bndPart._edgeWOLLen[1] = fSide.EdgeLength( iE + 1 );
+
+ bndPart._tol = std::numeric_limits<double>::max(); // tolerance by segment size
+ for ( size_t i = 1; i < bndPart._nodes.size(); ++i )
+ bndPart._tol = Min( bndPart._tol,
+ ( bndPart._nodes[i-1] - bndPart._nodes[i] ).SquareModulus() );
}
- std::vector<const SMDS_MeshNode*> nodes = fSide.GetOrderedNodes( iE );
- bndPart._nodes.assign( nodes.begin(), nodes.end() );
- bndPart._nbSegments = bndPart._nodes.size() - 1;
if ( _boundary.empty() || ! _boundary.back().CanAppend( bndPart ))
_boundary.push_back( bndPart );
}
SMESHDS_Mesh* meshDS = dataSrc->GetHelper().GetMeshDS();
+ dumpFunction(SMESH_Comment("periodicMoveNodes_F")
+ << _shriFace[iSrc]->_subMesh->GetId() << "_F"
+ << _shriFace[iTgt]->_subMesh->GetId() );
TNode2Edge::iterator n2e;
TNodeNodeMap::iterator n2n = _nnMap.begin();
for ( ; n2n != _nnMap.end(); ++n2n )
SMESH_NodeXYZ pSrc = leSrc->_nodes[ iN ];
gp_XYZ pTgt = trsf->Transform( pSrc );
meshDS->MoveNode( leTgt->_nodes[ iN ], pTgt.X(), pTgt.Y(), pTgt.Z() );
+
+ dumpMove( leTgt->_nodes[ iN ]);
}
}
}
<< _shriFace[iSrc]->_subMesh->GetId() << " -> "
<< _shriFace[iTgt]->_subMesh->GetId() << " -- "
<< ( done ? "DONE" : "FAIL"));
+ dumpFunctionEnd();
return done;
}
{
_EdgesOnShape& eos = * subEOS[ iS ];
if ( eos.ShapeType() != TopAbs_EDGE ) continue;
+ if ( eos.size() == 0 )
+ continue;
const TopoDS_Edge& E = TopoDS::Edge( eos._shape );
data.SortOnEdge( E, eos._edges );
uvPtVec[ i ].param = helper.GetNodeU( E, edges[i]->_nodes[0] );
uvPtVec[ i ].SetUV( helper.GetNodeUV( F, edges[i]->_nodes.back() ));
}
+ if ( uvPtVec[ 0 ].node == uvPtVec.back().node && // closed
+ helper.IsSeamShape( uvPtVec[ 0 ].node->GetShapeID() ))
+ {
+ uvPtVec[ 0 ].SetUV( helper.GetNodeUV( F,
+ edges[0]->_nodes.back(),
+ edges[1]->_nodes.back() ));
+ size_t i = edges.size() - 1;
+ uvPtVec[ i ].SetUV( helper.GetNodeUV( F,
+ edges[i ]->_nodes.back(),
+ edges[i-1]->_nodes.back() ));
+ }
+ // if ( edges.empty() )
+ // continue;
BRep_Tool::Range( E, uvPtVec[0].param, uvPtVec.back().param );
StdMeshers_FaceSide fSide( uvPtVec, F, E, _mesh );
StdMeshers_ViscousLayers2D::SetProxyMeshOfEdge( fSide );
smDS->Clear();
// compute the mesh on the FACE
+ TopTools_IndexedMapOfShape allowed(1);
+ allowed.Add( sm->GetSubShape() );
+ sm->SetAllowedSubShapes( &allowed );
sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
sm->ComputeStateEngine( SMESH_subMesh::COMPUTE_SUBMESH );
+ sm->SetAllowedSubShapes( nullptr );
// re-fill proxy sub-meshes of the FACE
for ( size_t i = 0 ; i < _sdVec.size(); ++i )
if ( !n2 )
return error(SMESH_Comment("Wrongly meshed EDGE ") << getMeshDS()->ShapeToIndex( E ));
- if ( n2 == tgtNode ) // for 3D_mesh_GHS3D_01/B1
+ if ( n2 == tgtNode || // for 3D_mesh_GHS3D_01/B1
+ n2 == edge._nodes[1] ) // bos #20643
{
// shrunk by other SOLID
edge.Set( _LayerEdge::SHRUNK ); // ???
*/
//================================================================================
-bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& /*surface*/,
+bool _LayerEdge::SetNewLength2d( Handle(Geom_Surface)& surface,
const TopoDS_Face& F,
_EdgesOnShape& eos,
SMESH_MesherHelper& helper )
continue; // simplex of quadrangle created by addBoundaryElements()
// find intersection of 2 lines: curUV-tgtUV and that connecting simplex nodes
- gp_XY uvN1 = helper.GetNodeUV( F, _simplices[i]._nPrev );
- gp_XY uvN2 = helper.GetNodeUV( F, _simplices[i]._nNext );
+ gp_XY uvN1 = helper.GetNodeUV( F, _simplices[i]._nPrev, tgtNode );
+ gp_XY uvN2 = helper.GetNodeUV( F, _simplices[i]._nNext, tgtNode );
gp_XY dirN = uvN2 - uvN1;
double det = uvDir.Crossed( dirN );
if ( Abs( det ) < std::numeric_limits<double>::min() ) continue;
gp_Pnt p = surface->Value( newUV.X(), newUV.Y() );
tgtNode->setXYZ( p.X(), p.Y(), p.Z() );
dumpMove( tgtNode );
+#else
+ if ( surface.IsNull() ) {}
#endif
}
else // _sWOL is TopAbs_EDGE
edgeSize.back() = edgeSize.front();
gp_XY newPos(0,0);
- //int nbEdges = 0;
- double sumSize = 0;
+ double sumWgt = 0;
for ( size_t i = 1; i < edgeDir.size(); ++i )
{
- if ( edgeDir[i-1].X() > 1. ) continue;
- int i1 = i-1;
+ const int i1 = i-1;
+ if ( edgeDir[i1].X() > 1. ) continue;
while ( edgeDir[i].X() > 1. && ++i < edgeDir.size() );
if ( i == edgeDir.size() ) break;
gp_XY p = uv[i];
gp_XY norm1( -edgeDir[i1].Y(), edgeDir[i1].X() );
- gp_XY norm2( -edgeDir[i].Y(), edgeDir[i].X() );
+ gp_XY norm2( -edgeDir[i ].Y(), edgeDir[i ].X() );
gp_XY bisec = norm1 + norm2;
double bisecSize = bisec.Modulus();
if ( bisecSize < numeric_limits<double>::min() )
}
bisec /= bisecSize;
- gp_XY dirToN = uvToFix - p;
- double distToN = dirToN.Modulus();
+ gp_XY dirToN = uvToFix - p;
+ double distToN = bisec * dirToN;
if ( bisec * dirToN < 0 )
distToN = -distToN;
- newPos += ( p + bisec * distToN ) * ( edgeSize[i1] + edgeSize[i] );
- //++nbEdges;
- sumSize += edgeSize[i1] + edgeSize[i];
+ double wgt = edgeSize[i1] + edgeSize[i];
+ newPos += ( p + bisec * distToN ) * wgt;
+ sumWgt += wgt;
}
- newPos /= /*nbEdges * */sumSize;
+ newPos /= sumWgt;
return newPos;
}
double u = helper.GetNodeU( _geomEdge, e->_nodes[0], e->_nodes.back());
_edges[ u < 0.5*(f+l) ? 0 : 1 ] = e;
- // Update _nodes
+ // Check if the nodes are already shrunk by another SOLID
const SMDS_MeshNode* tgtNode0 = TgtNode( 0 );
const SMDS_MeshNode* tgtNode1 = TgtNode( 1 );
+ _done = (( tgtNode0 && tgtNode0->NbInverseElements( SMDSAbs_Edge ) == 2 ) ||
+ ( tgtNode1 && tgtNode1->NbInverseElements( SMDSAbs_Edge ) == 2 ));
+ if ( _done )
+ _nodes.resize( 1, nullptr );
+
+ // Update _nodes
+
if ( _nodes.empty() )
{
SMESHDS_SubMesh * eSubMesh = helper.GetMeshDS()->MeshElements( _geomEdge );
double f,l;
if ( set3D || _done )
{
+ dumpFunction(SMESH_Comment("shrink1D_E") << helper.GetMeshDS()->ShapeToIndex( _geomEdge )<<
+ "_F" << helper.GetSubShapeID() );
Handle(Geom_Curve) C = BRep_Tool::Curve(_geomEdge, f,l);
GeomAdaptor_Curve aCurve(C, f,l);
pos->SetUParameter( u );
gp_Pnt p = C->Value( u );
const_cast< SMDS_MeshNode*>( _nodes[i] )->setXYZ( p.X(), p.Y(), p.Z() );
+ dumpMove( _nodes[i] );
}
+ dumpFunctionEnd();
}
else
{
}
}
+//================================================================================
+/*!
+ * \brief Setup quadPoints
+ */
+//================================================================================
+
+_Mapper2D::_Mapper2D( const TParam2ColumnMap & param2ColumnMap, const TNode2Edge& n2eMap )
+{
+ size_t i, iSize = _quadPoints.iSize = param2ColumnMap.size();
+ size_t j, jSize = _quadPoints.jSize = param2ColumnMap.begin()->second.size();
+ if ( _quadPoints.iSize < 3 ||
+ _quadPoints.jSize < 3 )
+ return;
+ _quadPoints.uv_grid.resize( iSize * jSize );
+
+ // set nodes
+ i = 0;
+ for ( auto & u_columnNodes : param2ColumnMap )
+ {
+ for ( j = 0; j < u_columnNodes.second.size(); ++j )
+ _quadPoints.UVPt( i, j ).node = u_columnNodes.second[ j ];
+ ++i;
+ }
+
+ // compute x parameter on borders
+ uvPnt( 0, 0 ).x = 0;
+ uvPnt( 0, jSize-1 ).x = 0;
+ gp_Pnt p0, pPrev0 = SMESH_NodeXYZ( uvPnt( 0, 0 ).node );
+ gp_Pnt p1, pPrev1 = SMESH_NodeXYZ( uvPnt( 0, jSize-1 ).node );
+ for ( i = 1; i < iSize; ++i )
+ {
+ p0 = SMESH_NodeXYZ( uvPnt( i, 0 ).node );
+ p1 = SMESH_NodeXYZ( uvPnt( i, jSize-1 ).node );
+ uvPnt( i, 0 ).x = uvPnt( i-1, 0 ).x + p0.Distance( pPrev0 );
+ uvPnt( i, jSize-1 ).x = uvPnt( i-1, jSize-1 ).x + p1.Distance( pPrev1 );
+ pPrev0 = p0;
+ pPrev1 = p1;
+ }
+ for ( i = 1; i < iSize-1; ++i )
+ {
+ uvPnt( i, 0 ).x /= uvPnt( iSize-1, 0 ).x;
+ uvPnt( i, jSize-1 ).x /= uvPnt( iSize-1, jSize-1 ).x;
+ uvPnt( i, 0 ).y = 0;
+ uvPnt( i, jSize-1 ).y = 1;
+ }
+
+ // compute y parameter on borders
+ uvPnt( 0, 0 ).y = 0;
+ uvPnt( iSize-1, 0 ).y = 0;
+ pPrev0 = SMESH_NodeXYZ( uvPnt( 0, 0 ).node );
+ pPrev1 = SMESH_NodeXYZ( uvPnt( iSize-1, 0 ).node );
+ for ( j = 1; j < jSize; ++j )
+ {
+ p0 = SMESH_NodeXYZ( uvPnt( 0, j ).node );
+ p1 = SMESH_NodeXYZ( uvPnt( iSize-1, j ).node );
+ uvPnt( 0, j ).y = uvPnt( 0, j-1 ).y + p0.Distance( pPrev0 );
+ uvPnt( iSize-1, j ).y = uvPnt( iSize-1, j-1 ).y + p1.Distance( pPrev1 );
+ pPrev0 = p0;
+ pPrev1 = p1;
+ }
+ for ( j = 1; j < jSize-1; ++j )
+ {
+ uvPnt( 0, j ).y /= uvPnt( 0, jSize-1 ).y;
+ uvPnt( iSize-1, j ).y /= uvPnt( iSize-1, jSize-1 ).y;
+ uvPnt( 0, j ).x = 0;
+ uvPnt( iSize-1, j ).x = 1;
+ }
+
+ // compute xy of internal nodes
+ for ( i = 1; i < iSize-1; ++i )
+ {
+ const double x0 = uvPnt( i, 0 ).x;
+ const double x1 = uvPnt( i, jSize-1 ).x;
+ for ( j = 1; j < jSize-1; ++j )
+ {
+ const double y0 = uvPnt( 0, j ).y;
+ const double y1 = uvPnt( iSize-1, j ).y;
+ double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0));
+ double y = y0 + x * (y1 - y0);
+ uvPnt( i, j ).x = x;
+ uvPnt( i, j ).y = y;
+ }
+ }
+
+ // replace base nodes with target ones
+ for ( i = 0; i < iSize; ++i )
+ for ( j = 0; j < jSize; ++j )
+ {
+ auto n2e = n2eMap.find( uvPnt( i, j ).node );
+ uvPnt( i, j ).node = n2e->second->_nodes.back();
+ }
+
+ return;
+}
+
+//================================================================================
+/*!
+ * \brief Compute positions of nodes of 2D structured mesh using TFI
+ */
+//================================================================================
+
+bool _Mapper2D::ComputeNodePositions()
+{
+ if ( _quadPoints.uv_grid.empty() )
+ return true;
+
+ size_t i, iSize = _quadPoints.iSize;
+ size_t j, jSize = _quadPoints.jSize;
+
+ SMESH_NodeXYZ a0 ( uvPnt( 0, 0 ).node );
+ SMESH_NodeXYZ a1 ( uvPnt( iSize-1, 0 ).node );
+ SMESH_NodeXYZ a2 ( uvPnt( iSize-1, jSize-1 ).node );
+ SMESH_NodeXYZ a3 ( uvPnt( 0, jSize-1 ).node );
+
+ for ( i = 1; i < iSize-1; ++i )
+ {
+ SMESH_NodeXYZ p0 ( uvPnt( i, 0 ).node );
+ SMESH_NodeXYZ p2 ( uvPnt( i, jSize-1 ).node );
+ for ( j = 1; j < jSize-1; ++j )
+ {
+ SMESH_NodeXYZ p1 ( uvPnt( iSize-1, j ).node );
+ SMESH_NodeXYZ p3 ( uvPnt( 0, j ).node );
+ double x = uvPnt( i, j ).x;
+ double y = uvPnt( i, j ).y;
+
+ gp_XYZ p = SMESH_MesherHelper::calcTFI( x, y, a0,a1,a2,a3, p0,p1,p2,p3 );
+ const_cast< SMDS_MeshNode* >( uvPnt( i, j ).node )->setXYZ( p.X(), p.Y(), p.Z() );
+
+ dumpMove( uvPnt( i, j ).node );
+ }
+ }
+ return true;
+}
+
//================================================================================
/*!
* \brief Creates 2D and 1D elements on boundaries of new prisms