当前位置: 首页 > news >正文

第9章:Clipper 类结构与初始化

第9章:Clipper 类结构与初始化

9.1 概述

Clipper 类继承自 ClipperBase,是用户直接使用的主要类。它实现了多边形布尔运算的核心算法,包括交集、并集、差集和异或运算。

9.2 类定义

public class Clipper : ClipperBase
{// 初始化选项常量public const int ioReverseSolution = 1;public const int ioStrictlySimple = 2;public const int ioPreserveCollinear = 4;// 私有成员private ClipType m_ClipType;private Maxima m_Maxima;private TEdge m_SortedEdges;private List<IntersectNode> m_IntersectList;IComparer<IntersectNode> m_IntersectNodeComparer;private bool m_ExecuteLocked;private PolyFillType m_ClipFillType;private PolyFillType m_SubjFillType;private List<Join> m_Joins;private List<Join> m_GhostJoins;private bool m_UsingPolyTree;#if use_xyzpublic delegate void ZFillCallback(IntPoint bot1, IntPoint top1, IntPoint bot2, IntPoint top2, ref IntPoint pt);public ZFillCallback ZFillFunction { get; set; }
#endif// 公共属性public bool ReverseSolution { get; set; }public bool StrictlySimple { get; set; }
}

9.3 成员变量详解

9.3.1 运算状态

成员 类型 说明
m_ClipType ClipType 当前裁剪操作类型
m_ClipFillType PolyFillType 裁剪多边形的填充规则
m_SubjFillType PolyFillType 主体多边形的填充规则
m_ExecuteLocked bool 防止重入执行
m_UsingPolyTree bool 是否使用 PolyTree 输出

9.3.2 数据结构

成员 类型 说明
m_Maxima Maxima 局部极大值链表
m_SortedEdges TEdge 排序边列表头
m_IntersectList List<IntersectNode> 交点列表
m_Joins List<Join> 连接点列表
m_GhostJoins List<Join> 幽灵连接点(水平边)

9.3.3 辅助结构

Maxima 结构

internal class Maxima
{internal cInt X;        // 极大值的 X 坐标internal Maxima Next;   // 下一个极大值internal Maxima Prev;   // 上一个极大值
}

IntersectNode 结构

public class IntersectNode
{internal TEdge Edge1;   // 参与交点的第一条边internal TEdge Edge2;   // 参与交点的第二条边internal IntPoint Pt;   // 交点坐标
}

Join 结构

internal class Join
{internal OutPt OutPt1;  // 第一个输出点internal OutPt OutPt2;  // 第二个输出点internal IntPoint OffPt; // 偏移点(用于判断连接方向)
}

9.4 构造函数

public Clipper(int InitOptions = 0) : base()
{m_Scanbeam = null;m_Maxima = null;m_ActiveEdges = null;m_SortedEdges = null;m_IntersectList = new List<IntersectNode>();m_IntersectNodeComparer = new MyIntersectNodeSort();m_ExecuteLocked = false;m_UsingPolyTree = false;m_PolyOuts = new List<OutRec>();m_Joins = new List<Join>();m_GhostJoins = new List<Join>();// 解析初始化选项ReverseSolution = (ioReverseSolution & InitOptions) != 0;StrictlySimple = (ioStrictlySimple & InitOptions) != 0;PreserveCollinear = (ioPreserveCollinear & InitOptions) != 0;#if use_xyzZFillFunction = null;
#endif
}

9.4.1 初始化选项

选项 说明
ioReverseSolution 1 反转结果多边形方向
ioStrictlySimple 2 确保结果是简单多边形
ioPreserveCollinear 4 保留共线顶点

使用示例

// 默认选项
Clipper c1 = new Clipper();// 反转结果
Clipper c2 = new Clipper(Clipper.ioReverseSolution);// 组合多个选项
Clipper c3 = new Clipper(Clipper.ioStrictlySimple | Clipper.ioPreserveCollinear
);

9.5 Execute 方法

Clipper 提供了四个 Execute 重载方法:

9.5.1 返回 Paths(简化版)

public bool Execute(ClipType clipType, Paths solution, PolyFillType FillType = PolyFillType.pftEvenOdd)
{return Execute(clipType, solution, FillType, FillType);
}

9.5.2 返回 Paths(完整版)

public bool Execute(ClipType clipType, Paths solution,PolyFillType subjFillType, PolyFillType clipFillType)
{if (m_ExecuteLocked) return false;if (m_HasOpenPaths) throw new ClipperException("Error: PolyTree struct is needed for open path clipping.");m_ExecuteLocked = true;solution.Clear();m_SubjFillType = subjFillType;m_ClipFillType = clipFillType;m_ClipType = clipType;m_UsingPolyTree = false;bool succeeded;try{succeeded = ExecuteInternal();if (succeeded) BuildResult(solution);}finally{DisposeAllPolyPts();m_ExecuteLocked = false;}return succeeded;
}

9.5.3 返回 PolyTree(简化版)

