clipper库使用的一些心得

clipper 

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


1. 版本号差异

之前project里面使用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自带的demo程序比对,最终发现了问题所在:问题出在Clipper内部的IntPoint。假设未定义宏use_int32,採用的是long long存储顶点XY值,而上面code中printf是%d。使用%lld或者cout 就没问题了。坑啊。。。

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

clipper中定义了,EvenOdd,NonZero。Positive,Negative四中填充规则。

相应參考OpenGL红皮书上关于多边形填充规则的说明:http://glprogramming.com/red/chapter11.html


多边形填充规则的使用引入了一个围绕数(Winding Numbers)和围绕规则(Winding Rules)的概念。

围绕规则一般CCW为正。CW为负。围绕数和填充规则的示比例如以下图:



为了表示一个带洞的多边形,比如上图中的回字型,须要内外两个路径表示,那么须要注意顶点的存储顺序吗? 这个问题的答案是,取决于多边形的填充规则。假设使用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顶点顺序,效果图例如以下:



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Clipper是一个用于快速开发高性能微服务的Python框架。它提供了丰富的功能,能够帮助开发人员快速构建可伸缩、可靠、高性能的微服务应用程序。 Clipper的中文文档提供了详细的说明和使用指南,以方便国内开发人员更好地理解和使用。文档主要包含以下几个方面内容: 1. 安装与配置:文档详细介绍了Clipper的安装和配置过程,包括各种操作系统的适配和依赖的安装。此外,还介绍了如何设置和调整Clipper的配置参数,以满足不同应用场景的需求。 2. 快速入门:文档提供了基本的示例代码和步骤,帮助开发人员快速上手Clipper。通过简单的示例,开发人员可以了解如何定义模型、创建容器和部署模型等基本操作。 3. 功能介绍:文档详细介绍了Clipper提供的各种功能和特性。例如,它可以支持多种模型类型,包括Python函数、Docker容器、TensorFlow模型等。此外,Clipper还提供了多种部署模式和自动伸缩的功能,以满足不同应用场景的需求。 4. 高级特性:文档进一步介绍了Clipper提供的一些高级特性和技术,例如如何进行A/B测试、如何进行模型版本管理以及如何进行性能调优等。这些高级特性可帮助开发人员更好地应对复杂的微服务应用开发需求。 综上所述,Clipper中文文档提供了丰富的内容,可以帮助开发人员快速上手Clipper,并全面了解其各种功能和特性,从而更好地进行微服务应用的开发和部署。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值