明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 297|回复: 0

ObjectArx 基于循环链表实现的SimplePolygon

[复制链接]
发表于 2025-6-28 20:47:57 | 显示全部楼层 |阅读模式
本帖最后由 枫叶棋语 于 2025-6-28 21:15 编辑
  1. #pragma once
  2. #include <vector>
  3. // AutoCAD几何头文件
  4. #include <gepnt2d.h>
  5. #include <gevec2d.h>
  6. #include <gelnsg2d.h>
  7. #include <CgalDef.h>
  8. #include <looplist.h>
  9. #include <gepnt3d.h>
  10. #include <dbpl.h>
  11. #include <getol.h>
  12. #include <type_traits>
  13. #include <utility>



  14. // ======================
  15. // AutoCAD兼容类型转换 ,使用LoopList 双向链表快速进行节点删增操作
  16. // ======================

  17. class VertexData {
  18. public:
  19.   union {
  20.     struct {
  21.       double x;
  22.       double y;
  23.     };
  24.     AcGePoint2d cadPoint;
  25.     CgalPoint2d cgalPoint;
  26.   };
  27.   // 最简单的构造函数
  28.   VertexData(const VertexData& other) :x(other.x), y(other.y) {}
  29.   VertexData(const AcGePoint2d& p) : cadPoint(p) {}
  30.   VertexData(const CgalPoint2d& p) : cgalPoint(p) {}
  31.   VertexData(double x, double y) :x(x), y(y) {}
  32.   // 隐式转换,自动转换类型
  33.   operator const AcGePoint2d& () const { return cadPoint; }
  34.   operator const CgalPoint2d& () const { return cgalPoint; }
  35.   operator const AcGePoint3d& () const { return { x,y,0 }; }
  36.   // 基本操作
  37.   void setPoint(const AcGePoint2d& p) { cadPoint = p; }
  38.   void setPoint(const CgalPoint2d& p) { cgalPoint = p; }

  39.   bool operator==(const VertexData& other) const {
  40.     return cadPoint.isEqualTo(other.cadPoint, { 1e-5,1e-5 });
  41.   }
  42.   bool operator < (const VertexData& other) const {
  43.     if (x == other.x) {
  44.       return  y < other.y;
  45.     }
  46.     return x < other.x;
  47.   }
  48.   AcGeVector2d  operator - (const VertexData& other)  const {
  49.     return this->cadPoint - other.cadPoint;
  50.   }
  51. };

  52. class SimplePolygon : public LoopList<VertexData> {
  53. private:
  54.   bool m_isclockwise = false;
  55.   // 多边形处理函数
  56.   void ensureLockWise(bool clockwise = true);
  57.   bool isSelfIntersected() const;
  58.   void removeCollinearVertices(AcGeTol tol = { 1e-5,1e-5 });

  59.   template<typename ResultType>
  60.   std::vector<ResultType>  convertSegments() const;

  61. public:
  62.   SimplePolygon() = default;
  63.   SimplePolygon(AcDbPolyline* polyline, bool isclockwise = false);
  64.   template <typename Container>
  65.   SimplePolygon(const Container& points, bool isclockwise = false);

  66.   bool isValid();
  67.   CgalPolygon2d toCgalPolygon2d() const;
  68.   auto toCgalLines() const { return convertSegments<CgalSegment2d>(); }
  69.   auto toCadLines() const { return convertSegments<AcGeLineSeg2d>(); }
  70.   auto toCgalPointPairs() const { return convertSegments<std::pair<CgalPoint2d, CgalPoint2d>>(); }
  71.   auto toCadPointPairs() const { return convertSegments<std::pair<AcGePoint2d, AcGePoint2d>>(); }

  72. };

  73. // 构造函数
  74. inline SimplePolygon::SimplePolygon(AcDbPolyline* polyline, bool isclockwise) : m_isclockwise(isclockwise) {
  75.   if (!polyline) return;
  76.   AcGePoint2d pnt;
  77.   for (uint i = 0; i < polyline->numVerts(); ++i) {
  78.     polyline->getPointAt(i, pnt);
  79.     push_back(VertexData(pnt));
  80.   }
  81.   this->uniqueAdjacent();
  82.   this->removeCollinearVertices();
  83.   ensureLockWise(m_isclockwise);

  84. }
  85. // 容器转换
  86. template<typename Container>
  87. inline SimplePolygon::SimplePolygon(const Container& points, bool)
  88. {
  89.   static_assert(
  90.     std::is_same_v<typename Container::value_type, AcGePoint2d>,
  91.     "Container must contain AcGePoint2d"
  92.     );
  93.   for (const auto& pnt : points) {
  94.     push_back(VertexData(pnt));
  95.   }
  96.   this->uniqueAdjacent();
  97.   this->removeCollinearVertices();
  98.   ensureLockWise(m_isclockwise);
  99. }

  100. // 确保多边形方向
  101. inline void SimplePolygon::ensureLockWise(bool clockwise) {
  102.   if (size() < 3) return;

  103.   double area = 0.0;
  104.   auto* current = front();
  105.   auto* next = current->next;

  106.   do {
  107.     const auto& pt1 = current->data;
  108.     const auto& pt2 = next->data;
  109.     area += (pt2.x - pt1.x) * (pt2.y + pt1.y);
  110.     current = next;
  111.     next = next->next;

  112.   } while (current != front());

  113.   bool isCurrentlyClockwise = area > 0;
  114.   if (isCurrentlyClockwise != clockwise) {
  115.     reverse();
  116.   }
  117.   m_isclockwise = clockwise;
  118. }

  119. //移除共线点
  120. inline void SimplePolygon::removeCollinearVertices(AcGeTol tol) {
  121.   acutPrintf(L"移除共线点开始,原始length = %d", length);

  122.   if (length < 3) return;

  123.   Node* start = front()->next; // 从第二个节点开始操作
  124.   Node* current = start;
  125.   int process = 0;
  126.   do {
  127.     Node* prev = current->prev;
  128.     Node* next = current->next;

  129.     // 计算方向向量(修正向量方向)
  130.     AcGeVector2d v1 = current->data - prev->data;
  131.     AcGeVector2d v2 = next->data - current->data;

  132.     if (v1.isParallelTo(v2, tol)) {
  133.       Node* toRemove = current;
  134.       current = next; // 先移动到下一节点
  135.       removeNode(toRemove);
  136.       continue;
  137.     }

  138.     current = next;
  139.     process++;

  140.   } while (length > 2 && process < length + 1);
  141.   acutPrintf(L"移除共线点结束,还剩length = %d", length);

  142. }

  143. // 检查自相交,偷个懒,直接调用CGAL 方法
  144. inline bool SimplePolygon::isSelfIntersected() const {
  145.   if (length < 4) return false;
  146.   // 转换为CGAL多边形
  147.   auto cgalPoly = toCgalPolygon2d();
  148.   return cgalPoly.is_simple() == false;
  149. }


  150. // 判断是否符合条件
  151. inline bool SimplePolygon::isValid() {
  152.   if (size() < 3) return false;
  153.   if (isSelfIntersected()) return false;
  154.   return true;
  155. }


  156. //获取边
  157. template<typename ResultType>
  158. inline std::vector<ResultType> SimplePolygon::convertSegments() const {
  159.   std::vector<ResultType> result;

  160.   if (length < 2) return result;
  161.   if (length == 2) {
  162.     result.reserve(1);
  163.     result.emplace_back(head->data, head->next->data);
  164.     return result;
  165.   }
  166.   result.reserve(length);
  167.   auto* current = head;
  168.   do {
  169.     result.emplace_back(current->data, current->next->data);
  170.     current = current->next;
  171.   } while (current != head);

  172.   return result;
  173. }

  174. //转换为CGAL Polygon2d
  175. inline CgalPolygon2d SimplePolygon::toCgalPolygon2d() const
  176. {
  177.   const std::vector<VertexData>& cadPoints = toVector();
  178.   return CgalPolygon2d(cadPoints.begin(), cadPoints.end());
  179. }

代码包括判断是否自相交,回环方向,获取边以及兼容CAD 和 CGAL 的二维坐标隐式转换,可以接入CGAL 的应用
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-7-27 04:20 , Processed in 0.173063 second(s), 22 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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