C/C++ · 2026年3月4日 0

Clipper2 库详解:功能、C++ 使用教程与实战示例

一、Clipper2 库核心功能

Clipper2 是 AngusJohnson 开发的一款高性能、跨平台的 2D 多边形裁剪 / 偏移(Offset)C++ 库,是经典 Clipper 库的升级版,解决了原版本的精度、性能和功能短板,核心能力如下:

1. 核心功能

  • 多边形裁剪:支持对任意 2D 多边形(含简单多边形、带孔多边形)执行布尔运算(交集、并集、差集、异或);
  • 多边形偏移:实现多边形的向内 / 向外偏移(扩大 / 收缩),支持圆角、斜角等偏移样式,适用于轮廓加粗、路径扩边等场景;
  • 高精度计算:基于 64 位整数运算,避免浮点数精度丢失,可通过缩放因子适配浮点数坐标;
  • 跨平台兼容:纯 C++ 实现,无第三方依赖,支持 Windows、Linux、macOS 等主流平台;
  • 灵活的几何类型:支持闭合多边形(Polygon)、开放路径(Path),以及多多边形集合(PolyTree/Paths)。

2. 适用场景

  • GIS 地理数据处理、CAD 图形编辑;
  • 游戏开发中的碰撞检测、轮廓绘制;
  • 图像 /svg 路径裁剪、排版系统的区域计算。

二、环境配置(C++)

1. 下载与集成

Clipper2 是无依赖的纯头文件 + 源文件库,集成步骤如下:

bash

运行

# 克隆源码(或直接下载 Release 包)
git clone https://github.com/AngusJohnson/Clipper2.git

将源码中 Clipper2/include/Clipper2Lib 目录下的所有头文件,以及 Clipper2/src 目录下的 .cpp 文件复制到你的项目中,在代码中引入头文件即可:

cpp

运行

#include "Clipper2Lib/clipper.h"
// 命名空间别名(简化代码)
namespace clipper2 = Clipper2Lib;

2. 编译注意事项

  • 支持 C++11 及以上标准;
  • 无需链接额外库,直接编译源码即可;
  • 若使用 CMake,可添加如下配置:

cmake

# 添加 Clipper2 源码目录
add_subdirectory(Clipper2)
# 链接 Clipper2 库
target_link_libraries(你的项目名 Clipper2)

三、核心概念与基础类型

在使用前,先了解 Clipper2 的核心数据类型:

表格

类型说明
clipper2::Path单个路径,本质是 std::vector<clipper2::Point64>,表示多边形的顶点序列(闭合 / 开放);
clipper2::Paths路径集合,本质是 std::vector<clipper2::Path>,用于存储多个多边形;
clipper2::Point6464 位整数坐标点,构造:Point64(x, y);若需浮点数,可先缩放(如乘以 1000),计算后再还原;
clipper2::PolyTree带层级的多边形树,用于存储带孔的多边形(外层多边形为父节点,孔为子节点);
clipper2::ClipType裁剪类型:ClipType::Intersection(交集)、Union(并集)、Difference(差集)、Xor(异或);
clipper2::FillRule填充规则:FillRule::EvenOdd(奇偶规则)、NonZero(非零环绕规则),用于判断点是否在多边形内;

四、C++ 实战示例

示例 1:基础布尔运算(并集)

实现两个多边形的并集运算,这是最常用的场景:

cpp

运行

#include &lt;iostream>
#include "Clipper2Lib/clipper.h"

namespace clipper2 = Clipper2Lib;

int main() {
    // 1. 定义两个多边形(使用 64 位整数坐标)
    clipper2::Path subj = {
        {10, 10}, {100, 10}, {100, 100}, {10, 100} // 矩形 1
    };
    clipper2::Path clip = {
        {50, 50}, {150, 50}, {150, 150}, {50, 150} // 矩形 2
    };

    // 2. 构造裁剪器对象
    clipper2::Clipper64 clipper;
    // 添加被裁剪对象(主体)
    clipper.AddSubject(subj);
    // 添加裁剪对象
    clipper.AddClip(clip);

    // 3. 执行并集运算
    clipper2::Paths64 result;
    clipper.Execute(clipper2::ClipType::Union, clipper2::FillRule::NonZero, result);

    // 4. 输出结果
    std::cout &lt;&lt; "并集运算结果(顶点数):" &lt;&lt; result.size() &lt;&lt; std::endl;
    for (size_t i = 0; i &lt; result.size(); ++i) {
        std::cout &lt;&lt; "多边形 " &lt;&lt; i + 1 &lt;&lt; " 顶点:" &lt;&lt; std::endl;
        for (const auto&amp; p : result[i]) {
            std::cout &lt;&lt; "(" &lt;&lt; p.x &lt;&lt; ", " &lt;&lt; p.y &lt;&lt; ") ";
        }
        std::cout &lt;&lt; std::endl;
    }

    return 0;
}

输出结果

plaintext

并集运算结果(顶点数):1
多边形 1 顶点:
(10, 10) (100, 10) (150, 50) (150, 150) (50, 150) (100, 100) (10, 100) 

示例 2:带孔多边形的裁剪

Clipper2 支持带孔多边形(父多边形为顺时针,孔为逆时针,或反之),示例如下:

cpp

运行

#include "Clipper2Lib/clipper.h"

