Skip to content

Commit

Permalink
feat: add intersect, union, difference, and xor ops
Browse files Browse the repository at this point in the history
Expose functions for the boolean geometry
operations intersect, union, difference, and xor.
  • Loading branch information
tirithen committed Mar 16, 2024
1 parent 95b9241 commit 83e6408
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "clipper2"
version = "0.1.1"
version = "0.1.2"
authors = ["Fredrik Söderström <tirithen@gmail.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
Expand Down
9 changes: 4 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,10 @@ fn main() {
.allowlist_type("PathC")
.allowlist_type("PolygonC")
.allowlist_function("inflate_c")
// .allowlist_function("clean")
// .allowlist_function("simplify")
// .allowlist_function("execute")
// .allowlist_function("offset")
// .allowlist_function("offset_simplify_clean")
.allowlist_function("intersect_c")
.allowlist_function("union_c")
.allowlist_function("difference_c")
.allowlist_function("xor_c")
.allowlist_function("free_path_c")
.allowlist_function("free_polygon_c")
.allowlist_function("free_polygons_c")
Expand Down
32 changes: 28 additions & 4 deletions clipper2/wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
#include "wrapper.h"
#include "clipper.core.h"
#include "clipper.h"
#include <iostream>
#include <queue>

using Clipper2Lib::InflatePaths;
using Clipper2Lib::Paths64;
using Clipper2Lib::Point64;
using Clipper2Lib::PolyTree64;
using Clipper2Lib::PolyTreeToPaths64;
using Clipper2Lib::ScalePaths;

Clipper2Lib::Path64 get_path(const PathC &path)
{
Expand Down Expand Up @@ -147,6 +144,33 @@ PolygonsC inflate_c(
return get_polygons_from_closed_paths(paths);
}

PolygonsC intersect_c(PolygonsC subjects, PolygonsC clips) {
Paths64 subjects_paths = get_closed_paths_from_polygons(subjects);
Paths64 clips_paths = get_closed_paths_from_polygons(clips);
Paths64 result = Clipper2Lib::Intersect(subjects_paths, clips_paths, Clipper2Lib::FillRule::NonZero);
return get_polygons_from_closed_paths(result);
}

PolygonsC union_c(PolygonsC subjects) {
Paths64 subjects_paths = get_closed_paths_from_polygons(subjects);
Paths64 result = Clipper2Lib::Union(subjects_paths, Clipper2Lib::FillRule::NonZero);
return get_polygons_from_closed_paths(result);
}

PolygonsC difference_c(PolygonsC subjects, PolygonsC clips) {
Paths64 subjects_paths = get_closed_paths_from_polygons(subjects);
Paths64 clips_paths = get_closed_paths_from_polygons(clips);
Paths64 result = Clipper2Lib::Difference(subjects_paths, clips_paths, Clipper2Lib::FillRule::NonZero);
return get_polygons_from_closed_paths(result);
}

PolygonsC xor_c(PolygonsC subjects, PolygonsC clips) {
Paths64 subjects_paths = get_closed_paths_from_polygons(subjects);
Paths64 clips_paths = get_closed_paths_from_polygons(clips);
Paths64 result = Clipper2Lib::Xor(subjects_paths, clips_paths, Clipper2Lib::FillRule::NonZero);
return get_polygons_from_closed_paths(result);
}

void free_path_c(PathC path)
{
delete[] path.vertices;
Expand Down
8 changes: 8 additions & 0 deletions clipper2/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ extern "C"
double miter_limit,
double arc_tolerance);

PolygonsC intersect_c(PolygonsC subjects, PolygonsC clips);

PolygonsC union_c(PolygonsC subjects);

PolygonsC difference_c(PolygonsC subjects, PolygonsC clips);

PolygonsC xor_c(PolygonsC subjects, PolygonsC clips);

void free_path_c(PathC path);
void free_polygon_c(PolygonC polygon);
void free_polygons_c(PolygonsC polygons);
Expand Down
12 changes: 12 additions & 0 deletions generated/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ extern "C" {
arc_tolerance: f64,
) -> PolygonsC;
}
extern "C" {
pub fn intersect_c(subjects: PolygonsC, clips: PolygonsC) -> PolygonsC;
}
extern "C" {
pub fn union_c(subjects: PolygonsC) -> PolygonsC;
}
extern "C" {
pub fn difference_c(subjects: PolygonsC, clips: PolygonsC) -> PolygonsC;
}
extern "C" {
pub fn xor_c(subjects: PolygonsC, clips: PolygonsC) -> PolygonsC;
}
extern "C" {
pub fn free_path_c(path: PathC);
}
Expand Down
198 changes: 198 additions & 0 deletions src/clipper2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ pub fn inflate(
}
}

pub fn intersect(subjects: Polygons, clips: Polygons) -> Polygons {
unsafe { intersect_c(subjects.into(), clips.into()).into() }
}

pub fn union(subjects: Polygons) -> Polygons {
unsafe { union_c(subjects.into()).into() }
}

pub fn difference(subjects: Polygons, clips: Polygons) -> Polygons {
unsafe { difference_c(subjects.into(), clips.into()).into() }
}

pub fn xor(subjects: Polygons, clips: Polygons) -> Polygons {
unsafe { xor_c(subjects.into(), clips.into()).into() }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Vertex(i64, i64);

Expand Down Expand Up @@ -594,4 +610,186 @@ mod tests {
]
);
}

