| name | clipper1 |
| description | Use when maintaining legacy code that depends on Clipper 1.x API for polygon clipping and offsetting. Clipper1: the original widely-deployed polygon boolean library. Prefer Clipper2 for new projects. |
| tags | ["2d","geometry","boolean","offset","polygon","csharp","python","cpp"] |
项目地址: https://github.com/AngusJohnson/Clipper
官方文档: http://www.angusj.com/delphi/clipper.php
NuGet: Clipper(多个第三方移植版)
许可证: Boost Software License 1.0
概述
Clipper1 主要特征:
- 整数算法(
IntPoint),通过 scale 系数模拟浮点
- 核心 API:
Clipper、ClipperOffset、ClipperBase
- 支持:布尔运算 + 偏移 + 多边形简化
- 多语言移植:C++(含 Header-only)、C#、Delphi/Pascal、JS、Python
新项目优先使用 Clipper2,其性能与 API 均优于 Clipper1。本 SKILL 主要用于维护遗留代码。
安装
dotnet add package Clipper
npm install js-clipper
pip install pyclipper
C++ 通常直接拷贝 clipper.hpp/.cpp 到工程。
核心数据结构
using ClipperLib;
using IntPoint = ClipperLib.IntPoint;
const long Scale = 1000000;
List<IntPoint> path = new() {
new IntPoint(0, 0),
new IntPoint(100 * Scale, 0),
new IntPoint(100 * Scale, 100 * Scale),
new IntPoint(0, 100 * Scale),
};
List<List<IntPoint>> paths = new() { path };
布尔运算
var clipper = new Clipper();
clipper.AddPath(subject, PolyType.ptSubject, true);
clipper.AddPath(clip, PolyType.ptClip, true);
var solution = new List<List<IntPoint>>();
clipper.Execute(ClipType.ctUnion, solution,
PolyFillType.pftNonZero, PolyFillType.pftNonZero);
ClipType:ctIntersection、ctUnion、ctDifference、ctXor
PolyFillType:pftEvenOdd、pftNonZero、pftPositive、pftNegative
多边形偏移(ClipperOffset)
var co = new ClipperOffset();
co.AddPaths(paths, JoinType.jtRound, EndType.etClosedPolygon);
var solution = new List<List<IntPoint>>();
co.Execute(ref solution, 10 * Scale);
JoinType:jtSquare、jtMiter、jtRound
EndType:etClosedPolygon、etClosedLine、etOpenButt、etOpenSquare、etOpenRound
PolyTree(保留环层级)
var tree = new PolyTree();
clipper.Execute(ClipType.ctUnion, tree,
PolyFillType.pftNonZero, PolyFillType.pftNonZero);
foreach (var node in tree.Childs)
foreach (var hole in node.Childs)
Console.WriteLine(hole.Contour.Count);
实用方法
double area = Clipper.Area(path);
bool ccw = Clipper.Orientation(path);
var cleaned = Clipper.CleanPolygon(path, 1.415);
var simp = Clipper.SimplifyPolygon(path, PolyFillType.pftNonZero);
var reverse = Clipper.ReversePath(path);
Python(pyclipper)
import pyclipper
scale = 1_000_000
subj = [[(0,0),(100,0),(100,100),(0,100)]]
clip = [[(50,50),(150,50),(150,150),(50,150)]]
pc = pyclipper.Pyclipper()
pc.AddPaths(pyclipper.scale_to_clipper(subj, scale),
pyclipper.PT_SUBJECT, True)
pc.AddPaths(pyclipper.scale_to_clipper(clip, scale),
pyclipper.PT_CLIP, True)
sol = pc.Execute(pyclipper.CT_UNION,
pyclipper.PFT_NONZERO,
pyclipper.PFT_NONZERO)
sol = pyclipper.scale_from_clipper(sol, scale)
pco = pyclipper.PyclipperOffset()
pco.AddPaths(pyclipper.scale_to_clipper(subj, scale),
pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
sol = pco.Execute(10 * scale)
C++ 用法
#include "clipper.hpp"
using namespace ClipperLib;
Paths subj{{ {0,0},{1000,0},{1000,1000},{0,1000} }};
Paths clip{{ {500,500},{1500,500},{1500,1500},{500,1500} }};
Clipper c;
c.AddPaths(subj, ptSubject, true);
c.AddPaths(clip, ptClip, true);
Paths solution;
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
典型工作流
工作流一:CAD/GIS 中多边形布尔运算
- 确定浮点精度需求,选定
scale 系数(如 1,000,000 表示微米精度)
- 将输入几何(Polygon/MultiLine 等)转换为
List<IntPoint> 格式,乘以 scale 取整
- 创建
Clipper 实例,AddPath 添加 Subject 和 Clip
- 调用
Execute 执行布尔运算(Union/Intersect/Difference/Xor)
- 将结果坐标除以 scale 还原为浮点坐标
- 如需保留孔洞关系,使用
PolyTree 替代 List<List<IntPoint>>
工作流二:多边形轮廓偏移(生成安全区/缓冲区)
- 构建多边形路径(闭合路径用
etClosedPolygon,开放用 etOpenButt 等)
- 创建
ClipperOffset,通过 AddPaths 添加输入
- 调用
Execute,正值为外扩(膨胀),负值为内缩(侵蚀)
- 检查结果是否自交——偏移前可先用
SimplifyPolygon 清理输入
- 输出偏移后的多边形用于刀路生成、安全距离计算等
与 Clipper2 主要差异
| 维度 | Clipper1 | Clipper2 |
|---|
| 数值类型 | 整数 + scale | 整数 / 浮点双模式 |
| 性能 | 较慢 | 显著更快 |
| API | Clipper 类 | 顶层 Union/Intersect/... |
| 简化 | SimplifyPolygon | SimplifyPaths 更准确 |
| 维护 | 已停止新功能 | 活跃维护 |
迁移要点:
IntPoint → Point64
- 移除 scale,使用
PathsD 或保留 Paths64
- API 改为静态函数
常见问题
| 问题 | 解决 |
|---|
| 浮点 → 整数舍入失真 | 增大 scale |
| 偏移产生自相交 | 偏移前 SimplifyPolygon |
| 闭合 path 多余首尾点 | Clipper 不需要重复首点 |
| Mac/Linux 编译失败 | 启用 use_int32/use_xyz 对应宏 |
AI 使用建议
- 推荐工作流模式:AI 助手应将几何数据统一转换为 Clipper 的整数坐标格式(选择恰当的 scale),然后按「创建 Clipper → 添加路径 → 执行运算 → 还原坐标」的流程处理。对于带孔多边形,优先使用
PolyTree 保留层级关系。
- 关键注意事项:① scale 选择需权衡精度与整数溢出——常用 1e6(微米级);② Clipper1 的闭合路径不需要重复首点;③
PolyFillType 需 Subject 和 Clip 各指定一次,非零环绕(NonZero)是最常用的填充规则;④ Clipper1 为非线程安全,多线程需各自持有实例。
- 常用代码模式:
new Clipper() → AddPath(subject, ptSubject, true) → AddPath(clip, ptClip, true) → Execute(ctUnion, solution, pftNonZero, pftNonZero)。
相关技能
参考资源