找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 827|回复: 0

[在线文档] How to Convert Polyfacemesh to 3dSolid

[复制链接]

已领礼包: 1268个

财富等级: 财源广进

发表于 2017-6-7 15:23:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
http://adndevblog.typepad.com/au ... esh-to-3dsolid.html

By Madhukar Moogala
We have an inbuilt AutoCAD command CONVTOSOLID, but this command is very limited doesn’t work effectively on
Polyfacemesh <AcDbPolyFaceMesh> entities.
We will create an in-memory subDMesh <AcDbSubDMesh> object from pfmesh [read as Polyfacemesh], first we will extract vertex and face information from pfmesh and use this information in constructing a subDMesh, convert this mesh object solid using convertToSolid API.
Before we get in to this, if you must know commands and their meaning while working on Meshs.
You can find full glossary at MeshPrimitives, a quick reference for the reader is below:
DIVMESHBOXWIDTH: Sets the number of subdivisions for the width of a mesh box along the Y axis.DIVMESHBOXHEIGHT : Sets the number of subdivisions for the height of a mesh box along the Z axis.DIVMESHCONEAXIS : Sets the number of subdivisions around the perimeter of the mesh cone base.DIVMESHCONEHEIGHT : Sets the number of subdivisions between the base and the point or top of the mesh cone.DIVMESHCONEBASE : Sets the number of subdivisions between the perimeter and the center point of the mesh cone base.DIVMESHCYLAXIS : Sets the number of subdivisions around the perimeter of the mesh cylinder base.DIVMESHCYLHEIGHT : Sets the number of subdivisions between the base and the top of the mesh cylinder.DIVMESHCYLBASE : Sets the number of radial subdivisions from the center of the mesh cylinder base to its perimeter.DIVMESHPYRLENGTH : Sets the number of subdivisions along each dimension of a mesh pyramid base.DIVMESHPYRHEIGHT : Sets the number of subdivisions between the base and the top of the mesh pyramid.DIVMESHPYRBASE : Sets the number of radial subdivisions between the center of the mesh pyramid base and its perimeter.DIVMESHSPHEREAXIS : Sets the number of radial subdivisions around the axis endpoint of the mesh sphere.DIVMESHSPHEREHEIGHT : Sets the number of subdivisions between the two axis endpoints of the mesh sphere.DIVMESHWEDGELENGTH : Sets the number of subdivisions for the length of a mesh wedge along the X axis.DIVMESHWEDGEWIDTH : Sets the number of subdivisions for the width of the mesh wedge along the Y axis.DIVMESHWEDGEHEIGHT : Sets the number of subdivisions for the height of the mesh wedge along the Z axis.DIVMESHWEDGESLOPE : Sets the number of subdivisions in the slope that extends from the apex of the wedge to the edge of the base.DIVMESHWEDGEBASE : Sets the number of subdivisions between the midpoint of the perimeter of triangular dimension of the mesh wedge.DIVMESHTORUSSECTION : Sets the number of subdivisions in the profile that sweeps the path of a mesh torus.DIVMESHTORUSPATH : Sets the number of subdivisions in the path that is swept by the profile of a mesh torusWe have an API
AcDbSubDMesh::setSubDMesh which creates Mesh entity for a given vertex array and face array,  first we will try to understand about vertex array and face array
What is vertex array ?
An array of vertex points that makes each face.
What is Face array ?
The face Array defines an array of faces, and each face is defined by a set of numbers. The first number specifies the number of vertices in the face, the following numbers are the indices of the vertices making up the face.  

