use scirs2_core::ndarray::{array, Array2};
use scirs2_spatial::boolean_ops::{
compute_polygon_area, is_convex_polygon, is_self_intersecting, polygon_difference,
polygon_intersection, polygon_symmetric_difference, polygon_union,
};
#[allow(dead_code)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Boolean Operations Example ===\n");
println!("1. Overlapping Squares");
overlapping_squares_example()?;
println!();
println!("2. Non-overlapping Polygons");
non_overlapping_example()?;
println!();
println!("3. Complex Polygon Operations");
complex_polygon_example()?;
println!();
println!("4. Polygon Property Checking");
polygon_properties_example()?;
println!();
println!("5. Triangle Operations");
triangle_operations_example()?;
println!();
println!("6. L-shaped Polygon Operations");
lshape_operations_example()?;
println!();
println!("7. Self-intersection Detection");
self_intersection_example()?;
Ok(())
}
#[allow(dead_code)]
fn overlapping_squares_example() -> Result<(), Box<dyn std::error::Error>> {
let poly1 = array![[0.0, 0.0], [2.0, 0.0], [2.0, 2.0], [0.0, 2.0]];
let poly2 = array![[1.0, 1.0], [3.0, 1.0], [3.0, 3.0], [1.0, 3.0]];
println!("First square: [0,0] to [2,2]");
println!("Second square: [1,1] to [3,3]");
let area1 = compute_polygon_area(&poly1.view())?;
let area2 = compute_polygon_area(&poly2.view())?;
println!("Areas: {area1:.1}, {area2:.1}");
let union_result = polygon_union(&poly1.view(), &poly2.view())?;
let union_area = compute_polygon_area(&union_result.view())?;
println!("Union:");
println!(" Vertices: {}", union_result.nrows());
println!(" Area: {union_area:.3}");
print_vertices(&union_result);
let intersection_result = polygon_intersection(&poly1.view(), &poly2.view())?;
println!("Intersection:");
println!(" Vertices: {}", intersection_result.nrows());
if intersection_result.nrows() > 0 {
let intersection_area = compute_polygon_area(&intersection_result.view())?;
println!(" Area: {intersection_area:.3}");
print_vertices(&intersection_result);
} else {
println!(" No intersection");
}
let difference_result = polygon_difference(&poly1.view(), &poly2.view())?;
println!("Difference (poly1 - poly2):");
println!(" Vertices: {}", difference_result.nrows());
if difference_result.nrows() > 0 {
let difference_area = compute_polygon_area(&difference_result.view())?;
println!(" Area: {difference_area:.3}");
print_vertices(&difference_result);
}
let sym_diff_result = polygon_symmetric_difference(&poly1.view(), &poly2.view())?;
println!("Symmetric difference:");
println!(" Vertices: {}", sym_diff_result.nrows());
if sym_diff_result.nrows() > 0 {
let sym_diff_area = compute_polygon_area(&sym_diff_result.view())?;
println!(" Area: {sym_diff_area:.3}");
}
Ok(())
}
#[allow(dead_code)]
fn non_overlapping_example() -> Result<(), Box<dyn std::error::Error>> {
let poly1 = array![[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
let poly2 = array![[2.0, 0.0], [3.0, 0.0], [3.0, 1.0], [2.0, 1.0]];
println!("Two non-overlapping unit squares");
let area1 = compute_polygon_area(&poly1.view())?;
let area2 = compute_polygon_area(&poly2.view())?;
println!("Individual areas: {area1:.1}, {area2:.1}");
let union_result = polygon_union(&poly1.view(), &poly2.view())?;
println!("Union result:");
println!(" Vertices: {}", union_result.nrows());
let union_area = compute_polygon_area(&union_result.view())?;
println!(
" Area: {:.3} (should be close to {:.1})",
union_area,
area1 + area2
);
let intersection_result = polygon_intersection(&poly1.view(), &poly2.view())?;
println!("Intersection result:");
println!(" Vertices: {}", intersection_result.nrows());
if intersection_result.nrows() > 0 {
let intersection_area = compute_polygon_area(&intersection_result.view())?;
println!(" Area: {intersection_area:.6}");
} else {
println!(" Empty (as expected)");
}
Ok(())
}
#[allow(dead_code)]
fn complex_polygon_example() -> Result<(), Box<dyn std::error::Error>> {
let hexagon = regular_hexagon(2.0, 0.0, 0.0);
let triangle = array![[-1.0, -1.0], [1.0, -1.0], [0.0, 2.0]];
println!("Regular hexagon and triangle");
let hex_area = compute_polygon_area(&hexagon.view())?;
let tri_area = compute_polygon_area(&triangle.view())?;
println!("Areas: hexagon = {hex_area:.3}, triangle = {tri_area:.3}");
let hex_convex = is_convex_polygon(&hexagon.view())?;
let tri_convex = is_convex_polygon(&triangle.view())?;
println!("Convex: hexagon = {hex_convex}, triangle = {tri_convex}");
let union_result = polygon_union(&hexagon.view(), &triangle.view())?;
println!("Union:");
println!(" Vertices: {}", union_result.nrows());
let union_area = compute_polygon_area(&union_result.view())?;
println!(" Area: {union_area:.3}");
let intersection_result = polygon_intersection(&hexagon.view(), &triangle.view())?;
println!("Intersection:");
println!(" Vertices: {}", intersection_result.nrows());
if intersection_result.nrows() > 0 {
let intersection_area = compute_polygon_area(&intersection_result.view())?;
println!(" Area: {intersection_area:.3}");
}
Ok(())
}
#[allow(dead_code)]
fn polygon_properties_example() -> Result<(), Box<dyn std::error::Error>> {
let polygons = vec![
(
"Square",
array![[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]],
),
("Triangle", array![[0.0, 0.0], [1.0, 0.0], [0.5, 1.0]]),
(
"L-shape",
array![
[0.0, 0.0],
[2.0, 0.0],
[2.0, 1.0],
[1.0, 1.0],
[1.0, 2.0],
[0.0, 2.0]
],
),
("Star", create_star_polygon()),
];
for (name, poly) in polygons {
println!("{name}:");
let area = compute_polygon_area(&poly.view())?;
let is_convex = is_convex_polygon(&poly.view())?;
let is_self_intersecting = is_self_intersecting(&poly.view())?;
println!(" Area: {area:.3}");
println!(" Convex: {is_convex}");
println!(" Self-intersecting: {is_self_intersecting}");
println!(" Vertices: {}", poly.nrows());
println!();
}
Ok(())
}
#[allow(dead_code)]
fn triangle_operations_example() -> Result<(), Box<dyn std::error::Error>> {
let triangle1 = array![[0.0, 0.0], [2.0, 0.0], [1.0, 2.0]];
let triangle2 = array![[1.0, 0.0], [3.0, 0.0], [2.0, 2.0]];
println!("Two overlapping triangles");
let area1 = compute_polygon_area(&triangle1.view())?;
let area2 = compute_polygon_area(&triangle2.view())?;
println!("Areas: {area1:.3}, {area2:.3}");
let union_result = polygon_union(&triangle1.view(), &triangle2.view())?;
println!("Union:");
println!(" Vertices: {}", union_result.nrows());
let union_area = compute_polygon_area(&union_result.view())?;
println!(" Area: {union_area:.3}");
let intersection_result = polygon_intersection(&triangle1.view(), &triangle2.view())?;
println!("Intersection:");
println!(" Vertices: {}", intersection_result.nrows());
if intersection_result.nrows() > 0 {
let intersection_area = compute_polygon_area(&intersection_result.view())?;
println!(" Area: {intersection_area:.3}");
}
Ok(())
}
#[allow(dead_code)]
fn lshape_operations_example() -> Result<(), Box<dyn std::error::Error>> {
let lshape = array![
[0.0, 0.0],
[2.0, 0.0],
[2.0, 1.0],
[1.0, 1.0],
[1.0, 2.0],
[0.0, 2.0]
];
let square = array![[0.5, 0.5], [1.5, 0.5], [1.5, 1.5], [0.5, 1.5]];
println!("L-shaped polygon and square");
let l_area = compute_polygon_area(&lshape.view())?;
let sq_area = compute_polygon_area(&square.view())?;
println!("Areas: L-shape = {l_area:.3}, square = {sq_area:.3}");
let l_convex = is_convex_polygon(&lshape.view())?;
let sq_convex = is_convex_polygon(&square.view())?;
println!("Convex: L-shape = {l_convex}, square = {sq_convex}");
let union_result = polygon_union(&lshape.view(), &square.view())?;
println!("Union:");
println!(" Vertices: {}", union_result.nrows());
let union_area = compute_polygon_area(&union_result.view())?;
println!(" Area: {union_area:.3}");
let intersection_result = polygon_intersection(&lshape.view(), &square.view())?;
println!("Intersection:");
println!(" Vertices: {}", intersection_result.nrows());
if intersection_result.nrows() > 0 {
let intersection_area = compute_polygon_area(&intersection_result.view())?;
println!(" Area: {intersection_area:.3}");
print_vertices(&intersection_result);
}
Ok(())
}
#[allow(dead_code)]
fn self_intersection_example() -> Result<(), Box<dyn std::error::Error>> {
let simple = array![[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
let bowtie = array![[0.0, 0.0], [1.0, 1.0], [1.0, 0.0], [0.0, 1.0]];
let complex_self_intersecting =
array![[0.0, 0.0], [2.0, 0.0], [0.0, 1.0], [2.0, 1.0], [1.0, 2.0]];
let shapes = vec![
("Simple square", simple),
("Bowtie", bowtie),
("Complex self-intersecting", complex_self_intersecting),
];
for (name, shape) in shapes {
let is_self_intersecting = is_self_intersecting(&shape.view())?;
let is_convex = is_convex_polygon(&shape.view())?;
println!("{name}:");
println!(" Self-intersecting: {is_self_intersecting}");
println!(" Convex: {is_convex}");
if !is_self_intersecting {
let area = compute_polygon_area(&shape.view())?;
println!(" Area: {area:.3}");
} else {
println!(" Area: (undefined for self-intersecting polygon)");
}
println!();
}
Ok(())
}
#[allow(dead_code)]
fn regular_hexagon(_radius: f64, center_x: f64, center_y: f64) -> Array2<f64> {
let mut vertices = Vec::with_capacity(12);
for i in 0..6 {
let angle = 2.0 * std::f64::consts::PI * (i as f64) / 6.0;
let _x = center_x + _radius * angle.cos();
let _y = center_y + _radius * angle.sin();
vertices.push(_x);
vertices.push(_y);
}
Array2::from_shape_vec((6, 2), vertices).expect("Operation failed")
}
#[allow(dead_code)]
fn create_star_polygon() -> Array2<f64> {
let outer_radius = 1.0;
let inner_radius = 0.4;
let mut vertices = Vec::with_capacity(20);
for i in 0..10 {
let angle = 2.0 * std::f64::consts::PI * (i as f64) / 10.0;
let radius = if i % 2 == 0 {
outer_radius
} else {
inner_radius
};
let x = radius * angle.cos();
let y = radius * angle.sin();
vertices.push(x);
vertices.push(y);
}
Array2::from_shape_vec((10, 2), vertices).expect("Operation failed")
}
#[allow(dead_code)]
fn print_vertices(poly: &Array2<f64>) {
let max_vertices = 6; let n = poly.nrows().min(max_vertices);
print!(" Vertices:");
for i in 0..n {
print!(" [{:.2}, {:.2}]", poly[[i, 0]], poly[[i, 1]]);
}
if poly.nrows() > max_vertices {
print!(" ... ({} more)", poly.nrows() - max_vertices);
}
println!();
}