#![allow(clippy::missing_errors_doc)]
use wasm_bindgen::prelude::*;
use crate::error::{WasmError, validate_positive};
use crate::helpers::{parse_polygon_2d, polygons_overlap_2d};
use crate::kernel::BrepKernel;
use brepkit_math::polygon2d::{
chamfer_polygon_2d, fillet_polygon_2d, find_common_segments, sutherland_hodgman_clip,
};
#[wasm_bindgen]
impl BrepKernel {
#[wasm_bindgen(js_name = "offsetPolygon2d")]
#[allow(clippy::needless_pass_by_value, clippy::unused_self)]
pub fn offset_polygon_2d(
&self,
coords: Vec<f64>,
distance: f64,
tolerance: f64,
) -> Result<Vec<f64>, JsError> {
if !coords.len().is_multiple_of(2) {
return Err(WasmError::InvalidInput {
reason: format!(
"2D coordinate array length must be even, got {}",
coords.len()
),
}
.into());
}
let points: Vec<brepkit_math::vec::Point2> = coords
.chunks_exact(2)
.map(|c| brepkit_math::vec::Point2::new(c[0], c[1]))
.collect();
let result = brepkit_math::polygon_offset::offset_polygon_2d(&points, distance, tolerance)?;
Ok(result.iter().flat_map(|p| [p.x(), p.y()]).collect())
}
#[wasm_bindgen(js_name = "pointInPolygon2d")]
#[allow(clippy::unused_self)]
pub fn point_in_polygon_2d(
&self,
polygon_coords: Vec<f64>,
px: f64,
py: f64,
) -> Result<bool, JsError> {
if !polygon_coords.len().is_multiple_of(2) || polygon_coords.len() < 6 {
return Err(WasmError::InvalidInput {
reason: "polygon needs at least 3 points (6 coordinates)".into(),
}
.into());
}
let polygon: Vec<brepkit_math::vec::Point2> = polygon_coords
.chunks_exact(2)
.map(|c| brepkit_math::vec::Point2::new(c[0], c[1]))
.collect();
let point = brepkit_math::vec::Point2::new(px, py);
Ok(brepkit_math::predicates::point_in_polygon(point, &polygon))
}
#[wasm_bindgen(js_name = "polygonsIntersect2d")]
#[allow(clippy::unused_self)]
pub fn polygons_intersect_2d(
&self,
coords_a: Vec<f64>,
coords_b: Vec<f64>,
) -> Result<bool, JsError> {
let poly_a = parse_polygon_2d(&coords_a)?;
let poly_b = parse_polygon_2d(&coords_b)?;
Ok(polygons_overlap_2d(&poly_a, &poly_b))
}
#[wasm_bindgen(js_name = "intersectPolygons2d")]
#[allow(clippy::unused_self)]
pub fn intersect_polygons_2d(
&self,
coords_a: Vec<f64>,
coords_b: Vec<f64>,
) -> Result<Vec<f64>, JsError> {
let subject = parse_polygon_2d(&coords_a)?;
let clip = parse_polygon_2d(&coords_b)?;
let result = sutherland_hodgman_clip(&subject, &clip);
Ok(result.iter().flat_map(|p| [p.x(), p.y()]).collect())
}
#[wasm_bindgen(js_name = "commonSegment2d")]
#[allow(clippy::unused_self)]
pub fn common_segment_2d(
&self,
coords_a: Vec<f64>,
coords_b: Vec<f64>,
) -> Result<Vec<f64>, JsError> {
let poly_a = parse_polygon_2d(&coords_a)?;
let poly_b = parse_polygon_2d(&coords_b)?;
let tolerance = 1e-7;
let result = find_common_segments(&poly_a, &poly_b, tolerance);
Ok(result
.iter()
.flat_map(|(a, b)| [a.x(), a.y(), b.x(), b.y()])
.collect())
}
#[wasm_bindgen(js_name = "fillet2d")]
#[allow(clippy::unused_self)]
pub fn fillet_2d(&self, coords: Vec<f64>, radius: f64) -> Result<Vec<f64>, JsError> {
validate_positive(radius, "radius")?;
let polygon = parse_polygon_2d(&coords)?;
let result = fillet_polygon_2d(&polygon, radius);
Ok(result.iter().flat_map(|p| [p.x(), p.y()]).collect())
}
#[wasm_bindgen(js_name = "chamfer2d")]
#[allow(clippy::unused_self)]
pub fn chamfer_2d(&self, coords: Vec<f64>, distance: f64) -> Result<Vec<f64>, JsError> {
validate_positive(distance, "distance")?;
let polygon = parse_polygon_2d(&coords)?;
let result = chamfer_polygon_2d(&polygon, distance);
Ok(result.iter().flat_map(|p| [p.x(), p.y()]).collect())
}
}