예제 #1
0
bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh,
                                     SMESH_MesherHelper* aHelper)
{
    MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume);
    const int invalid_ID = -1;
    bool _quadraticMesh = false;
    typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
    TNodeToIDMap nodeToNetgenID;
    list< const SMDS_MeshElement* > triangles;
    SMESHDS_Mesh* MeshDS = aHelper->GetMeshDS();

    SMESH_MesherHelper::MType MeshType = aHelper->IsQuadraticMesh();

    if(MeshType == SMESH_MesherHelper::COMP)
        return error( COMPERR_BAD_INPUT_MESH,
                      SMESH_Comment("Mesh with linear and quadratic elements given."));
    else if (MeshType == SMESH_MesherHelper::QUADRATIC)
        _quadraticMesh = true;

    StdMeshers_QuadToTriaAdaptor Adaptor;
    Adaptor.Compute(aMesh);

    SMDS_FaceIteratorPtr fIt = MeshDS->facesIterator();
    TIDSortedElemSet sortedFaces; //  0020279: control the "random" use when using mesh algorithms
    while( fIt->more()) sortedFaces.insert( fIt->next() );

    TIDSortedElemSet::iterator itFace = sortedFaces.begin(), fEnd = sortedFaces.end();
    for ( ; itFace != fEnd; ++itFace ) {
        // check element
        const SMDS_MeshElement* elem = *itFace;
        if ( !elem )
            return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
        bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 ));
        if ( !isTraingle ) {
            //return error( COMPERR_BAD_INPUT_MESH,
            //              SMESH_Comment("Not triangle element ")<<elem->GetID());
            // using adaptor
            const list<const SMDS_FaceOfNodes*>* faces = Adaptor.GetTriangles(elem);
            if(faces==0) {
                return error( COMPERR_BAD_INPUT_MESH,
                              SMESH_Comment("Not triangles in adaptor for element ")<<elem->GetID());
            }
            list<const SMDS_FaceOfNodes*>::const_iterator itf = faces->begin();
            for(; itf!=faces->end(); itf++ ) {
                triangles.push_back( (*itf) );
                // put triange's nodes to nodeToNetgenID map
                SMDS_ElemIteratorPtr triangleNodesIt = (*itf)->nodesIterator();
                while ( triangleNodesIt->more() ) {
                    const SMDS_MeshNode * node =
                        static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
                    if(aHelper->IsMedium(node))
                        continue;
                    nodeToNetgenID.insert( make_pair( node, invalid_ID ));
                }
            }
        }
        else {
            // keep a triangle
            triangles.push_back( elem );
            // put elem nodes to nodeToNetgenID map
            SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator();
            while ( triangleNodesIt->more() ) {
                const SMDS_MeshNode * node =
                    static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
                if(aHelper->IsMedium(node))
                    continue;
                nodeToNetgenID.insert( make_pair( node, invalid_ID ));
            }
        }
    }

    // ---------------------------------
    // Feed the Netgen with surface mesh
    // ---------------------------------

    int Netgen_NbOfNodes = 0;
    int Netgen_param2ndOrder = 0;
    double Netgen_paramFine = 1.;
    double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );

    double Netgen_point[3];
    int Netgen_triangle[3];
    int Netgen_tetrahedron[4];

    Ng_Init();

    Ng_Mesh * Netgen_mesh = Ng_NewMesh();

    // set nodes and remember thier netgen IDs

    TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
    for ( ; n_id != nodeToNetgenID.end(); ++n_id )
    {
        const SMDS_MeshNode* node = n_id->first;

        Netgen_point [ 0 ] = node->X();
        Netgen_point [ 1 ] = node->Y();
        Netgen_point [ 2 ] = node->Z();
        Ng_AddPoint(Netgen_mesh, Netgen_point);
        n_id->second = ++Netgen_NbOfNodes; // set netgen ID

    }

    // set triangles
    list< const SMDS_MeshElement* >::iterator tria = triangles.begin();
    for ( ; tria != triangles.end(); ++tria)
    {
        int i = 0;
        SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator();
        while ( triangleNodesIt->more() ) {
            const SMDS_MeshNode * node =
                static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
            if(aHelper->IsMedium(node))
                continue;
            Netgen_triangle[ i ] = nodeToNetgenID[ node ];
            ++i;
        }

        Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
    }

    // -------------------------
    // Generate the volume mesh
    // -------------------------

    Ng_Meshing_Parameters Netgen_param;

    Netgen_param.secondorder = Netgen_param2ndOrder;
    Netgen_param.fineness = Netgen_paramFine;
    Netgen_param.maxh = Netgen_paramSize;

    Ng_Result status;

    try {
#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
        OCC_CATCH_SIGNALS;
#endif
        status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param);
    }
    catch (Standard_Failure& exc) {
        error(COMPERR_OCC_EXCEPTION, exc.GetMessageString());
        status = NG_VOLUME_FAILURE;
    }
    catch (...) {
        error("Bad mesh input!!!");
        status = NG_VOLUME_FAILURE;
    }
    if ( GetComputeError()->IsOK() ) {
        error( status, "Bad mesh input!!!");
    }

    int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);

    int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh);

    MESSAGE("End of Volume Mesh Generation. status=" << status <<
            ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
            ", nb tetra: " << Netgen_NbOfTetra);

    // -------------------------------------------------------------------
    // Feed back the SMESHDS with the generated Nodes and Volume Elements
    // -------------------------------------------------------------------

    bool isOK = ( Netgen_NbOfTetra > 0 );// get whatever built
    if ( isOK )
    {
        // vector of nodes in which node index == netgen ID
        vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 );
        // insert old nodes into nodeVec
        for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) {
            nodeVec.at( n_id->second ) = n_id->first;
        }
        // create and insert new nodes into nodeVec
        int nodeIndex = Netgen_NbOfNodes + 1;

        for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
        {
            Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point );
            SMDS_MeshNode * node = aHelper->AddNode(Netgen_point[0],
                                                    Netgen_point[1],
                                                    Netgen_point[2]);
            nodeVec.at(nodeIndex) = node;
        }

        // create tetrahedrons
        for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
        {
            Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron);
            aHelper->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
                                nodeVec.at( Netgen_tetrahedron[1] ),
                                nodeVec.at( Netgen_tetrahedron[2] ),
                                nodeVec.at( Netgen_tetrahedron[3] ));
        }
    }

    Ng_DeleteMesh(Netgen_mesh);
    Ng_Exit();

    NETGENPlugin_Mesher::RemoveTmpFiles();

    return (status == NG_OK);
}
bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
                                     SMESH_MesherHelper* aHelper)
{
  const int invalid_ID = -1;

  netgen::multithread.terminate = 0;
  _progressByTic = -1.;

  SMESH_MesherHelper::MType MeshType = aHelper->IsQuadraticMesh();
  if ( MeshType == SMESH_MesherHelper::COMP )
    return error( COMPERR_BAD_INPUT_MESH,
                  SMESH_Comment("Mesh with linear and quadratic elements given"));

  aHelper->SetIsQuadratic( MeshType == SMESH_MesherHelper::QUADRATIC );

  // ---------------------------------
  // Feed the Netgen with surface mesh
  // ---------------------------------

  int Netgen_NbOfNodes = 0;
  int Netgen_param2ndOrder = 0;
  double Netgen_paramFine = 1.;
  double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );

  double Netgen_point[3];
  int Netgen_triangle[3];
  int Netgen_tetrahedron[4];

  NETGENPlugin_NetgenLibWrapper ngLib;
  Ng_Mesh * Netgen_mesh = ngLib._ngMesh;

  SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh ));
  if ( aMesh.NbQuadrangles() > 0 )
  {
    StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor;
    Adaptor->Compute(aMesh);
    proxyMesh.reset( Adaptor );
  }

  // maps nodes to ng ID
  typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
  typedef TNodeToIDMap::value_type                     TN2ID;
  TNodeToIDMap nodeToNetgenID;

  SMDS_ElemIteratorPtr fIt = proxyMesh->GetFaces();
  while( fIt->more())
  {
    // check element
    const SMDS_MeshElement* elem = fIt->next();
    if ( !elem )
      return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
    if ( elem->NbCornerNodes() != 3 )
      return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters");
      
    // add three nodes of triangle
    for ( int iN = 0; iN < 3; ++iN )
    {
      const SMDS_MeshNode* node = elem->GetNode( iN );
      int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second;
      if ( ngID == invalid_ID )
      {
        ngID = ++Netgen_NbOfNodes;
        Netgen_point [ 0 ] = node->X();
        Netgen_point [ 1 ] = node->Y();
        Netgen_point [ 2 ] = node->Z();
        Ng_AddPoint(Netgen_mesh, Netgen_point);
      }
      Netgen_triangle[ iN ] = ngID;
    }
    Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
  }
  proxyMesh.reset(); // delete tmp faces

  // vector of nodes in which node index == netgen ID
  vector< const SMDS_MeshNode* > nodeVec ( nodeToNetgenID.size() + 1 );
  // insert old nodes into nodeVec
  TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
  for ( ; n_id != nodeToNetgenID.end(); ++n_id )
    nodeVec.at( n_id->second ) = n_id->first;
  nodeToNetgenID.clear();

  // -------------------------
  // Generate the volume mesh
  // -------------------------

  return ( ngLib._isComputeOk = compute( aMesh, *aHelper, nodeVec, Netgen_mesh));
}
예제 #3
0
bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
                                     const TopoDS_Shape& aShape)
{
    MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume);

    SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();

    const int invalid_ID = -1;

    SMESH::Controls::Area areaControl;
    SMESH::Controls::TSequenceOfXYZ nodesCoords;

    // -------------------------------------------------------------------
    // get triangles on aShell and make a map of nodes to Netgen node IDs
    // -------------------------------------------------------------------

    SMESH_MesherHelper helper(aMesh);
    SMESH_MesherHelper* myTool = &helper;
    bool _quadraticMesh = myTool->IsQuadraticSubMesh(aShape);

    typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
    TNodeToIDMap nodeToNetgenID;
    list< const SMDS_MeshElement* > triangles;
    list< bool >                    isReversed; // orientation of triangles

    TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType();
    bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID );

    // for the degeneraged edge: ignore all but one node on it;
    // map storing ids of degen edges and vertices and their netgen id:
    map< int, int* > degenShapeIdToPtrNgId;
    map< int, int* >::iterator shId_ngId;
    list< int > degenNgIds;

    StdMeshers_QuadToTriaAdaptor Adaptor;
    Adaptor.Compute(aMesh,aShape);

    for (TopExp_Explorer exp(aShape,TopAbs_FACE); exp.More(); exp.Next())
    {
        const TopoDS_Shape& aShapeFace = exp.Current();
        const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace );
        if ( aSubMeshDSFace )
        {
            bool isRev = false;
            if ( checkReverse && helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
                // IsReversedSubMesh() can work wrong on strongly curved faces,
                // so we use it as less as possible
                isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS );

            SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
            while ( iteratorElem->more() ) // loop on elements on a face
            {
                // check element
                const SMDS_MeshElement* elem = iteratorElem->next();
                if ( !elem )
                    return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
                bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 ));
                if ( !isTraingle ) {
                    //return error( COMPERR_BAD_INPUT_MESH,
                    //              SMESH_Comment("Not triangle element ")<<elem->GetID());
                    // using adaptor
                    const list<const SMDS_FaceOfNodes*>* faces = Adaptor.GetTriangles(elem);
                    if(faces==0) {
                        return error( COMPERR_BAD_INPUT_MESH,
                                      SMESH_Comment("Not triangles in adaptor for element ")<<elem->GetID());
                    }
                    list<const SMDS_FaceOfNodes*>::const_iterator itf = faces->begin();
                    for(; itf!=faces->end(); itf++ ) {
                        triangles.push_back( (*itf) );
                        isReversed.push_back( isRev );
                        // put triange's nodes to nodeToNetgenID map
                        SMDS_ElemIteratorPtr triangleNodesIt = (*itf)->nodesIterator();
                        while ( triangleNodesIt->more() ) {
                            const SMDS_MeshNode * node =
                                static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
                            if(myTool->IsMedium(node))
                                continue;
                            nodeToNetgenID.insert( make_pair( node, invalid_ID ));
                        }
                    }
                }
                else {
                    // keep a triangle
                    triangles.push_back( elem );
                    isReversed.push_back( isRev );
                    // put elem nodes to nodeToNetgenID map
                    SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator();
                    while ( triangleNodesIt->more() ) {
                        const SMDS_MeshNode * node =
                            static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
                        if(myTool->IsMedium(node))
                            continue;
                        nodeToNetgenID.insert( make_pair( node, invalid_ID ));
                    }
                }
