多边形剪裁算法
用 box 剪裁任意多边形。
算法原理:
原多边形↓ 用 LEFT 裁剪
中间多边形↓ 用 RIGHT 裁剪
中间多边形↓ 用 BOTTOM 裁剪
中间多边形↓ 用 TOP 裁剪
最终结果每一步都保证输出多边形在当前剪裁边的内侧。
- 处理 box 的 4 条边,对于每一条边:
- 遍历多边形的所有点,获取当前点 prev 和前一个点 curr 和这条边的关系,根据下面表格做处理,判断有哪些点要加入生成的多边形:
| prev | curr | 行为 |
| ------- | ------- | -------------- |
| inside | inside | 保留curr|
| outside | inside | 加交点 + curr |
| inside | outside | 加交点 |
| outside | outside | 全丢弃 |
- 遍历多边形的所有点,获取当前点 prev 和前一个点 curr 和这条边的关系,根据下面表格做处理,判断有哪些点要加入生成的多边形:
对于下图类型的 polygon 会出现折返线,暂未解决。

实现代码:
enum Edge { LEFT, RIGHT, BOTTOM, TOP };
// 判断这个点和box 的位置关系
bool inside(const zaPoint& p, Edge e, const zaBox& box) {switch (e) {case LEFT:return p.x() > box.l();case RIGHT:return p.x() < box.r();case BOTTOM:return p.y() > box.b();case TOP:return p.y() < box.t();}return false;
}static zaPoint
intersect(const zaPoint& a, const zaPoint& b, Edge e,const zaBox& box) {// 使用 __int128 防止中间溢出__int128 dx = (__int128)b.x() - a.x();__int128 dy = (__int128)b.y() - a.y();if (e == LEFT || e == RIGHT) {zaIntx X = (e == LEFT) ? box.l() : box.r();__int128 t_num = (__int128)X - a.x();__int128 y = (__int128)a.y() + t_num * dy / dx;return {X, (zaIntx)y};} else {zaIntx Y = (e == BOTTOM) ? box.b() : box.t();__int128 t_num = (__int128)Y - a.y();__int128 x = (__int128)a.x() + t_num * dx / dy;return zaPoint(x, Y);}
}abDensity1::clipPolygonWithBox(const zaPointArray& poly, const zaBox& box) {auto clipEdge = [&](const zaPointArray& in, Edge e) {vector<zaPoint> out;int n = (int)in.getNumPoints();if (n == 0) return zaPointArray(0);out.reserve(n + 2);for (int i = 0; i < n; ++i) {const zaPoint& curr = in[i];const zaPoint& prev = in[(i + n - 1) % n];bool currIn = inside(curr, e, box);bool prevIn = inside(prev, e, box);if (currIn) {if (!prevIn) {out.push_back(intersect(prev, curr, e, box));}out.push_back(curr);} else if (prevIn) {out.push_back(intersect(prev, curr, e, box));}}zaPointArray res(out.size());res.set(out.data(), out.size());return res;};zaPointArray result = poly;result = clipEdge(result, LEFT);result = clipEdge(result, RIGHT);result = clipEdge(result, BOTTOM);result = clipEdge(result, TOP);return result;
}