Ejemplo n.º 1
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));
}
Ejemplo n.º 3
0
bool SMESH_Gen::Compute(SMESH_Mesh &          aMesh,
                        const TopoDS_Shape &  aShape,
                        const bool            aShapeOnly /*=false*/,
                        const bool            anUpward /*=false*/,
                        const ::MeshDimension aDim /*=::MeshDim_3D*/,
                        TSetOfInt*            aShapesId /*=0*/)
{
  MESSAGE("SMESH_Gen::Compute");
  MEMOSTAT;

  bool ret = true;

  SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);

  const bool includeSelf = true;
  const bool complexShapeFirst = true;
  const int  globalAlgoDim = 100;

  SMESH_subMeshIteratorPtr smIt;

  // Fix of Issue 22150. Due to !BLSURF->OnlyUnaryInput(), BLSURF computes edges
  // that must be computed by Projection 1D-2D when Projection asks to compute
  // one face only.
  SMESH_subMesh::compute_event computeEvent =
    aShapeOnly ? SMESH_subMesh::COMPUTE_SUBMESH : SMESH_subMesh::COMPUTE;

  if ( anUpward ) // is called from the below code in this method
  {
    // ===============================================
    // Mesh all the sub-shapes starting from vertices
    // ===============================================

    smIt = sm->getDependsOnIterator(includeSelf, !complexShapeFirst);
    while ( smIt->more() )
    {
      SMESH_subMesh* smToCompute = smIt->next();

      // do not mesh vertices of a pseudo shape
      const TopoDS_Shape&        shape = smToCompute->GetSubShape();
      const TopAbs_ShapeEnum shapeType = shape.ShapeType();
      if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX )
        continue;

      // check for preview dimension limitations
      if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
      {
        // clear compute state not to show previous compute errors
        //  if preview invoked less dimension less than previous
        smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
        continue;
      }

      if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
      {
        if (_compute_canceled)
          return false;
        setCurrentSubMesh( smToCompute );
        smToCompute->ComputeStateEngine( computeEvent );
        setCurrentSubMesh( NULL );
      }

      // we check all the sub-meshes here and detect if any of them failed to compute
      if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE &&
          ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape ))))
        ret = false;
      else if ( aShapesId )
        aShapesId->insert( smToCompute->GetId() );
    }
    //aMesh.GetMeshDS()->Modified();
    return ret;
  }
  else
  {
    // ================================================================
    // Apply algos that do NOT require discreteized boundaries
    // ("all-dimensional") and do NOT support sub-meshes, starting from
    // the most complex shapes and collect sub-meshes with algos that 
    // DO support sub-meshes
    // ================================================================

    list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes[4]; // for each dim

    // map to sort sm with same dim algos according to dim of
    // the shape the algo assigned to (issue 0021217).
    // Other issues influenced the algo applying order:
    // 21406, 21556, 21893, 20206
    multimap< int, SMESH_subMesh* > shDim2sm;
    multimap< int, SMESH_subMesh* >::reverse_iterator shDim2smIt;
    TopoDS_Shape algoShape;
    int prevShapeDim = -1, aShapeDim;

    smIt = sm->getDependsOnIterator(includeSelf, complexShapeFirst);
    while ( smIt->more() )
    {
      SMESH_subMesh* smToCompute = smIt->next();
      if ( smToCompute->GetComputeState() != SMESH_subMesh::READY_TO_COMPUTE )
        continue;

      const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
      aShapeDim = GetShapeDim( aSubShape );
      if ( aShapeDim < 1 ) break;
      
      // check for preview dimension limitations
      if ( aShapesId && aShapeDim > (int)aDim )
        continue;

      SMESH_Algo* algo = GetAlgo( smToCompute, &algoShape );
      if ( algo && !algo->NeedDiscreteBoundary() )
      {
        if ( algo->SupportSubmeshes() )
        {
          // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
          // so that more local algos to go first
          if ( prevShapeDim != aShapeDim )
          {
            prevShapeDim = aShapeDim;
            for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
              if ( shDim2smIt->first == globalAlgoDim )
                smWithAlgoSupportingSubmeshes[ aShapeDim ].push_back( shDim2smIt->second );
              else
                smWithAlgoSupportingSubmeshes[ aShapeDim ].push_front( shDim2smIt->second );
            shDim2sm.clear();
          }
          // add smToCompute to shDim2sm map
          if ( algoShape.IsSame( aMesh.GetShapeToMesh() ))
          {
            aShapeDim = globalAlgoDim; // to compute last
          }
          else
          {
            aShapeDim = GetShapeDim( algoShape );
            if ( algoShape.ShapeType() == TopAbs_COMPOUND )
            {
              TopoDS_Iterator it( algoShape );
              aShapeDim += GetShapeDim( it.Value() );
            }
          }
          shDim2sm.insert( make_pair( aShapeDim, smToCompute ));
        }
        else // Compute w/o support of sub-meshes
        {
          if (_compute_canceled)
            return false;
          setCurrentSubMesh( smToCompute );
          smToCompute->ComputeStateEngine( computeEvent );
          setCurrentSubMesh( NULL );
          if ( aShapesId )
            aShapesId->insert( smToCompute->GetId() );
        }
      }
    }
    // reload sub-meshes from shDim2sm into smWithAlgoSupportingSubmeshes
    for ( shDim2smIt = shDim2sm.rbegin(); shDim2smIt != shDim2sm.rend(); ++shDim2smIt )
      if ( shDim2smIt->first == globalAlgoDim )
        smWithAlgoSupportingSubmeshes[3].push_back( shDim2smIt->second );
      else
        smWithAlgoSupportingSubmeshes[0].push_front( shDim2smIt->second );

    // ======================================================
    // Apply all-dimensional algorithms supporing sub-meshes
    // ======================================================

    std::vector< SMESH_subMesh* > smVec;
    for ( aShapeDim = 0; aShapeDim < 4; ++aShapeDim )
    {
      // ------------------------------------------------
      // sort list of sub-meshes according to mesh order
      // ------------------------------------------------
      smVec.assign( smWithAlgoSupportingSubmeshes[ aShapeDim ].begin(),
                    smWithAlgoSupportingSubmeshes[ aShapeDim ].end() );
      aMesh.SortByMeshOrder( smVec );

      // ------------------------------------------------------------
      // compute sub-meshes with local uni-dimensional algos under
      // sub-meshes with all-dimensional algos
      // ------------------------------------------------------------
      // start from lower shapes
      for ( size_t i = 0; i < smVec.size(); ++i )
      {
        sm = smVec[i];

        // get a shape the algo is assigned to
        if ( !GetAlgo( sm, & algoShape ))
          continue; // strange...

        // look for more local algos
        smIt = sm->getDependsOnIterator(!includeSelf, !complexShapeFirst);
        while ( smIt->more() )
        {
          SMESH_subMesh* smToCompute = smIt->next();

          const TopoDS_Shape& aSubShape = smToCompute->GetSubShape();
          const int aShapeDim = GetShapeDim( aSubShape );
          //if ( aSubShape.ShapeType() == TopAbs_VERTEX ) continue;
          if ( aShapeDim < 1 ) continue;

          // check for preview dimension limitations
          if ( aShapesId && GetShapeDim( aSubShape.ShapeType() ) > (int)aDim )
            continue;

          SMESH_HypoFilter filter( SMESH_HypoFilter::IsAlgo() );
          filter
            .And( SMESH_HypoFilter::IsApplicableTo( aSubShape ))
            .And( SMESH_HypoFilter::IsMoreLocalThan( algoShape, aMesh ));

          if ( SMESH_Algo* subAlgo = (SMESH_Algo*) aMesh.GetHypothesis( smToCompute, filter, true))
          {
            if ( ! subAlgo->NeedDiscreteBoundary() ) continue;
            SMESH_Hypothesis::Hypothesis_Status status;
            if ( subAlgo->CheckHypothesis( aMesh, aSubShape, status ))
              // mesh a lower smToCompute starting from vertices
              Compute( aMesh, aSubShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId );
          }
        }
      }
      // --------------------------------
      // apply the all-dimensional algos
      // --------------------------------
      for ( size_t i = 0; i < smVec.size(); ++i )
      {
        sm = smVec[i];
        if ( sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE)
        {
          const TopAbs_ShapeEnum shapeType = sm->GetSubShape().ShapeType();
          // check for preview dimension limitations
          if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
            continue;

          if (_compute_canceled)
            return false;
          setCurrentSubMesh( sm );
          sm->ComputeStateEngine( computeEvent );
          setCurrentSubMesh( NULL );
          if ( aShapesId )
            aShapesId->insert( sm->GetId() );
        }
      }
    } // loop on shape dimensions

    // -----------------------------------------------
    // mesh the rest sub-shapes starting from vertices
    // -----------------------------------------------
    ret = Compute( aMesh, aShape, aShapeOnly, /*anUpward=*/true, aDim, aShapesId );
  }

  MESSAGE( "VSR - SMESH_Gen::Compute() finished, OK = " << ret);
  MEMOSTAT;

  SMESHDS_Mesh *myMesh = aMesh.GetMeshDS();
  MESSAGE("*** compactMesh after compute");
  myMesh->compactMesh();

  // fix quadratic mesh by bending iternal links near concave boundary
  if ( aShape.IsSame( aMesh.GetShapeToMesh() ) &&
       !aShapesId && // not preview
       ret ) // everything is OK
  {
    SMESH_MesherHelper aHelper( aMesh );
    if ( aHelper.IsQuadraticMesh() != SMESH_MesherHelper::LINEAR )
    {
      aHelper.FixQuadraticElements( sm->GetComputeError() );
    }
  }
  return ret;
}
Ejemplo n.º 4
0
Mesh::MeshObject* Mesher::createMesh() const
{
    // OCC standard mesher
    if (method == Standard) {
        Handle_StlMesh_Mesh aMesh = new StlMesh_Mesh();

        if (!shape.IsNull()) {
            BRepTools::Clean(shape);
#if OCC_VERSION_HEX >= 0x060801
            BRepMesh_IncrementalMesh bMesh(shape, deflection, Standard_False, angularDeflection);
            StlTransfer::RetrieveMesh(shape,aMesh);
#else
            StlTransfer::BuildIncrementalMesh(shape, deflection,
#if OCC_VERSION_HEX >= 0x060503
                Standard_True,
#endif
                aMesh);
#endif
        }

        std::map<uint32_t, std::vector<std::size_t> > colorMap;
        for (std::size_t i=0; i<colors.size(); i++) {
            colorMap[colors[i]].push_back(i);
        }

        bool createSegm = (static_cast<int>(colors.size()) == aMesh->NbDomains());

        MeshCore::MeshFacetArray faces;
        faces.reserve(aMesh->NbTriangles());

        std::set<Vertex> vertices;
        Standard_Real x1, y1, z1;
        Standard_Real x2, y2, z2;
        Standard_Real x3, y3, z3;

        std::vector< std::vector<unsigned long> > meshSegments;
        std::size_t numMeshFaces = 0;
        StlMesh_MeshExplorer xp(aMesh);
        for (Standard_Integer nbd=1;nbd<=aMesh->NbDomains();nbd++) {
            std::size_t numDomainFaces = 0;
            for (xp.InitTriangle(nbd); xp.MoreTriangle(); xp.NextTriangle()) {
                xp.TriangleVertices(x1,y1,z1,x2,y2,z2,x3,y3,z3);
                std::set<Vertex>::iterator it;
                MeshCore::MeshFacet face;

                // 1st vertex
                Vertex v1(x1,y1,z1);
                it = vertices.find(v1);
                if (it == vertices.end()) {
                    v1.i = vertices.size();
                    face._aulPoints[0] = v1.i;
                    vertices.insert(v1);
                }
                else {
                    face._aulPoints[0] = it->i;
                }

                // 2nd vertex
                Vertex v2(x2,y2,z2);
                it = vertices.find(v2);
                if (it == vertices.end()) {
                    v2.i = vertices.size();
                    face._aulPoints[1] = v2.i;
                    vertices.insert(v2);
                }
                else {
                    face._aulPoints[1] = it->i;
                }

                // 3rd vertex
                Vertex v3(x3,y3,z3);
                it = vertices.find(v3);
                if (it == vertices.end()) {
                    v3.i = vertices.size();
                    face._aulPoints[2] = v3.i;
                    vertices.insert(v3);
                }
                else {
                    face._aulPoints[2] = it->i;
                }

                // make sure that we don't insert invalid facets
                if (face._aulPoints[0] != face._aulPoints[1] &&
                    face._aulPoints[1] != face._aulPoints[2] &&
                    face._aulPoints[2] != face._aulPoints[0]) {
                    faces.push_back(face);
                    numDomainFaces++;
                }
            }

            // add a segment for the face
            if (createSegm || this->segments) {
                std::vector<unsigned long> segment(numDomainFaces);
                std::generate(segment.begin(), segment.end(), Base::iotaGen<unsigned long>(numMeshFaces));
                numMeshFaces += numDomainFaces;
                meshSegments.push_back(segment);
            }
        }

        MeshCore::MeshPointArray verts;
        verts.resize(vertices.size());
        for (auto it : vertices)
            verts[it.i] = it.toPoint();

        MeshCore::MeshKernel kernel;
        kernel.Adopt(verts, faces, true);

        Mesh::MeshObject* meshdata = new Mesh::MeshObject();
        meshdata->swap(kernel);
        if (createSegm) {
            int index = 0;
            for (auto it : colorMap) {
                Mesh::Segment segm(meshdata, false);
                for (auto jt : it.second) {
                    segm.addIndices(meshSegments[jt]);
                }
                segm.save(true);
                std::stringstream str;
                str << "patch" << index++;
                segm.setName(str.str());
                meshdata->addSegment(segm);
            }
        }
        else {
            for (auto it : meshSegments) {
                meshdata->addSegment(it);
            }
        }
        return meshdata;
    }

#ifndef HAVE_SMESH
    throw Base::Exception("SMESH is not available on this platform");
#else
    std::list<SMESH_Hypothesis*> hypoth;

    SMESH_Gen* meshgen = SMESH_Gen::get();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    int hyp=0;

    switch (method) {
#if defined (HAVE_NETGEN)
    case Netgen: {
        NETGENPlugin_Hypothesis_2D* hyp2d = new NETGENPlugin_Hypothesis_2D(hyp++,0,meshgen);

        if (fineness >=0 && fineness < 5) {
            hyp2d->SetFineness(NETGENPlugin_Hypothesis_2D::Fineness(fineness));
        }
        // user defined values
        else {
            if (growthRate > 0)
                hyp2d->SetGrowthRate(growthRate);
            if (nbSegPerEdge > 0)
                hyp2d->SetNbSegPerEdge(nbSegPerEdge);
            if (nbSegPerRadius > 0)
                hyp2d->SetNbSegPerRadius(nbSegPerRadius);
        }

        hyp2d->SetQuadAllowed(allowquad);
        hyp2d->SetOptimize(optimize);
        hyp2d->SetSecondOrder(secondOrder); // apply bisecting to create four triangles out of one
        hypoth.push_back(hyp2d);

        NETGENPlugin_NETGEN_2D* alg2d = new NETGENPlugin_NETGEN_2D(hyp++,0,meshgen);
        hypoth.push_back(alg2d);
    } break;
#endif
#if defined (HAVE_MEFISTO)
    case Mefisto: {
        if (maxLength > 0) {
            StdMeshers_MaxLength* hyp1d = new StdMeshers_MaxLength(hyp++, 0, meshgen);
            hyp1d->SetLength(maxLength);
            hypoth.push_back(hyp1d);
        }
        else if (localLength > 0) {
            StdMeshers_LocalLength* hyp1d = new StdMeshers_LocalLength(hyp++,0,meshgen);
            hyp1d->SetLength(localLength);
            hypoth.push_back(hyp1d);
        }
        else if (maxArea > 0) {
            StdMeshers_MaxElementArea* hyp2d = new StdMeshers_MaxElementArea(hyp++,0,meshgen);
            hyp2d->SetMaxArea(maxArea);
            hypoth.push_back(hyp2d);
        }
        else if (deflection > 0) {
            StdMeshers_Deflection1D* hyp1d = new StdMeshers_Deflection1D(hyp++,0,meshgen);
            hyp1d->SetDeflection(deflection);
            hypoth.push_back(hyp1d);
        }
        else if (minLen > 0 && maxLen > 0) {
            StdMeshers_Arithmetic1D* hyp1d = new StdMeshers_Arithmetic1D(hyp++,0,meshgen);
            hyp1d->SetLength(minLen, false);
            hyp1d->SetLength(maxLen, true);
            hypoth.push_back(hyp1d);
        }
        else {
            StdMeshers_AutomaticLength* hyp1d = new StdMeshers_AutomaticLength(hyp++,0,meshgen);
            hypoth.push_back(hyp1d);
        }

        {
            StdMeshers_NumberOfSegments* hyp1d = new StdMeshers_NumberOfSegments(hyp++,0,meshgen);
            hyp1d->SetNumberOfSegments(1);
            hypoth.push_back(hyp1d);
        }

        if (regular) {
            StdMeshers_Regular_1D* hyp1d = new StdMeshers_Regular_1D(hyp++,0,meshgen);
            hypoth.push_back(hyp1d);
        }

        StdMeshers_TrianglePreference* hyp2d_1 = new StdMeshers_TrianglePreference(hyp++,0,meshgen);
        hypoth.push_back(hyp2d_1);
        StdMeshers_MEFISTO_2D* alg2d = new StdMeshers_MEFISTO_2D(hyp++,0,meshgen);
        hypoth.push_back(alg2d);
    } break;
#endif
    default:
        break;
    }

    // Set new cout
    MeshingOutput stdcout;
    std::streambuf* oldcout = std::cout.rdbuf(&stdcout);

    // Apply the hypothesis and create the mesh
    mesh->ShapeToMesh(shape);
    for (int i=0; i<hyp;i++)
        mesh->AddHypothesis(shape, i);
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());

    // Restore old cout
    std::cout.rdbuf(oldcout);

    // build up the mesh structure
    SMDS_FaceIteratorPtr aFaceIter = mesh->GetMeshDS()->facesIterator();
    SMDS_NodeIteratorPtr aNodeIter = mesh->GetMeshDS()->nodesIterator();

    MeshCore::MeshPointArray verts;
    MeshCore::MeshFacetArray faces;
    verts.reserve(mesh->NbNodes());
    faces.reserve(mesh->NbFaces());

    int index=0;
    std::map<const SMDS_MeshNode*, int> mapNodeIndex;
    for (;aNodeIter->more();) {
        const SMDS_MeshNode* aNode = aNodeIter->next();
        MeshCore::MeshPoint p;
        p.Set((float)aNode->X(), (float)aNode->Y(), (float)aNode->Z());
        verts.push_back(p);
        mapNodeIndex[aNode] = index++;
    }
    for (;aFaceIter->more();) {
        const SMDS_MeshFace* aFace = aFaceIter->next();
        if (aFace->NbNodes() == 3) {
            MeshCore::MeshFacet f;
            for (int i=0; i<3;i++) {
                const SMDS_MeshNode* node = aFace->GetNode(i);
                f._aulPoints[i] = mapNodeIndex[node];
            }
            faces.push_back(f);
        }
        else if (aFace->NbNodes() == 4) {
            MeshCore::MeshFacet f1, f2;
            const SMDS_MeshNode* node0 = aFace->GetNode(0);
            const SMDS_MeshNode* node1 = aFace->GetNode(1);
            const SMDS_MeshNode* node2 = aFace->GetNode(2);
            const SMDS_MeshNode* node3 = aFace->GetNode(3);

            f1._aulPoints[0] = mapNodeIndex[node0];
            f1._aulPoints[1] = mapNodeIndex[node1];
            f1._aulPoints[2] = mapNodeIndex[node2];

            f2._aulPoints[0] = mapNodeIndex[node0];
            f2._aulPoints[1] = mapNodeIndex[node2];
            f2._aulPoints[2] = mapNodeIndex[node3];

            faces.push_back(f1);
            faces.push_back(f2);
        }
        else if (aFace->NbNodes() == 6) {
            MeshCore::MeshFacet f1, f2, f3, f4;
            const SMDS_MeshNode* node0 = aFace->GetNode(0);
            const SMDS_MeshNode* node1 = aFace->GetNode(1);
            const SMDS_MeshNode* node2 = aFace->GetNode(2);
            const SMDS_MeshNode* node3 = aFace->GetNode(3);
            const SMDS_MeshNode* node4 = aFace->GetNode(4);
            const SMDS_MeshNode* node5 = aFace->GetNode(5);

            f1._aulPoints[0] = mapNodeIndex[node0];
            f1._aulPoints[1] = mapNodeIndex[node3];
            f1._aulPoints[2] = mapNodeIndex[node5];

            f2._aulPoints[0] = mapNodeIndex[node1];
            f2._aulPoints[1] = mapNodeIndex[node4];
            f2._aulPoints[2] = mapNodeIndex[node3];

            f3._aulPoints[0] = mapNodeIndex[node2];
            f3._aulPoints[1] = mapNodeIndex[node5];
            f3._aulPoints[2] = mapNodeIndex[node4];

            f4._aulPoints[0] = mapNodeIndex[node3];
            f4._aulPoints[1] = mapNodeIndex[node4];
            f4._aulPoints[2] = mapNodeIndex[node5];

            faces.push_back(f1);
            faces.push_back(f2);
            faces.push_back(f3);
            faces.push_back(f4);
        }
        else if (aFace->NbNodes() == 8) {
            MeshCore::MeshFacet f1, f2, f3, f4, f5, f6;
            const SMDS_MeshNode* node0 = aFace->GetNode(0);
            const SMDS_MeshNode* node1 = aFace->GetNode(1);
            const SMDS_MeshNode* node2 = aFace->GetNode(2);
            const SMDS_MeshNode* node3 = aFace->GetNode(3);
            const SMDS_MeshNode* node4 = aFace->GetNode(4);
            const SMDS_MeshNode* node5 = aFace->GetNode(5);
            const SMDS_MeshNode* node6 = aFace->GetNode(6);
            const SMDS_MeshNode* node7 = aFace->GetNode(7);

            f1._aulPoints[0] = mapNodeIndex[node0];
            f1._aulPoints[1] = mapNodeIndex[node4];
            f1._aulPoints[2] = mapNodeIndex[node7];

            f2._aulPoints[0] = mapNodeIndex[node1];
            f2._aulPoints[1] = mapNodeIndex[node5];
            f2._aulPoints[2] = mapNodeIndex[node4];

            f3._aulPoints[0] = mapNodeIndex[node2];
            f3._aulPoints[1] = mapNodeIndex[node6];
            f3._aulPoints[2] = mapNodeIndex[node5];

            f4._aulPoints[0] = mapNodeIndex[node3];
            f4._aulPoints[1] = mapNodeIndex[node7];
            f4._aulPoints[2] = mapNodeIndex[node6];

            // Two solutions are possible:
            // <4,6,7>, <4,5,6> or <4,5,7>, <5,6,7>
            Base::Vector3d v4(node4->X(),node4->Y(),node4->Z());
            Base::Vector3d v5(node5->X(),node5->Y(),node5->Z());
            Base::Vector3d v6(node6->X(),node6->Y(),node6->Z());
            Base::Vector3d v7(node7->X(),node7->Y(),node7->Z());
            double dist46 = Base::DistanceP2(v4,v6);
            double dist57 = Base::DistanceP2(v5,v7);
            if (dist46 > dist57) {
                f5._aulPoints[0] = mapNodeIndex[node4];
                f5._aulPoints[1] = mapNodeIndex[node6];
                f5._aulPoints[2] = mapNodeIndex[node7];

                f6._aulPoints[0] = mapNodeIndex[node4];
                f6._aulPoints[1] = mapNodeIndex[node5];
                f6._aulPoints[2] = mapNodeIndex[node6];
            }
            else {
                f5._aulPoints[0] = mapNodeIndex[node4];
                f5._aulPoints[1] = mapNodeIndex[node5];
                f5._aulPoints[2] = mapNodeIndex[node7];

                f6._aulPoints[0] = mapNodeIndex[node5];
                f6._aulPoints[1] = mapNodeIndex[node6];
                f6._aulPoints[2] = mapNodeIndex[node7];
            }

            faces.push_back(f1);
            faces.push_back(f2);
            faces.push_back(f3);
            faces.push_back(f4);
            faces.push_back(f5);
            faces.push_back(f6);
        }
        else {
            Base::Console().Warning("Face with %d nodes ignored\n", aFace->NbNodes());
        }
    }

    // clean up
    TopoDS_Shape aNull;
    mesh->ShapeToMesh(aNull);
    mesh->Clear();
    delete mesh;
    for (std::list<SMESH_Hypothesis*>::iterator it = hypoth.begin(); it != hypoth.end(); ++it)
        delete *it;
    
    MeshCore::MeshKernel kernel;
    kernel.Adopt(verts, faces, true);

    Mesh::MeshObject* meshdata = new Mesh::MeshObject();
    meshdata->swap(kernel);
    return meshdata;
