clipper库使用的一些心得

clipper库使用的一些心得多边形处理库 clipper 的使用心得总结

clipper 

sourceforge官网:http://sourceforge.net/projects/polyclipping/

1. 版本差异

之前工程里面使用4.8.6,最近升级到最新版本6.2.1,接口层面有点差别:

老版本使用Polygon概念,最新版本用Path代替了Polygon,对用的Polygons用Paths代替,Clipper::AddPath的时候还需要制定是否封闭

2. 注意数据类型

一个测试,回字上半部分和下半部分,两半部分进行合并,但是输出结果总是不对:

void transform_array_to_path(int* arr, int size, ClipperLib::Path& path, int scale = 1) { for (int i = 0; i < size; i += 2) { path.push_back(ClipperLib::IntPoint(arr[i] * scale, arr[i + 1] * scale)); } } void ClipperTest::merge_case() { using namespace ClipperLib; Clipper union_worker; Paths solution; Path positive_path; { int points[] = { 1, 1, 1, 0, 2, 0, 2, 2, -2, 2, -2, 0, -1, 0, -1, 1 }; transform_array_to_path(points, sizeof(points) / sizeof(points[0]), positive_path, 10); } union_worker.AddPath(positive_path, ClipperLib::ptSubject, true); Path negative_path; { int points[] = { 1, -1, 1, 0, 2, 0, 2, -2, -2, -2, -2, 0, -1, 0, -1, -1 }; transform_array_to_path(points, sizeof(points) / sizeof(points[0]), negative_path, 10); } union_worker.AddPath(negative_path, ClipperLib::ptClip, true); union_worker.Execute(ClipperLib::ctUnion, solution, pftEvenOdd, pftEvenOdd); for (int k = 0; k < solution.size(); k++) { Path& path = solution[k]; printf("[ %dth ] : ", k + 1); for (int t = 0; t < path.size(); t++) { printf("%d,%d ", path[t].X, path[t].Y); } printf("\n"); } } 

合并后的结果输出:

// [1th] : -10, -1 - 10, -1 10, 0 10, 0 // [2th] : -20, -1 - 20, -1 20, 0 20, 0

结果百思不得其解,结果怎么是一个线段了,莫名其妙???正确结果如下图,合并后是一个回字型。

clipper库使用的一些心得

2. 带洞多边形和多边形填充规则

clipper中定义了,EvenOdd,NonZero,Positive,Negative四中填充规则。对应参考OpenGL红皮书上关于多边形填充规则的说明: http://glprogramming.com/red/chapter11.html



多边形填充规则的使用引入了一个环绕数(Winding Numbers)和环绕规则(Winding Rules)的概念。环绕规则一般CCW为正,CW为负。环绕数和填充规则的示例如下图:
clipper库使用的一些心得





为了表示一个带洞的多边形,例如上图中的回字型,需要内外两个路径表示,那么需要注意顶点的存储顺序吗? 这个问题的答案是,取决于多边形的填充规则。如果使用EvenOdd规则,则不用关心顶点的存储顺序。因为:
第一圈为+1/-1,一定是奇数,然后加1或者减1,结果都是偶数,然后再加1或减1结果一定是奇数



