2009-02-17 07:15:34 +00:00
|
|
|
// Copyright (C) 2007-2008 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
|
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2.1 of the License.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Lesser General Public License for more details.
|
2006-05-06 08:54:13 +00:00
|
|
|
//
|
2009-02-17 07:15:34 +00:00
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2006-05-06 08:54:13 +00:00
|
|
|
//
|
2009-02-17 07:15:34 +00:00
|
|
|
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
2006-05-06 08:54:13 +00:00
|
|
|
//
|
2009-02-17 07:15:34 +00:00
|
|
|
// NETGENPlugin : C++ implementation
|
2006-05-06 08:54:13 +00:00
|
|
|
// File : NETGENPlugin_Mesher.cxx
|
|
|
|
// Author : Michael Sazonov (OCN)
|
|
|
|
// Date : 31/03/2006
|
|
|
|
// Project : SALOME
|
|
|
|
//=============================================================================
|
2009-02-17 07:15:34 +00:00
|
|
|
//
|
2006-05-06 08:54:13 +00:00
|
|
|
#include "NETGENPlugin_Mesher.hxx"
|
|
|
|
#include "NETGENPlugin_Hypothesis_2D.hxx"
|
2009-02-17 07:15:34 +00:00
|
|
|
#include "NETGENPlugin_SimpleHypothesis_3D.hxx"
|
2006-05-06 08:54:13 +00:00
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
#include <SMESH_Mesh.hxx>
|
|
|
|
#include <SMESH_Comment.hxx>
|
|
|
|
#include <SMESH_ComputeError.hxx>
|
|
|
|
#include <SMESH_subMesh.hxx>
|
2009-02-17 07:15:34 +00:00
|
|
|
#include <SMESH_MesherHelper.hxx>
|
2006-05-06 08:54:13 +00:00
|
|
|
#include <SMESHDS_Mesh.hxx>
|
|
|
|
#include <SMDS_MeshElement.hxx>
|
|
|
|
#include <SMDS_MeshNode.hxx>
|
|
|
|
#include <utilities.h>
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <BRep_Tool.hxx>
|
|
|
|
#include <TopExp.hxx>
|
|
|
|
#include <TopExp_Explorer.hxx>
|
|
|
|
#include <TopoDS.hxx>
|
|
|
|
#include <NCollection_Map.hxx>
|
2008-03-07 07:47:18 +00:00
|
|
|
#include <OSD_Path.hxx>
|
|
|
|
#include <OSD_File.hxx>
|
|
|
|
#include <TCollection_AsciiString.hxx>
|
2009-02-17 07:15:34 +00:00
|
|
|
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
2009-06-29 13:17:40 +00:00
|
|
|
#include <TopTools_DataMapOfShapeInteger.hxx>
|
2009-02-17 07:15:34 +00:00
|
|
|
#include <Standard_ErrorHandler.hxx>
|
2009-10-01 11:15:36 +00:00
|
|
|
#include <Standard_ProgramError.hxx>
|
2006-05-06 08:54:13 +00:00
|
|
|
|
|
|
|
// Netgen include files
|
|
|
|
namespace nglib {
|
|
|
|
#include <nglib.h>
|
|
|
|
}
|
|
|
|
#define OCCGEOMETRY
|
|
|
|
#include <occgeom.hpp>
|
|
|
|
#include <meshing.hpp>
|
|
|
|
//#include <ngexception.hpp>
|
|
|
|
namespace netgen {
|
|
|
|
extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*);
|
|
|
|
extern MeshingParameters mparam;
|
|
|
|
}
|
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
using namespace std;
|
|
|
|
|
2009-10-01 11:15:36 +00:00
|
|
|
static void removeFile( const TCollection_AsciiString& fileName )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
OSD_File( fileName ).Remove();
|
|
|
|
}
|
|
|
|
catch ( Standard_ProgramError ) {
|
|
|
|
MESSAGE("Can't remove file: " << fileName.ToCString() << " ; file does not exist or permission denied");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-06 08:54:13 +00:00
|
|
|
//=============================================================================
|
|
|
|
/*!
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
//=============================================================================
|
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh,
|
2006-05-06 08:54:13 +00:00
|
|
|
const TopoDS_Shape& aShape,
|
|
|
|
const bool isVolume)
|
2009-02-17 07:15:34 +00:00
|
|
|
: _mesh (mesh),
|
2006-05-06 08:54:13 +00:00
|
|
|
_shape (aShape),
|
|
|
|
_isVolume(isVolume),
|
2009-02-17 07:15:34 +00:00
|
|
|
_optimize(true),
|
|
|
|
_simpleHyp(NULL)
|
|
|
|
{
|
|
|
|
defaultParameters();
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Initialize global NETGEN parameters with default values
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
void NETGENPlugin_Mesher::defaultParameters()
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
#ifdef WNT
|
|
|
|
netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
|
|
|
|
#else
|
|
|
|
netgen::MeshingParameters& mparams = netgen::mparam;
|
|
|
|
#endif
|
2006-05-06 08:54:13 +00:00
|
|
|
// maximal mesh edge size
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.maxh = NETGENPlugin_Hypothesis::GetDefaultMaxSize();
|
2006-05-06 08:54:13 +00:00
|
|
|
// minimal number of segments per edge
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.segmentsperedge = NETGENPlugin_Hypothesis::GetDefaultNbSegPerEdge();
|
2006-05-06 08:54:13 +00:00
|
|
|
// rate of growth of size between elements
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.grading = NETGENPlugin_Hypothesis::GetDefaultGrowthRate();
|
2006-05-06 08:54:13 +00:00
|
|
|
// safety factor for curvatures (elements per radius)
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.curvaturesafety = NETGENPlugin_Hypothesis::GetDefaultNbSegPerRadius();
|
2006-05-06 08:54:13 +00:00
|
|
|
// create elements of second order
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.secondorder = NETGENPlugin_Hypothesis::GetDefaultSecondOrder() ? 1 : 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
// quad-dominated surface meshing
|
|
|
|
if (_isVolume)
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.quad = 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
else
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() ? 1 : 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
/*!
|
|
|
|
* Pass parameters to NETGEN
|
|
|
|
*/
|
|
|
|
//=============================================================================
|
|
|
|
void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp)
|
|
|
|
{
|
|
|
|
if (hyp)
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
#ifdef WNT
|
|
|
|
netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
|
|
|
|
#else
|
|
|
|
netgen::MeshingParameters& mparams = netgen::mparam;
|
|
|
|
#endif
|
2006-05-06 08:54:13 +00:00
|
|
|
// Initialize global NETGEN parameters:
|
|
|
|
// maximal mesh segment size
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.maxh = hyp->GetMaxSize();
|
2006-05-06 08:54:13 +00:00
|
|
|
// minimal number of segments per edge
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.segmentsperedge = hyp->GetNbSegPerEdge();
|
2006-05-06 08:54:13 +00:00
|
|
|
// rate of growth of size between elements
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.grading = hyp->GetGrowthRate();
|
2006-05-06 08:54:13 +00:00
|
|
|
// safety factor for curvatures (elements per radius)
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.curvaturesafety = hyp->GetNbSegPerRadius();
|
2006-05-06 08:54:13 +00:00
|
|
|
// create elements of second order
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.secondorder = hyp->GetSecondOrder() ? 1 : 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
// quad-dominated surface meshing
|
|
|
|
// only triangles are allowed for volumic mesh
|
|
|
|
if (!_isVolume)
|
2008-03-07 07:47:18 +00:00
|
|
|
mparams.quad = static_cast<const NETGENPlugin_Hypothesis_2D*>
|
2006-05-06 08:54:13 +00:00
|
|
|
(hyp)->GetQuadAllowed() ? 1 : 0;
|
|
|
|
_optimize = hyp->GetOptimize();
|
2009-02-17 07:15:34 +00:00
|
|
|
_simpleHyp = NULL;
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-17 07:15:34 +00:00
|
|
|
//=============================================================================
|
|
|
|
/*!
|
|
|
|
* Pass simple parameters to NETGEN
|
|
|
|
*/
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_SimpleHypothesis_2D* hyp)
|
|
|
|
{
|
|
|
|
_simpleHyp = hyp;
|
|
|
|
if ( _simpleHyp )
|
|
|
|
defaultParameters();
|
|
|
|
}
|
|
|
|
|
2006-05-06 08:54:13 +00:00
|
|
|
//=============================================================================
|
|
|
|
/*!
|
|
|
|
* Link - a pair of integer numbers
|
|
|
|
*/
|
|
|
|
//=============================================================================
|
|
|
|
struct Link
|
|
|
|
{
|
|
|
|
int n1, n2;
|
|
|
|
Link(int _n1, int _n2) : n1(_n1), n2(_n2) {}
|
|
|
|
Link() : n1(0), n2(0) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
int HashCode(const Link& aLink, int aLimit)
|
|
|
|
{
|
|
|
|
return HashCode(aLink.n1 + aLink.n2, aLimit);
|
|
|
|
}
|
|
|
|
|
|
|
|
Standard_Boolean IsEqual(const Link& aLink1, const Link& aLink2)
|
|
|
|
{
|
|
|
|
return (aLink1.n1 == aLink2.n1 && aLink1.n2 == aLink2.n2 ||
|
|
|
|
aLink1.n1 == aLink2.n2 && aLink1.n2 == aLink2.n1);
|
|
|
|
}
|
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Initialize netgen::OCCGeometry with OCCT shape
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
2009-02-17 07:15:34 +00:00
|
|
|
void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo,
|
|
|
|
const TopoDS_Shape& shape,
|
|
|
|
SMESH_Mesh& mesh,
|
|
|
|
list< SMESH_subMesh* > * meshedSM)
|
2008-03-07 07:47:18 +00:00
|
|
|
{
|
|
|
|
BRepTools::Clean (shape);
|
2009-02-17 07:15:34 +00:00
|
|
|
try {
|
|
|
|
#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
|
|
|
|
OCC_CATCH_SIGNALS;
|
|
|
|
#endif
|
|
|
|
BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh (shape, 0.01, true);
|
|
|
|
} catch (Standard_Failure) {
|
|
|
|
}
|
2008-03-07 07:47:18 +00:00
|
|
|
Bnd_Box bb;
|
|
|
|
BRepBndLib::Add (shape, bb);
|
|
|
|
double x1,y1,z1,x2,y2,z2;
|
|
|
|
bb.Get (x1,y1,z1,x2,y2,z2);
|
|
|
|
MESSAGE("shape bounding box:\n" <<
|
|
|
|
"(" << x1 << " " << y1 << " " << z1 << ") " <<
|
|
|
|
"(" << x2 << " " << y2 << " " << z2 << ")");
|
|
|
|
netgen::Point<3> p1 = netgen::Point<3> (x1,y1,z1);
|
|
|
|
netgen::Point<3> p2 = netgen::Point<3> (x2,y2,z2);
|
|
|
|
occgeo.boundingbox = netgen::Box<3> (p1,p2);
|
2009-02-17 07:15:34 +00:00
|
|
|
|
|
|
|
occgeo.shape = shape;
|
|
|
|
occgeo.changed = 1;
|
|
|
|
//occgeo.BuildFMap();
|
|
|
|
|
|
|
|
// fill maps of shapes of occgeo with not yet meshed subshapes
|
|
|
|
|
|
|
|
// get root submeshes
|
|
|
|
list< SMESH_subMesh* > rootSM;
|
|
|
|
if ( SMESH_subMesh* sm = mesh.GetSubMeshContaining( shape )) {
|
|
|
|
rootSM.push_back( sm );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for ( TopoDS_Iterator it( shape ); it.More(); it.Next() )
|
|
|
|
rootSM.push_back( mesh.GetSubMesh( it.Value() ));
|
|
|
|
}
|
|
|
|
|
|
|
|
// add subshapes of empty submeshes
|
|
|
|
list< SMESH_subMesh* >::iterator rootIt = rootSM.begin(), rootEnd = rootSM.end();
|
|
|
|
for ( ; rootIt != rootEnd; ++rootIt ) {
|
|
|
|
SMESH_subMesh * root = *rootIt;
|
|
|
|
SMESH_subMeshIteratorPtr smIt = root->getDependsOnIterator(/*includeSelf=*/true,
|
|
|
|
/*complexShapeFirst=*/true);
|
|
|
|
// to find a right orientation of subshapes (PAL20462)
|
|
|
|
TopTools_IndexedMapOfShape subShapes;
|
|
|
|
TopExp::MapShapes(root->GetSubShape(), subShapes);
|
|
|
|
while ( smIt->more() ) {
|
|
|
|
SMESH_subMesh* sm = smIt->next();
|
2009-10-08 13:39:52 +00:00
|
|
|
if ( !meshedSM || sm->IsEmpty() ) {
|
2009-02-17 07:15:34 +00:00
|
|
|
TopoDS_Shape shape = sm->GetSubShape();
|
|
|
|
if ( shape.ShapeType() != TopAbs_VERTEX )
|
|
|
|
shape = subShapes( subShapes.FindIndex( shape ));// - shape->index->oriented shape
|
|
|
|
switch ( shape.ShapeType() ) {
|
|
|
|
case TopAbs_FACE : occgeo.fmap.Add( shape ); break;
|
|
|
|
case TopAbs_EDGE : occgeo.emap.Add( shape ); break;
|
|
|
|
case TopAbs_VERTEX: occgeo.vmap.Add( shape ); break;
|
|
|
|
case TopAbs_SOLID :occgeo.somap.Add( shape ); break;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// collect submeshes of meshed shapes
|
|
|
|
else if (meshedSM) {
|
|
|
|
meshedSM->push_back( sm );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
occgeo.facemeshstatus.SetSize (occgeo.fmap.Extent());
|
|
|
|
occgeo.facemeshstatus = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief return id of netgen point corresponding to SMDS node
|
|
|
|
*/
|
|
|
|
//================================================================================
|
2009-03-12 12:11:11 +00:00
|
|
|
typedef map< const SMDS_MeshNode*, int > TNode2IdMap;
|
2009-02-17 07:15:34 +00:00
|
|
|
|
2009-03-12 12:11:11 +00:00
|
|
|
static int ngNodeId( const SMDS_MeshNode* node,
|
|
|
|
netgen::Mesh& ngMesh,
|
|
|
|
TNode2IdMap& nodeNgIdMap)
|
2009-02-17 07:15:34 +00:00
|
|
|
{
|
|
|
|
int newNgId = ngMesh.GetNP() + 1;
|
|
|
|
|
2009-03-12 12:11:11 +00:00
|
|
|
pair< TNode2IdMap::iterator, bool > it_isNew = nodeNgIdMap.insert( make_pair( node, newNgId ));
|
2009-02-17 07:15:34 +00:00
|
|
|
|
|
|
|
if ( it_isNew.second ) {
|
|
|
|
netgen::MeshPoint p( netgen::Point<3> (node->X(), node->Y(), node->Z()) );
|
|
|
|
ngMesh.AddPoint( p );
|
|
|
|
}
|
|
|
|
return it_isNew.first->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief fill ngMesh with nodes and elements of computed submeshes
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool NETGENPlugin_Mesher::fillNgMesh(netgen::OCCGeometry& occgeom,
|
|
|
|
netgen::Mesh& ngMesh,
|
|
|
|
vector<SMDS_MeshNode*>& nodeVec,
|
|
|
|
const list< SMESH_subMesh* > & meshedSM)
|
|
|
|
{
|
2009-03-12 12:11:11 +00:00
|
|
|
TNode2IdMap nodeNgIdMap;
|
2009-02-17 07:15:34 +00:00
|
|
|
|
|
|
|
TopTools_MapOfShape visitedShapes;
|
|
|
|
|
|
|
|
SMESH_MesherHelper helper (*_mesh);
|
|
|
|
|
|
|
|
int faceID = occgeom.fmap.Extent();
|
|
|
|
_faceDescriptors.clear();
|
|
|
|
|
|
|
|
list< SMESH_subMesh* >::const_iterator smIt, smEnd = meshedSM.end();
|
|
|
|
for ( smIt = meshedSM.begin(); smIt != smEnd; ++smIt )
|
|
|
|
{
|
|
|
|
SMESH_subMesh* sm = *smIt;
|
|
|
|
if ( !visitedShapes.Add( sm->GetSubShape() ))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SMESHDS_SubMesh * smDS = sm->GetSubMeshDS();
|
|
|
|
|
|
|
|
switch ( sm->GetSubShape().ShapeType() )
|
|
|
|
{
|
|
|
|
case TopAbs_EDGE: { // EDGE
|
|
|
|
// ----------------------
|
|
|
|
const TopoDS_Edge& geomEdge = TopoDS::Edge( sm->GetSubShape() );
|
|
|
|
|
|
|
|
// Add ng segments for each not meshed face the edge bounds
|
|
|
|
TopTools_MapOfShape visitedAncestors;
|
|
|
|
const TopTools_ListOfShape& ancestors = _mesh->GetAncestors( geomEdge );
|
|
|
|
TopTools_ListIteratorOfListOfShape ancestorIt ( ancestors );
|
|
|
|
for ( ; ancestorIt.More(); ancestorIt.Next() )
|
|
|
|
{
|
|
|
|
const TopoDS_Shape & ans = ancestorIt.Value();
|
|
|
|
if ( ans.ShapeType() != TopAbs_FACE || !visitedAncestors.Add( ans ))
|
|
|
|
continue;
|
|
|
|
const TopoDS_Face& face = TopoDS::Face( ans );
|
|
|
|
|
|
|
|
int faceID = occgeom.fmap.FindIndex( face );
|
|
|
|
if ( faceID < 1 )
|
|
|
|
continue; // meshed face
|
|
|
|
|
|
|
|
// find out orientation of geomEdge within face
|
|
|
|
bool isForwad = false;
|
|
|
|
for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() ) {
|
|
|
|
if ( geomEdge.IsSame( exp.Current() )) {
|
|
|
|
isForwad = ( exp.Current().Orientation() == geomEdge.Orientation() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool isQuad = smDS->GetElements()->next()->IsQuadratic();
|
|
|
|
|
|
|
|
// get all nodes from geomEdge
|
|
|
|
StdMeshers_FaceSide fSide( face, geomEdge, _mesh, isForwad, isQuad );
|
|
|
|
const vector<UVPtStruct>& points = fSide.GetUVPtStruct();
|
|
|
|
int i, nbSeg = fSide.NbSegments();
|
|
|
|
|
|
|
|
double otherSeamParam = 0;
|
|
|
|
helper.SetSubShape( face );
|
|
|
|
bool isSeam = helper.IsRealSeam( geomEdge );
|
|
|
|
if ( isSeam )
|
|
|
|
otherSeamParam =
|
|
|
|
helper.GetOtherParam( helper.GetPeriodicIndex() == 1 ? points[0].u : points[0].v );
|
|
|
|
|
|
|
|
// add segments
|
|
|
|
|
|
|
|
int prevNgId = ngNodeId( points[0].node, ngMesh, nodeNgIdMap );
|
|
|
|
|
|
|
|
for ( i = 0; i < nbSeg; ++i )
|
|
|
|
{
|
|
|
|
const UVPtStruct& p1 = points[ i ];
|
|
|
|
const UVPtStruct& p2 = points[ i+1 ];
|
|
|
|
|
|
|
|
netgen::Segment seg;
|
|
|
|
// ng node ids
|
|
|
|
seg.p1 = prevNgId;
|
|
|
|
seg.p2 = prevNgId = ngNodeId( p2.node, ngMesh, nodeNgIdMap );
|
|
|
|
// node param on curve
|
|
|
|
seg.epgeominfo[ 0 ].dist = p1.param;
|
|
|
|
seg.epgeominfo[ 1 ].dist = p2.param;
|
|
|
|
// uv on face
|
|
|
|
seg.epgeominfo[ 0 ].u = p1.u;
|
|
|
|
seg.epgeominfo[ 0 ].v = p1.v;
|
|
|
|
seg.epgeominfo[ 1 ].u = p2.u;
|
|
|
|
seg.epgeominfo[ 1 ].v = p2.v;
|
|
|
|
|
|
|
|
//seg.epgeominfo[ iEnd ].edgenr = edgeID; // = geom.emap.FindIndex(edge);
|
|
|
|
seg.si = faceID; // = geom.fmap.FindIndex (face);
|
|
|
|
seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
|
|
|
|
ngMesh.AddSegment (seg);
|
|
|
|
|
|
|
|
if ( isSeam )
|
|
|
|
{
|
|
|
|
if ( helper.GetPeriodicIndex() == 1 ) {
|
|
|
|
seg.epgeominfo[ 0 ].u = otherSeamParam;
|
|
|
|
seg.epgeominfo[ 1 ].u = otherSeamParam;
|
|
|
|
swap (seg.epgeominfo[0].v, seg.epgeominfo[1].v);
|
|
|
|
} else {
|
|
|
|
seg.epgeominfo[ 0 ].v = otherSeamParam;
|
|
|
|
seg.epgeominfo[ 1 ].v = otherSeamParam;
|
|
|
|
swap (seg.epgeominfo[0].u, seg.epgeominfo[1].u);
|
|
|
|
}
|
|
|
|
swap (seg.p1, seg.p2);
|
|
|
|
swap (seg.epgeominfo[0].dist, seg.epgeominfo[1].dist);
|
|
|
|
seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
|
|
|
|
ngMesh.AddSegment (seg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // loop on geomEdge ancestors
|
|
|
|
|
|
|
|
break;
|
|
|
|
} // case TopAbs_EDGE
|
|
|
|
|
|
|
|
case TopAbs_FACE: { // FACE
|
|
|
|
// ----------------------
|
|
|
|
const TopoDS_Face& geomFace = TopoDS::Face( sm->GetSubShape() );
|
|
|
|
helper.SetSubShape( geomFace );
|
|
|
|
|
2009-03-12 12:11:11 +00:00
|
|
|
// Find solids the geomFace bounds
|
2009-02-17 07:15:34 +00:00
|
|
|
int solidID1 = 0, solidID2 = 0;
|
|
|
|
const TopTools_ListOfShape& ancestors = _mesh->GetAncestors( geomFace );
|
|
|
|
TopTools_ListIteratorOfListOfShape ancestorIt ( ancestors );
|
|
|
|
for ( ; ancestorIt.More(); ancestorIt.Next() )
|
|
|
|
{
|
|
|
|
const TopoDS_Shape & solid = ancestorIt.Value();
|
|
|
|
if ( solid.ShapeType() == TopAbs_SOLID ) {
|
|
|
|
int id = occgeom.somap.FindIndex ( solid );
|
|
|
|
if ( solidID1 && id != solidID1 ) solidID2 = id;
|
|
|
|
else solidID1 = id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
faceID++;
|
|
|
|
_faceDescriptors[ faceID ].first = solidID1;
|
|
|
|
_faceDescriptors[ faceID ].second = solidID2;
|
|
|
|
|
2009-03-12 12:11:11 +00:00
|
|
|
// Orient the face correctly in solidID1 (issue 0020206)
|
|
|
|
bool reverse = false;
|
|
|
|
if ( solidID1 ) {
|
|
|
|
TopoDS_Shape solid = occgeom.somap( solidID1 );
|
|
|
|
for ( TopExp_Explorer f( solid, TopAbs_FACE ); f.More(); f.Next() ) {
|
|
|
|
if ( geomFace.IsSame( f.Current() )) {
|
|
|
|
reverse = SMESH_Algo::IsReversedSubMesh( TopoDS::Face( f.Current()), helper.GetMeshDS() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add surface elements
|
2009-02-17 07:15:34 +00:00
|
|
|
SMDS_ElemIteratorPtr faces = smDS->GetElements();
|
|
|
|
while ( faces->more() ) {
|
|
|
|
|
|
|
|
const SMDS_MeshElement* f = faces->next();
|
|
|
|
if ( f->NbNodes() % 3 != 0 ) { // not triangle
|
|
|
|
for ( ancestorIt.Initialize(ancestors); ancestorIt.More(); ancestorIt.Next() )
|
|
|
|
if ( ancestorIt.Value().ShapeType() == TopAbs_SOLID ) {
|
|
|
|
sm = _mesh->GetSubMesh( ancestorIt.Value() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
|
|
|
|
smError.reset( new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,"Not triangle submesh"));
|
|
|
|
smError->myBadElements.push_back( f );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
netgen::Element2d tri(3);
|
|
|
|
tri.SetIndex ( faceID );
|
|
|
|
|
|
|
|
for ( int i = 0; i < 3; ++i ) {
|
|
|
|
const SMDS_MeshNode* node = f->GetNode( i ), * inFaceNode=0;
|
|
|
|
if ( helper.IsSeamShape( node->GetPosition()->GetShapeId() ))
|
2009-06-10 09:02:43 +00:00
|
|
|
if ( helper.IsSeamShape( f->GetNodeWrap( i+1 )->GetPosition()->GetShapeId() ))
|
|
|
|
inFaceNode = f->GetNodeWrap( i-1 );
|
2009-02-17 07:15:34 +00:00
|
|
|
else
|
2009-06-10 09:02:43 +00:00
|
|
|
inFaceNode = f->GetNodeWrap( i+1 );
|
|
|
|
|
2009-02-17 07:15:34 +00:00
|
|
|
gp_XY uv = helper.GetNodeUV( geomFace, node, inFaceNode );
|
2009-03-12 12:11:11 +00:00
|
|
|
if ( reverse ) {
|
|
|
|
tri.GeomInfoPi(3-i).u = uv.X();
|
|
|
|
tri.GeomInfoPi(3-i).v = uv.Y();
|
|
|
|
tri.PNum (3-i) = ngNodeId( node, ngMesh, nodeNgIdMap );
|
|
|
|
} else {
|
|
|
|
tri.GeomInfoPi(i+1).u = uv.X();
|
|
|
|
tri.GeomInfoPi(i+1).v = uv.Y();
|
|
|
|
tri.PNum (i+1) = ngNodeId( node, ngMesh, nodeNgIdMap );
|
|
|
|
}
|
2009-02-17 07:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ngMesh.AddSurfaceElement (tri);
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} //
|
|
|
|
|
|
|
|
case TopAbs_VERTEX: { // VERTEX
|
|
|
|
// --------------------------
|
|
|
|
SMDS_NodeIteratorPtr nodeIt = smDS->GetNodes();
|
|
|
|
if ( nodeIt->more() )
|
|
|
|
ngNodeId( nodeIt->next(), ngMesh, nodeNgIdMap );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:;
|
|
|
|
} // switch
|
|
|
|
} // loop on submeshes
|
|
|
|
|
|
|
|
// fill nodeVec
|
|
|
|
nodeVec.resize( ngMesh.GetNP() + 1 );
|
2009-03-12 12:11:11 +00:00
|
|
|
TNode2IdMap::iterator node_NgId, nodeNgIdEnd = nodeNgIdMap.end();
|
2009-02-17 07:15:34 +00:00
|
|
|
for ( node_NgId = nodeNgIdMap.begin(); node_NgId != nodeNgIdEnd; ++node_NgId)
|
|
|
|
nodeVec[ node_NgId->second ] = (SMDS_MeshNode*) node_NgId->first;
|
|
|
|
|
|
|
|
return true;
|
2008-03-07 07:47:18 +00:00
|
|
|
}
|
|
|
|
|
2006-05-06 08:54:13 +00:00
|
|
|
//=============================================================================
|
|
|
|
/*!
|
|
|
|
* Here we are going to use the NETGEN mesher
|
|
|
|
*/
|
|
|
|
//=============================================================================
|
|
|
|
bool NETGENPlugin_Mesher::Compute()
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
#ifdef WNT
|
|
|
|
netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
|
|
|
|
#else
|
|
|
|
netgen::MeshingParameters& mparams = netgen::mparam;
|
|
|
|
#endif
|
2006-05-06 08:54:13 +00:00
|
|
|
MESSAGE("Compute with:\n"
|
2008-03-07 07:47:18 +00:00
|
|
|
" max size = " << mparams.maxh << "\n"
|
|
|
|
" segments per edge = " << mparams.segmentsperedge);
|
2006-05-06 08:54:13 +00:00
|
|
|
MESSAGE("\n"
|
2008-03-07 07:47:18 +00:00
|
|
|
" growth rate = " << mparams.grading << "\n"
|
|
|
|
" elements per radius = " << mparams.curvaturesafety << "\n"
|
|
|
|
" second order = " << mparams.secondorder << "\n"
|
|
|
|
" quad allowed = " << mparams.quad);
|
2006-05-06 08:54:13 +00:00
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
SMESH_ComputeErrorPtr error = SMESH_ComputeError::New();
|
2006-05-06 08:54:13 +00:00
|
|
|
nglib::Ng_Init();
|
|
|
|
|
|
|
|
// -------------------------
|
|
|
|
// Prepare OCC geometry
|
|
|
|
// -------------------------
|
|
|
|
|
|
|
|
netgen::OCCGeometry occgeo;
|
2009-02-17 07:15:34 +00:00
|
|
|
list< SMESH_subMesh* > meshedSM;
|
|
|
|
PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM );
|
2006-05-06 08:54:13 +00:00
|
|
|
|
|
|
|
// -------------------------
|
|
|
|
// Generate the mesh
|
|
|
|
// -------------------------
|
|
|
|
|
|
|
|
netgen::Mesh *ngMesh = NULL;
|
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
SMESH_Comment comment;
|
2009-02-17 07:15:34 +00:00
|
|
|
int err = 0;
|
|
|
|
int nbInitNod = 0;
|
|
|
|
int nbInitSeg = 0;
|
|
|
|
int nbInitFac = 0;
|
|
|
|
// vector of nodes in which node index == netgen ID
|
|
|
|
vector< SMDS_MeshNode* > nodeVec;
|
2006-05-06 08:54:13 +00:00
|
|
|
try
|
|
|
|
{
|
2009-02-17 07:15:34 +00:00
|
|
|
// ----------------
|
|
|
|
// compute 1D mesh
|
|
|
|
// ----------------
|
|
|
|
// pass 1D simple parameters to NETGEN
|
|
|
|
if ( _simpleHyp ) {
|
|
|
|
if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) {
|
|
|
|
// nb of segments
|
|
|
|
mparams.segmentsperedge = nbSeg + 0.1;
|
|
|
|
mparams.maxh = occgeo.boundingbox.Diam();
|
2009-03-10 10:51:11 +00:00
|
|
|
mparams.grading = 0.01;
|
2009-02-17 07:15:34 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// segment length
|
|
|
|
mparams.segmentsperedge = 1;
|
|
|
|
mparams.maxh = _simpleHyp->GetLocalLength();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// let netgen create ngMesh and calculate element size on not meshed shapes
|
|
|
|
char *optstr = 0;
|
|
|
|
int startWith = netgen::MESHCONST_ANALYSE;
|
|
|
|
int endWith = netgen::MESHCONST_ANALYSE;
|
2006-05-06 08:54:13 +00:00
|
|
|
err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
|
2009-02-17 07:15:34 +00:00
|
|
|
if (err) comment << "Error in netgen::OCCGenerateMesh() at MESHCONST_ANALYSE step";
|
|
|
|
|
|
|
|
// fill ngMesh with nodes and elements of computed submeshes
|
|
|
|
err = ! fillNgMesh(occgeo, *ngMesh, nodeVec, meshedSM);
|
|
|
|
nbInitNod = ngMesh->GetNP();
|
|
|
|
nbInitSeg = ngMesh->GetNSeg();
|
|
|
|
nbInitFac = ngMesh->GetNSE();
|
|
|
|
|
|
|
|
// compute mesh
|
|
|
|
if (!err)
|
|
|
|
{
|
|
|
|
startWith = endWith = netgen::MESHCONST_MESHEDGES;
|
|
|
|
err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
|
|
|
|
if (err) comment << "Error in netgen::OCCGenerateMesh() at 1D mesh generation";
|
|
|
|
}
|
|
|
|
// ---------------------
|
|
|
|
// compute surface mesh
|
|
|
|
// ---------------------
|
|
|
|
if (!err)
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
2009-02-17 07:15:34 +00:00
|
|
|
// pass 2D simple parameters to NETGEN
|
|
|
|
if ( _simpleHyp ) {
|
|
|
|
if ( double area = _simpleHyp->GetMaxElementArea() ) {
|
|
|
|
// face area
|
|
|
|
mparams.maxh = sqrt(2. * area/sqrt(3.0));
|
|
|
|
mparams.grading = 0.4; // moderate size growth
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// length from edges
|
|
|
|
double length = 0;
|
2009-10-08 13:39:52 +00:00
|
|
|
TopTools_MapOfShape tmpMap;
|
2009-10-08 13:48:26 +00:00
|
|
|
for ( TopExp_Explorer exp( _shape, TopAbs_EDGE ); exp.More(); exp.Next() )
|
|
|
|
if( tmpMap.Add(exp.Current()) )
|
|
|
|
length += SMESH_Algo::EdgeLength( TopoDS::Edge( exp.Current() ));
|
|
|
|
|
2009-06-29 13:17:40 +00:00
|
|
|
if ( ngMesh->GetNSeg() ) {
|
2009-10-08 13:39:52 +00:00
|
|
|
// we have to multiply length by 2 since for each TopoDS_Edge there
|
|
|
|
// are double set of NETGEN edges or, in other words, we have to
|
|
|
|
// divide ngMesh->GetNSeg() on 2.
|
2009-06-29 13:17:40 +00:00
|
|
|
mparams.maxh = 2*length / ngMesh->GetNSeg();
|
2009-10-08 13:39:52 +00:00
|
|
|
}
|
2009-02-17 07:15:34 +00:00
|
|
|
else
|
|
|
|
mparams.maxh = 1000;
|
|
|
|
mparams.grading = 0.2; // slow size growth
|
|
|
|
}
|
|
|
|
mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
|
|
|
|
ngMesh->SetGlobalH (mparams.maxh);
|
2009-10-08 13:39:52 +00:00
|
|
|
netgen::Box<3> bb = occgeo.GetBoundingBox();
|
|
|
|
bb.Increase (bb.Diam()/20);
|
2009-02-17 07:15:34 +00:00
|
|
|
ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparams.grading);
|
|
|
|
}
|
|
|
|
// let netgen compute 2D mesh
|
|
|
|
startWith = netgen::MESHCONST_MESHSURFACE;
|
|
|
|
endWith = _optimize ? netgen::MESHCONST_OPTSURFACE : netgen::MESHCONST_MESHSURFACE;
|
|
|
|
err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
|
|
|
|
if (err) comment << "Error in netgen::OCCGenerateMesh() at surface mesh generation";
|
|
|
|
}
|
|
|
|
// ---------------------
|
|
|
|
// generate volume mesh
|
|
|
|
// ---------------------
|
|
|
|
if (!err && _isVolume)
|
|
|
|
{
|
|
|
|
// add ng face descriptors of meshed faces
|
|
|
|
std::map< int, std::pair<int,int> >::iterator fId_soIds = _faceDescriptors.begin();
|
|
|
|
for ( ; fId_soIds != _faceDescriptors.end(); ++fId_soIds ) {
|
|
|
|
int faceID = fId_soIds->first;
|
|
|
|
int solidID1 = fId_soIds->second.first;
|
|
|
|
int solidID2 = fId_soIds->second.second;
|
|
|
|
ngMesh->AddFaceDescriptor (netgen::FaceDescriptor(faceID, solidID1, solidID2, 0));
|
|
|
|
}
|
|
|
|
// pass 3D simple parameters to NETGEN
|
|
|
|
const NETGENPlugin_SimpleHypothesis_3D* simple3d =
|
|
|
|
dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp );
|
|
|
|
if ( simple3d ) {
|
|
|
|
if ( double vol = simple3d->GetMaxElementVolume() ) {
|
|
|
|
// max volume
|
|
|
|
mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. );
|
|
|
|
mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// length from faces
|
|
|
|
mparams.maxh = ngMesh->AverageH();
|
|
|
|
}
|
2009-10-08 13:39:52 +00:00
|
|
|
// netgen::ARRAY<double> maxhdom;
|
|
|
|
// maxhdom.SetSize (occgeo.NrSolids());
|
|
|
|
// maxhdom = mparams.maxh;
|
|
|
|
// ngMesh->SetMaxHDomain (maxhdom);
|
2009-02-17 07:15:34 +00:00
|
|
|
ngMesh->SetGlobalH (mparams.maxh);
|
|
|
|
mparams.grading = 0.4;
|
|
|
|
ngMesh->CalcLocalH();
|
|
|
|
}
|
|
|
|
// let netgen compute 3D mesh
|
|
|
|
startWith = netgen::MESHCONST_MESHVOLUME;
|
|
|
|
endWith = _optimize ? netgen::MESHCONST_OPTVOLUME : netgen::MESHCONST_MESHVOLUME;
|
2006-05-06 08:54:13 +00:00
|
|
|
err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
|
2008-03-07 07:47:18 +00:00
|
|
|
if (err) comment << "Error in netgen::OCCGenerateMesh()";
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
2008-03-07 07:47:18 +00:00
|
|
|
if (!err && mparams.secondorder > 0)
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
|
|
|
netgen::OCCRefinementSurfaces ref (occgeo);
|
|
|
|
ref.MakeSecondOrder (*ngMesh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (netgen::NgException exc)
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
error->myName = err = COMPERR_ALGO_FAILED;
|
|
|
|
comment << exc.What();
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int nbNod = ngMesh->GetNP();
|
|
|
|
int nbSeg = ngMesh->GetNSeg();
|
|
|
|
int nbFac = ngMesh->GetNSE();
|
|
|
|
int nbVol = ngMesh->GetNE();
|
|
|
|
|
|
|
|
MESSAGE((err ? "Mesh Generation failure" : "End of Mesh Generation") <<
|
|
|
|
", nb nodes: " << nbNod <<
|
|
|
|
", nb segments: " << nbSeg <<
|
|
|
|
", nb faces: " << nbFac <<
|
|
|
|
", nb volumes: " << nbVol);
|
|
|
|
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
// Feed back the SMESHDS with the generated Nodes and Elements
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
|
2006-05-06 08:54:13 +00:00
|
|
|
bool isOK = ( !err && (_isVolume ? (nbVol > 0) : (nbFac > 0)) );
|
2008-03-07 07:47:18 +00:00
|
|
|
if ( true /*isOK*/ ) // get whatever built
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
|
|
|
// map of nodes assigned to submeshes
|
|
|
|
NCollection_Map<int> pindMap;
|
|
|
|
// create and insert nodes into nodeVec
|
2009-02-17 07:15:34 +00:00
|
|
|
nodeVec.resize( nbNod + 1 );
|
2006-05-06 08:54:13 +00:00
|
|
|
int i;
|
2009-02-17 07:15:34 +00:00
|
|
|
for (i = nbInitNod+1; i <= nbNod /*&& isOK*/; ++i )
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
|
|
|
const netgen::MeshPoint& ngPoint = ngMesh->Point(i);
|
|
|
|
SMDS_MeshNode* node = NULL;
|
|
|
|
bool newNodeOnVertex = false;
|
|
|
|
TopoDS_Vertex aVert;
|
2009-02-17 07:15:34 +00:00
|
|
|
if (i-nbInitNod <= occgeo.vmap.Extent())
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
|
|
|
// point on vertex
|
2009-02-17 07:15:34 +00:00
|
|
|
aVert = TopoDS::Vertex(occgeo.vmap(i-nbInitNod));
|
2008-03-07 07:47:18 +00:00
|
|
|
SMESHDS_SubMesh * submesh = meshDS->MeshElements(aVert);
|
2006-05-06 08:54:13 +00:00
|
|
|
if (submesh)
|
|
|
|
{
|
|
|
|
SMDS_NodeIteratorPtr it = submesh->GetNodes();
|
|
|
|
if (it->more())
|
|
|
|
{
|
|
|
|
node = const_cast<SMDS_MeshNode*> (it->next());
|
|
|
|
pindMap.Add(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!node)
|
|
|
|
newNodeOnVertex = true;
|
|
|
|
}
|
|
|
|
if (!node)
|
2008-03-07 07:47:18 +00:00
|
|
|
node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z());
|
2006-05-06 08:54:13 +00:00
|
|
|
if (!node)
|
|
|
|
{
|
|
|
|
MESSAGE("Cannot create a mesh node");
|
2008-03-07 07:47:18 +00:00
|
|
|
if ( !comment.size() ) comment << "Cannot create a mesh node";
|
|
|
|
nbSeg = nbFac = nbVol = isOK = 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
nodeVec.at(i) = node;
|
|
|
|
if (newNodeOnVertex)
|
|
|
|
{
|
|
|
|
// point on vertex
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetNodeOnVertex(node, aVert);
|
2006-05-06 08:54:13 +00:00
|
|
|
pindMap.Add(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create mesh segments along geometric edges
|
|
|
|
NCollection_Map<Link> linkMap;
|
2009-02-17 07:15:34 +00:00
|
|
|
for (i = nbInitSeg+1; i <= nbSeg/* && isOK*/; ++i )
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
|
|
|
const netgen::Segment& seg = ngMesh->LineSegment(i);
|
|
|
|
Link link(seg.p1, seg.p2);
|
|
|
|
if (linkMap.Contains(link))
|
|
|
|
continue;
|
|
|
|
linkMap.Add(link);
|
|
|
|
TopoDS_Edge aEdge;
|
|
|
|
int pinds[3] = { seg.p1, seg.p2, seg.pmid };
|
|
|
|
int nbp = 0;
|
|
|
|
double param2 = 0;
|
|
|
|
for (int j=0; j < 3; ++j)
|
|
|
|
{
|
|
|
|
int pind = pinds[j];
|
|
|
|
if (pind <= 0) continue;
|
|
|
|
++nbp;
|
|
|
|
double param;
|
|
|
|
if (j < 2)
|
|
|
|
{
|
|
|
|
if (aEdge.IsNull())
|
|
|
|
{
|
|
|
|
int aGeomEdgeInd = seg.epgeominfo[j].edgenr;
|
|
|
|
if (aGeomEdgeInd > 0 && aGeomEdgeInd <= occgeo.emap.Extent())
|
|
|
|
aEdge = TopoDS::Edge(occgeo.emap(aGeomEdgeInd));
|
|
|
|
}
|
|
|
|
param = seg.epgeominfo[j].dist;
|
|
|
|
param2 += param;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
param = param2 * 0.5;
|
2009-02-17 07:15:34 +00:00
|
|
|
if (pind <= nbInitNod || pindMap.Contains(pind))
|
2006-05-06 08:54:13 +00:00
|
|
|
continue;
|
|
|
|
if (!aEdge.IsNull())
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetNodeOnEdge(nodeVec.at(pind), aEdge, param);
|
2006-05-06 08:54:13 +00:00
|
|
|
pindMap.Add(pind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SMDS_MeshEdge* edge;
|
|
|
|
if (nbp < 3) // second order ?
|
2008-03-07 07:47:18 +00:00
|
|
|
edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]));
|
2006-05-06 08:54:13 +00:00
|
|
|
else
|
2008-03-07 07:47:18 +00:00
|
|
|
edge = meshDS->AddEdge(nodeVec.at(pinds[0]), nodeVec.at(pinds[1]),
|
2006-05-06 08:54:13 +00:00
|
|
|
nodeVec.at(pinds[2]));
|
|
|
|
if (!edge)
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
if ( !comment.size() ) comment << "Cannot create a mesh edge";
|
2006-05-06 08:54:13 +00:00
|
|
|
MESSAGE("Cannot create a mesh edge");
|
2008-03-07 07:47:18 +00:00
|
|
|
nbSeg = nbFac = nbVol = isOK = 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!aEdge.IsNull())
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetMeshElementOnShape(edge, aEdge);
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create mesh faces along geometric faces
|
2009-02-17 07:15:34 +00:00
|
|
|
for (i = nbInitFac+1; i <= nbFac/* && isOK*/; ++i )
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
|
|
|
const netgen::Element2d& elem = ngMesh->SurfaceElement(i);
|
|
|
|
int aGeomFaceInd = elem.GetIndex();
|
|
|
|
TopoDS_Face aFace;
|
|
|
|
if (aGeomFaceInd > 0 && aGeomFaceInd <= occgeo.fmap.Extent())
|
|
|
|
aFace = TopoDS::Face(occgeo.fmap(aGeomFaceInd));
|
|
|
|
vector<SMDS_MeshNode*> nodes;
|
|
|
|
for (int j=1; j <= elem.GetNP(); ++j)
|
|
|
|
{
|
|
|
|
int pind = elem.PNum(j);
|
|
|
|
SMDS_MeshNode* node = nodeVec.at(pind);
|
|
|
|
nodes.push_back(node);
|
2009-02-17 07:15:34 +00:00
|
|
|
if (pind <= nbInitNod || pindMap.Contains(pind))
|
2006-05-06 08:54:13 +00:00
|
|
|
continue;
|
|
|
|
if (!aFace.IsNull())
|
|
|
|
{
|
|
|
|
const netgen::PointGeomInfo& pgi = elem.GeomInfoPi(j);
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetNodeOnFace(node, aFace, pgi.u, pgi.v);
|
2006-05-06 08:54:13 +00:00
|
|
|
pindMap.Add(pind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SMDS_MeshFace* face = NULL;
|
|
|
|
switch (elem.GetType())
|
|
|
|
{
|
|
|
|
case netgen::TRIG:
|
2008-03-07 07:47:18 +00:00
|
|
|
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2]);
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
case netgen::QUAD:
|
2008-03-07 07:47:18 +00:00
|
|
|
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
case netgen::TRIG6:
|
2008-03-07 07:47:18 +00:00
|
|
|
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[5],nodes[3],nodes[4]);
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
case netgen::QUAD8:
|
2008-03-07 07:47:18 +00:00
|
|
|
face = meshDS->AddFace(nodes[0],nodes[1],nodes[2],nodes[3],
|
2006-05-06 08:54:13 +00:00
|
|
|
nodes[4],nodes[7],nodes[5],nodes[6]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MESSAGE("NETGEN created a face of unexpected type, ignoring");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!face)
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
if ( !comment.size() ) comment << "Cannot create a mesh face";
|
2006-05-06 08:54:13 +00:00
|
|
|
MESSAGE("Cannot create a mesh face");
|
2008-03-07 07:47:18 +00:00
|
|
|
nbSeg = nbFac = nbVol = isOK = 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!aFace.IsNull())
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetMeshElementOnShape(face, aFace);
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create tetrahedra
|
2008-03-07 07:47:18 +00:00
|
|
|
for (i = 1; i <= nbVol/* && isOK*/; ++i)
|
2006-05-06 08:54:13 +00:00
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
const netgen::Element& elem = ngMesh->VolumeElement(i);
|
2006-05-06 08:54:13 +00:00
|
|
|
int aSolidInd = elem.GetIndex();
|
|
|
|
TopoDS_Solid aSolid;
|
|
|
|
if (aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent())
|
|
|
|
aSolid = TopoDS::Solid(occgeo.somap(aSolidInd));
|
|
|
|
vector<SMDS_MeshNode*> nodes;
|
|
|
|
for (int j=1; j <= elem.GetNP(); ++j)
|
|
|
|
{
|
|
|
|
int pind = elem.PNum(j);
|
|
|
|
SMDS_MeshNode* node = nodeVec.at(pind);
|
|
|
|
nodes.push_back(node);
|
2009-02-17 07:15:34 +00:00
|
|
|
if (pind <= nbInitNod || pindMap.Contains(pind))
|
2006-05-06 08:54:13 +00:00
|
|
|
continue;
|
|
|
|
if (!aSolid.IsNull())
|
|
|
|
{
|
|
|
|
// point in solid
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetNodeInVolume(node, aSolid);
|
2006-05-06 08:54:13 +00:00
|
|
|
pindMap.Add(pind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SMDS_MeshVolume* vol = NULL;
|
|
|
|
switch (elem.GetType())
|
|
|
|
{
|
|
|
|
case netgen::TET:
|
2008-03-07 07:47:18 +00:00
|
|
|
vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3]);
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
case netgen::TET10:
|
2008-03-07 07:47:18 +00:00
|
|
|
vol = meshDS->AddVolume(nodes[0],nodes[1],nodes[2],nodes[3],
|
|
|
|
nodes[4],nodes[7],nodes[5],nodes[6],nodes[8],nodes[9]);
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MESSAGE("NETGEN created a volume of unexpected type, ignoring");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!vol)
|
|
|
|
{
|
2008-03-07 07:47:18 +00:00
|
|
|
if ( !comment.size() ) comment << "Cannot create a mesh volume";
|
2006-05-06 08:54:13 +00:00
|
|
|
MESSAGE("Cannot create a mesh volume");
|
2008-03-07 07:47:18 +00:00
|
|
|
nbSeg = nbFac = nbVol = isOK = 0;
|
2006-05-06 08:54:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!aSolid.IsNull())
|
2008-03-07 07:47:18 +00:00
|
|
|
meshDS->SetMeshElementOnShape(vol, aSolid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( error->IsOK() && ( !isOK || comment.size() > 0 ))
|
|
|
|
error->myName = COMPERR_ALGO_FAILED;
|
|
|
|
if ( !comment.empty() )
|
|
|
|
error->myComment = comment;
|
|
|
|
|
|
|
|
// set bad compute error to subshapes of all failed subshapes shapes
|
|
|
|
if ( !error->IsOK() && err )
|
|
|
|
{
|
|
|
|
for (int i = 1; i <= occgeo.fmap.Extent(); i++) {
|
|
|
|
int status = occgeo.facemeshstatus[i-1];
|
|
|
|
if (status == 1 ) continue;
|
|
|
|
if ( SMESH_subMesh* sm = _mesh->GetSubMeshContaining( occgeo.fmap( i ))) {
|
|
|
|
SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
|
|
|
|
if ( !smError || smError->IsOK() ) {
|
|
|
|
if ( status == -1 )
|
|
|
|
smError.reset( new SMESH_ComputeError( error->myName, error->myComment ));
|
|
|
|
else
|
|
|
|
smError.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, "Ignored" ));
|
|
|
|
}
|
|
|
|
}
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nglib::Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh);
|
|
|
|
nglib::Ng_Exit();
|
|
|
|
|
2008-03-07 07:47:18 +00:00
|
|
|
RemoveTmpFiles();
|
|
|
|
|
|
|
|
return error->IsOK();
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Remove "test.out" and "problemfaces" files in current directory
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
void NETGENPlugin_Mesher::RemoveTmpFiles()
|
|
|
|
{
|
2009-10-01 11:15:36 +00:00
|
|
|
removeFile("test.out");
|
|
|
|
removeFile("problemfaces");
|
2006-05-06 08:54:13 +00:00
|
|
|
}
|
2009-06-29 13:17:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
/*!
|
|
|
|
* Evaluate
|
|
|
|
*/
|
|
|
|
//=============================================================================
|
|
|
|
bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap)
|
|
|
|
{
|
|
|
|
#ifdef WNT
|
|
|
|
netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
|
|
|
|
#else
|
|
|
|
netgen::MeshingParameters& mparams = netgen::mparam;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------
|
|
|
|
// Prepare OCC geometry
|
|
|
|
// -------------------------
|
|
|
|
netgen::OCCGeometry occgeo;
|
|
|
|
list< SMESH_subMesh* > meshedSM;
|
|
|
|
PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM );
|
|
|
|
|
|
|
|
// ----------------
|
|
|
|
// evaluate 1D
|
|
|
|
// ----------------
|
|
|
|
// pass 1D simple parameters to NETGEN
|
|
|
|
int nbs = 0;
|
|
|
|
if ( _simpleHyp ) {
|
|
|
|
if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) {
|
|
|
|
nbs = nbSeg;
|
|
|
|
// nb of segments
|
|
|
|
mparams.segmentsperedge = nbSeg + 0.1;
|
|
|
|
mparams.maxh = occgeo.boundingbox.Diam();
|
|
|
|
mparams.grading = 0.01;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// segment length
|
|
|
|
mparams.segmentsperedge = 1;
|
|
|
|
mparams.maxh = _simpleHyp->GetLocalLength();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TopTools_DataMapOfShapeInteger EdgesMap;
|
|
|
|
double fullLen = 0.0;
|
|
|
|
double fullNbSeg = 0;
|
|
|
|
for (TopExp_Explorer exp(_shape, TopAbs_EDGE); exp.More(); exp.Next()) {
|
|
|
|
TopoDS_Edge E = TopoDS::Edge( exp.Current() );
|
|
|
|
if( EdgesMap.IsBound(E) )
|
|
|
|
continue;
|
|
|
|
SMESH_subMesh *sm = _mesh->GetSubMesh(E);
|
|
|
|
double aLen = SMESH_Algo::EdgeLength(E);
|
|
|
|
fullLen += aLen;
|
|
|
|
int nb1d = nbs;
|
|
|
|
if(nb1d==0) {
|
2009-07-10 06:26:38 +00:00
|
|
|
nb1d = (int)( aLen/mparams.maxh + 1 );
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
fullNbSeg += nb1d;
|
2009-08-25 05:47:16 +00:00
|
|
|
std::vector<int> aVec(SMDSEntity_Last);
|
|
|
|
for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
|
2009-06-29 13:17:40 +00:00
|
|
|
if( mparams.secondorder > 0 ) {
|
2009-08-25 05:47:16 +00:00
|
|
|
aVec[SMDSEntity_Node] = 2*nb1d - 1;
|
|
|
|
aVec[SMDSEntity_Quad_Edge] = nb1d;
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-08-25 05:47:16 +00:00
|
|
|
aVec[SMDSEntity_Node] = nb1d - 1;
|
|
|
|
aVec[SMDSEntity_Edge] = nb1d;
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
aResMap.insert(std::make_pair(sm,aVec));
|
|
|
|
EdgesMap.Bind(E,nb1d);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------
|
|
|
|
// evaluate 2D
|
|
|
|
// ----------------
|
|
|
|
if ( _simpleHyp ) {
|
|
|
|
if ( double area = _simpleHyp->GetMaxElementArea() ) {
|
|
|
|
// face area
|
|
|
|
mparams.maxh = sqrt(2. * area/sqrt(3.0));
|
|
|
|
mparams.grading = 0.4; // moderate size growth
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// length from edges
|
|
|
|
mparams.maxh = fullLen/fullNbSeg;
|
|
|
|
mparams.grading = 0.2; // slow size growth
|
|
|
|
}
|
|
|
|
mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
|
|
|
|
}
|
|
|
|
for (TopExp_Explorer exp(_shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
|
|
|
TopoDS_Face F = TopoDS::Face( exp.Current() );
|
|
|
|
SMESH_subMesh *sm = _mesh->GetSubMesh(F);
|
|
|
|
GProp_GProps G;
|
|
|
|
BRepGProp::SurfaceProperties(F,G);
|
|
|
|
double anArea = G.Mass();
|
|
|
|
int nb1d = 0;
|
|
|
|
for (TopExp_Explorer exp1(F,TopAbs_EDGE); exp1.More(); exp1.Next()) {
|
|
|
|
nb1d += EdgesMap.Find(exp1.Current());
|
|
|
|
}
|
2009-07-10 06:26:38 +00:00
|
|
|
int nbFaces = (int) ( anArea / ( mparams.maxh*mparams.maxh*sqrt(3.) / 4 ) );
|
|
|
|
int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );
|
2009-08-25 05:47:16 +00:00
|
|
|
std::vector<int> aVec(SMDSEntity_Last);
|
|
|
|
for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
|
2009-06-29 13:17:40 +00:00
|
|
|
if( mparams.secondorder > 0 ) {
|
|
|
|
int nb1d_in = (nbFaces*3 - nb1d) / 2;
|
2009-08-25 05:47:16 +00:00
|
|
|
aVec[SMDSEntity_Node] = nbNodes + nb1d_in;
|
|
|
|
aVec[SMDSEntity_Quad_Triangle] = nbFaces;
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-08-25 05:47:16 +00:00
|
|
|
aVec[SMDSEntity_Node] = nbNodes;
|
|
|
|
aVec[SMDSEntity_Triangle] = nbFaces;
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
aResMap.insert(std::make_pair(sm,aVec));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------
|
|
|
|
// evaluate 3D
|
|
|
|
// ----------------
|
|
|
|
if(_isVolume) {
|
|
|
|
// pass 3D simple parameters to NETGEN
|
|
|
|
const NETGENPlugin_SimpleHypothesis_3D* simple3d =
|
|
|
|
dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp );
|
|
|
|
if ( simple3d ) {
|
|
|
|
if ( double vol = simple3d->GetMaxElementVolume() ) {
|
2009-10-08 13:39:52 +00:00
|
|
|
// max volume
|
|
|
|
mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. );
|
|
|
|
mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-10-08 13:39:52 +00:00
|
|
|
// using previous length from faces
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
mparams.grading = 0.4;
|
|
|
|
}
|
|
|
|
GProp_GProps G;
|
|
|
|
BRepGProp::VolumeProperties(_shape,G);
|
|
|
|
double aVolume = G.Mass();
|
|
|
|
double tetrVol = 0.1179*mparams.maxh*mparams.maxh*mparams.maxh;
|
2009-10-08 13:39:52 +00:00
|
|
|
int nbVols = int(aVolume/tetrVol);
|
|
|
|
int nb1d_in = int(( nbVols*6 - fullNbSeg ) / 6 );
|
2009-08-25 05:47:16 +00:00
|
|
|
std::vector<int> aVec(SMDSEntity_Last);
|
|
|
|
for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
|
2009-06-29 13:17:40 +00:00
|
|
|
if( mparams.secondorder > 0 ) {
|
2009-08-25 05:47:16 +00:00
|
|
|
aVec[SMDSEntity_Node] = nb1d_in/3 + 1 + nb1d_in;
|
|
|
|
aVec[SMDSEntity_Quad_Tetra] = nbVols;
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-08-25 05:47:16 +00:00
|
|
|
aVec[SMDSEntity_Node] = nb1d_in/3 + 1;
|
|
|
|
aVec[SMDSEntity_Tetra] = nbVols;
|
2009-06-29 13:17:40 +00:00
|
|
|
}
|
|
|
|
SMESH_subMesh *sm = _mesh->GetSubMesh(_shape);
|
|
|
|
aResMap.insert(std::make_pair(sm,aVec));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|