明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 253|回复: 11

两点和圆心点计算凸度方式:多段线增删顶点(支持弧段)

  [复制链接]
发表于 前天 10:29 | 显示全部楼层 |阅读模式
本帖最后由 gzxl 于 2025-8-11 10:42 编辑

保持起点不变及面积不变的情况下

继上一个贴: getSplitCurves 应用之:经量多段线添加顶点(支持弧段)
http://bbs.mjtd.com/thread-193321-1-1.html

此处采用两点和圆心点计算凸度方式



  1. // 多段线添加顶点(支持弧段)
  2. Acad::ErrorStatus es = Acad::eOk;
  3. ads_name ename;
  4. AcGePoint3d ptPick;
  5. if (RTNORM != acedEntSel(_T("\n请单选需要添加顶点的经量多段线:\n"), ename, asDblArray(ptPick)))
  6. {
  7.     acutPrintf(_T("\n您退出了选择!"));
  8.     return;
  9. }
  10. AcDbObjectId entId = AcDbObjectId::kNull;
  11. es = acdbGetObjectId(entId, ename);
  12. if (es != Acad::eOk)
  13. {
  14.     acutPrintf(_T("\n获取对象ID失败,错误码: es=%s\n"), acadErrorStatusText(es));
  15.     return;
  16. }
  17. AcDbEntity* pEnt = NULL;
  18. es = acdbOpenAcDbEntity(pEnt, entId, AcDb::kForRead);
  19. if (es != Acad::eOk)
  20. {
  21.     acutPrintf(_T("\n打开对象失败,错误码: es=%s\n"), acadErrorStatusText(es));
  22.     return;
  23. }
  24. // 检查选择对象是否是一条轻量多段线
  25. AcDbPolyline* pPolyline = AcDbPolyline::cast(pEnt);
  26. if (!pPolyline)
  27. {
  28.     acutPrintf(_T("\n您选择的对象不是经量多段线\n"));
  29.     pEnt->close();
  30.     return;
  31. }
  32. // 多段线是否闭合
  33. bool bClosed = pPolyline->isClosed();
  34. // 多段线颜色
  35. int nColorIndex = pPolyline->colorIndex();
  36. // 多段线全局宽度
  37. double dWidth = 0.0;
  38. pPolyline->getConstantWidth(dWidth);
  39. // 强制转换为曲线类
  40. AcDbCurve* pCurve = static_cast<AcDbCurve*>(pPolyline);
  41. // 用户输入
  42. TCHAR szKword1[10];
  43. acedInitGet(0, _T("A B"));
  44. int nRe1 = acedGetKword(_T("输入添加顶点方式选项[拾取点(A)/两节点间按指定距离(B)]:"), szKword1);
  45. if (nRe1 != RTNORM)
  46. {
  47.     pCurve->close();
  48.     pEnt->close();
  49. }
  50. int nCmdecho = 0, nOsmode = 0;
  51. // 回显系统变量, 0-关闭回显 1-打开回显
  52. GetVar(_T("cmdecho"), nCmdecho);
  53. // 关闭回显
  54. SetVar(_T("cmdecho"), 0);
  55. // 添加顶点点集
  56. AcGePoint3dArray addPoints;
  57. if (_tcscmp(szKword1, _T("A")) == 0)
  58. {
  59.     // 命令标志 ACRX_CMD_USEPICKSET | ACRX_CMD_REDRAW
  60.     // 对象捕捉系统变量
  61.     GetVar(_T("osmode"), nOsmode);
  62.     // 设置对象捕捉系统变量(最近点和中点)
  63.     SetVar(_T("osmode"), 514);
  64.     ads_name ss, aname;
  65.     // 创建一个选择集
  66.     acedSSAdd(NULL, NULL, ss);
  67.     // 从 objectID 获取 ads name
  68.     acdbGetAdsName(aname, entId);
  69.     // 将选定的实体 adsname 添加到选择集
  70.     acedSSAdd(aname, ss, ss);
  71.     // 选择集夹点
  72.     acedSSSetFirst(ss, NULL);
  73.     AcGePoint3d ptClick;
  74.     while (acedGetPoint(0, _T("\n指定添加顶点的位置:\n"), asDblArray(ptClick)) == RTNORM)
  75.     {
  76.         // 转换为WCS坐标
  77.         AcGePoint3d ptWcs;
  78.         acdbUcs2Wcs(asDblArray(ptClick), asDblArray(ptWcs), Adesk::kFalse);
  79.         // 获取曲线上离指定点最近的点(在 WCS 上)
  80.         AcGePoint3d ptNearest;
  81.         pCurve->getClosestPointTo(ptWcs, ptNearest);
  82.         double dParam = 0.0;
  83.         pCurve->getParamAtPoint(ptNearest, dParam);
  84.         int n = (int)dParam;
  85.         AcGePoint3d startVertPt, endVertPt;
  86.         pCurve->getPointAtParam((double)n, startVertPt);
  87.         pCurve->getPointAtParam((double)n + 1, endVertPt);
  88.         double dStartBugle = 0.0, dEndBugle = 0.0;
  89.         pPolyline->getBulgeAt(n, dStartBugle);
  90.         pPolyline->getBulgeAt(n + 1, dEndBugle);
  91.         double dInsertBugle = 0.0;
  92.         if (fabs(dStartBugle) > 1e-6)
  93.         {
  94.             // 通过两点和凸度,求圆心点
  95.             AcGePoint3d ptCenter = GetCenterPoint(startVertPt, endVertPt, dStartBugle);
  96.             // 两点和圆心点,求凸度
  97.             dInsertBugle = GetBulge(ptWcs, endVertPt, ptCenter);
  98.             dStartBugle = GetBulge(startVertPt, ptWcs, ptCenter);
  99.         }
  100.         pPolyline->upgradeOpen();
  101.         pPolyline->setBulgeAt(n, dStartBugle);
  102.         pPolyline->addVertexAt(n + 1, AcGePoint2d(ptWcs.x, ptWcs.y), dInsertBugle, dWidth, dWidth);
  103.         pPolyline->downgradeOpen();
  104.         //acutPrintf(_T("\n起始端点:%.3f,%.3f,%.6f\n"), startvertPt.x, startvertPt.y, dStartBugle);
  105.         //acutPrintf(_T("\n结束端点:%.3f,%.3f,%.6f\n"), endvertPt.x, endvertPt.y, dEndBugle);
  106.     }
  107.     acedSSFree(ss);
  108.     acedSSSetFirst(NULL, NULL);
  109.     pCurve->close();
  110.     pEnt->close();
  111.     // 还原对象捕捉系统变量
  112.     SetVar(_T("osmode"), nOsmode);
  113. }
  114. else if (_tcscmp(szKword1, _T("B")) == 0)
  115. {
  116.     TCHAR szKword2[10];
  117.     acedInitGet(0, _T("C D E"));
  118.     int nRe2 = acedGetKword(_T("输入添加顶点的多段线子段类型[直线段(C)/弧段(D)/全部(E)]:"), szKword2);
  119.     if (nRe2 != RTNORM)
  120.     {
  121.         pCurve->close();
  122.         pEnt->close();
  123.         return;
  124.     }
  125.     double dDist = 0.0;
  126.     if (!GetReal(_T("\n请输入指定间距"), 1.0, 1, dDist))
  127.     {
  128.         pCurve->close();
  129.         pEnt->close();
  130.         return;
  131.     }
  132.     // 曲线的起始参数和终点参数
  133.     double startParam, endParam;
  134.     es = pCurve->getStartParam(startParam);
  135.     es = pCurve->getEndParam(endParam);
  136.     for (double i = startParam; i <= endParam; ++i)
  137.     {
  138.         // 由参数获取对应的当前点
  139.         AcGePoint3d ptCurrent;
  140.         es = pCurve->getPointAtParam(i, ptCurrent);
  141.         // 获取当前点的凸度值
  142.         double dBugle = 0.0;
  143.         pPolyline->getBulgeAt((int)i, dBugle);
  144.         // 由参数获取的下一个顶点
  145.         AcGePoint3d ptNext;
  146.         es = pCurve->getPointAtParam(i + 1, ptNext);
  147.         // 获取当前点至起点的距离
  148.         double dLenCurrent = 0.0;
  149.         pCurve->getDistAtPoint(ptCurrent, dLenCurrent);
  150.         // 获取下一个顶点至起点的距离,曲线终点距离需要单独用 getDistAtParam 获取
  151.         double dLenNext = 0.0;
  152.         if (i == (endParam - 1))
  153.         {
  154.             pCurve->getDistAtParam(endParam, dLenNext);
  155.         }
  156.         else
  157.         {
  158.             pCurve->getDistAtPoint(ptNext, dLenNext);
  159.         }
  160.         // 弧段的圆心点
  161.         AcGePoint3d ptCenter;
  162.         // 直线段添加顶点选项
  163.         if (_tcscmp(szKword2, _T("C")) == 0)
  164.         {
  165.             // 当前点的凸度值为零,说明当前线段是直线段
  166.             if (dBugle < 1e-6)
  167.             {
  168.                 addPoints.append(ptCurrent);
  169.                 GetLineSegmentsPoints(dLenCurrent, dLenNext, dDist, pCurve, addPoints);
  170.             }
  171.             if (fabs(dBugle) > 1e-6)
  172.             {
  173.                 addPoints.append(AcGePoint3d(ptCurrent.x, ptCurrent.y, dBugle));
  174.             }
  175.         }
  176.         // 弧段添加顶点选项
  177.         else if (_tcscmp(szKword2, _T("D")) == 0)
  178.         {
  179.             if (dBugle < 1e-6)
  180.             {
  181.                 addPoints.append(ptCurrent);
  182.             }
  183.             if (fabs(dBugle) > 1e-6)
  184.             {
  185.                 GetArcSegmentsPoints(ptCurrent, ptNext, dBugle, dLenCurrent, dLenNext, dDist, pCurve, addPoints);
  186.             }
  187.         }
  188.         // 直线段和弧段都添加顶点
  189.         else if (_tcscmp(szKword2, _T("E")) == 0)
  190.         {
  191.             // 当前点的凸度值为零,说明当前线段是直线段
  192.             if (dBugle < 1e-6)
  193.             {
  194.                 addPoints.append(ptCurrent);
  195.                 GetLineSegmentsPoints(dLenCurrent, dLenNext, dDist, pCurve, addPoints);
  196.             }
  197.             else if (fabs(dBugle) > 1e-6)
  198.             {
  199.                 GetArcSegmentsPoints(ptCurrent, ptNext, dBugle, dLenCurrent, dLenNext, dDist, pCurve, addPoints);
  200.             }
  201.         }
  202.     }
  203.     if (addPoints.length() > 2)
  204.     {

  205.         AcGePoint3d firstPoint = addPoints.at(0);
  206.         AcGePoint3d lastPoint = addPoints.at(addPoints.length() - 1);
  207.         if (IsEqual(firstPoint, lastPoint))
  208.         {
  209.               addPoints.removeAt(addPoints.length() - 1);
  210.         }
  211.         // 创建新的经量多段线
  212.         int numVertices = addPoints.length();
  213.         AcDbPolyline *pNewPoly = new AcDbPolyline(numVertices);
  214.         for (int i = 0; i < numVertices; i++)
  215.         {
  216.             AcGePoint3d pt = addPoints.at(i);
  217.             pNewPoly->addVertexAt(i, AcGePoint2d(pt.x, pt.y), pt.z, dWidth, dWidth);
  218.         }
  219.         // 如果原多段线是闭合的,则设置新创建的多段线闭合
  220.         if (bClosed)
  221.         {
  222.             pNewPoly->setClosed(Adesk::kTrue);
  223.         }
  224.         pNewPoly->setColorIndex(nColorIndex);
  225.         AcDbObjectId polyId = PostToModelSpace(pNewPoly);
  226.         // 删除原曲线
  227.         pCurve->close();
  228.         if (acdbOpenObject(pEnt, entId, AcDb::kForWrite) == Acad::eOk)
  229.         {
  230.             pEnt->erase();
  231.             pEnt->close();
  232.         }
  233.         acutPrintf(_T("\n添加多段线顶点已完成!\n"));
  234.     }
  235. }
  236. // 还原回显系统变量
  237. SetVar(_T("cmdecho"), nCmdecho);


  1. // 两点和圆心点计算凸度方式:多段线删除顶点(支持弧段)
  2. // 命令标志 ACRX_CMD_USEPICKSET | ACRX_CMD_REDRAW

  3. Acad::ErrorStatus es = Acad::eOk;
  4. ads_name ename;
  5. AcGePoint3d ptPick;
  6. if (RTNORM != acedEntSel(_T("\n请单选需要添加顶点的经量多段线:\n"), ename, asDblArray(ptPick)))
  7. {
  8.     acutPrintf(_T("\n您退出了选择!"));
  9.     return;
  10. }
  11. AcDbObjectId entId = AcDbObjectId::kNull;
  12. es = acdbGetObjectId(entId, ename);
  13. if (es != Acad::eOk)
  14. {
  15.     acutPrintf(_T("\n获取对象ID失败,错误码: es=%s\n"), acadErrorStatusText(es));
  16.     return;
  17. }
  18. AcDbEntity* pEnt = NULL;
  19. es = acdbOpenAcDbEntity(pEnt, entId, AcDb::kForRead);
  20. if (es != Acad::eOk)
  21. {
  22.     acutPrintf(_T("\n打开对象失败,错误码: es=%s\n"), acadErrorStatusText(es));
  23.     return;
  24. }
  25. // 检查选择对象是否是一条轻量多段线
  26. AcDbPolyline* pPolyline = AcDbPolyline::cast(pEnt);
  27. if (!pPolyline)
  28. {
  29.     acutPrintf(_T("\n您选择的对象不是经量多段线\n"));
  30.     pEnt->close();
  31.     return;
  32. }
  33. // 强制转换为曲线类
  34. AcDbCurve* pCurve = static_cast<AcDbCurve*>(pPolyline);
  35. int nCmdecho = 0, nOsmode = 0;
  36. // 回显系统变量, 0-关闭回显 1-打开回显
  37. GetVar(_T("cmdecho"), nCmdecho);
  38. // 关闭回显
  39. SetVar(_T("cmdecho"), 0);
  40. // 对象捕捉系统变量
  41. GetVar(_T("osmode"), nOsmode);
  42. // 设置对象捕捉系统变量(端点)
  43. SetVar(_T("osmode"), 1);
  44. ads_name ss, aname;
  45. // 创建一个选择集
  46. acedSSAdd(NULL, NULL, ss);
  47. // 从 objectID 获取 ads name
  48. acdbGetAdsName(aname, entId);
  49. // 将选定的实体 adsname 添加到选择集
  50. acedSSAdd(aname, ss, ss);
  51. // 选择集夹点
  52. acedSSSetFirst(ss, NULL);
  53. AcGePoint3d ptClick;
  54. while (acedGetPoint(0, _T("\n指定删除顶点的位置:\n"), asDblArray(ptClick)) == RTNORM)
  55. {
  56.     // 转换为WCS坐标
  57.     AcGePoint3d ptWcs;
  58.     acdbUcs2Wcs(asDblArray(ptClick), asDblArray(ptWcs), Adesk::kFalse);
  59.     // 获取曲线上离指定点最近的点(在 WCS 上)
  60.     AcGePoint3d ptNearest;
  61.     pCurve->getClosestPointTo(ptWcs, ptNearest);
  62.     // 由参数获取点
  63.     double dParam = 0.0;
  64.     pCurve->getParamAtPoint(ptNearest, dParam);
  65.     int n = (int)dParam;
  66.     AcGePoint3d startVertPt, endVertPt;
  67.     pCurve->getPointAtParam((double)(n - 1), startVertPt);
  68.     pCurve->getPointAtParam((double)(n + 1), endVertPt);
  69.     double dStartBugle = 0.0;
  70.     pPolyline->getBulgeAt(n - 1, dStartBugle);
  71.     double dNewBugle = 0.0;
  72.     if (fabs(dStartBugle) > 1e-6)
  73.     {
  74.         // 通过两点和凸度,求圆心点
  75.         AcGePoint3d ptCenter = GetCenterPoint(startVertPt, ptWcs, dStartBugle);
  76.         // 两点和圆心点,求凸度
  77.         dNewBugle = GetBulge(startVertPt, endVertPt, ptCenter);
  78.     }
  79.     int num = pPolyline->numVerts();
  80.     if (num > 2)
  81.     {
  82.         pPolyline->upgradeOpen();
  83.         pPolyline->setBulgeAt(n - 1, dNewBugle);
  84.         pPolyline->removeVertexAt(n);
  85.         pPolyline->downgradeOpen();
  86.     }
  87.     else
  88.     {
  89.         acedAlert(_T("多段线顶点个数至少为2点!"));
  90.     }
  91. }
  92. acedSSFree(ss);
  93. acedSSSetFirst(NULL, NULL);
  94. pCurve->close();
  95. pEnt->close();
  96. // 还原对象捕捉系统变量
  97. SetVar(_T("osmode"), nOsmode);
  98. // 还原回显系统变量
  99. SetVar(_T("cmdecho"), nCmdecho);





