Skip to content

Commit 5347dba

Browse files
committed
add complex geometry functions and documentation
1 parent 7c472e6 commit 5347dba

File tree

5 files changed

+212
-0
lines changed

5 files changed

+212
-0
lines changed

core/core_bind.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,6 +1004,90 @@ TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2
10041004
return ret;
10051005
}
10061006

1007+
TypedArray<PackedVector2Array> Geometry2D::merge_polygons_complex(const TypedArray<Vector<Vector2>> &p_polygon_a, const TypedArray<Vector<Vector2>> &p_polygon_b) {
1008+
Vector<Vector<Vector2>> polygon_a;
1009+
for (int i = 0; i < p_polygon_a.size(); i++) {
1010+
polygon_a.push_back(p_polygon_a[i]);
1011+
}
1012+
1013+
Vector<Vector<Vector2>> polygon_b;
1014+
for (int i = 0; i < p_polygon_b.size(); i++) {
1015+
polygon_b.push_back(p_polygon_b[i]);
1016+
}
1017+
1018+
Vector<Vector<Vector2>> polys = ::Geometry2D::merge_polygons_complex(polygon_a, polygon_b);
1019+
1020+
TypedArray<PackedVector2Array> ret;
1021+
1022+
for (int i = 0; i < polys.size(); ++i) {
1023+
ret.push_back(polys[i]);
1024+
}
1025+
return ret;
1026+
}
1027+
1028+
TypedArray<PackedVector2Array> Geometry2D::clip_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b) {
1029+
Vector<Vector<Vector2>> polygon_a;
1030+
for (int i = 0; i < p_polygon_a.size(); i++) {
1031+
polygon_a.push_back(p_polygon_a[i]);
1032+
}
1033+
1034+
Vector<Vector<Vector2>> polygon_b;
1035+
for (int i = 0; i < p_polygon_b.size(); i++) {
1036+
polygon_b.push_back(p_polygon_b[i]);
1037+
}
1038+
1039+
Vector<Vector<Vector2>> polys = ::Geometry2D::clip_polygons_complex(polygon_a, polygon_b);
1040+
1041+
TypedArray<PackedVector2Array> ret;
1042+
1043+
for (int i = 0; i < polys.size(); ++i) {
1044+
ret.push_back(polys[i]);
1045+
}
1046+
return ret;
1047+
}
1048+
1049+
TypedArray<PackedVector2Array> Geometry2D::intersect_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b) {
1050+
Vector<Vector<Vector2>> polygon_a;
1051+
for (int i = 0; i < p_polygon_a.size(); i++) {
1052+
polygon_a.push_back(p_polygon_a[i]);
1053+
}
1054+
1055+
Vector<Vector<Vector2>> polygon_b;
1056+
for (int i = 0; i < p_polygon_b.size(); i++) {
1057+
polygon_b.push_back(p_polygon_b[i]);
1058+
}
1059+
1060+
Vector<Vector<Vector2>> polys = ::Geometry2D::intersect_polygons_complex(polygon_a, polygon_b);
1061+
1062+
TypedArray<PackedVector2Array> ret;
1063+
1064+
for (int i = 0; i < polys.size(); ++i) {
1065+
ret.push_back(polys[i]);
1066+
}
1067+
return ret;
1068+
}
1069+
1070+
TypedArray<PackedVector2Array> Geometry2D::exclude_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b) {
1071+
Vector<Vector<Vector2>> polygon_a;
1072+
for (int i = 0; i < p_polygon_a.size(); i++) {
1073+
polygon_a.push_back(p_polygon_a[i]);
1074+
}
1075+
1076+
Vector<Vector<Vector2>> polygon_b;
1077+
for (int i = 0; i < p_polygon_b.size(); i++) {
1078+
polygon_b.push_back(p_polygon_b[i]);
1079+
}
1080+
1081+
Vector<Vector<Vector2>> polys = ::Geometry2D::exclude_polygons_complex(polygon_a, polygon_b);
1082+
1083+
TypedArray<PackedVector2Array> ret;
1084+
1085+
for (int i = 0; i < polys.size(); ++i) {
1086+
ret.push_back(polys[i]);
1087+
}
1088+
return ret;
1089+
}
1090+
10071091
TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
10081092
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon);
10091093