namespace clipper2 = Clipper2Lib;

int main() {
    // 1. 定义外层多边形(顺时针)和内部孔(逆时针)
    clipper2::Path outer = {{0,0}, {200,0}, {200,200}, {0,200}}; // 外层矩形
    clipper2::Path hole = {{50,50}, {150,50}, {150,150}, {50,150}}; // 内部孔(注意顶点顺序为逆时针)
    
    // 2. 构造带孔的主体
    clipper2::Paths64 subj;
    subj.push_back(outer);
    subj.push_back(hole);

    // 3. 定义裁剪矩形
    clipper2::Path clip = {{100,100}, {300,100}, {300,300}, {100,300}};

    // 4. 执行交集运算
    clipper2::Clipper64 clipper;
    clipper.AddSubject(subj);
    clipper.AddClip(clip);
    
    clipper2::PolyTree64 result_tree;
    clipper.Execute(clipper2::ClipType::Intersection, clipper2::FillRule::NonZero, result_tree);

    // 5. 转换为 Paths 并输出
    clipper2::Paths64 result = clipper2::PolyTreeToPaths64(result_tree);
    for (const auto&amp; path : result) {
        for (const auto&amp; p : path) {
            std::cout &lt;&lt; "(" &lt;&lt; p.x &lt;&lt; ", " &lt;&lt; p.y &lt;&lt; ") ";
        }
        std::cout &lt;&lt; std::endl;
    }

    return 0;
}

示例 3:多边形偏移(扩边 / 收缩)

偏移是 Clipper2 的核心功能之一,适用于轮廓加粗、生成边框等场景:

cpp

运行

#include "Clipper2Lib/clipper.h"

namespace clipper2 = Clipper2Lib;

int main() {
    // 1. 定义原始多边形
    clipper2::Path path = {{100,100}, {200,100}, {200,200}, {150,150}, {100,200}};

    // 2. 构造偏移器
    // 参数1:偏移距离(正数向外,负数向内);参数2:端点样式;参数3:连接样式
    clipper2::ClipperOffset64 offset;
    offset.AddPath(path, clipper2::EndType::Polygon, clipper2::JoinType::Round);

    // 3. 执行偏移(Round 表示圆角连接,精度 2.0)
    clipper2::Paths64 result;
    offset.Execute(result, 20.0, 2.0); // 向外偏移 20 个单位,圆角精度 2.0

    // 4. 输出结果
    std::cout &lt;&lt; "偏移后多边形顶点:" &lt;&lt; std::endl;
    for (const auto&amp; p : result[0]) {
        std::cout &lt;&lt; "(" &lt;&lt; p.x &lt;&lt; ", " &lt;&lt; p.y &lt;&lt; ") ";
    }

    return 0;
}

关键参数说明

  • EndType:端点样式,Polygon(闭合多边形)、OpenRound(开放路径圆角端点)、OpenSquare(开放路径方角端点);
  • JoinType:连接样式,Round(圆角)、Miter(斜角)、Square(方角);
  • 偏移精度:最后一个参数越大,圆角越平滑(建议 2.0~5.0)。

示例 4:浮点数坐标适配

Clipper2 基于整数运算,若需使用浮点数坐标,需通过缩放因子转换:

cpp

运行

#include "Clipper2Lib/clipper.h"

namespace clipper2 = Clipper2Lib;

// 缩放因子(1000 表示保留 3 位小数)
const double SCALE = 1000.0;

// 浮点数转 64 位整数
clipper2::Point64 to_point64(double x, double y) {
    return {static_cast&lt;int64_t>(x * SCALE), static_cast&lt;int64_t>(y * SCALE)};
}

// 64 位整数转浮点数
clipper2::PointD to_pointd(const clipper2::Point64&amp; p) {
    return {static_cast&lt;double>(p.x) / SCALE, static_cast&lt;double>(p.y) / SCALE};
}

int main() {
    // 浮点数坐标的多边形
    clipper2::Path subj = {
        to_point64(10.5, 10.5),
        to_point64(100.2, 10.5),
        to_point64(100.2, 100.8),
        to_point64(10.5, 100.8)
    };

    // 执行裁剪(同整数逻辑)
    clipper2::Clipper64 clipper;
    clipper.AddSubject(subj);
    // ... 后续逻辑与整数版本一致,最终结果转回浮点数即可

    return 0;
}

五、性能与优化建议

  1. 坐标缩放:避免过大的缩放因子(如超过 1e6),否则可能导致整数溢出;
  2. 批量处理:若需处理大量多边形,建议一次性添加所有对象,而非多次调用 AddSubject/AddClip
  3. 结果复用PolyTreePaths 更占内存,若无需层级信息,优先使用 Paths 存储结果;
  4. 64 位编译:Clipper2 依赖 64 位整数,建议使用 64 位编译器编译项目,避免 32 位环境下的溢出风险。

总结

  1. Clipper2 是高性能 2D 多边形处理库,核心支持布尔运算和偏移操作,纯 C++ 无依赖,适配多平台;
  2. C++ 使用核心步骤:定义 Path/Paths → 构造 Clipper 对象 → 添加主体 / 裁剪对象 → 执行运算 → 处理结果;
  3. 浮点数坐标需通过缩放因子转换为 64 位整数,偏移操作可通过 ClipperOffset 实现,支持圆角 / 斜角等样式。