游客,如果您要查看本帖隐藏内容请回复









本帖子中包含更多资源

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

x
回复

使用道具 举报

 楼主| 发表于 前天 11:15 | 显示全部楼层
运用于房产测绘中加点,逆向减点应用好像不多吧?
回复 支持 0 反对 1

使用道具 举报

发表于 前天 20:36 | 显示全部楼层
gzxl 发表于 2025-8-10 11:15
运用于房产测绘中加点,逆向减点应用好像不多吧?

点支持点错了
逆向减少点,还是很有用的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 前天 20:50 | 显示全部楼层
逆向减少点感觉原理一样的,就是 AcDbPolyline::removeVertexAt
遇到有弧段的就重新计算重设上一个点的凸度
回复 支持 反对

使用道具 举报

发表于 前天 11:05 | 显示全部楼层
其实我是想看看逆向减点的代码
回复 支持 反对

使用道具 举报

发表于 前天 21:30 | 显示全部楼层
感谢大神的分享
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 00:18 | 显示全部楼层
一楼已经补贴了个删除顶点。
回复 支持 反对

使用道具 举报

发表于 昨天 10:01 | 显示全部楼层
谢谢分享,很有用
回复 支持 反对

使用道具 举报

发表于 昨天 21:26 | 显示全部楼层
看看怎么样
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-8-12 09:29 , Processed in 0.173817 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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