#[test]
fn test_intersect() {
let path1 = Path::new(
vec![
Vertex::new(0.0, 0.0),
Vertex::new(10.0, 0.0),
Vertex::new(10.0, 10.0),
Vertex::new(0.0, 10.0),
],
true,
);
let path2 = Path::new(
vec![
Vertex::new(5.0, 5.0),
Vertex::new(15.0, 5.0),
Vertex::new(15.0, 15.0),
Vertex::new(5.0, 15.0),
],
true,
);
let subjects = Polygons::new(vec![Polygon::new(vec![path1.clone()], PathType::Subject)]);
let clips = Polygons::new(vec![Polygon::new(vec![path2.clone()], PathType::Clip)]);

let output = intersect(subjects, clips);

assert_eq!(
output
.polygons()
.first()
.unwrap()
.paths()
.first()
.unwrap()
.vertices(),
&vec![
Vertex::new(10.0, 10.0),
Vertex::new(5.0, 10.0),
Vertex::new(5.0, 5.0),
Vertex::new(10.0, 5.0),
]
);
}

#[test]
fn test_union() {
let path1 = Path::new(
vec![
Vertex::new(0.0, 0.0),
Vertex::new(10.0, 0.0),
Vertex::new(10.0, 10.0),
Vertex::new(0.0, 10.0),
],
true,
);
let path2 = Path::new(
vec![
Vertex::new(5.0, 5.0),
Vertex::new(15.0, 5.0),
Vertex::new(15.0, 15.0),
Vertex::new(5.0, 15.0),
],
true,
);
let polygons = Polygons::new(vec![Polygon::new(
vec![path1.clone(), path2.clone()],
PathType::Subject,
)]);

let output = union(polygons);

assert_eq!(
output
.polygons()
.first()
.unwrap()
.paths()
.first()
.unwrap()
.vertices(),
&vec![
Vertex::new(10.0, 5.0),
Vertex::new(15.0, 5.0),
Vertex::new(15.0, 15.0),
Vertex::new(5.0, 15.0),
Vertex::new(5.0, 10.0),
Vertex::new(0.0, 10.0),
Vertex::new(0.0, 0.0),
Vertex::new(10.0, 0.0)
]
);
}

#[test]
fn test_difference() {
let path1 = Path::new(
vec![
Vertex::new(0.0, 0.0),
Vertex::new(10.0, 0.0),
Vertex::new(10.0, 10.0),
Vertex::new(0.0, 10.0),
],
true,
);
let path2 = Path::new(
vec![
Vertex::new(5.0, 5.0),
Vertex::new(15.0, 5.0),
Vertex::new(15.0, 15.0),
Vertex::new(5.0, 15.0),
],
true,
);
let subjects = Polygons::new(vec![Polygon::new(vec![path1.clone()], PathType::Subject)]);
let clips = Polygons::new(vec![Polygon::new(vec![path2.clone()], PathType::Clip)]);

let output = difference(subjects, clips);

assert_eq!(
output
.polygons()
.first()
.unwrap()
.paths()
.first()
.unwrap()
.vertices(),
&vec![
Vertex::new(10.0, 5.0),
Vertex::new(5.0, 5.0),
Vertex::new(5.0, 10.0),
Vertex::new(0.0, 10.0),
Vertex::new(0.0, 0.0),
Vertex::new(10.0, 0.0),
]
);
}

#[test]
fn test_xor() {
let path1 = Path::new(
vec![
Vertex::new(0.0, 0.0),
Vertex::new(10.0, 0.0),
Vertex::new(10.0, 10.0),
Vertex::new(0.0, 10.0),
],
true,
);
let path2 = Path::new(
vec![
Vertex::new(5.0, 5.0),
Vertex::new(15.0, 5.0),
Vertex::new(15.0, 15.0),
Vertex::new(5.0, 15.0),
],
true,
);
let subjects = Polygons::new(vec![Polygon::new(vec![path1.clone()], PathType::Subject)]);
let clips = Polygons::new(vec![Polygon::new(vec![path2.clone()], PathType::Clip)]);

let output = xor(subjects, clips);

assert_eq!(
output
.polygons()
.first()
.unwrap()
.paths()
.first()
.unwrap()
.vertices(),
&vec![
Vertex::new(15.0, 15.0),
Vertex::new(5.0, 15.0),
Vertex::new(5.0, 10.0),
Vertex::new(10.0, 10.0),
Vertex::new(10.0, 5.0),
Vertex::new(15.0, 5.0),
]
);
}
}

0 comments on commit 83e6408

Please sign in to comment.