#ifdef _DEBUG_
                // check if a trainge is degenerated
                areaControl.GetPoints( elem, nodesCoords );
                double area = areaControl.GetValue( nodesCoords );
                if ( area <= DBL_MIN ) {
                    MESSAGE( "Warning: Degenerated " << elem );
                }
#endif
            }
            // look for degeneraged edges and vetices
            for (TopExp_Explorer expE(aShapeFace,TopAbs_EDGE); expE.More(); expE.Next())
            {
                TopoDS_Edge aShapeEdge = TopoDS::Edge( expE.Current() );
                if ( BRep_Tool::Degenerated( aShapeEdge ))
                {
                    degenNgIds.push_back( invalid_ID );
                    int* ptrIdOnEdge = & degenNgIds.back();
                    // remember edge id
                    int edgeID = meshDS->ShapeToIndex( aShapeEdge );
                    degenShapeIdToPtrNgId.insert( make_pair( edgeID, ptrIdOnEdge ));
                    // remember vertex id
                    int vertexID = meshDS->ShapeToIndex( TopExp::FirstVertex( aShapeEdge ));
                    degenShapeIdToPtrNgId.insert( make_pair( vertexID, ptrIdOnEdge ));
                }
            }
        }
    }
    // ---------------------------------
    // Feed the Netgen with surface mesh
    // ---------------------------------

    int Netgen_NbOfNodes = 0;
    int Netgen_param2ndOrder = 0;
    double Netgen_paramFine = 1.;
    double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );

    double Netgen_point[3];
    int Netgen_triangle[3];
    int Netgen_tetrahedron[4];

    Ng_Init();

    Ng_Mesh * Netgen_mesh = Ng_NewMesh();

    // set nodes and remember thier netgen IDs
    bool isDegen = false, hasDegen = !degenShapeIdToPtrNgId.empty();
    TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
    for ( ; n_id != nodeToNetgenID.end(); ++n_id )
    {
        const SMDS_MeshNode* node = n_id->first;

        // ignore nodes on degenerated edge
        if ( hasDegen ) {
            int shapeId = node->GetPosition()->GetShapeId();
            shId_ngId = degenShapeIdToPtrNgId.find( shapeId );
            isDegen = ( shId_ngId != degenShapeIdToPtrNgId.end() );
            if ( isDegen && *(shId_ngId->second) != invalid_ID ) {
                n_id->second = *(shId_ngId->second);
                continue;
            }
        }
        Netgen_point [ 0 ] = node->X();
        Netgen_point [ 1 ] = node->Y();
        Netgen_point [ 2 ] = node->Z();
        Ng_AddPoint(Netgen_mesh, Netgen_point);
        n_id->second = ++Netgen_NbOfNodes; // set netgen ID

        if ( isDegen ) // all nodes on a degen edge get one netgen ID
            *(shId_ngId->second) = n_id->second;
    }

    // set triangles
    list< const SMDS_MeshElement* >::iterator tria = triangles.begin();
    list< bool >::iterator                 reverse = isReversed.begin();
    for ( ; tria != triangles.end(); ++tria, ++reverse )
    {
        int i = 0;
        SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator();
        while ( triangleNodesIt->more() ) {
            const SMDS_MeshNode * node =
                static_cast<const SMDS_MeshNode *>(triangleNodesIt->next());
            if(myTool->IsMedium(node))
                continue;
            Netgen_triangle[ *reverse ? 2 - i : i ] = nodeToNetgenID[ node ];
            ++i;
        }
        if ( !hasDegen ||
                // ignore degenerated triangles, they have 2 or 3 same ids
                (Netgen_triangle[0] != Netgen_triangle[1] &&
                 Netgen_triangle[0] != Netgen_triangle[2] &&
                 Netgen_triangle[2] != Netgen_triangle[1] ))
        {
            Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
        }
    }

    // -------------------------
    // Generate the volume mesh
    // -------------------------

    Ng_Meshing_Parameters Netgen_param;

    Netgen_param.secondorder = Netgen_param2ndOrder;
    Netgen_param.fineness = Netgen_paramFine;
    Netgen_param.maxh = Netgen_paramSize;

    Ng_Result status;

    try {
#if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
        OCC_CATCH_SIGNALS;
#endif
        status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param);
    }
    catch (Standard_Failure& exc) {
        error(COMPERR_OCC_EXCEPTION, exc.GetMessageString());
        status = NG_VOLUME_FAILURE;
    }
    catch (...) {
        error("Exception in Ng_GenerateVolumeMesh()");
        status = NG_VOLUME_FAILURE;
    }
    if ( GetComputeError()->IsOK() ) {
        switch ( status ) {
        case NG_SURFACE_INPUT_ERROR:
            error( status, "NG_SURFACE_INPUT_ERROR");
        case NG_VOLUME_FAILURE:
            error( status, "NG_VOLUME_FAILURE");
        case NG_STL_INPUT_ERROR:
            error( status, "NG_STL_INPUT_ERROR");
        case NG_SURFACE_FAILURE:
            error( status, "NG_SURFACE_FAILURE");
        case NG_FILE_NOT_FOUND:
            error( status, "NG_FILE_NOT_FOUND");
        };
    }

    int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh);

    int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh);

    MESSAGE("End of Volume Mesh Generation. status=" << status <<
            ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes <<
            ", nb tetra: " << Netgen_NbOfTetra);

    // -------------------------------------------------------------------
    // Feed back the SMESHDS with the generated Nodes and Volume Elements
    // -------------------------------------------------------------------

    bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built
    if ( isOK )
    {
        // vector of nodes in which node index == netgen ID
        vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 );
        // insert old nodes into nodeVec
        for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) {
            nodeVec.at( n_id->second ) = n_id->first;
        }
        // create and insert new nodes into nodeVec
        int nodeIndex = Netgen_NbOfNodes + 1;
        int shapeID = meshDS->ShapeToIndex( aShape );
        for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex )
        {
            Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point );
            SMDS_MeshNode * node = meshDS->AddNode(Netgen_point[0],
                                                   Netgen_point[1],
                                                   Netgen_point[2]);
            meshDS->SetNodeInVolume(node, shapeID);
            nodeVec.at(nodeIndex) = node;
        }

        // create tetrahedrons
        for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex )
        {
            Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron);
            SMDS_MeshVolume * elt = myTool->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ),
                                    nodeVec.at( Netgen_tetrahedron[1] ),
                                    nodeVec.at( Netgen_tetrahedron[2] ),
                                    nodeVec.at( Netgen_tetrahedron[3] ));
            meshDS->SetMeshElementOnShape(elt, shapeID );
        }
    }

    Ng_DeleteMesh(Netgen_mesh);
    Ng_Exit();

    NETGENPlugin_Mesher::RemoveTmpFiles();

    return (status == NG_OK);
}
bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh&         aMesh,
                                     const TopoDS_Shape& aShape)
{
  netgen::multithread.terminate = 0;
  netgen::multithread.task = "Volume meshing";
  _progressByTic = -1.;

  SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();

  SMESH_MesherHelper helper(aMesh);
  bool _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
  helper.SetElementsOnShape( true );

  int Netgen_NbOfNodes = 0;
  double Netgen_point[3];
  int Netgen_triangle[3];

  NETGENPlugin_NetgenLibWrapper ngLib;
  Ng_Mesh * Netgen_mesh = ngLib._ngMesh;

  // vector of nodes in which node index == netgen ID
  vector< const SMDS_MeshNode* > nodeVec;
  {
    const int invalid_ID = -1;

    SMESH::Controls::Area areaControl;
    SMESH::Controls::TSequenceOfXYZ nodesCoords;

    // maps nodes to ng ID
    typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
    typedef TNodeToIDMap::value_type                     TN2ID;
    TNodeToIDMap nodeToNetgenID;

    // find internal shapes
    NETGENPlugin_Internals internals( aMesh, aShape, /*is3D=*/true );

    // ---------------------------------
    // Feed the Netgen with surface mesh
    // ---------------------------------

    TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType();
    bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID );

    SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh ));
    if ( _viscousLayersHyp )
    {
      netgen::multithread.percent = 3;
      proxyMesh = _viscousLayersHyp->Compute( aMesh, aShape );
      if ( !proxyMesh )
        return false;
    }
    if ( aMesh.NbQuadrangles() > 0 )
    {
      netgen::multithread.percent = 6;
      StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor;
      Adaptor->Compute(aMesh,aShape,proxyMesh.get());
      proxyMesh.reset( Adaptor );
    }

    for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next())
    {
      const TopoDS_Shape& aShapeFace = exFa.Current();
      int faceID = meshDS->ShapeToIndex( aShapeFace );
      bool isInternalFace = internals.isInternalShape( faceID );
      bool isRev = false;
      if ( checkReverse && !isInternalFace &&
           helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
        // IsReversedSubMesh() can work wrong on strongly curved faces,
        // so we use it as less as possible
        isRev = helper.IsReversedSubMesh( TopoDS::Face( aShapeFace ));

      const SMESHDS_SubMesh * aSubMeshDSFace = proxyMesh->GetSubMesh( aShapeFace );
      if ( !aSubMeshDSFace ) continue;
      SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
      while ( iteratorElem->more() ) // loop on elements on a geom face
      {
        // check mesh face
        const SMDS_MeshElement* elem = iteratorElem->next();
        if ( !elem )
          return error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
        if ( elem->NbCornerNodes() != 3 )
          return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters");

        // Add nodes of triangles and triangles them-selves to netgen mesh

        // add three nodes of triangle
        bool hasDegen = false;
        for ( int iN = 0; iN < 3; ++iN )
        {
          const SMDS_MeshNode* node = elem->GetNode( iN );
          const int shapeID = node->getshapeId();
          if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE &&
               helper.IsDegenShape( shapeID ))
          {
            // ignore all nodes on degeneraged edge and use node on its vertex instead
            TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value();
            node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS );
            hasDegen = true;
          }
          int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second;
          if ( ngID == invalid_ID )
          {
            ngID = ++Netgen_NbOfNodes;
            Netgen_point [ 0 ] = node->X();
            Netgen_point [ 1 ] = node->Y();
            Netgen_point [ 2 ] = node->Z();
            Ng_AddPoint(Netgen_mesh, Netgen_point);
          }
          Netgen_triangle[ isRev ? 2-iN : iN ] = ngID;
        }
        // add triangle
        if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] ||
                          Netgen_triangle[0] == Netgen_triangle[2] ||
                          Netgen_triangle[2] == Netgen_triangle[1] ))
          continue;

        Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);

        if ( isInternalFace && !proxyMesh->IsTemporary( elem ))
        {
          swap( Netgen_triangle[1], Netgen_triangle[2] );
          Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle);
        }
      } // loop on elements on a face
    } // loop on faces of a SOLID or SHELL

    // insert old nodes into nodeVec
    nodeVec.resize( nodeToNetgenID.size() + 1, 0 );
    TNodeToIDMap::iterator n_id = nodeToNetgenID.begin();
    for ( ; n_id != nodeToNetgenID.end(); ++n_id )
      nodeVec[ n_id->second ] = n_id->first;
    nodeToNetgenID.clear();

    if ( internals.hasInternalVertexInSolid() )
    {
      netgen::OCCGeometry occgeo;
      NETGENPlugin_Mesher::AddIntVerticesInSolids( occgeo,
                                                   (netgen::Mesh&) *Netgen_mesh,
                                                   nodeVec,
                                                   internals);
    }
  }

  // -------------------------
  // Generate the volume mesh
  // -------------------------

  return ( ngLib._isComputeOk = compute( aMesh, helper, nodeVec, Netgen_mesh));
}