Writing Skills
writing-skills
效率与协作技能,来自 obra/superpowers,查看原文获取完整用途和操作说明。
clipper1【部署与运维】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.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
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:
项目地址(V6 官方主页): https://sourceforge.net/p/polyclipping/
说明: 原 GitHub 仓库
github.com/AngusJohnson/Clipper现重定向到 Clipper2,V6 末版为 6.4.2,已不再新增功能NuGet:
Clipper(多个第三方移植版)许可证: Boost Software License 1.0
Clipper1 主要特征:
IntPoint),通过 scale 系数模拟浮点Clipper、ClipperOffset、ClipperBase新项目优先使用 Clipper2,其性能与 API 均优于 Clipper1。本 SKILL 主要用于维护遗留代码。
# C#
dotnet add package Clipper
# JavaScript
npm install js-clipper # 或 clipper-lib
# Python
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); // 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
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
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);
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)
#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);
scale 系数(如 1,000,000 表示微米精度)List<IntPoint> 格式,乘以 scale 取整Clipper 实例,AddPath 添加 Subject 和 ClipExecute 执行布尔运算(Union/Intersect/Difference/Xor)PolyTree 替代 List<List<IntPoint>>etClosedPolygon,开放用 etOpenButt 等)ClipperOffset,通过 AddPaths 添加输入Execute,正值为外扩(膨胀),负值为内缩(侵蚀)SimplifyPolygon 清理输入| 维度 | Clipper1 | Clipper2 |
|---|---|---|
| 数值类型 | 整数 + scale | 整数 / 浮点双模式 |
| 性能 | 较慢 | 显著更快 |
| API | Clipper 类 | 顶层 Union/Intersect/... |
| 简化 | SimplifyPolygon | SimplifyPaths 更准确 |
| 维护 | 已停止新功能 | 活跃维护 |
迁移要点:
IntPoint → Point64PathsD 或保留 Paths64| 问题 | 解决 |
|---|---|
| 浮点 → 整数舍入失真 | 增大 scale |
| 偏移产生自相交 | 偏移前 SimplifyPolygon |
| 闭合 path 多余首尾点 | Clipper 不需要重复首点 |
| Mac/Linux 编译失败 | 启用 use_int32/use_xyz 对应宏 |
PolyTree 保留层级关系。PolyFillType 需 Subject 和 Clip 各指定一次,非零环绕(NonZero)是最常用的填充规则;④ Clipper1 为非线程安全,多线程需各自持有实例。new Clipper() → AddPath(subject, ptSubject, true) → AddPath(clip, ptClip, true) → Execute(ctUnion, solution, pftNonZero, pftNonZero)。