Face array F[] = {N0,a0,...,aN0,N1,b0,...,bN1} Where N0 is Number of vertices in that particular face and a0,...,aN0 are the corresponding vertex indices in the Vertex array
To illustrate :
ec419b076fa7bd1c387a18e8fa77417e.jpg
Face array F[] for the above faces would be - {3, 0, 1, 2,     -3, 3, 4, 5,      3, 6, 7, 8};  A negative before a Number of vertices <for e.g.,-3> indicates the face is lying inside or a hole.
Code:
  void test4()
  {
  AcDbObjectId entId;
  ads_name ent_name;
  AcGePoint3d pickPnt;

  if (acedEntSel(_T("\n Pick a PFACE\n"), ent_name,
          asDblArray(pickPnt)) != RTNORM) return;
  if (!eOkVerify(acdbGetObjectId(entId, ent_name))) return;
  AcDbSmartObjectPointer<AcDbPolyFaceMesh> pFace(entId, AcDb::kForWrite);
  // polyface mesh
  if (!eOkVerify(pFace.openStatus())) return;

  AcGePoint3dArray vertexArray;
  AcArray<Adesk::Int32> faceArray;
  AcArray<AcCmColor> colorArray;
  AcArray<AcDbObjectId> materialArray;
  Acad::ErrorStatus es = GetPolyFaceMeshData(pFace, vertexArray, faceArray);
  if (es != eOk)
    return;

  /*Mesh Type ":
      Specifies the type of mesh to be used in the conversion. (FACETERMESHTYPE system variable)
      0 : Smooth Mesh Optimized. Sets the shape of the mesh faces to adapt to the shape of the mesh object.
      1 : Mostly Quads. Sets the shape of the mesh faces to be mostly quadrilateral.
      2 : Triangles. Sets the shape of the mesh faces to be mostly triangular.*/
  int faceterMeshType = 0;
  int nSmoothLevel = 0;
  int nMaxFaces = 0;
  resbuf rb;
  /*
  This variable sets the default level of smoothness that is applied to
  mesh that is created as a result of conversion from another object with the MESHSMOOTH command.
  The value cannot be greater than the value of SMOOTHMESHMAXLEV.
  */
  if (acedGetVar(_T("FACETERSMOOTHLEV"), &rb) == RTNORM)
  {
    nSmoothLevel = rb.resval.rint;
    nSmoothLevel = (nSmoothLevel < 0 ? 0 : nSmoothLevel);
  }        
  if (acedGetVar(_T("FACETERMESHTYPE"), &rb) == RTNORM)
  {
    faceterMeshType = rb.resval.rint;
  }
  int newSubdLevel = (faceterMeshType == 0) ? nSmoothLevel : 0;
  int oldSubdLevel = nSmoothLevel;
  // If oldSubdivLevel > SmoothMeshMaxLev, we need to reset oldSubdivLevel
  // value to SmoothMeshMaxLev.
  // If newSubdivLevel > SmoothMeshMaxLev, we need to reset newSubdivLevel
  // value to SmoothMeshMaxLev.

  //The valid range is from 1 to 255. The recommended range is 1 - 5.
  //Use this limit to prevent creating extremely dense meshes that might affect program performance.
  if (acedGetVar(_T("SMOOTHMESHMAXLEV"), &rb) == RTNORM)
  {
    int nMaxLevel = rb.resval.rint;
    if (nMaxLevel >= 0 && oldSubdLevel > nMaxLevel)
      oldSubdLevel = nMaxLevel;
    if (nMaxLevel >= 0 && newSubdLevel > nMaxLevel)
      newSubdLevel = nMaxLevel;
  }
  /*We create an in-memory mesh and convert mesh to solid*/
  AcDbSubDMesh* pSubDMesh = nullptr;
  if (!eOkVerify(CreateSubdMesh(vertexArray, faceArray, newSubdLevel, pSubDMesh)))
    return;
  pSubDMesh->setPropertiesFrom(pFace);   
  /*Create A solid and Convert SubDMesh to Solid*/
  AcDb3dSolid* pMeshSolid = new AcDb3dSolid();
  AcDbObjectId meshSolId;
  /*Now convert to Solid using CONVTOSOLID  API*/
  /*We will restrict to polygonal solid, we set false for smoothness, so not to abuse CPU*/
  pSubDMesh->convertToSolid(false, false, pMeshSolid);
  postToDatabase(NULL, pMeshSolid, meshSolId);
  /*Delete Pface */
  if (pFace)
  {
    pFace->erase();
  }


  }

Helper Methods
  /*Get the Mesh data, not accounted for Color and Material of Faces*/
  Acad::ErrorStatus GetPolyFaceMeshData(AcDbPolyFaceMesh* pMesh,
                       AcGePoint3dArray& vertexArray,
                       AcArray<Adesk::Int32>& faceArray)
  {
    if (pMesh == NULL)
      return eNullObjectPointer;
    const bool dbResident = (pMesh->database() != NULL);
    AcDbObjectIterator*  pIter = pMesh->vertexIterator();
    if (pIter == NULL)
      return eNullObjectPointer;
    Acad::ErrorStatus es;
    AcGePoint3d pt;
    AcDbVertex* pVtxObj = NULL;
    AcDbPolyFaceMeshVertex *pVertex = NULL;
    AcDbFaceRecord *pFaceRec = NULL;  
    int nFaces = pMesh->numFaces();  
    for (; !pIter->done(); pIter->step())
    {
      if (acdbHostApplicationServices()->userBreak())
      {
        delete pIter;
        return eUserBreak;
      }
      if (dbResident)
      {
        es = acdbOpenObject(pVtxObj, pIter->objectId(), AcDb::kForRead);
        if (es != Acad::eOk)
          continue;
      }
      else
      {
        pVtxObj = (AcDbVertex*)pIter->entity();
      }
      // Build vertex list
      if ((pVertex = AcDbPolyFaceMeshVertex::cast(pVtxObj)) != NULL)
      {
        pt = pVertex->position();
        vertexArray.append(pt);
      }// Build face list   
      else if ((pFaceRec = AcDbFaceRecord::cast(pVtxObj)) != NULL)
      {
        int count = 0;
        Adesk::Int16 indices[4], newIndex =0;
        for (int i = 0; i < 4; i++)
        {
          pFaceRec->getVertexAt(i, indices);
          if (indices == 0)
            break;
          count++;

        }
        // Quick triangle test by checking if the first vertex
        // is the same as the last vertex
        if (count == 4 && (abs(indices[0]) == abs(indices[3])))
          count = 3;

        // Per face record can be a triangle or quad
        if (count > 2)
        {              
          faceArray.append(count);
          for (int i = 0; i < count; i++)
          {
            newIndex = abs(indices) - 1;

            faceArray.append(newIndex);
          }
        }
      }
      if (dbResident)
        pVtxObj->close();
    }
    delete pIter;
    return eOk;
  }

  Acad::ErrorStatus CreateSubdMesh(AcGePoint3dArray& vertexArray,
              AcArray<Adesk::Int32>&  faceArray,
              int nSubdivLevel,
              AcDbSubDMesh*& poly)

  {
    if (vertexArray.length() <= 0 || faceArray.length() <= 0)
      return Acad::eCreateFailed;
    poly = new AcDbSubDMesh();
    ASSERT(poly != NULL);
    if (poly == NULL)
      return Acad::eCreateFailed;
    Acad::ErrorStatus es = poly->setSubDMesh(vertexArray, faceArray, nSubdivLevel);
    return es;

  }


论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-5-22 22:57 , Processed in 0.363453 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表