Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions core/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,90 @@ TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2
return ret;
}

TypedArray<PackedVector2Array> Geometry2D::merge_polygons_complex(const TypedArray<Vector<Vector2>> &p_polygon_a, const TypedArray<Vector<Vector2>> &p_polygon_b) {
Vector<Vector<Vector2>> polygon_a;
for (int i = 0; i < p_polygon_a.size(); i++) {
polygon_a.push_back(p_polygon_a[i]);
}

Vector<Vector<Vector2>> polygon_b;
for (int i = 0; i < p_polygon_b.size(); i++) {
polygon_b.push_back(p_polygon_b[i]);
}

Vector<Vector<Vector2>> polys = ::Geometry2D::merge_polygons_complex(polygon_a, polygon_b);

TypedArray<PackedVector2Array> ret;

for (int i = 0; i < polys.size(); ++i) {
ret.push_back(polys[i]);
}
return ret;
}

TypedArray<PackedVector2Array> Geometry2D::clip_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b) {
Vector<Vector<Vector2>> polygon_a;
for (int i = 0; i < p_polygon_a.size(); i++) {
polygon_a.push_back(p_polygon_a[i]);
}

Vector<Vector<Vector2>> polygon_b;
for (int i = 0; i < p_polygon_b.size(); i++) {
polygon_b.push_back(p_polygon_b[i]);
}

Vector<Vector<Vector2>> polys = ::Geometry2D::clip_polygons_complex(polygon_a, polygon_b);

TypedArray<PackedVector2Array> ret;

for (int i = 0; i < polys.size(); ++i) {
ret.push_back(polys[i]);
}
return ret;
}

TypedArray<PackedVector2Array> Geometry2D::intersect_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b) {
Vector<Vector<Vector2>> polygon_a;
for (int i = 0; i < p_polygon_a.size(); i++) {
polygon_a.push_back(p_polygon_a[i]);
}

Vector<Vector<Vector2>> polygon_b;
for (int i = 0; i < p_polygon_b.size(); i++) {
polygon_b.push_back(p_polygon_b[i]);
}

Vector<Vector<Vector2>> polys = ::Geometry2D::intersect_polygons_complex(polygon_a, polygon_b);

TypedArray<PackedVector2Array> ret;

for (int i = 0; i < polys.size(); ++i) {
ret.push_back(polys[i]);
}
return ret;
}

TypedArray<PackedVector2Array> Geometry2D::exclude_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b) {
Vector<Vector<Vector2>> polygon_a;
for (int i = 0; i < p_polygon_a.size(); i++) {
polygon_a.push_back(p_polygon_a[i]);
}

Vector<Vector<Vector2>> polygon_b;
for (int i = 0; i < p_polygon_b.size(); i++) {
polygon_b.push_back(p_polygon_b[i]);
}

Vector<Vector<Vector2>> polys = ::Geometry2D::exclude_polygons_complex(polygon_a, polygon_b);

TypedArray<PackedVector2Array> ret;

for (int i = 0; i < polys.size(); ++i) {
ret.push_back(polys[i]);
}
return ret;
}

TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon);

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