有了这个认识,我们写个测试例子,一个回字,跟一个四边形就行融合,Subject是一个Paths,包含两个Path表示,内外圈顺序无关;Clip是一个Path,进行合并的结果包含两个Path。
void ClipperTest::polygon_with_hole_merge_test() { using namespace ClipperLib; Path path1_outer; Path path1_inner; { int outer[] = { -2, -2, 2, -2, 2, 2, -2, 2 }; int inner[] = { -1, -1, 1, -1, 1, 1, -1, 1 }; transform_array_to_path(outer, sizeof(outer)/sizeof(outer[0]), path1_outer); transform_array_to_path(inner, sizeof(inner)/sizeof(inner[0]), path1_inner); } Path path2; { int outer[] = { 2, 2, 3, 2, 3, -2, 2, -2 }; transform_array_to_path(outer, sizeof(outer) / sizeof(outer[0]), path2); } Paths sub_poly; sub_poly.push_back(path1_outer); sub_poly.push_back(path1_inner); Clipper union_worker; union_worker.AddPaths(sub_poly, ptSubject, true); union_worker.AddPath(path2, ptClip, true); Paths solution; union_worker.Execute(ClipperLib::ctUnion, solution, pftEvenOdd, pftEvenOdd); for (int k = 0; k < solution.size(); k++) { Path& path = solution[k]; printf("[ %dth ] : ", k + 1); for (int t = 0; t < path.size(); t++) { // printf("%d,%d ", path[t].X, path[t].Y); cout << path[t].X << "," << path[t].Y << " "; } printf("\n"); } }

不用care顶点顺序,效果图如下:

clipper库使用的一些心得







版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/225197.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 上午9:52
下一篇 2026年3月17日 上午9:52


相关推荐

  • CMD命令实现数字雨

    CMD命令实现数字雨使用cmd命令可以实现类似黑客帝国中的数字雨,这里给出脚本和演示效果:digitalrain.bat@echoofftitledigitalraincolor0bsetlocalENABLEDELAYEDEXPANSIONfor/l%%iin(0)do(set”line=”for/l%%jin(1,1,80)do(set/aDown%%…

    2022年6月9日
    50
  • 哈希表(三)——哈希冲突

    哈希表(三)——哈希冲突之前的两篇文章多次提到哈希冲突 这里再解释一下 所谓哈希冲突 就是两个 key 值经过哈希函数计算以后得到了相同的哈希值 而一个下标只能存放一个 key 这就产生了哈希冲突 如果这个下标其中一个 key 先存着了 那另一个 key 就必须通过别的方法找到属于自己的存放位置 产生了哈希冲突 我们就要解决 选择一个好的解决哈希冲突的方法 也是提高哈希表效率的关键 开发定址法为产生冲突的地址 Hash

    2026年3月18日
    2
  • 最新面试题汇总(附带答案)【建议看看】

    最新面试题汇总(附带答案)【建议看看】1.性能测试关注的指标是什么?从外部看,性能测试主要关注如下三个指标:吞吐量:每秒钟系统能够处理的请求数、任务数响应时间:服务处理一个请求或一个任务的耗时错误率:一批请求中结果出错的请求所占比例从服务器的角度看,性能测试主要关注CPU、内存、服务器负载、网络、磁盘IO等。2.性能测试怎么做的?/如果你要进行性能测试,你是如何展开操作的?1.确定关键业务,关键路径;2.确定测试的关键数据。比如并发量,响应时间,循环次数等;3.准备测试环境,完成脚本录制或脚本开发;4.执行测试,观察或监控

    2026年4月16日
    4
  • 十个实用的谷歌搜索小技巧

    十个实用的谷歌搜索小技巧今天 我们要来分享十个实用的谷歌搜索小技巧 这能让你在最短的时间内找到需要的东西 成为谷歌大神 技巧一 如何搜索准确的短语或引用如果你想要确定引用或短语的来源 或者排除任何不包括你想要的词语的网站 那么就简单地将搜索词用引号括起来 如果我在没有引号的情况下复制粘贴了来自柏拉图理想国的一行 你会注意到 谷歌实际上推荐了不同的措辞 并提供了超过 4 百万的搜索结果 如果我加上引号 我们突然把它缩小

    2026年3月26日
    2
  • jvm的垃圾回收_java垃圾回收方法

    jvm的垃圾回收_java垃圾回收方法上文回顾:《可能是把Java内存区域讲的最清楚的一篇文章》写在前面本节常见面试题:问题答案在文中都有提到如何判断对象是否死亡(两种方法)。简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。如何判断一个常量是废弃常量如何判断一个类是无用的类垃圾收集有哪些算法,各自的特点?HotSpot为什么要分为新生代和老年代?…

    2025年10月27日
    6
  • ssh-server配置文件参数PermitRootLogin介绍

    ssh-server配置文件参数PermitRootLogin介绍sshd_config是sshd的配置文件,其中PermitRootLogin可以限定root用户通过ssh的登录方式,如禁止登陆、禁止密码登录、仅允许密钥登陆和开放登陆,以下是对可选项的概括:参数类别是否允许ssh登陆登录方式交互shellyes允许没有限制没有限制without-password允许除密码以外没

    2022年6月11日
    70

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号