Clipper
Official site of SourceForge: http://sourceforge.net/projects/polyclipping/
1. Version differences
Previously, 4.8.6 was used in the project and was recently upgraded to the latest version 6.2.1. The interface layer is slightly different:
The old version uses the polygon concept. The latest version uses path instead of polygon, and replaces polygons with paths. When clipper: addpath, you also need to determine whether to close it..
2. Pay attention to the Data Type
In a test, the upper half and lower half of the response are merged, but the output result is always incorrect:
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");}}
Result output after merging:
// [1th] : -10, -1 - 10, -1 10, 0 10, 0// [2th] : -20, -1 - 20, -1 20, 0 20, 0
The result is puzzling. How is the result a line segment? Why ???The correct result is, for example, a return font after merging.
Constantly compare with the demo program that comes with clipper, and finally find the problem: the problem lies in the intpoint inside clipper. If the macro use_int32 is not specified, the system uses long to store the vertex XY value, in the preceding code, the value of printf is % d. If % LLD or cout is used, no problem occurs. Pitfalls...
2. Fill rules for polygon with holes and polygon are defined in clipper. Fill rules for evenodd, nonzero, positive, and negative are defined. Corresponding reference OpenGL redbooks on polygon fill Rules Description: http://glprogramming.com/red/chapter11.html
The use of polygon filling rules introduces the concept of winding numbers and winding rules. Generally, CCW is positive and CW is negative. Examples of loops and filling rules are as follows:
In order to represent a polygon with holes, for example, two internal and external paths are required to represent the back-shaped polygon, do you need to pay attention to the storage sequence of vertices? The answer to this question is that it depends on the polygon filling rules. If you use the evenodd rule, you do not need to care about the storage sequence of vertices. Because:
The first circle is + 1/-1, it must be an odd number, then add 1 or minus 1, the result is an even number, and then add 1 or minus 1, the result must be an odd number.
With this understanding, we will write a test example, a back-word, and a quadrilateral, and the subject is a paths, which contains two paths and has no relation to the internal and external circles; clip is a path. The merged result contains two paths.
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");}}
Do not care about the vertex order, as shown below:
Clipper library usage