-// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2013 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_Gen.hxx"
#include "SMESH_Group.hxx"
#include "SMESH_Mesh.hxx"
+#include "SMESH_MeshAlgos.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_ProxyMesh.hxx"
#include "SMESH_subMesh.hxx"
#include "SMESH_subMeshEventListener.hxx"
-#include "utilities.h"
-
#include <BRepAdaptor_Curve2d.hxx>
#include <BRep_Tool.hxx>
#include <Bnd_B2d.hxx>
using namespace std;
//================================================================================
-namespace VISCOUS
+namespace VISCOUS_3D
{
typedef int TGeomID;
* \brief Listener of events of 3D sub-meshes computed with viscous layers.
* It is used to clear an inferior dim sub-meshes modified by viscous layers
*/
- class _SrinkShapeListener : SMESH_subMeshEventListener
+ class _ShrinkShapeListener : SMESH_subMeshEventListener
{
- _SrinkShapeListener()
+ _ShrinkShapeListener()
: SMESH_subMeshEventListener(/*isDeletable=*/false,
- "StdMeshers_ViscousLayers::_SrinkShapeListener") {}
- static SMESH_subMeshEventListener* Get() { static _SrinkShapeListener l; return &l; }
+ "StdMeshers_ViscousLayers::_ShrinkShapeListener") {}
public:
+ static SMESH_subMeshEventListener* Get() { static _ShrinkShapeListener l; return &l; }
virtual void ProcessEvent(const int event,
const int eventType,
SMESH_subMesh* solidSM,
SMESH_subMeshEventListener::ProcessEvent(event,eventType,solidSM,data,hyp);
}
}
- static void ToClearSubMeshWithSolid( SMESH_subMesh* sm,
- const TopoDS_Shape& solid)
- {
- SMESH_subMesh* solidSM = sm->GetFather()->GetSubMesh( solid );
- SMESH_subMeshEventListenerData* data = solidSM->GetEventListenerData( Get());
- if ( data )
- {
- if ( find( data->mySubMeshes.begin(), data->mySubMeshes.end(), sm ) ==
- data->mySubMeshes.end())
- data->mySubMeshes.push_back( sm );
- }
- else
- {
- data = SMESH_subMeshEventListenerData::MakeData( /*dependent=*/sm );
- sm->SetEventListener( Get(), data, /*whereToListenTo=*/solidSM );
- }
- }
};
//--------------------------------------------------------------------------------
/*!
}
};
+ //================================================================================
+ /*!
+ * \brief sets a sub-mesh event listener to clear sub-meshes of sub-shapes of
+ * the main shape when sub-mesh of the main shape is cleared,
+ * for example to clear sub-meshes of FACEs when sub-mesh of a SOLID
+ * is cleared
+ */
+ //================================================================================
+
+ void ToClearSubWithMain( SMESH_subMesh* sub, const TopoDS_Shape& main)
+ {
+ SMESH_subMesh* mainSM = sub->GetFather()->GetSubMesh( main );
+ SMESH_subMeshEventListenerData* data =
+ mainSM->GetEventListenerData( _ShrinkShapeListener::Get());
+ if ( data )
+ {
+ if ( find( data->mySubMeshes.begin(), data->mySubMeshes.end(), sub ) ==
+ data->mySubMeshes.end())
+ data->mySubMeshes.push_back( sub );
+ }
+ else
+ {
+ data = SMESH_subMeshEventListenerData::MakeData( /*dependent=*/sub );
+ sub->SetEventListener( _ShrinkShapeListener::Get(), data, /*whereToListenTo=*/mainSM );
+ }
+ }
//--------------------------------------------------------------------------------
/*!
* \brief Simplex (triangle or tetrahedron) based on 1 (tria) or 2 (tet) nodes of
struct _Simplex
{
const SMDS_MeshNode *_nPrev, *_nNext; // nodes on a smoothed mesh surface
- _Simplex(const SMDS_MeshNode* nPrev=0, const SMDS_MeshNode* nNext=0)
- : _nPrev(nPrev), _nNext(nNext) {}
+ const SMDS_MeshNode *_nOpp; // in 2D case, a node opposite to a smoothed node in QUAD
+ _Simplex(const SMDS_MeshNode* nPrev=0,
+ const SMDS_MeshNode* nNext=0,
+ const SMDS_MeshNode* nOpp=0)
+ : _nPrev(nPrev), _nNext(nNext), _nOpp(nOpp) {}
bool IsForward(const SMDS_MeshNode* nSrc, const gp_XYZ* pntTgt) const
{
const double M[3][3] =
{
double _r; // radius
double _k; // factor to correct node smoothed position
+ double _h2lenRatio; // avgNormProj / (2*avgDist)
public:
static _Curvature* New( double avgNormProj, double avgDist )
{
c->_r = avgDist * avgDist / avgNormProj;
c->_k = avgDist * avgDist / c->_r / c->_r;
c->_k *= ( c->_r < 0 ? 1/1.1 : 1.1 ); // not to be too restrictive
+ c->_h2lenRatio = avgNormProj / ( avgDist + avgDist );
}
return c;
}
double lenDelta(double len) const { return _k * ( _r + len ); }
+ double lenDeltaByDist(double dist) const { return dist * _h2lenRatio; }
};
struct _LayerEdge;
//--------------------------------------------------------------------------------
//vector<const SMDS_MeshNode*> _nodesAround;
vector<_Simplex> _simplices; // for quality check
+ enum SmoothType { LAPLACIAN, CENTROIDAL, ANGULAR };
+
bool Smooth(int& badNb,
Handle(Geom_Surface)& surface,
SMESH_MesherHelper& helper,
const double refSign,
- bool isCentroidal,
+ SmoothType how,
bool set3D);
+
+ gp_XY computeAngularPos(vector<gp_XY>& uv,
+ const gp_XY& uvToFix,
+ const double refSign );
};
//--------------------------------------------------------------------------------
/*!
_nn[3]=_le2->_nodes[0];
}
};
-} // namespace VISCOUS
+} // namespace VISCOUS_3D
//================================================================================
// StdMeshers_ViscousLayers hypothesis
//
StdMeshers_ViscousLayers::StdMeshers_ViscousLayers(int hypId, int studyId, SMESH_Gen* gen)
:SMESH_Hypothesis(hypId, studyId, gen),
- _nbLayers(1), _thickness(1), _stretchFactor(1)
+ _isToIgnoreShapes(18), _nbLayers(1), _thickness(1), _stretchFactor(1)
{
_name = StdMeshers_ViscousLayers::GetHypType();
_param_algo_dim = -3; // auxiliary hyp used by 3D algos
} // --------------------------------------------------------------------------------
-void StdMeshers_ViscousLayers::SetIgnoreFaces(const std::vector<int>& faceIds)
+void StdMeshers_ViscousLayers::SetBndShapes(const std::vector<int>& faceIds, bool toIgnore)
{
- if ( faceIds != _ignoreFaceIds )
- _ignoreFaceIds = faceIds, NotifySubMeshesHypothesisModification();
+ if ( faceIds != _shapeIds )
+ _shapeIds = faceIds, NotifySubMeshesHypothesisModification();
+ if ( _isToIgnoreShapes != toIgnore )
+ _isToIgnoreShapes = toIgnore, NotifySubMeshesHypothesisModification();
} // --------------------------------------------------------------------------------
void StdMeshers_ViscousLayers::SetTotalThickness(double thickness)
{
const TopoDS_Shape& theShape,
const bool toMakeN2NMap) const
{
- using namespace VISCOUS;
+ using namespace VISCOUS_3D;
_ViscousBuilder bulder;
SMESH_ComputeErrorPtr err = bulder.Compute( theMesh, theShape );
if ( err && !err->IsOK() )
save << " " << _nbLayers
<< " " << _thickness
<< " " << _stretchFactor
- << " " << _ignoreFaceIds.size();
- for ( unsigned i = 0; i < _ignoreFaceIds.size(); ++i )
- save << " " << _ignoreFaceIds[i];
+ << " " << _shapeIds.size();
+ for ( unsigned i = 0; i < _shapeIds.size(); ++i )
+ save << " " << _shapeIds[i];
+ save << " " << !_isToIgnoreShapes; // negate to keep the behavior in old studies.
return save;
} // --------------------------------------------------------------------------------
std::istream & StdMeshers_ViscousLayers::LoadFrom(std::istream & load)
{
- int nbFaces, faceID;
+ int nbFaces, faceID, shapeToTreat;
load >> _nbLayers >> _thickness >> _stretchFactor >> nbFaces;
- while ( _ignoreFaceIds.size() < nbFaces && load >> faceID )
- _ignoreFaceIds.push_back( faceID );
+ while ( _shapeIds.size() < nbFaces && load >> faceID )
+ _shapeIds.push_back( faceID );
+ if ( load >> shapeToTreat )
+ _isToIgnoreShapes = !shapeToTreat;
+ else
+ _isToIgnoreShapes = true; // old behavior
return load;
} // --------------------------------------------------------------------------------
bool StdMeshers_ViscousLayers::SetParametersByMesh(const SMESH_Mesh* theMesh,
gp_XYZ dir(0,0,0);
if ( !( ok = ( edges.size() > 0 ))) return dir;
// get average dir of edges going fromV
- gp_Vec edgeDir;
- for ( unsigned i = 0; i < edges.size(); ++i )
- {
- edgeDir = getEdgeDir( edges[i], fromV );
- double size2 = edgeDir.SquareMagnitude();
- if ( size2 > numeric_limits<double>::min() )
- edgeDir /= sqrt( size2 );
- else
- ok = false;
- dir += edgeDir.XYZ();
- }
+ gp_XYZ edgeDir;
+ //if ( edges.size() > 1 )
+ for ( unsigned i = 0; i < edges.size(); ++i )
+ {
+ edgeDir = getEdgeDir( edges[i], fromV );
+ double size2 = edgeDir.SquareModulus();
+ if ( size2 > numeric_limits<double>::min() )
+ edgeDir /= sqrt( size2 );
+ else
+ ok = false;
+ dir += edgeDir;
+ }
gp_XYZ fromEdgeDir = getFaceDir( F, edges[0], node, helper, ok );
- if ( edges.size() == 1 || dir.SquareModulus() < 1e-10)
+ if ( edges.size() == 1 )
dir = fromEdgeDir;
+ else if ( dir.SquareModulus() < 0.1 ) // ~< 20 degrees
+ dir = fromEdgeDir + getFaceDir( F, edges[1], node, helper, ok );
else if ( dir * fromEdgeDir < 0 )
dir *= -1;
if ( ok )
{
//dir /= edges.size();
if ( cosin ) {
- double angle = edgeDir.Angle( dir );
+ double angle = gp_Vec( edgeDir ).Angle( dir );
*cosin = cos( angle );
}
}
for ( ; eExp.More(); eExp.Next() )
{
const TopoDS_Edge& E = TopoDS::Edge( eExp.Current() );
- if ( BRep_Tool::Degenerated( E )) continue;
+ if ( SMESH_Algo::isDegenerated( E )) continue;
// check if 2D curve is concave
BRepAdaptor_Curve2d curve( E, F );
const int nbIntervals = curve.NbIntervals( GeomAbs_C2 );
#endif
}
-using namespace VISCOUS;
+using namespace VISCOUS_3D;
//================================================================================
/*!
{
if ( ! makeLayer(_sdVec[i]) )
return _error;
+
+ if ( _sdVec[i]._edges.size() == 0 )
+ continue;
if ( ! inflate(_sdVec[i]) )
return _error;
vector<TopoDS_Shape> ignoreFaces;
for ( unsigned i = 0; i < _sdVec.size(); ++i )
{
- vector<TGeomID> ids = _sdVec[i]._hyp->GetIgnoreFaces();
+ vector<TGeomID> ids = _sdVec[i]._hyp->GetBndShapes();
for ( unsigned i = 0; i < ids.size(); ++i )
{
const TopoDS_Shape& s = getMeshDS()->IndexToShape( ids[i] );
{
_ignoreShapeIds.insert( faceInd );
ignoreFaces.push_back( exp.Current() );
- if ( SMESH_Algo::IsReversedSubMesh( TopoDS::Face( exp.Current() ), getMeshDS()))
+ if ( helper.IsReversedSubMesh( TopoDS::Face( exp.Current() )))
_sdVec[i]._reversedFaceIds.insert( faceInd );
}
}
if ( data._stepSize < 1. )
data._epsilon *= data._stepSize;
- // Put _LayerEdge's into a vector
+ // Put _LayerEdge's into the vector data._edges
if ( !sortEdges( data, edgesByGeom ))
return false;
}
case SMDS_TOP_VERTEX: {
TopoDS_Vertex V = TopoDS::Vertex( helper.GetSubShapeByNode( node, getMeshDS()));
- gp_Vec inFaceDir = getFaceDir( F, V, node, helper, normOK);
- double angle = inFaceDir.Angle( edge._normal ); // [0,PI]
+ gp_XYZ inFaceDir = getFaceDir( F, V, node, helper, normOK);
+ double angle = gp_Vec( inFaceDir).Angle( edge._normal ); // [0,PI]
edge._cosin = cos( angle );
//cout << "Cosin on VERTEX " << edge._cosin << " node " << node->GetID() << endl;
break;
int srcInd = f->GetNodeIndex( node );
const SMDS_MeshNode* nPrev = f->GetNode( SMESH_MesherHelper::WrapIndex( srcInd-1, nbNodes ));
const SMDS_MeshNode* nNext = f->GetNode( SMESH_MesherHelper::WrapIndex( srcInd+1, nbNodes ));
+ const SMDS_MeshNode* nOpp = f->GetNode( SMESH_MesherHelper::WrapIndex( srcInd+2, nbNodes ));
if ( dataToCheckOri && dataToCheckOri->_reversedFaceIds.count( shapeInd ))
std::swap( nPrev, nNext );
- simplices.push_back( _Simplex( nPrev, nNext ));
+ simplices.push_back( _Simplex( nPrev, nNext, nOpp ));
}
if ( toSort )
// Limit inflation step size by geometry size found by itersecting
// normals of _LayerEdge's with mesh faces
double geomSize = Precision::Infinite(), intersecDist;
- SMESH_MeshEditor editor( _mesh );
auto_ptr<SMESH_ElementSearcher> searcher
- ( editor.GetElementSearcher( data._proxyMesh->GetFaces( data._solid )) );
+ ( SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(),
+ data._proxyMesh->GetFaces( data._solid )) );
for ( unsigned i = 0; i < data._edges.size(); ++i )
{
if ( data._edges[i]->IsOnEdge() ) continue;
data._edges[i]->FindIntersection( *searcher, intersecDist, data._epsilon );
- if ( geomSize > intersecDist )
+ if ( geomSize > intersecDist && intersecDist > 0 )
geomSize = intersecDist;
}
if ( data._stepSize > 0.3 * geomSize )
// Check if the last segments of _LayerEdge intersects 2D elements;
// checked elements are either temporary faces or faces on surfaces w/o the layers
- SMESH_MeshEditor editor( _mesh );
auto_ptr<SMESH_ElementSearcher> searcher
- ( editor.GetElementSearcher( data._proxyMesh->GetFaces( data._solid )) );
+ ( SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(),
+ data._proxyMesh->GetFaces( data._solid )) );
distToIntersection = Precision::Infinite();
double dist;
if ( F.IsNull() ) // 3D
{
+ if ( data._edges[iFrom]->_2neibors->_nodes[0] ==
+ data._edges[iTo-1]->_2neibors->_nodes[1] )
+ return true; // closed EDGE - nothing to do
+
return false; // TODO ???
}
else // 2D
{
const gp_XY center( center3D.X(), center3D.Y() );
-
+
gp_XY uv0 = helper.GetNodeUV( F, data._edges[iFrom]->_2neibors->_nodes[0]);
gp_XY uvM = helper.GetNodeUV( F, data._edges[iFrom]->_nodes.back());
gp_XY uv1 = helper.GetNodeUV( F, data._edges[iTo-1]->_2neibors->_nodes[1]);
gp_Vec2d vec0( center, uv0 );
- gp_Vec2d vecM( center, uvM);
+ gp_Vec2d vecM( center, uvM );
gp_Vec2d vec1( center, uv1 );
double uLast = vec0.Angle( vec1 ); // -PI - +PI
double uMidl = vec0.Angle( vecM );
- if ( uLast < 0 ) uLast += 2.*M_PI; // 0.0 - 2*PI
- if ( uMidl < 0 ) uMidl += 2.*M_PI;
- const bool sense = ( uMidl < uLast );
+ if ( uLast * uMidl < 0. )
+ uLast += ( uMidl > 0 ? +2. : -2. ) * M_PI;
const double radius = 0.5 * ( vec0.Magnitude() + vec1.Magnitude() );
- gp_Ax2d axis( center, vec0 );
- gp_Circ2d circ ( axis, radius, sense );
+ gp_Ax2d axis( center, vec0 );
+ gp_Circ2d circ( axis, radius );
for ( int i = iFrom; i < iTo; ++i )
{
double newU = uLast * len[i-iFrom] / len.back();
// 1) to find and fix intersection
// 2) to check that no new intersection appears as result of 1)
- SMESH_MeshEditor editor( _mesh );
SMDS_ElemIteratorPtr fIt( new SMDS_ElementVectorIterator( tmpFaces.begin(),
tmpFaces.end()));
- auto_ptr<SMESH_ElementSearcher> searcher ( editor.GetElementSearcher( fIt ));
+ auto_ptr<SMESH_ElementSearcher> searcher
+ ( SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), fIt ));
// 1) Find intersections
double dist;
}
if ( intFound )
{
- if ( dist < segLen*(1.01))
+ if ( dist < segLen*(1.01) && dist > -(_len-segLen) )
segmentIntersected = true;
if ( distance > dist )
distance = dist, iFace = j;
double lenDelta = 0;
if ( _curvature )
{
- lenDelta = _curvature->lenDelta( _len );
+ //lenDelta = _curvature->lenDelta( _len );
+ lenDelta = _curvature->lenDeltaByDist( dist01 );
newPos.ChangeCoord() += _normal * lenDelta;
}
}
}
+ if ( !getMeshDS()->IsEmbeddedMode() )
+ // Log node movement
+ for ( unsigned i = 0; i < data._edges.size(); ++i )
+ {
+ _LayerEdge& edge = *data._edges[i];
+ SMESH_TNodeXYZ p ( edge._nodes.back() );
+ getMeshDS()->MoveNode( p._node, p.X(), p.Y(), p.Z() );
+ }
+
// TODO: make quadratic prisms and polyhedrons(?)
helper.SetElementsOnShape(true);
helper.ToFixNodeParameters( true );
// EDGE's to shrink
- map< int, _Shrinker1D > e2shrMap;
+ map< TGeomID, _Shrinker1D > e2shrMap;
// loop on FACES to srink mesh on
map< TGeomID, _SolidData* >::iterator f2sd = f2sdMap.begin();
sm->getDependsOnIterator(/*includeSelf=*/false, /*complexShapeFirst=*/false);
while ( subIt->more() )
{
- SMESH_subMesh* sub = subIt->next();
+ SMESH_subMesh* sub = subIt->next();
SMESHDS_SubMesh* subDS = sub->GetSubMeshDS();
if ( subDS->NbNodes() == 0 || !n2eMap.count( subDS->GetNodes()->next() ))
continue;
vector< _SmoothNode > nodesToSmooth( smoothNodes.size() );
{
dumpFunction(SMESH_Comment("beforeShrinkFace")<<f2sd->first); // debug
+ const bool sortSimplices = isConcaveFace;
for ( unsigned i = 0; i < smoothNodes.size(); ++i )
{
const SMDS_MeshNode* n = smoothNodes[i];
nodesToSmooth[ i ]._node = n;
// src nodes must be replaced by tgt nodes to have tgt nodes in _simplices
- getSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes, NULL, isConcaveFace );
+ getSimplices( n, nodesToSmooth[ i ]._simplices, ignoreShapes, NULL, sortSimplices );
// fix up incorrect uv of nodes on the FACE
helper.GetNodeUV( F, n, 0, &isOkUV);
dumpMove( n );
_Shrinker1D& srinker = e2shrMap[ edgeIndex ];
eShri1D.insert( & srinker );
srinker.AddEdge( edge, helper );
+ VISCOUS_3D::ToClearSubWithMain( _mesh->GetSubMesh( edge->_sWOL ), data._solid );
// restore params of nodes on EGDE if the EDGE has been already
// srinked while srinking another FACE
srinker.RestoreParams();
bool shrinked = true;
int badNb, shriStep=0, smooStep=0;
+ _SmoothNode::SmoothType smoothType
+ = isConcaveFace ? _SmoothNode::CENTROIDAL : _SmoothNode::LAPLACIAN;
while ( shrinked )
{
// Move boundary nodes (actually just set new UV)
dumpFunctionEnd();
// Move nodes on EDGE's
+ // (XYZ is set as soon as a needed length reached in SetNewLength2d())
set< _Shrinker1D* >::iterator shr = eShri1D.begin();
for ( ; shr != eShri1D.end(); ++shr )
(*shr)->Compute( /*set3D=*/false, helper );
for ( unsigned i = 0; i < nodesToSmooth.size(); ++i )
{
moved |= nodesToSmooth[i].Smooth( badNb,surface,helper,refSign,
- /*isCentroidal=*/isConcaveFace,/*set3D=*/false );
+ smoothType, /*set3D=*/isConcaveFace);
}
if ( badNb < oldBadNb )
nbNoImpSteps = 0;
if ( badNb > 0 )
return error(SMESH_Comment("Can't shrink 2D mesh on face ") << f2sd->first );
}
+
// No wrongly shaped faces remain; final smooth. Set node XYZ.
- // First, find out a needed quality of smoothing (high for quadrangles only)
- bool highQuality;
+ bool isStructuredFixed = false;
+ if ( SMESH_2D_Algo* algo = dynamic_cast<SMESH_2D_Algo*>( sm->GetAlgo() ))
+ isStructuredFixed = algo->FixInternalNodes( *data._proxyMesh, F );
+ if ( !isStructuredFixed )
{
- const bool hasTria = _mesh->NbTriangles(), hasQuad = _mesh->NbQuadrangles();
- if ( hasTria != hasQuad )
+ if ( isConcaveFace )
+ fixBadFaces( F, helper ); // fix narrow faces by swapping diagonals
+ for ( int st = /*highQuality ? 10 :*/ 3; st; --st )
{
- highQuality = hasQuad;
- }
- else
- {
- set<int> nbNodesSet;
- SMDS_ElemIteratorPtr fIt = smDS->GetElements();
- while ( fIt->more() && nbNodesSet.size() < 2 )
- nbNodesSet.insert( fIt->next()->NbCornerNodes() );
- highQuality = ( *nbNodesSet.begin() == 4 );
+ dumpFunction(SMESH_Comment("shrinkFace")<<f2sd->first<<"_st"<<++smooStep); // debug
+ for ( unsigned i = 0; i < nodesToSmooth.size(); ++i )
+ {
+ nodesToSmooth[i].Smooth( badNb,surface,helper,refSign,
+ smoothType,/*set3D=*/st==1 );
+ }
+ dumpFunctionEnd();
}
}
- if ( !highQuality && isConcaveFace )
- fixBadFaces( F, helper ); // fix narrow faces by swaping diagonals
- for ( int st = highQuality ? 10 : 3; st; --st )
- {
- dumpFunction(SMESH_Comment("shrinkFace")<<f2sd->first<<"_st"<<++smooStep); // debug
- for ( unsigned i = 0; i < nodesToSmooth.size(); ++i )
- nodesToSmooth[i].Smooth( badNb,surface,helper,refSign,
- /*isCentroidal=*/isConcaveFace,/*set3D=*/st==1 );
- dumpFunctionEnd();
- }
// Set an event listener to clear FACE sub-mesh together with SOLID sub-mesh
- _SrinkShapeListener::ToClearSubMeshWithSolid( sm, data._solid );
+ VISCOUS_3D::ToClearSubWithMain( sm, data._solid );
+
+ if ( !getMeshDS()->IsEmbeddedMode() )
+ // Log node movement
+ for ( unsigned i = 0; i < nodesToSmooth.size(); ++i )
+ {
+ SMESH_TNodeXYZ p ( nodesToSmooth[i]._node );
+ getMeshDS()->MoveNode( nodesToSmooth[i]._node, p.X(), p.Y(), p.Z() );
+ }
} // loop on FACES to srink mesh on
double uvLen = uvDir.Magnitude();
uvDir /= uvLen;
edge._normal.SetCoord( uvDir.X(),uvDir.Y(), 0);
+ edge._len = uvLen;
// IMPORTANT to have src nodes NOT yet REPLACED by tgt nodes in shrinked faces
vector<const SMDS_MeshElement*> faces;
}
multimap< double, const SMDS_MeshNode* >::iterator p2n = proj2node.begin(), p2nEnd;
- const double minProj = p2n->first;
+ const double minProj = p2n->first;
const double projThreshold = 1.1 * uvLen;
if ( minProj > projThreshold )
{
const SMDS_MeshNode* n1 = badTrias[iTia]->GetNode( iSide );
const SMDS_MeshNode* n2 = badTrias[iTia]->GetNode(( iSide+1 ) % 3 );
trias [iSide].first = badTrias[iTia];
- trias [iSide].second = SMESH_MeshEditor::FindFaceInSet( n1, n2, emptySet, involvedFaces,
- & i1, & i2 );
+ trias [iSide].second = SMESH_MeshAlgos::FindFaceInSet( n1, n2, emptySet, involvedFaces,
+ & i1, & i2 );
if ( ! trias[iSide].second || trias[iSide].second->NbCornerNodes() != 3 )
continue;
double proj = uvDirN * uvDir * kSafe;
if ( proj < stepSize && proj > minStepSize )
stepSize = proj;
+ else if ( proj < minStepSize )
+ stepSize = minStepSize;
}
}
gp_Pnt2d newUV;
- if ( stepSize == uvLen )
+ if ( uvLen - stepSize < _len / 20. )
{
newUV = tgtUV;
_pos.clear();
{
TopoDS_Edge E = TopoDS::Edge( _sWOL );
const SMDS_MeshNode* n2 = _simplices[0]._nPrev;
+ SMDS_EdgePosition* tgtPos = static_cast<SMDS_EdgePosition*>( tgtNode->GetPosition() );
const double u2 = helper.GetNodeU( E, n2, tgtNode );
const double uSrc = _pos[0].Coord( U_SRC );
const double lenTgt = _pos[0].Coord( LEN_TGT );
double newU = _pos[0].Coord( U_TGT );
- if ( lenTgt < 0.99 * fabs( uSrc-u2 ))
+ if ( lenTgt < 0.99 * fabs( uSrc-u2 )) // n2 got out of src-tgt range
{
_pos.clear();
}
else
{
- newU = 0.1 * uSrc + 0.9 * u2;
+ newU = 0.1 * tgtPos->GetUParameter() + 0.9 * u2;
}
- SMDS_EdgePosition* pos = static_cast<SMDS_EdgePosition*>( tgtNode->GetPosition() );
- pos->SetUParameter( newU );
+ tgtPos->SetUParameter( newU );
#ifdef __myDEBUG
gp_XY newUV = helper.GetNodeUV( F, tgtNode, _nodes[0]);
gp_Pnt p = surface->Value( newUV.X(), newUV.Y() );
Handle(Geom_Surface)& surface,
SMESH_MesherHelper& helper,
const double refSign,
- bool isCentroidal,
+ SmoothType how,
bool set3D)
{
const TopoDS_Face& face = TopoDS::Face( helper.GetSubShape() );
// compute new UV for the node
gp_XY newPos (0,0);
- if ( isCentroidal && _simplices.size() > 3 )
+/* if ( how == ANGULAR && _simplices.size() == 4 )
+ {
+ vector<gp_XY> corners; corners.reserve(4);
+ for ( size_t i = 0; i < _simplices.size(); ++i )
+ if ( _simplices[i]._nOpp )
+ corners.push_back( helper.GetNodeUV( face, _simplices[i]._nOpp, _node ));
+ if ( corners.size() == 4 )
+ {
+ newPos = helper.calcTFI
+ ( 0.5, 0.5,
+ corners[0], corners[1], corners[2], corners[3],
+ uv[1], uv[2], uv[3], uv[0] );
+ }
+ // vector<gp_XY> p( _simplices.size() * 2 + 1 );
+ // p.clear();
+ // for ( size_t i = 0; i < _simplices.size(); ++i )
+ // {
+ // p.push_back( uv[i] );
+ // if ( _simplices[i]._nOpp )
+ // p.push_back( helper.GetNodeUV( face, _simplices[i]._nOpp, _node ));
+ // }
+ // newPos = computeAngularPos( p, helper.GetNodeUV( face, _node ), refSign );
+ }
+ else*/ if ( how == CENTROIDAL && _simplices.size() > 3 )
{
// average centers of diagonals wieghted with their reciprocal lengths
if ( _simplices.size() == 4 )
newPos += w * ( uv[i]+uv[i2] );
}
}
- newPos /= 2 * sumWeight;
+ newPos /= 2 * sumWeight; // 2 is to get a middle between uv's
}
}
else
{
// Laplacian smooth
- isCentroidal = false;
+ //isCentroidal = false;
for ( size_t i = 0; i < _simplices.size(); ++i )
newPos += uv[i];
newPos /= _simplices.size();
return ( (tgtUV-newPos).SquareModulus() > 1e-10 );
}
+//================================================================================
+/*!
+ * \brief Computes new UV using angle based smoothing technic
+ */
+//================================================================================
+
+gp_XY _SmoothNode::computeAngularPos(vector<gp_XY>& uv,
+ const gp_XY& uvToFix,
+ const double refSign)
+{
+ uv.push_back( uv.front() );
+
+ vector< gp_XY > edgeDir( uv.size() );
+ vector< double > edgeSize( uv.size() );
+ for ( size_t i = 1; i < edgeDir.size(); ++i )
+ {
+ edgeDir[i-1] = uv[i] - uv[i-1];
+ edgeSize[i-1] = edgeDir[i-1].Modulus();
+ if ( edgeSize[i-1] < numeric_limits<double>::min() )
+ edgeDir[i-1].SetX( 100 );
+ else
+ edgeDir[i-1] /= edgeSize[i-1] * refSign;
+ }
+ edgeDir.back() = edgeDir.front();
+ edgeSize.back() = edgeSize.front();
+
+ gp_XY newPos(0,0);
+ int nbEdges = 0;
+ double sumSize = 0;
+ for ( size_t i = 1; i < edgeDir.size(); ++i )
+ {
+ if ( edgeDir[i-1].X() > 1. ) continue;
+ int i1 = i-1;
+ 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 bisec = norm1 + norm2;
+ double bisecSize = bisec.Modulus();
+ if ( bisecSize < numeric_limits<double>::min() )
+ {
+ bisec = -edgeDir[i1] + edgeDir[i];
+ bisecSize = bisec.Modulus();
+ }
+ bisec /= bisecSize;
+
+ gp_XY dirToN = uvToFix - p;
+ double distToN = dirToN.Modulus();
+ if ( bisec * dirToN < 0 )
+ distToN = -distToN;
+
+ newPos += ( p + bisec * distToN ) * ( edgeSize[i1] + edgeSize[i] );
+ ++nbEdges;
+ sumSize += edgeSize[i1] + edgeSize[i];
+ }
+ newPos /= /*nbEdges * */sumSize;
+ return newPos;
+}
+
//================================================================================
/*!
* \brief Delete _SolidData
GeomAdaptor_Curve aCurve(C, f,l);
const double totLen = GCPnts_AbscissaPoint::Length(aCurve, f, l);
- int nbExpectNodes = eSubMesh->NbNodes() - e->_nodes.size();
+ int nbExpectNodes = eSubMesh->NbNodes();
_initU .reserve( nbExpectNodes );
_normPar.reserve( nbExpectNodes );
_nodes .reserve( nbExpectNodes );
F = e2f->second.Oriented( TopAbs_FORWARD );
reverse = ( helper.GetSubShapeOri( F, E ) == TopAbs_REVERSED );
if ( helper.GetSubShapeOri( data._solid, F ) == TopAbs_REVERSED )
+ reverse = !reverse, F.Reverse();
+ if ( helper.IsReversedSubMesh( TopoDS::Face(F) ))
reverse = !reverse;
}
else
vector< const SMDS_MeshNode*>& nn1 = ledges[j-dj1]->_nodes;
vector< const SMDS_MeshNode*>& nn2 = ledges[j-dj2]->_nodes;
if ( isOnFace )
- for ( unsigned z = 1; z < nn1.size(); ++z )
+ for ( size_t z = 1; z < nn1.size(); ++z )
sm->AddElement( getMeshDS()->AddFace( nn1[z-1], nn2[z-1], nn2[z], nn1[z] ));
else
- for ( unsigned z = 1; z < nn1.size(); ++z )
+ for ( size_t z = 1; z < nn1.size(); ++z )
sm->AddElement( new SMDS_FaceOfNodes( nn1[z-1], nn2[z-1], nn2[z], nn1[z]));
}
+
+ // Make edges
+ for ( int isFirst = 0; isFirst < 2; ++isFirst )
+ {
+ _LayerEdge* edge = isFirst ? ledges.front() : ledges.back();
+ if ( !edge->_sWOL.IsNull() && edge->_sWOL.ShapeType() == TopAbs_EDGE )
+ {
+ vector< const SMDS_MeshNode*>& nn = edge->_nodes;
+ if ( nn[1]->GetInverseElementIterator( SMDSAbs_Edge )->more() )
+ continue;
+ helper.SetSubShape( edge->_sWOL );
+ helper.SetElementsOnShape( true );
+ for ( size_t z = 1; z < nn.size(); ++z )
+ helper.AddEdge( nn[z-1], nn[z] );
+ }
+ }
}
}