//=======================================================================
//function : IsQuadraticSubMesh
-//purpose : Check submesh for given shape: if all elements on this shape
+//purpose : Check sub-meshes of a given shape: if all elements on sub-shapes
// are quadratic, quadratic elements will be created.
-// Also fill myTLinkNodeMap
+// Fill myTLinkNodeMap
//=======================================================================
bool SMESH_MesherHelper::IsQuadraticSubMesh(const TopoDS_Shape& aSh)
SMESHDS_Mesh* meshDS = GetMeshDS();
// we can create quadratic elements only if all elements
// created on sub-shapes of given shape are quadratic
- // also we have to fill myTLinkNodeMap
myCreateQuadratic = true;
mySeamShapeIds.clear();
myDegenShapeIds.clear();
}
SMDSAbs_ElementType elemType( subType==TopAbs_FACE ? SMDSAbs_Face : SMDSAbs_Edge );
-
- //int nbOldLinks = myTLinkNodeMap.size();
-
if ( !myMesh->HasShapeToMesh() )
{
if (( myCreateQuadratic = myMesh->NbFaces( ORDER_QUADRATIC )))
}
}
+//=======================================================================
+/*!
+ * \brief Copy shape information from another helper. Used to improve performance
+ * since SetSubShape() can be time consuming if there are many edges
+ */
+//=======================================================================
+
+void SMESH_MesherHelper::CopySubShapeInfo(const SMESH_MesherHelper& other)
+{
+ this->myShape = other.myShape;
+ this->myShapeID = other.myShapeID;
+ this->myDegenShapeIds = other.myDegenShapeIds;
+ this->mySeamShapeIds = other.mySeamShapeIds;
+ this->myPar1[0] = other.myPar1[0];
+ this->myPar1[1] = other.myPar1[1];
+ this->myPar2[0] = other.myPar2[0];
+ this->myPar2[1] = other.myPar2[1];
+ this->myParIndex = other.myParIndex;
+ this->myFace2Surface = other.myFace2Surface;
+}
+
//=======================================================================
//function : ShapeToIndex
//purpose : Convert a shape to its index in the SMESHDS_Mesh
if ( !bestEdge.IsNull() )
{
- // move n12 to position of a successfull projection
+ // move n12 to position of a successful projection
//double tol = BRep_Tool::Tolerance(edges[ iOkEdge ]);
if ( !force3d /*&& distMiddleProj > 2*tol*/ )
{
}
// nb rows of nodes
- size_t prevNbRows = theParam2ColumnMap.begin()->second.size(); // current, at least 1 here
+ size_t prevNbRows = theParam2ColumnMap.begin()->second.size(); // current, at least 1 here
size_t expectNbRows = faceSubMesh->NbElements() / ( theParam2ColumnMap.size()-1 ); // to be added
// fill theParam2ColumnMap column by column by passing from nodes on
//purpose : Return true if 2D mesh on FACE is ditorted
//=======================================================================
-bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM,
- bool checkUV)
+bool SMESH_MesherHelper::IsDistorted2D( SMESH_subMesh* faceSM,
+ bool checkUV,
+ SMESH_MesherHelper* faceHelper)
{
if ( !faceSM || faceSM->GetSubShape().ShapeType() != TopAbs_FACE )
return false;
bool haveBadFaces = false;
SMESH_MesherHelper helper( *faceSM->GetFather() );
+ if ( faceHelper )
+ helper.CopySubShapeInfo( *faceHelper );
helper.SetSubShape( faceSM->GetSubShape() );
const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() );
SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F );
if ( !smDS || smDS->NbElements() == 0 ) return false;
+ bool subIdsValid = true; // shape ID of nodes is OK
+ if ( helper.HasSeam() )
+ {
+ // check if nodes are bound to seam edges
+ SMESH_subMeshIteratorPtr smIt = faceSM->getDependsOnIterator(/*includeSelf=*/false);
+ while ( smIt->more() && subIdsValid )
+ {
+ SMESH_subMesh* sm = smIt->next();
+ if ( helper.IsSeamShape( sm->GetId() ) && sm->IsEmpty() )
+ subIdsValid = false;
+ }
+ }
SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
double prevArea = 0;
vector< const SMDS_MeshNode* > nodes;
if ( isOnDegen )
continue;
}
- // prepare to getting UVs
+ // prepare for getting UVs
const SMDS_MeshNode* inFaceNode = 0;
if ( helper.HasSeam() ) {
for ( size_t i = 0; ( i < nodes.size() && !inFaceNode ); ++i )
if ( !helper.IsSeamShape( nodes[ i ]->getshapeId() ))
+ {
inFaceNode = nodes[ i ];
+ if ( !subIdsValid )
+ {
+ gp_XY uv = helper.GetNodeUV( F, inFaceNode );
+ if ( helper.IsOnSeam( uv ))
+ inFaceNode = NULL;
+ }
+ }
if ( !inFaceNode )
continue;
}
for ( size_t i = 0; i < nodes.size(); ++i )
uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode, toCheckUV );
+ if ( !subIdsValid ) // fix uv on seam
+ {
+ gp_XY uvInFace = helper.GetNodeUV( F, inFaceNode );
+ for ( size_t i = 0; i < uv.size(); ++i )
+ if ( helper.IsOnSeam( uv[i] ))
+ uv[i] = helper.getUVOnSeam( uv[i], uvInFace ).XY();
+ }
+
// compare orientation of triangles
double faceArea = 0;
for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT )
//=======================================================================
//function : IsSubShape
-//purpose :
+//purpose :
//=======================================================================
bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape,
* of the FACE normal
* \return double - the angle (between -Pi and Pi), negative if the angle is concave,
* 1e100 in case of failure
- * \waring Care about order of the EDGEs and their orientation to be as they are
+ * \warning Care about order of the EDGEs and their orientation to be as they are
* within the FACE! Don't pass degenerated EDGEs neither!
*/
//================================================================================
return fabs(param-myPar1[i]) < fabs(param-myPar2[i]) ? myPar2[i] : myPar1[i];
}
+//=======================================================================
+//function : IsOnSeam
+//purpose : Check if UV is on seam. Return 0 if not, 1 for U seam, 2 for V seam
+//=======================================================================
+
+int SMESH_MesherHelper::IsOnSeam(const gp_XY& uv) const
+{
+ for ( int i = U_periodic; i <= V_periodic ; ++i )
+ if ( myParIndex & i )
+ {
+ double p = uv.Coord( i );
+ double tol = ( myPar2[i-1] - myPar1[i-1] ) / 100.;
+ if ( Abs( p - myPar1[i-1] ) < tol ||
+ Abs( p - myPar2[i-1] ) < tol )
+ return i;
+ }
+ return 0;
+}
+
namespace {
//=======================================================================
* \brief Make up a chain of links
* \param iSide - link to add first
* \param chain - chain to fill in
- * \param pos - postion of medium nodes the links should have
+ * \param pos - position of medium nodes the links should have
* \param error - out, specifies what is wrong
* \retval bool - false if valid chain can't be built; "valid" means that links
* of the chain belongs to rectangles bounding hexahedrons
if ( _sideIsAdded[ iSide ]) // already in chain
return true;
- if ( _sides.size() != 4 ) { // triangle - visit all my continous faces
+ if ( _sides.size() != 4 ) { // triangle - visit all my continuous faces
MSGBEG( *this );
TLinkSet links;
list< const QFace* > faces( 1, this );
if ( link->MediumPos() >= pos ) {
int nbLinkFaces = link->_faces.size();
if ( nbLinkFaces == 4 || (/*nbLinkFaces < 4 && */link->OnBoundary())) {
- // hexahedral mesh or boundary quadrangles - goto a continous face
+ // hexahedral mesh or boundary quadrangles - goto a continuous face
if ( const QFace* f = link->GetContinuesFace( this ))
if ( f->_sides.size() == 4 )
return f->GetLinkChain( *chLink, chain, pos, error );
* \brief Move medium node of theLink according to its distance from boundary
* \param theLink - link to fix
* \param theRefVec - movement of boundary
- * \param theLinks - all adjacent links of continous triangles
+ * \param theLinks - all adjacent links of continuous triangles
* \param theFaceHelper - helper is not used so far
* \param thePrevLen - distance from the boundary
* \param theStep - number of steps till movement propagation limit
< const SMDS_MeshElement*, vector< SMDS_ElemIteratorPtr > > TIterOnIter;
SMDS_ElemIteratorPtr faceIter( new TIterOnIter( faceIterVec ));
- // a seacher to check if a volume is close to a concave face
+ // search to check if a volume is close to a concave face
SMESHUtils::Deleter< SMESH_ElementSearcher > faceSearcher
( SMESH_MeshAlgos::GetElementSearcher( *theHelper.GetMeshDS(), faceIter ));