-// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
//
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
#include <TopExp_Explorer.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
#include <TopoDS.hxx>
#include <gp_Ax2.hxx>
#include <gp_Ax3.hxx>
// get ordered src EDGEs
TError err;
srcWires = StdMeshers_FaceSide::GetFaceWires( srcFace, *srcMesh,/*skipMediumNodes=*/0, err);
- if ( err && !err->IsOK() )
+ if ( err && !err->IsOK() || srcWires.empty() )
return err;
+ SMESH_MesherHelper srcHelper( *srcMesh );
+ srcHelper.SetSubShape( srcFace );
+
// make corresponding sequence of tgt EDGEs
tgtWires.resize( srcWires.size() );
for ( size_t iW = 0; iW < srcWires.size(); ++iW )
{
- list< TopoDS_Edge > tgtEdges;
+ // check ori
+ bool reverse = false;
StdMeshers_FaceSidePtr srcWire = srcWires[iW];
+ // for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
+ // {
+ // if ( srcHelper.IsRealSeam( srcWire->EdgeID( iE )))
+ // continue;
+ // TopoDS_Shape srcE = srcWire->Edge( iE );
+ // TopoDS_Shape tgtE = shape2ShapeMap( srcE, /*isSrc=*/true);
+ // if ( shape2ShapeMap._assocType == TShapeShapeMap::PROPAGATION ||
+ // shape2ShapeMap._assocType == TShapeShapeMap::PROPAGATION)
+ // {
+ // reverse = false;
+ // }
+ // else if ( tgtMesh == srcMesh )
+ // {
+ // reverse = (( srcE.Orientation() == srcHelper.GetSubShapeOri( srcFace, srcE )) !=
+ // ( tgtE.Orientation() == srcHelper.GetSubShapeOri( tgtFace, tgtE )));
+ // }
+ // else
+ // {
+ // TopoDS_Shape srcEbis = shape2ShapeMap( tgtE, /*isSrc=*/false );
+ // reverse = ( srcE.Orientation() != srcEbis.Orientation() );
+ // }
+ // break;
+ // }
+
+ list< TopoDS_Edge > tgtEdges;
TopTools_IndexedMapOfShape edgeMap; // to detect seam edges
for ( int iE = 0; iE < srcWire->NbEdges(); ++iE )
{
TopoDS_Edge tgtE = TopoDS::Edge( shape2ShapeMap( srcE, /*isSrc=*/true));
TopoDS_Shape srcEbis = shape2ShapeMap( tgtE, /*isSrc=*/false );
if ( srcE.Orientation() != srcEbis.Orientation() )
+ //if ( reverse )
tgtE.Reverse();
// reverse a seam edge encountered for the second time
const int index = edgeMap.Add( tgtE );
vector< gp_XYZ > srcPnts, tgtPnts;
srcPnts.reserve( totNbSeg );
tgtPnts.reserve( totNbSeg );
+ gp_XYZ srcBC( 0,0,0 ), tgtBC( 0,0,0 );
for ( size_t iW = 0; iW < srcWires.size(); ++iW )
{
const double minSegLen = srcWires[iW]->Length() / totNbSeg;
tgtPnts.push_back( tgtWires[iW]->Value3d( tgtU ).XYZ() );
srcU += srcDu;
tgtU += tgtDu;
+ srcBC += srcPnts.back();
+ tgtBC += tgtPnts.back();
}
}
}
const int nbTestPnt = 20;
const size_t iStep = Max( 1, int( srcPnts.size() / nbTestPnt ));
// check boundary
+ gp_Pnt trsfTgt = trsf.Transform( srcBC / srcPnts.size() );
+ trsfIsOK = ( trsfTgt.SquareDistance( tgtBC / tgtPnts.size() ) < tol*tol );
for ( size_t i = 0; ( i < srcPnts.size() && trsfIsOK ); i += iStep )
{
gp_Pnt trsfTgt = trsf.Transform( srcPnts[i] );
{
BRepAdaptor_Surface srcSurf( srcFace );
gp_Pnt srcP =
- srcSurf.Value( 0.5 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ),
- 0.5 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() ));
+ srcSurf.Value( 0.321 * ( srcSurf.FirstUParameter() + srcSurf.LastUParameter() ),
+ 0.123 * ( srcSurf.FirstVParameter() + srcSurf.LastVParameter() ));
gp_Pnt tgtTrsfP = trsf.Transform( srcP );
TopLoc_Location loc;
GeomAPI_ProjectPointOnSurf& proj = helper.GetProjector( tgtFace, loc, 0.1*tol );
if ( !tgtFace.IsPartner( srcFace ) )
{
+ SMESH_MesherHelper edgeHelper( *tgtMesh );
+ edgeHelper.ToFixNodeParameters( true );
+ helper.ToFixNodeParameters( true );
+
int nbOkPos = 0;
+ bool toCheck = true;
const double tol2d = 1e-12;
srcN_tgtN = src2tgtNodes.begin();
for ( ; srcN_tgtN != src2tgtNodes.end(); ++srcN_tgtN )
{
case SMDS_TOP_FACE:
{
+ if ( nbOkPos > 10 ) break;
gp_XY uv = helper.GetNodeUV( tgtFace, n ), uvBis = uv;
if (( helper.CheckNodeUV( tgtFace, n, uv, tol )) &&
- (( uv - uvBis ).SquareModulus() < tol2d ) &&
- ( ++nbOkPos > 10 ))
- return true;
+ (( uv - uvBis ).SquareModulus() < tol2d ))
+ ++nbOkPos;
else
- nbOkPos = 0;
+ nbOkPos = -((int) src2tgtNodes.size() );
break;
}
case SMDS_TOP_EDGE:
{
const TopoDS_Edge & tgtE = TopoDS::Edge( tgtMeshDS->IndexToShape( n->getshapeId() ));
- double u = helper.GetNodeU( tgtE, n ), uBis = u;
- if (( !helper.CheckNodeU( tgtE, n, u, tol )) ||
- (( u - uBis ) < tol2d ))
- nbOkPos = 0;
+ edgeHelper.SetSubShape( tgtE );
+ edgeHelper.GetNodeU( tgtE, n, 0, &toCheck );
break;
}
default:;
case SMDS_TOP_EDGE: {
TopoDS_Shape srcEdge = srcHelper.GetSubShapeByNode( srcNode, srcHelper.GetMeshDS() );
TopoDS_Edge tgtEdge = TopoDS::Edge( shape2ShapeMap( srcEdge, /*isSrc=*/true ));
- tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ));
- double U = srcHelper.GetNodeU( TopoDS::Edge( srcEdge ), srcNode );
+ double U = Precision::Infinite();
helper.CheckNodeU( tgtEdge, n, U, Precision::PConfusion());
- n->SetPosition(SMDS_PositionPtr(new SMDS_EdgePosition( U )));
+ tgtMeshDS->SetNodeOnEdge( n, TopoDS::Edge( tgtEdge ), U );
break;
}
case SMDS_TOP_VERTEX: {
*/
//================================================================================
- void fixDistortedFaces( SMESH_MesherHelper& helper,
- TSideVector& )
+ bool fixDistortedFaces( SMESH_MesherHelper& helper,
+ TSideVector& tgtWires )
{
- // Detect bad faces
-
- bool haveBadFaces = false;
-
- const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
- SMESHDS_SubMesh* smDS = helper.GetMeshDS()->MeshElements( F );
- if ( !smDS || smDS->NbElements() == 0 ) return;
-
- SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
- double prevArea2D = 0;
- vector< const SMDS_MeshNode* > nodes;
- vector< gp_XY > uv;
- while ( faceIt->more() && !haveBadFaces )
- {
- const SMDS_MeshElement* face = faceIt->next();
-
- // get nodes
- nodes.resize( face->NbCornerNodes() );
- SMDS_MeshElement::iterator n = face->begin_nodes();
- for ( size_t i = 0; i < nodes.size(); ++n, ++i )
- nodes[ i ] = *n;
-
- // avoid elems on degenarate shapes as UV on them can be wrong
- if ( helper.HasDegeneratedEdges() )
- {
- bool isOnDegen = false;
- for ( size_t i = 0; ( i < nodes.size() && !isOnDegen ); ++i )
- isOnDegen = helper.IsDegenShape( nodes[ i ]->getshapeId() );
- if ( isOnDegen )
- continue;
- }
- // prepare to 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 ];
-
- // get UVs
- uv.resize( nodes.size() );
- for ( size_t i = 0; i < nodes.size(); ++i )
- uv[ i ] = helper.GetNodeUV( F, nodes[ i ], inFaceNode );
-
- // compare orientation of triangles
- for ( int iT = 0, nbT = nodes.size()-2; iT < nbT; ++iT )
- {
- gp_XY v1 = uv[ iT+1 ] - uv[ 0 ];
- gp_XY v2 = uv[ iT+2 ] - uv[ 0 ];
- double area2D = v2 ^ v1;
- if (( haveBadFaces = ( area2D * prevArea2D < 0 )))
- break;
- prevArea2D = area2D;
- }
- }
-
- // Fix faces
+ SMESH_subMesh* faceSM = helper.GetMesh()->GetSubMesh( helper.GetSubShape() );
- if ( haveBadFaces )
+ if ( helper.IsDistorted2D( faceSM, /*checkUV=*/false ))
{
SMESH_MeshEditor editor( helper.GetMesh() );
+ SMESHDS_SubMesh* smDS = faceSM->GetSubMeshDS();
+ const TopoDS_Face& F = TopoDS::Face( faceSM->GetSubShape() );
TIDSortedElemSet faces;
+ SMDS_ElemIteratorPtr faceIt = smDS->GetElements();
for ( faceIt = smDS->GetElements(); faceIt->more(); )
faces.insert( faces.end(), faceIt->next() );
// choose smoothing algo
//SMESH_MeshEditor:: SmoothMethod algo = SMESH_MeshEditor::CENTROIDAL;
bool isConcaveBoundary = false;
- TError err;
- TSideVector tgtWires =
- StdMeshers_FaceSide::GetFaceWires( F, *helper.GetMesh(),/*skipMediumNodes=*/0, err);
for ( size_t iW = 0; iW < tgtWires.size() && !isConcaveBoundary; ++iW )
{
TopoDS_Edge prevEdge = tgtWires[iW]->Edge( tgtWires[iW]->NbEdges() - 1 );
set<const SMDS_MeshNode*> fixedNodes;
editor.Smooth( faces, fixedNodes, algo, /*nbIterations=*/ 10,
/*theTgtAspectRatio=*/1.0, /*the2D=*/!isPlanar);
+
+ helper.ToFixNodeParameters( true );
+
+ return !helper.IsDistorted2D( faceSM, /*checkUV=*/true );
}
+ return true;
}
} // namespace
srcMesh = tgtMesh;
SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
+ SMESH_MesherHelper helper( theMesh );
// ---------------------------
// Make sub-shapes association
{
if ( srcShape.ShapeType() == TopAbs_FACE )
{
- int nbE1 = SMESH_MesherHelper::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true );
- int nbE2 = SMESH_MesherHelper::Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true );
+ int nbE1 = helper.Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true );
+ int nbE2 = helper.Count( srcShape, TopAbs_EDGE, /*ignoreSame=*/true );
if ( nbE1 != nbE2 )
return error(COMPERR_BAD_SHAPE,
SMESH_Comment("Different number of edges in source and target faces: ")
}
TopoDS_Face srcFace = TopoDS::Face( shape2ShapeMap( tgtFace ).Oriented(TopAbs_FORWARD));
+ // orient faces
+ // if ( srcMesh == tgtMesh )
+ // {
+ // TopoDS_Shape solid =
+ // helper.GetCommonAncestor( srcFace, tgtFace, *tgtMesh, TopAbs_SOLID );
+ // if ( !solid.IsNull() )
+ // {
+ // srcFace.Orientation( helper.GetSubShapeOri( solid, srcFace ));
+ // tgtFace.Orientation( helper.GetSubShapeOri( solid, tgtFace ));
+ // }
+ // else if ( helper.NbAncestors( srcFace, *tgtMesh, TopAbs_SOLID ) == 1 &&
+ // helper.NbAncestors( tgtFace, *tgtMesh, TopAbs_SOLID ) == 1 )
+ // {
+ // srcFace.Orientation( helper.GetSubShapeOri( tgtMesh->GetShapeToMesh(), srcFace ));
+ // tgtFace.Orientation( helper.GetSubShapeOri( tgtMesh->GetShapeToMesh(), tgtFace ));
+ // }
+ // }
// ----------------------------------------------
// Assure that mesh on a source Face is computed
// ----------------------------------------------
if ( err && !err->IsOK() )
return error( err );
- bool done = false;
+ bool projDone = false;
- if ( !done )
+ if ( !projDone )
{
// try to project from the same face with different location
- done = projectPartner( tgtFace, srcFace, tgtWires, srcWires,
- shape2ShapeMap, _src2tgtNodes, is1DComputed );
+ projDone = projectPartner( tgtFace, srcFace, tgtWires, srcWires,
+ shape2ShapeMap, _src2tgtNodes, is1DComputed );
}
- if ( !done )
+ if ( !projDone )
{
// projection in case if the faces are similar in 2D space
- done = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires,
- shape2ShapeMap, _src2tgtNodes, is1DComputed);
+ projDone = projectBy2DSimilarity( tgtFace, srcFace, tgtWires, srcWires,
+ shape2ShapeMap, _src2tgtNodes, is1DComputed);
}
- SMESH_MesherHelper helper( theMesh );
helper.SetSubShape( tgtFace );
- if ( !done )
+ // it will remove mesh built on edges and vertices in failure case
+ MeshCleaner cleaner( tgtSubMesh );
+
+ if ( !projDone )
{
_src2tgtNodes.clear();
// --------------------
// Check if node projection to a face is needed
Bnd_B2d uvBox;
SMDS_ElemIteratorPtr faceIt = srcSubMesh->GetSubMeshDS()->GetElements();
- int nbFaceNodes = 0;
- for ( ; nbFaceNodes < 3 && faceIt->more(); ) {
+ set< const SMDS_MeshNode* > faceNodes;
+ for ( ; faceNodes.size() < 3 && faceIt->more(); ) {
const SMDS_MeshElement* face = faceIt->next();
SMDS_ElemIteratorPtr nodeIt = face->nodesIterator();
while ( nodeIt->more() ) {
const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) {
- nbFaceNodes++;
+ if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&
+ faceNodes.insert( node ).second )
uvBox.Add( helper.GetNodeUV( srcFace, node ));
- }
}
}
- const bool toProjectNodes =
- ( nbFaceNodes > 0 && ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN ));
+ bool toProjectNodes = false;
+ if ( faceNodes.size() == 1 )
+ toProjectNodes = ( uvBox.IsVoid() || uvBox.CornerMin().IsEqual( gp_XY(0,0), 1e-12 ));
+ else if ( faceNodes.size() > 1 )
+ toProjectNodes = ( uvBox.IsVoid() || uvBox.SquareExtent() < DBL_MIN );
// Find the corresponding source and target vertex
// and <theReverse> flag needed to call mapper.Apply()
TopoDS_Vertex srcV1, tgtV1;
bool reverse = false;
- if ( _sourceHypo->HasVertexAssociation() ) {
- srcV1 = _sourceHypo->GetSourceVertex(1);
- tgtV1 = _sourceHypo->GetTargetVertex(1);
- } else {
- srcV1 = TopoDS::Vertex( TopExp_Explorer( srcFace, TopAbs_VERTEX ).Current() );
- tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true ));
- }
+ TopExp_Explorer vSrcExp( srcFace, TopAbs_VERTEX );
+ srcV1 = TopoDS::Vertex( vSrcExp.Current() );
+ tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true ));
+
list< TopoDS_Edge > tgtEdges, srcEdges;
list< int > nbEdgesInWires;
SMESH_Block::GetOrderedEdges( tgtFace, tgtEdges, nbEdgesInWires, tgtV1 );
TopoDS_Shape srcE1bis = shape2ShapeMap( tgtE1 );
reverse = ( ! srcE1.IsSame( srcE1bis ));
if ( reverse &&
- _sourceHypo->HasVertexAssociation() &&
+ //_sourceHypo->HasVertexAssociation() &&
nbEdgesInWires.front() > 2 &&
helper.IsRealSeam( tgtEdges.front() ))
{
// we can't use only theReverse flag to correctly associate source
// and target faces in the mapper. Thus we select srcV1 so that
// GetOrderedEdges() to return EDGEs in a needed order
- list< TopoDS_Edge >::iterator edge = srcEdges.begin();
- for ( ; edge != srcEdges.end(); ++edge ) {
- if ( srcE1bis.IsSame( *edge )) {
- srcV1 = helper.IthVertex( 0, *edge );
- break;
+ TopoDS_Face tgtFaceBis = tgtFace;
+ TopTools_MapOfShape checkedVMap( tgtEdges.size() );
+ checkedVMap.Add ( srcV1 );
+ for ( vSrcExp.Next(); vSrcExp.More(); )
+ {
+ tgtFaceBis.Reverse();
+ tgtEdges.clear();
+ SMESH_Block::GetOrderedEdges( tgtFaceBis, tgtEdges, nbEdgesInWires, tgtV1 );
+ bool ok = true;
+ list< TopoDS_Edge >::iterator edgeS = srcEdges.begin(), edgeT = tgtEdges.begin();
+ for ( ; edgeS != srcEdges.end() && ok ; ++edgeS, ++edgeT )
+ ok = edgeT->IsSame( shape2ShapeMap( *edgeS, /*isSrc=*/true ));
+ if ( ok )
+ break; // FOUND!
+
+ reverse = !reverse;
+ if ( reverse )
+ {
+ vSrcExp.Next();
+ while ( vSrcExp.More() && !checkedVMap.Add( vSrcExp.Current() ))
+ vSrcExp.Next();
+ }
+ else
+ {
+ srcV1 = TopoDS::Vertex( vSrcExp.Current() );
+ tgtV1 = TopoDS::Vertex( shape2ShapeMap( srcV1, /*isSrc=*/true ));
+ srcEdges.clear();
+ SMESH_Block::GetOrderedEdges( srcFace, srcEdges, nbEdgesInWires, srcV1 );
+ }
+ }
+ }
+ // for the case: project to a closed face from a non-closed face w/o vertex assoc;
+ // avoid projecting to a seam from two EDGEs with different nb nodes on them
+ // ( test mesh_Projection_2D_01/B1 )
+ if ( !_sourceHypo->HasVertexAssociation() &&
+ nbEdgesInWires.front() > 2 &&
+ helper.IsRealSeam( tgtEdges.front() ))
+ {
+ TopoDS_Shape srcEdge1 = shape2ShapeMap( tgtEdges.front() );
+ list< TopoDS_Edge >::iterator srcEdge2 =
+ std::find( srcEdges.begin(), srcEdges.end(), srcEdge1);
+ list< TopoDS_Edge >::iterator srcEdge3 =
+ std::find( srcEdges.begin(), srcEdges.end(), srcEdge1.Reversed());
+ if ( srcEdge2 == srcEdges.end() || srcEdge3 == srcEdges.end() ) // srcEdge1 is not a seam
+ {
+ // find srcEdge2 which also will be projected to tgtEdges.front()
+ for ( srcEdge2 = srcEdges.begin(); srcEdge2 != srcEdges.end(); ++srcEdge2 )
+ if ( !srcEdge1.IsSame( *srcEdge2 ) &&
+ tgtEdges.front().IsSame( shape2ShapeMap( *srcEdge2, /*isSrc=*/true )))
+ break;
+ // compare nb nodes on srcEdge1 and srcEdge2
+ if ( srcEdge2 != srcEdges.end() )
+ {
+ int nbN1 = 0, nbN2 = 0;
+ if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( srcEdge1 ))
+ nbN1 = sm->NbNodes();
+ if ( SMESHDS_SubMesh* sm = srcMesh->GetMeshDS()->MeshElements( *srcEdge2 ))
+ nbN2 = sm->NbNodes();
+ if ( nbN1 != nbN2 )
+ srcV1 = helper.IthVertex( 1, srcEdges.front() );
}
}
}
// Compute mesh on a target face
mapper.Apply( tgtFace, tgtV1, reverse );
- if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
+ if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK ) {
+ // std::ofstream file("/tmp/Pattern.smp" );
+ // mapper.Save( file );
return error("Can't apply source mesh pattern to the face");
+ }
// Create the mesh
if ( mapper.GetErrorCode() != SMESH_Pattern::ERR_OK )
return error("Can't make mesh by source mesh pattern");
- // it will remove mesh built by pattern mapper on edges and vertices
- // in failure case
- MeshCleaner cleaner( tgtSubMesh );
-
// -------------------------------------------------------------------------
// mapper doesn't take care of nodes already existing on edges and vertices,
// so we must merge nodes created by it with existing ones
u2nodesOnSeam.size() > 0 &&
seam.ShapeType() == TopAbs_EDGE )
{
- int nbE1 = SMESH_MesherHelper::Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true );
- int nbE2 = SMESH_MesherHelper::Count( srcFace, TopAbs_EDGE, /*ignoreSame=*/true );
+ int nbE1 = helper.Count( tgtFace, TopAbs_EDGE, /*ignoreSame=*/true );
+ int nbE2 = helper.Count( srcFace, TopAbs_EDGE, /*ignoreSame=*/true );
if ( nbE1 != nbE2 ) // 2 EDGEs are mapped to a seam EDGE
{
// find the 2 EDGEs of srcFace
if ( nbFaceBeforeMerge != nbFaceAtferMerge && !helper.HasDegeneratedEdges() )
return error(COMPERR_BAD_INPUT_MESH, "Probably invalid node parameters on geom faces");
-
- // ----------------------------------------------------------------
- // The mapper can create distorted faces by placing nodes out of the FACE
- // boundary -- fix bad faces by smoothing
- // ----------------------------------------------------------------
-
- fixDistortedFaces( helper, tgtWires );
-
// ----------------------------------------------------------------
// The mapper can't create quadratic elements, so convert if needed
// ----------------------------------------------------------------
editor.ConvertToQuadratic(/*theForce3d=*/false, tgtFaces, false);
}
- cleaner.Release(); // not to remove mesh
-
} // end of projection using Pattern mapping
+ if ( !projDone || is1DComputed )
+ // ----------------------------------------------------------------
+ // The mapper can create distorted faces by placing nodes out of the FACE
+ // boundary, also bad face can be created if EDGEs already discretized
+ // --> fix bad faces by smoothing
+ // ----------------------------------------------------------------
+ if ( !fixDistortedFaces( helper, tgtWires ))
+ return error("Invalid mesh generated");
+
// ---------------------------
// Check elements orientation
// ---------------------------
}
}
+ cleaner.Release(); // not to remove mesh
+
return true;
}