#endif // HAVE_SMESH
}
bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh&         aMesh,
        const TopoDS_Shape& aShape)
{
    netgen::multithread.terminate = 0;
    //netgen::multithread.task = "Surface meshing";

    SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
    SMESH_MesherHelper helper(aMesh);
    helper.SetElementsOnShape( true );

    NETGENPlugin_NetgenLibWrapper ngLib;
    ngLib._isComputeOk = false;

    netgen::Mesh   ngMeshNoLocSize;
#if NETGEN_VERSION < 6
    netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh,  & ngMeshNoLocSize };
#else
    netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh.get(),  & ngMeshNoLocSize };
#endif
    netgen::OCCGeometry occgeoComm;

    // min / max sizes are set as follows:
    // if ( _hypParameters )
    //    min and max are defined by the user
    // else if ( _hypLengthFromEdges )
    //    min = aMesher.GetDefaultMinSize()
    //    max = average segment len of a FACE
    // else if ( _hypMaxElementArea )
    //    min = aMesher.GetDefaultMinSize()
    //    max = f( _hypMaxElementArea )
    // else
    //    min = aMesher.GetDefaultMinSize()
    //    max = max segment len of a FACE

    NETGENPlugin_Mesher aMesher( &aMesh, aShape, /*isVolume=*/false);
    aMesher.SetParameters( _hypParameters ); // _hypParameters -> netgen::mparam
    const bool toOptimize = _hypParameters ? _hypParameters->GetOptimize() : true;
    if ( _hypMaxElementArea )
    {
        netgen::mparam.maxh = sqrt( 2. * _hypMaxElementArea->GetMaxArea() / sqrt(3.0) );
    }
    if ( _hypQuadranglePreference )
        netgen::mparam.quad = true;

    // local size is common for all FACEs in aShape?
    const bool isCommonLocalSize = ( !_hypLengthFromEdges && !_hypMaxElementArea && netgen::mparam.uselocalh );
    const bool isDefaultHyp = ( !_hypLengthFromEdges && !_hypMaxElementArea && !_hypParameters );

    if ( isCommonLocalSize ) // compute common local size in ngMeshes[0]
    {
        //list< SMESH_subMesh* > meshedSM[4]; --> all sub-shapes are added to occgeoComm
        aMesher.PrepareOCCgeometry( occgeoComm, aShape, aMesh );//, meshedSM );

        // local size set at MESHCONST_ANALYSE step depends on
        // minh, face_maxh, grading and curvaturesafety; find minh if not set by the user
        if ( !_hypParameters || netgen::mparam.minh < DBL_MIN )
        {
            if ( !_hypParameters )
                netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam() / 3.;
            netgen::mparam.minh = aMesher.GetDefaultMinSize( aShape, netgen::mparam.maxh );
        }
        // set local size depending on curvature and NOT closeness of EDGEs
        netgen::occparam.resthcloseedgeenable = false;
        //netgen::occparam.resthcloseedgefac = 1.0 + netgen::mparam.grading;
        occgeoComm.face_maxh = netgen::mparam.maxh;
        netgen::OCCSetLocalMeshSize( occgeoComm, *ngMeshes[0] );
        occgeoComm.emap.Clear();
        occgeoComm.vmap.Clear();

        // set local size according to size of existing segments
        const double factor = netgen::occparam.resthcloseedgefac;
        TopTools_IndexedMapOfShape edgeMap;
        TopExp::MapShapes( aMesh.GetShapeToMesh(), TopAbs_EDGE, edgeMap );
        for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
        {
            const TopoDS_Shape& edge = edgeMap( iE );
            if ( SMESH_Algo::isDegenerated( TopoDS::Edge( edge ))/* ||
           helper.IsSubShape( edge, aShape )*/)
                continue;
            SMESHDS_SubMesh* smDS = meshDS->MeshElements( edge );
            if ( !smDS ) continue;
            SMDS_ElemIteratorPtr segIt = smDS->GetElements();
            while ( segIt->more() )
            {
                const SMDS_MeshElement* seg = segIt->next();
                SMESH_TNodeXYZ n1 = seg->GetNode(0);
                SMESH_TNodeXYZ n2 = seg->GetNode(1);
                gp_XYZ p = 0.5 * ( n1 + n2 );
                netgen::Point3d pi(p.X(), p.Y(), p.Z());
                ngMeshes[0]->RestrictLocalH( pi, factor * ( n1 - n2 ).Modulus() );
            }
        }
    }
    netgen::mparam.uselocalh = toOptimize; // restore as it is used at surface optimization

    // ==================
    // Loop on all FACEs
    // ==================

    vector< const SMDS_MeshNode* > nodeVec;

    TopExp_Explorer fExp( aShape, TopAbs_FACE );
    for ( int iF = 0; fExp.More(); fExp.Next(), ++iF )
    {
        TopoDS_Face F = TopoDS::Face( fExp.Current() /*.Oriented( TopAbs_FORWARD )*/);
        int    faceID = meshDS->ShapeToIndex( F );
        SMESH_ComputeErrorPtr& faceErr = aMesh.GetSubMesh( F )->GetComputeError();

        _quadraticMesh = helper.IsQuadraticSubMesh( F );
        const bool ignoreMediumNodes = _quadraticMesh;

        // build viscous layers if required
        if ( F.Orientation() != TopAbs_FORWARD &&
                F.Orientation() != TopAbs_REVERSED )
            F.Orientation( TopAbs_FORWARD ); // avoid pb with TopAbs_INTERNAL
        SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F );
        if ( !proxyMesh )
            continue;

        // ------------------------
        // get all EDGEs of a FACE
        // ------------------------
        TSideVector wires =
            StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, faceErr, proxyMesh );
        if ( faceErr && !faceErr->IsOK() )
            continue;
        int nbWires = wires.size();
        if ( nbWires == 0 )
        {
            faceErr.reset
            ( new SMESH_ComputeError
              ( COMPERR_ALGO_FAILED, "Problem in StdMeshers_FaceSide::GetFaceWires()" ));
            continue;
        }
        if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments
        {
            faceErr.reset
            ( new SMESH_ComputeError
              ( COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments()) );
            continue;
        }

        // ----------------------
        // compute maxh of a FACE
        // ----------------------

        if ( !_hypParameters )
        {
            double edgeLength = 0;
            if (_hypLengthFromEdges )
            {
                // compute edgeLength as an average segment length
                int nbSegments = 0;
                for ( int iW = 0; iW < nbWires; ++iW )
                {
                    edgeLength += wires[ iW ]->Length();
                    nbSegments += wires[ iW ]->NbSegments();
                }
                if ( nbSegments )
                    edgeLength /= nbSegments;
                netgen::mparam.maxh = edgeLength;
            }
            else if ( isDefaultHyp )
            {
                // set edgeLength by a longest segment
                double maxSeg2 = 0;
                for ( int iW = 0; iW < nbWires; ++iW )
                {
                    const UVPtStructVec& points = wires[ iW ]->GetUVPtStruct();
                    if ( points.empty() )
                        return error( COMPERR_BAD_INPUT_MESH );
                    gp_Pnt pPrev = SMESH_TNodeXYZ( points[0].node );
                    for ( size_t i = 1; i < points.size(); ++i )
                    {
                        gp_Pnt p = SMESH_TNodeXYZ( points[i].node );
                        maxSeg2 = Max( maxSeg2, p.SquareDistance( pPrev ));
                        pPrev = p;
                    }
                }
                edgeLength = sqrt( maxSeg2 ) * 1.05;
                netgen::mparam.maxh = edgeLength;
            }
            if ( netgen::mparam.maxh < DBL_MIN )
                netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam();

            if ( !isCommonLocalSize )
            {
                netgen::mparam.minh = aMesher.GetDefaultMinSize( F, netgen::mparam.maxh );
            }
        }

        // prepare occgeom
        netgen::OCCGeometry occgeom;
        occgeom.shape = F;
        occgeom.fmap.Add( F );
        occgeom.CalcBoundingBox();
        occgeom.facemeshstatus.SetSize(1);
        occgeom.facemeshstatus = 0;
        occgeom.face_maxh_modified.SetSize(1);
        occgeom.face_maxh_modified = 0;
        occgeom.face_maxh.SetSize(1);
        occgeom.face_maxh = netgen::mparam.maxh;

        // -------------------------
        // Fill netgen mesh
        // -------------------------

        // MESHCONST_ANALYSE step may lead to a failure, so we make an attempt
        // w/o MESHCONST_ANALYSE at the second loop
        int err = 0;
        enum { LOC_SIZE, NO_LOC_SIZE };
        int iLoop = isCommonLocalSize ? 0 : 1;
        for ( ; iLoop < 2; iLoop++ )
        {
            //bool isMESHCONST_ANALYSE = false;
            InitComputeError();

            netgen::Mesh * ngMesh = ngMeshes[ iLoop ];
            ngMesh->DeleteMesh();

            if ( iLoop == NO_LOC_SIZE )
            {
                ngMesh->SetGlobalH ( mparam.maxh );
                ngMesh->SetMinimalH( mparam.minh );
                Box<3> bb = occgeom.GetBoundingBox();
                bb.Increase (bb.Diam()/10);
                ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparam.grading);
            }

            nodeVec.clear();
            faceErr = aMesher.AddSegmentsToMesh( *ngMesh, occgeom, wires, helper, nodeVec,
                                                 /*overrideMinH=*/!_hypParameters);
            if ( faceErr && !faceErr->IsOK() )
                break;

            //if ( !isCommonLocalSize )
            //limitSize( ngMesh, mparam.maxh * 0.8);

            // -------------------------
            // Generate surface mesh
            // -------------------------

            const int startWith = MESHCONST_MESHSURFACE;
            const int endWith   = toOptimize ? MESHCONST_OPTSURFACE : MESHCONST_MESHSURFACE;

            SMESH_Comment str;
            try {
                OCC_CATCH_SIGNALS;

#if NETGEN_VERSION >=6
                std::shared_ptr<netgen::Mesh> mesh_ptr(ngMesh,  [](netgen::Mesh*) {});
                err = netgen::OCCGenerateMesh(occgeom, mesh_ptr, netgen::mparam, startWith, endWith);
#elif NETGEN_VERSION > 4
                err = netgen::OCCGenerateMesh(occgeom, ngMesh, netgen::mparam, startWith, endWith);
#else
                char *optstr = 0;
                err = netgen::OCCGenerateMesh(occgeom, ngMesh, startWith, endWith, optstr);
#endif
                if ( netgen::multithread.terminate )
                    return false;
                if ( err )
                    str << "Error in netgen::OCCGenerateMesh() at " << netgen::multithread.task;
            }
            catch (Standard_Failure& ex)
            {
                err = 1;
                str << "Exception in  netgen::OCCGenerateMesh()"
                    << " at " << netgen::multithread.task
                    << ": " << ex.DynamicType()->Name();
                if ( ex.GetMessageString() && strlen( ex.GetMessageString() ))
                    str << ": " << ex.GetMessageString();
            }
            catch (...) {
                err = 1;
                str << "Exception in  netgen::OCCGenerateMesh()"
                    << " at " << netgen::multithread.task;
            }
            if ( err )
            {
                if ( aMesher.FixFaceMesh( occgeom, *ngMesh, 1 ))
                    break;
                if ( iLoop == LOC_SIZE )
                {
                    netgen::mparam.minh = netgen::mparam.maxh;
                    netgen::mparam.maxh = 0;
                    for ( int iW = 0; iW < wires.size(); ++iW )
                    {
                        StdMeshers_FaceSidePtr wire = wires[ iW ];
                        const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
                        for ( size_t iP = 1; iP < uvPtVec.size(); ++iP )
                        {
                            SMESH_TNodeXYZ   p( uvPtVec[ iP ].node );
                            netgen::Point3d np( p.X(),p.Y(),p.Z());
                            double segLen = p.Distance( uvPtVec[ iP-1 ].node );
                            double   size = ngMesh->GetH( np );
                            netgen::mparam.minh = Min( netgen::mparam.minh, size );
                            netgen::mparam.maxh = Max( netgen::mparam.maxh, segLen );
                        }
                    }
                    //cerr << "min " << netgen::mparam.minh << " max " << netgen::mparam.maxh << endl;
                    netgen::mparam.minh *= 0.9;
                    netgen::mparam.maxh *= 1.1;
                    continue;
                }
                else
                {
                    faceErr.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, str ));
                }
            }


            // ----------------------------------------------------
            // Fill the SMESHDS with the generated nodes and faces
            // ----------------------------------------------------

            int nbNodes = ngMesh->GetNP();
            int nbFaces = ngMesh->GetNSE();

            int nbInputNodes = nodeVec.size()-1;
            nodeVec.resize( nbNodes+1, 0 );

            // add nodes
            for ( int ngID = nbInputNodes + 1; ngID <= nbNodes; ++ngID )
            {
                const MeshPoint& ngPoint = ngMesh->Point( ngID );
                SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2));
                nodeVec[ ngID ] = node;
            }

            // create faces
            int i,j;
            vector<const SMDS_MeshNode*> nodes;
            for ( i = 1; i <= nbFaces ; ++i )
            {
                const Element2d& elem = ngMesh->SurfaceElement(i);
                nodes.resize( elem.GetNP() );
                for (j=1; j <= elem.GetNP(); ++j)
                {
                    int pind = elem.PNum(j);
                    if ( pind < 1 )
                        break;
                    nodes[ j-1 ] = nodeVec[ pind ];
                    if ( nodes[ j-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE )
                    {
                        const PointGeomInfo& pgi = elem.GeomInfoPi(j);
                        meshDS->SetNodeOnFace( nodes[ j-1 ], faceID, pgi.u, pgi.v);
                    }
                }
                if ( j > elem.GetNP() )
                {
                    SMDS_MeshFace* face = 0;
                    if ( elem.GetType() == TRIG )
                        face = helper.AddFace(nodes[0],nodes[1],nodes[2]);
                    else
                        face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
                }
            }

            break;
        } // two attempts
    } // loop on FACEs

    return true;
}
Ejemplo n.º 6
0
Mesh::MeshObject* Mesher::createMesh() const
{
#ifndef HAVE_SMESH
    throw Base::Exception("SMESH is not available on this platform");
#else
    std::list<SMESH_Hypothesis*> hypoth;

    SMESH_Gen* meshgen = SMESH_Gen::get();
    SMESH_Mesh* mesh = meshgen->CreateMesh(0, true);
    int hyp=0;

    switch (method) {
#if defined (HAVE_NETGEN)
    case Netgen: {
        NETGENPlugin_Hypothesis_2D* hyp2d = new NETGENPlugin_Hypothesis_2D(hyp++,0,meshgen);

        if (fineness >=0 && fineness < 5) {
            hyp2d->SetFineness(NETGENPlugin_Hypothesis_2D::Fineness(fineness));
        }
        // user defined values
        else {
            if (growthRate > 0)
                hyp2d->SetGrowthRate(growthRate);
            if (nbSegPerEdge > 0)
                hyp2d->SetNbSegPerEdge(nbSegPerEdge);
            if (nbSegPerRadius > 0)
                hyp2d->SetNbSegPerRadius(nbSegPerRadius);
        }

        hyp2d->SetQuadAllowed(allowquad);
        hyp2d->SetOptimize(optimize);
        hyp2d->SetSecondOrder(secondOrder); // apply bisecting to create four triangles out of one
        hypoth.push_back(hyp2d);

        NETGENPlugin_NETGEN_2D* alg2d = new NETGENPlugin_NETGEN_2D(hyp++,0,meshgen);
        hypoth.push_back(alg2d);
    } break;
#endif
#if defined (HAVE_MEFISTO)
    case Mefisto: {
        if (maxLength > 0) {
            StdMeshers_MaxLength* hyp1d = new StdMeshers_MaxLength(hyp++, 0, meshgen);
            hyp1d->SetLength(maxLength);
            hypoth.push_back(hyp1d);
        }
        else if (localLength > 0) {
            StdMeshers_LocalLength* hyp1d = new StdMeshers_LocalLength(hyp++,0,meshgen);
            hyp1d->SetLength(localLength);
            hypoth.push_back(hyp1d);
        }
        else if (maxArea > 0) {
            StdMeshers_MaxElementArea* hyp2d = new StdMeshers_MaxElementArea(hyp++,0,meshgen);
            hyp2d->SetMaxArea(maxArea);
            hypoth.push_back(hyp2d);
        }
        else if (deflection > 0) {
            StdMeshers_Deflection1D* hyp1d = new StdMeshers_Deflection1D(hyp++,0,meshgen);
            hyp1d->SetDeflection(deflection);
            hypoth.push_back(hyp1d);
        }
        else if (minLen > 0 && maxLen > 0) {
            StdMeshers_Arithmetic1D* hyp1d = new StdMeshers_Arithmetic1D(hyp++,0,meshgen);
            hyp1d->SetLength(minLen, false);
            hyp1d->SetLength(maxLen, true);
            hypoth.push_back(hyp1d);
        }
        else {
            StdMeshers_AutomaticLength* hyp1d = new StdMeshers_AutomaticLength(hyp++,0,meshgen);
            hypoth.push_back(hyp1d);
        }

        {
            StdMeshers_NumberOfSegments* hyp1d = new StdMeshers_NumberOfSegments(hyp++,0,meshgen);
            hyp1d->SetNumberOfSegments(1);
            hypoth.push_back(hyp1d);
        }

        if (regular) {
            StdMeshers_Regular_1D* hyp1d = new StdMeshers_Regular_1D(hyp++,0,meshgen);
            hypoth.push_back(hyp1d);
        }

        StdMeshers_TrianglePreference* hyp2d_1 = new StdMeshers_TrianglePreference(hyp++,0,meshgen);
        hypoth.push_back(hyp2d_1);
        StdMeshers_MEFISTO_2D* alg2d = new StdMeshers_MEFISTO_2D(hyp++,0,meshgen);
        hypoth.push_back(alg2d);
    } break;
#endif
    default:
        break;
    }

    // Set new cout
    MeshingOutput stdcout;
    std::streambuf* oldcout = std::cout.rdbuf(&stdcout);

    // Apply the hypothesis and create the mesh
    mesh->ShapeToMesh(shape);
    for (int i=0; i<hyp;i++)
        mesh->AddHypothesis(shape, i);
    meshgen->Compute(*mesh, mesh->GetShapeToMesh());

    // Restore old cout
    std::cout.rdbuf(oldcout);

    // build up the mesh structure
    SMDS_FaceIteratorPtr aFaceIter = mesh->GetMeshDS()->facesIterator();
    SMDS_NodeIteratorPtr aNodeIter = mesh->GetMeshDS()->nodesIterator();

    MeshCore::MeshPointArray verts;
    MeshCore::MeshFacetArray faces;
    verts.reserve(mesh->NbNodes());
    faces.reserve(mesh->NbFaces());

    int index=0;
    std::map<const SMDS_MeshNode*, int> mapNodeIndex;
    for (;aNodeIter->more();) {
        const SMDS_MeshNode* aNode = aNodeIter->next();
        MeshCore::MeshPoint p;
        p.Set((float)aNode->X(), (float)aNode->Y(), (float)aNode->Z());
        verts.push_back(p);
        mapNodeIndex[aNode] = index++;
    }
    for (;aFaceIter->more();) {
        const SMDS_MeshFace* aFace = aFaceIter->next();
        if (aFace->NbNodes() == 3) {
            MeshCore::MeshFacet f;
            for (int i=0; i<3;i++) {
                const SMDS_MeshNode* node = aFace->GetNode(i);
                f._aulPoints[i] = mapNodeIndex[node];
            }
            faces.push_back(f);
        }
        else if (aFace->NbNodes() == 4) {
            MeshCore::MeshFacet f1, f2;
            const SMDS_MeshNode* node0 = aFace->GetNode(0);
            const SMDS_MeshNode* node1 = aFace->GetNode(1);
            const SMDS_MeshNode* node2 = aFace->GetNode(2);
            const SMDS_MeshNode* node3 = aFace->GetNode(3);

            f1._aulPoints[0] = mapNodeIndex[node0];
            f1._aulPoints[1] = mapNodeIndex[node1];
            f1._aulPoints[2] = mapNodeIndex[node2];

            f2._aulPoints[0] = mapNodeIndex[node0];
            f2._aulPoints[1] = mapNodeIndex[node2];
            f2._aulPoints[2] = mapNodeIndex[node3];

            faces.push_back(f1);
            faces.push_back(f2);
        }
        else if (aFace->NbNodes() == 6) {
            MeshCore::MeshFacet f1, f2, f3, f4;
            const SMDS_MeshNode* node0 = aFace->GetNode(0);
            const SMDS_MeshNode* node1 = aFace->GetNode(1);
            const SMDS_MeshNode* node2 = aFace->GetNode(2);
            const SMDS_MeshNode* node3 = aFace->GetNode(3);
            const SMDS_MeshNode* node4 = aFace->GetNode(4);
            const SMDS_MeshNode* node5 = aFace->GetNode(5);

            f1._aulPoints[0] = mapNodeIndex[node0];
            f1._aulPoints[1] = mapNodeIndex[node3];
            f1._aulPoints[2] = mapNodeIndex[node5];

            f2._aulPoints[0] = mapNodeIndex[node1];
            f2._aulPoints[1] = mapNodeIndex[node4];
            f2._aulPoints[2] = mapNodeIndex[node3];

            f3._aulPoints[0] = mapNodeIndex[node2];
            f3._aulPoints[1] = mapNodeIndex[node5];
            f3._aulPoints[2] = mapNodeIndex[node4];

            f4._aulPoints[0] = mapNodeIndex[node3];
            f4._aulPoints[1] = mapNodeIndex[node4];
            f4._aulPoints[2] = mapNodeIndex[node5];

            faces.push_back(f1);
            faces.push_back(f2);
            faces.push_back(f3);
            faces.push_back(f4);
        }
        else if (aFace->NbNodes() == 8) {
            MeshCore::MeshFacet f1, f2, f3, f4, f5, f6;
            const SMDS_MeshNode* node0 = aFace->GetNode(0);
            const SMDS_MeshNode* node1 = aFace->GetNode(1);
            const SMDS_MeshNode* node2 = aFace->GetNode(2);
            const SMDS_MeshNode* node3 = aFace->GetNode(3);
            const SMDS_MeshNode* node4 = aFace->GetNode(4);
            const SMDS_MeshNode* node5 = aFace->GetNode(5);
            const SMDS_MeshNode* node6 = aFace->GetNode(6);
            const SMDS_MeshNode* node7 = aFace->GetNode(7);

            f1._aulPoints[0] = mapNodeIndex[node0];
            f1._aulPoints[1] = mapNodeIndex[node4];
            f1._aulPoints[2] = mapNodeIndex[node7];

            f2._aulPoints[0] = mapNodeIndex[node1];
            f2._aulPoints[1] = mapNodeIndex[node5];
            f2._aulPoints[2] = mapNodeIndex[node4];

            f3._aulPoints[0] = mapNodeIndex[node2];
            f3._aulPoints[1] = mapNodeIndex[node6];
            f3._aulPoints[2] = mapNodeIndex[node5];

            f4._aulPoints[0] = mapNodeIndex[node3];
            f4._aulPoints[1] = mapNodeIndex[node7];
            f4._aulPoints[2] = mapNodeIndex[node6];

            // Two solutions are possible:
            // <4,6,7>, <4,5,6> or <4,5,7>, <5,6,7>
            Base::Vector3d v4(node4->X(),node4->Y(),node4->Z());
            Base::Vector3d v5(node5->X(),node5->Y(),node5->Z());
            Base::Vector3d v6(node6->X(),node6->Y(),node6->Z());
            Base::Vector3d v7(node7->X(),node7->Y(),node7->Z());
            double dist46 = Base::DistanceP2(v4,v6);
            double dist57 = Base::DistanceP2(v5,v7);
            if (dist46 > dist57) {
                f5._aulPoints[0] = mapNodeIndex[node4];
                f5._aulPoints[1] = mapNodeIndex[node6];
                f5._aulPoints[2] = mapNodeIndex[node7];

                f6._aulPoints[0] = mapNodeIndex[node4];
                f6._aulPoints[1] = mapNodeIndex[node5];
                f6._aulPoints[2] = mapNodeIndex[node6];
            }
            else {
                f5._aulPoints[0] = mapNodeIndex[node4];
                f5._aulPoints[1] = mapNodeIndex[node5];
                f5._aulPoints[2] = mapNodeIndex[node7];

                f6._aulPoints[0] = mapNodeIndex[node5];
                f6._aulPoints[1] = mapNodeIndex[node6];
                f6._aulPoints[2] = mapNodeIndex[node7];
            }

            faces.push_back(f1);
            faces.push_back(f2);
            faces.push_back(f3);
            faces.push_back(f4);
            faces.push_back(f5);
            faces.push_back(f6);
        }
        else {
            Base::Console().Warning("Face with %d nodes ignored\n", aFace->NbNodes());
        }
    }

    // clean up
    TopoDS_Shape aNull;
    mesh->ShapeToMesh(aNull);
    mesh->Clear();
    delete mesh;
    for (std::list<SMESH_Hypothesis*>::iterator it = hypoth.begin(); it != hypoth.end(); ++it)
        delete *it;
    
    MeshCore::MeshKernel kernel;
    kernel.Adopt(verts, faces, true);

    Mesh::MeshObject* meshdata = new Mesh::MeshObject();
    meshdata->swap(kernel);
    return meshdata;
#endif // HAVE_SMESH
}