@@ -1111,6 +1195,11 @@ void Geometry2D::_bind_methods() {
11111195
ClassDB::bind_method(D_METHOD("intersect_polygons", "polygon_a", "polygon_b"), &Geometry2D::intersect_polygons);
11121196
ClassDB::bind_method(D_METHOD("exclude_polygons", "polygon_a", "polygon_b"), &Geometry2D::exclude_polygons);
11131197

1198+
ClassDB::bind_method(D_METHOD("merge_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::merge_polygons_complex);
1199+
ClassDB::bind_method(D_METHOD("clip_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::clip_polygons_complex);
1200+
ClassDB::bind_method(D_METHOD("intersect_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::intersect_polygons_complex);
1201+
ClassDB::bind_method(D_METHOD("exclude_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::exclude_polygons_complex);
1202+
11141203
ClassDB::bind_method(D_METHOD("clip_polyline_with_polygon", "polyline", "polygon"), &Geometry2D::clip_polyline_with_polygon);
11151204
ClassDB::bind_method(D_METHOD("intersect_polyline_with_polygon", "polyline", "polygon"), &Geometry2D::intersect_polyline_with_polygon);
11161205

core/core_bind.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,12 @@ class Geometry2D : public Object {
359359
TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
360360
TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
361361

362+
// 2D complex (multiple contours) polygon boolean operations
363+
TypedArray<PackedVector2Array> merge_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // Union (add).
364+
TypedArray<PackedVector2Array> clip_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // Difference (subtract).
365+
TypedArray<PackedVector2Array> intersect_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // Common area (multiply).
366+
TypedArray<PackedVector2Array> exclude_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // All but common area (xor).
367+
362368
// 2D polyline vs polygon operations.
363369
TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
364370
TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.

core/math/geometry_2d.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,70 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
304304
return polypaths;
305305
}
306306

307+
Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation_complex(PolyBooleanOperation p_op, const Vector<Vector<Point2>> &p_polypaths_a, const Vector<Vector<Point2>> &p_polypaths_b) {
308+
using namespace Clipper2Lib;
309+
310+
ClipType op = ClipType::Union;
311+
312+
switch (p_op) {
313+
case OPERATION_UNION:
314+
op = ClipType::Union;
315+
break;
316+
case OPERATION_DIFFERENCE:
317+
op = ClipType::Difference;
318+
break;
319+
case OPERATION_INTERSECTION:
320+
op = ClipType::Intersection;
321+
break;
322+
case OPERATION_XOR:
323+
op = ClipType::Xor;
324+
break;
325+
}
326+
327+
ClipperD clp(clipper_precision); // Scale points up internally to attain the desired precision.
328+
clp.PreserveCollinear(false); // Remove redundant vertices.
329+
330+
PathsD paths_a;
331+
for (int i = 0; i < p_polypaths_a.size(); i++) {
332+
const Vector<Point2> &sub_polypath = p_polypaths_a[i];
333+
334+
PathD path(sub_polypath.size());
335+
for (int j = 0; j != sub_polypath.size(); ++j) {
336+
path[j] = PointD(sub_polypath[j].x, sub_polypath[j].y);
337+
}
338+
paths_a.push_back(path);
339+
}
340+
clp.AddSubject(paths_a);
341+
342+
PathsD paths_b;
343+
for (int i = 0; i < p_polypaths_b.size(); i++) {
344+
const Vector<Point2> &sub_polypath = p_polypaths_b[i];
345+
346+
PathD path(sub_polypath.size());
347+
for (int j = 0; j != sub_polypath.size(); ++j) {
348+
path[j] = PointD(sub_polypath[j].x, sub_polypath[j].y);
349+
}
350+
paths_b.push_back(path);
351+
}
352+
clp.AddClip(paths_b);
353+
354+
PathsD out_paths;
355+
clp.Execute(op, FillRule::EvenOdd, out_paths);
356+
357+
Vector<Vector<Point2>> polypaths;
358+
for (PathsD::size_type i = 0; i < out_paths.size(); ++i) {
359+
const PathD &path = out_paths[i];
360+
361+
Vector<Vector2> polypath;
362+
for (PathsD::size_type j = 0; j < path.size(); ++j) {
363+
polypath.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y)));
364+
}
365+
polypaths.push_back(polypath);
366+
}
367+
return polypaths;
368+
}
369+
370+
307371
Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
308372
using namespace Clipper2Lib;
309373

core/math/geometry_2d.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,22 @@ class Geometry2D {
320320
return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b);
321321
}
322322

323+
static Vector<Vector<Point2>> merge_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
324+
return _polypaths_do_operation_complex(OPERATION_UNION, p_polygon_a, p_polygon_b);
325+
}
326+
327+
static Vector<Vector<Point2>> clip_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
328+
return _polypaths_do_operation_complex(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b);
329+
}
330+
331+
static Vector<Vector<Point2>> intersect_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
332+
return _polypaths_do_operation_complex(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b);
333+
}
334+
335+
static Vector<Vector<Point2>> exclude_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
336+
return _polypaths_do_operation_complex(OPERATION_XOR, p_polygon_a, p_polygon_b);
337+
}
338+
323339
static Vector<Vector<Point2>> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
324340
return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true);
325341
}
@@ -509,5 +525,6 @@ class Geometry2D {
509525

510526
private:
511527
static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
528+
static Vector<Vector<Point2>> _polypaths_do_operation_complex(PolyBooleanOperation p_op, const Vector<Vector<Point2>> &p_polypaths_a, const Vector<Vector<Point2>> &p_polypaths_b);
512529
static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
513530
};