ClassDB::bind_method(D_METHOD("merge_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::merge_polygons_complex);
ClassDB::bind_method(D_METHOD("clip_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::clip_polygons_complex);
ClassDB::bind_method(D_METHOD("intersect_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::intersect_polygons_complex);
ClassDB::bind_method(D_METHOD("exclude_polygons_complex", "polygon_a", "polygon_b"), &Geometry2D::exclude_polygons_complex);

ClassDB::bind_method(D_METHOD("clip_polyline_with_polygon", "polyline", "polygon"), &Geometry2D::clip_polyline_with_polygon);
ClassDB::bind_method(D_METHOD("intersect_polyline_with_polygon", "polyline", "polygon"), &Geometry2D::intersect_polyline_with_polygon);

Expand Down
6 changes: 6 additions & 0 deletions core/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,12 @@ class Geometry2D : public Object {
TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).

// 2D complex (multiple contours) polygon boolean operations
TypedArray<PackedVector2Array> merge_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // Union (add).
TypedArray<PackedVector2Array> clip_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // Difference (subtract).
TypedArray<PackedVector2Array> intersect_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // Common area (multiply).
TypedArray<PackedVector2Array> exclude_polygons_complex(const TypedArray<PackedVector2Array> &p_polygon_a, const TypedArray<PackedVector2Array> &p_polygon_b); // All but common area (xor).

// 2D polyline vs polygon operations.
TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
Expand Down
63 changes: 63 additions & 0 deletions core/math/geometry_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,69 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation
return polypaths;
}

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) {
using namespace Clipper2Lib;

ClipType op = ClipType::Union;

switch (p_op) {
case OPERATION_UNION:
op = ClipType::Union;
break;
case OPERATION_DIFFERENCE:
op = ClipType::Difference;
break;
case OPERATION_INTERSECTION:
op = ClipType::Intersection;
break;
case OPERATION_XOR:
op = ClipType::Xor;
break;
}

ClipperD clp(clipper_precision); // Scale points up internally to attain the desired precision.
clp.PreserveCollinear(false); // Remove redundant vertices.

PathsD paths_a;
for (int i = 0; i < p_polypaths_a.size(); i++) {
const Vector<Point2> &sub_polypath = p_polypaths_a[i];

PathD path(sub_polypath.size());
for (int j = 0; j != sub_polypath.size(); ++j) {
path[j] = PointD(sub_polypath[j].x, sub_polypath[j].y);
}
paths_a.push_back(path);
}
clp.AddSubject(paths_a);

PathsD paths_b;
for (int i = 0; i < p_polypaths_b.size(); i++) {
const Vector<Point2> &sub_polypath = p_polypaths_b[i];

PathD path(sub_polypath.size());
for (int j = 0; j != sub_polypath.size(); ++j) {
path[j] = PointD(sub_polypath[j].x, sub_polypath[j].y);
}
paths_b.push_back(path);
}
clp.AddClip(paths_b);

PathsD out_paths;
clp.Execute(op, FillRule::EvenOdd, out_paths);

Vector<Vector<Point2>> polypaths;
for (PathsD::size_type i = 0; i < out_paths.size(); ++i) {
const PathD &path = out_paths[i];

Vector<Vector2> polypath;
for (PathsD::size_type j = 0; j < path.size(); ++j) {
polypath.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y)));
}
polypaths.push_back(polypath);
}
return polypaths;
}

Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
using namespace Clipper2Lib;

Expand Down
17 changes: 17 additions & 0 deletions core/math/geometry_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,22 @@ class Geometry2D {
return _polypaths_do_operation(OPERATION_XOR, p_polygon_a, p_polygon_b);
}

static Vector<Vector<Point2>> merge_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
return _polypaths_do_operation_complex(OPERATION_UNION, p_polygon_a, p_polygon_b);
}

static Vector<Vector<Point2>> clip_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
return _polypaths_do_operation_complex(OPERATION_DIFFERENCE, p_polygon_a, p_polygon_b);
}

static Vector<Vector<Point2>> intersect_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
return _polypaths_do_operation_complex(OPERATION_INTERSECTION, p_polygon_a, p_polygon_b);
}

static Vector<Vector<Point2>> exclude_polygons_complex(const Vector<Vector<Point2>> &p_polygon_a, const Vector<Vector<Point2>> &p_polygon_b) {
return _polypaths_do_operation_complex(OPERATION_XOR, p_polygon_a, p_polygon_b);
}

static Vector<Vector<Point2>> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
return _polypaths_do_operation(OPERATION_DIFFERENCE, p_polyline, p_polygon, true);
}
Expand Down Expand Up @@ -509,5 +525,6 @@ class Geometry2D {

private:
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);
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);
static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
};
36 changes: 36 additions & 0 deletions doc/classes/Geometry2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@
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].
</description>
</method>
<method name="clip_polygons_complex">
<return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
<description>
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].
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].
</description>
</method>
<method name="clip_polyline_with_polygon">
<return type="PackedVector2Array[]" />
<param index="0" name="polyline" type="PackedVector2Array" />
Expand Down Expand Up @@ -63,6 +72,15 @@
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="exclude_polygons_complex">
<return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
<description>
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.
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="get_closest_point_to_segment">
<return type="Vector2" />
<param index="0" name="point" type="Vector2" />
Expand Down Expand Up @@ -100,6 +118,15 @@
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="intersect_polygons_complex">
<return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
<description>
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.
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="intersect_polyline_with_polygon">
<return type="PackedVector2Array[]" />
<param index="0" name="polyline" type="PackedVector2Array" />
Expand Down Expand Up @@ -186,6 +213,15 @@
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].
</description>
</method>
<method name="merge_polygons_complex">
<return type="PackedVector2Array[]" />
<param index="0" name="polygon_a" type="PackedVector2Array[]" />
<param index="1" name="polygon_b" type="PackedVector2Array[]" />
<description>
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.
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].
</description>
</method>
<method name="offset_polygon">
<return type="PackedVector2Array[]" />
<param index="0" name="polygon" type="PackedVector2Array" />
Expand Down
Loading