public bool Execute(ClipType clipType, PolyTree polytree,PolyFillType FillType = PolyFillType.pftEvenOdd)
{return Execute(clipType, polytree, FillType, FillType);
}

9.5.4 返回 PolyTree(完整版)

public bool Execute(ClipType clipType, PolyTree polytree,PolyFillType subjFillType, PolyFillType clipFillType)
{if (m_ExecuteLocked) return false;m_ExecuteLocked = true;m_SubjFillType = subjFillType;m_ClipFillType = clipFillType;m_ClipType = clipType;m_UsingPolyTree = true;bool succeeded;try{succeeded = ExecuteInternal();if (succeeded) BuildResult2(polytree);}finally{DisposeAllPolyPts();m_ExecuteLocked = false;}return succeeded;
}

9.6 ExecuteInternal 核心方法

private bool ExecuteInternal()
{try{Reset();m_SortedEdges = null;m_Maxima = null;cInt botY, topY;if (!PopScanbeam(out botY)) return false;InsertLocalMinimaIntoAEL(botY);while (PopScanbeam(out topY) || LocalMinimaPending()){ProcessHorizontals();m_GhostJoins.Clear();if (!ProcessIntersections(topY)) return false;ProcessEdgesAtTopOfScanbeam(topY);botY = topY;InsertLocalMinimaIntoAEL(botY);}// 修正方向foreach (OutRec outRec in m_PolyOuts){if (outRec.Pts == null || outRec.IsOpen) continue;if ((outRec.IsHole ^ ReverseSolution) == (Area(outRec) > 0))ReversePolyPtLinks(outRec.Pts);}// 处理连接JoinCommonEdges();// 清理输出foreach (OutRec outRec in m_PolyOuts){if (outRec.Pts == null) continue;else if (outRec.IsOpen)FixupOutPolyline(outRec);elseFixupOutPolygon(outRec);}// 处理严格简单模式if (StrictlySimple) DoSimplePolygons();return true;}finally {m_Joins.Clear();m_GhostJoins.Clear();          }
}

9.6.1 执行流程图

ExecuteInternal()│▼Reset()│▼
PopScanbeam(botY)│▼
InsertLocalMinimaIntoAEL(botY)│▼
┌──────────────────────────────┐
│  while (有扫描线或待处理LM)  │
│         │                    │
│         ▼                    │
│  ProcessHorizontals()        │
│         │                    │
│         ▼                    │
│  ProcessIntersections(topY)  │
│         │                    │
│         ▼                    │
│  ProcessEdgesAtTopOfScanbeam │
│         │                    │
│         ▼                    │
│  InsertLocalMinimaIntoAEL    │
│         │                    │
│         └────────────────────┘│▼方向修正│▼JoinCommonEdges()│▼输出清理│▼DoSimplePolygons() (可选)│▼返回结果

9.7 公共属性

9.7.1 ReverseSolution

public bool ReverseSolution { get; set; }

功能:反转结果多边形的方向。

默认行为

  • 外轮廓:逆时针(正面积)
  • 孔洞:顺时针(负面积)

启用后

  • 外轮廓:顺时针
  • 孔洞:逆时针

9.7.2 StrictlySimple

public bool StrictlySimple { get; set; }

功能:确保输出是严格简单的多边形(没有自交点)。

注意:启用此选项可能增加处理时间和输出多边形数量。

9.7.3 PreserveCollinear

public bool PreserveCollinear { get; set; }  // 继承自 ClipperBase

功能:保留共线顶点。

默认行为:移除共线顶点以简化输出。

9.8 Z 坐标处理(use_xyz)

#if use_xyz
public delegate void ZFillCallback(IntPoint bot1, IntPoint top1, IntPoint bot2, IntPoint top2, ref IntPoint pt);
public ZFillCallback ZFillFunction { get; set; }
#endif

用途:当两条边相交创建新点时,通过回调函数计算 Z 坐标。

使用示例

#if use_xyz
// 插值计算 Z
clipper.ZFillFunction = (bot1, top1, bot2, top2, ref IntPoint pt) =>
{// 基于两条边的端点插值计算交点的 Zdouble ratio1 = (double)(pt.Y - bot1.Y) / (top1.Y - bot1.Y);double z1 = bot1.Z + ratio1 * (top1.Z - bot1.Z);double ratio2 = (double)(pt.Y - bot2.Y) / (top2.Y - bot2.Y);double z2 = bot2.Z + ratio2 * (top2.Z - bot2.Z);pt.Z = (cInt)((z1 + z2) / 2);  // 平均值
};
#endif

9.9 使用示例

9.9.1 基本使用

// 创建多边形
Path subject = new Path();
subject.Add(new IntPoint(0, 0));
subject.Add(new IntPoint(100, 0));
subject.Add(new IntPoint(100, 100));
subject.Add(new IntPoint(0, 100));Path clip = new Path();
clip.Add(new IntPoint(50, 50));
clip.Add(new IntPoint(150, 50));
clip.Add(new IntPoint(150, 150));
clip.Add(new IntPoint(50, 150));// 执行裁剪
Clipper clipper = new Clipper();
clipper.AddPath(subject, PolyType.ptSubject, true);
clipper.AddPath(clip, PolyType.ptClip, true);Paths solution = new Paths();
bool success = clipper.Execute(ClipType.ctIntersection, solution);

9.9.2 使用 PolyTree 获取层次结构

Clipper clipper = new Clipper();
clipper.AddPaths(subjects, PolyType.ptSubject, true);
clipper.AddPaths(clips, PolyType.ptClip, true);PolyTree tree = new PolyTree();
clipper.Execute(ClipType.ctUnion, tree);// 遍历结果
void TraverseTree(PolyNode node, int depth)
{for (int i = 0; i < node.ChildCount; i++){PolyNode child = node.Childs[i];string type = child.IsHole ? "孔洞" : "外轮廓";Console.WriteLine($"{new string(' ', depth * 2)}{type}: {child.Contour.Count}点");TraverseTree(child, depth + 1);}
}TraverseTree(tree, 0);

9.9.3 复用 Clipper 实例

Clipper clipper = new Clipper();// 第一次操作
clipper.AddPaths(paths1, PolyType.ptSubject, true);
Paths result1 = new Paths();
clipper.Execute(ClipType.ctUnion, result1);// 清理并重用
clipper.Clear();
clipper.AddPaths(paths2, PolyType.ptSubject, true);
clipper.AddPaths(paths3, PolyType.ptClip, true);
Paths result2 = new Paths();
clipper.Execute(ClipType.ctDifference, result2);

9.10 本章小结

本章详细分析了 Clipper 类的结构:

  1. 类设计

    • 继承自 ClipperBase
    • 通过构造函数参数设置选项
    • 支持多种 Execute 重载
  2. 核心成员

    • 运算状态(ClipType、FillType等)
    • 数据结构(Maxima、IntersectList、Joins等)
    • 属性选项(ReverseSolution、StrictlySimple等)
  3. Execute 方法

    • 支持 Paths 和 PolyTree 两种输出
    • 可指定不同的填充规则
    • 通过 ExecuteInternal 执行核心算法
  4. 可选功能

    • Z 坐标处理(use_xyz)
    • 严格简单多边形
    • 保留共线顶点

理解 Clipper 类的结构是正确使用该库的基础。


上一章:局部极小值与扫描线 | 返回目录 | 下一章:布尔运算执行流程

http://www.jsqmd.com/news/622408/

相关文章:

  • 计算机毕业设计:Python全国气象数据采集与预报平台 Django框架 线性回归 数据分析 大数据 机器学习 大模型 气象数据(建议收藏)✅
  • 2026年4月江苏专业技术人员继续教育平台推荐:TOP5口碑服务评测对比领先 - 品牌推荐
  • 终极免费学术论文获取指南:如何用Unpaywall一键解锁付费墙
  • 最优化实践——从理论到代码:黄金分割法的Python/Matlab双实现
  • 南北阁Nanbeige 4.1-3B在AIGC内容创作中的应用:多模态生成实战
  • 第10章:布尔运算执行流程
  • NotaGen AI音乐生成:5分钟快速部署,零基础创作古典音乐
  • 深入理解 V8 引擎:C++ 与 JavaScript 的跨界传送门
  • 2026停车场照明改造品牌推荐及行业选择参考 - 品牌排行榜
  • 为什么AI时代真正稀缺的不是代码, 而是 Idea. 我因此做了一个“发现+判断”的项目
  • 2026年GESP3月认证C++五级真题解析
  • 第11章:活动边表 AEL 管理
  • SQL UPDATE 语句详解
  • 别再死记硬背了!用Python代码复现Photoshop 27种混合模式(附完整源码)
  • HTML5中Mediastream实现摄像头画面实时捕获
  • PowerPaint-V1 Gradio实现.NET图像处理应用:跨平台开发实战
  • 2026年4月酸性清洗剂品牌推荐,润滑剂/酸性清洗剂/氢氧化钠/碱性清洗剂/过氧乙酸,酸性清洗剂企业选哪家 - 品牌推荐师
  • SpringCloud快速入门--GateWay路由网关与Config配置中心型
  • 第13章:水平边处理算法
  • 如何轻松重置IDE试用期:终极JetBrains插件配置指南
  • NVIDIA Profile Inspector完全指南:解锁显卡隐藏性能的终极教程
  • Phi-4-mini-reasoning实战:分析并优化开源项目中的C++代码结构
  • Autovisor:智慧树课程自动化学习终极指南
  • 装了 QClaw 之后,我卸掉了好几个 Mac 软件
  • Phi-4-mini-reasoning完整指南:含health接口检测、日志定位、重启命令
  • 第14章:输出多边形构建
  • Eino-Workflow 实战详解
  • AI证书在面试中的价值分析
  • 投资者情绪指数(ISI与CICSI)二十年趋势解析:从数据到市场洞察
  • ICPC竞赛中的字符串优化技巧:以香港站K题LR String为例,详解预处理与加速查询