doc/classes/Geometry2D.xml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@
3232
If [param polygon_b] is enclosed by [param polygon_a], returns an outer polygon (boundary) and inner polygon (hole) which could be distinguished by calling [method is_polygon_clockwise].
3333
</description>
3434
</method>
35+
<method name="clip_polygons_complex">
36+
<return type="PackedVector2Array[]" />
37+
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
38+
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
39+
<description>
40+
Clips [param polygon_a] against [param polygon_b] and returns an array of clipped polygons. This operation will work on a polygon with holes. This performs [constant OPERATION_DIFFERENCE] between polygons. Returns an empty array if [param polygon_b] completely overlaps [param polygon_a].
41+
If [param polygon_b] is enclosed by [param polygon_a], returns an outer polygon (boundary) and inner polygon (hole) which could be distinguished by calling [method is_polygon_clockwise].
42+
</description>
43+
</method>
3544
<method name="clip_polyline_with_polygon">
3645
<return type="PackedVector2Array[]" />
3746
<param index="0" name="polyline" type="PackedVector2Array" />
@@ -63,6 +72,15 @@
6372
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
6473
</description>
6574
</method>
75+
<method name="exclude_polygons_complex">
76+
<return type="PackedVector2Array[]" />
77+
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
78+
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
79+
<description>
80+
Mutually excludes common area defined by intersection of [param polygon_a] and [param polygon_b] (see [method intersect_polygons]) and returns an array of excluded polygons. This operation will work on a polygon with holes. This performs [constant OPERATION_XOR] between polygons. In other words, returns all but common area between polygons.
81+
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
82+
</description>
83+
</method>
6684
<method name="get_closest_point_to_segment">
6785
<return type="Vector2" />
6886
<param index="0" name="point" type="Vector2" />
@@ -100,6 +118,15 @@
100118
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
101119
</description>
102120
</method>
121+
<method name="intersect_polygons_complex">
122+
<return type="PackedVector2Array[]" />
123+
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
124+
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
125+
<description>
126+
Intersects [param polygon_a] with [param polygon_b] and returns an array of intersected polygons. This operation will work on a polygon with holes. This performs [constant OPERATION_INTERSECTION] between polygons. In other words, returns common area shared by polygons. Returns an empty array if no intersection occurs.
127+
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
128+
</description>
129+
</method>
103130
<method name="intersect_polyline_with_polygon">
104131
<return type="PackedVector2Array[]" />
105132
<param index="0" name="polyline" type="PackedVector2Array" />
@@ -186,6 +213,15 @@
186213
The operation may result in an outer polygon (boundary) and multiple inner polygons (holes) produced which could be distinguished by calling [method is_polygon_clockwise].
187214
</description>
188215
</method>
216+
<method name="merge_polygons_complex">
217+
<return type="PackedVector2Array[]" />
218+
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
219+
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
220+
<description>
221+
Merges (combines) [param polygon_a] and [param polygon_b] and returns an array of merged polygons. This operation will work on a polygon with holes. This performs [constant OPERATION_UNION] between polygons.
222+
The operation may result in an outer polygon (boundary) and multiple inner polygons (holes) produced which could be distinguished by calling [method is_polygon_clockwise].
223+
</description>
224+
</method>
189225
<method name="offset_polygon">
190226
<return type="PackedVector2Array[]" />
191227
<param index="0" name="polygon" type="PackedVector2Array" />

0 commit comments

Comments
 (0)