use super::*;
impl Polygon {
#[inline]
pub fn from_raw(raw: ffi::b2Polygon) -> Self {
Self { raw }
}
#[inline]
pub fn into_raw(self) -> ffi::b2Polygon {
self.raw
}
#[inline]
pub fn count(&self) -> usize {
self.raw.count.clamp(0, MAX_POLYGON_VERTICES as i32) as usize
}
#[inline]
pub fn vertices(&self) -> &[Vec2] {
unsafe {
core::slice::from_raw_parts(self.raw.vertices.as_ptr().cast::<Vec2>(), self.count())
}
}
#[inline]
pub fn normals(&self) -> &[Vec2] {
unsafe {
core::slice::from_raw_parts(self.raw.normals.as_ptr().cast::<Vec2>(), self.count())
}
}
#[inline]
pub fn centroid(&self) -> Vec2 {
Vec2::from_raw(self.raw.centroid)
}
#[inline]
pub fn radius(&self) -> f32 {
self.raw.radius
}
#[inline]
pub fn is_valid(self) -> bool {
if !(1..=MAX_POLYGON_VERTICES as i32).contains(&self.raw.count) {
return false;
}
if !Vec2::from_raw(self.raw.centroid).is_valid()
|| !geometry_scalar_is_non_negative_finite(self.raw.radius)
{
return false;
}
self.vertices().iter().copied().all(Vec2::is_valid)
&& self.normals().iter().copied().all(Vec2::is_valid)
}
#[inline]
pub fn validate(self) -> ApiResult<()> {
geometry_is_valid_or_err(self.is_valid())
}
#[inline]
pub fn square_polygon(half_width: f32) -> Self {
assert_positive_finite_polygon_scalar("half_width", half_width);
Self::from_raw(unsafe { ffi::b2MakeSquare(half_width) })
}
#[inline]
pub fn try_square_polygon(half_width: f32) -> ApiResult<Self> {
check_positive_finite_polygon_scalar(half_width)?;
Ok(Self::from_raw(unsafe { ffi::b2MakeSquare(half_width) }))
}
#[inline]
pub fn box_polygon(half_width: f32, half_height: f32) -> Self {
assert_positive_finite_polygon_scalar("half_width", half_width);
assert_positive_finite_polygon_scalar("half_height", half_height);
Self::from_raw(unsafe { ffi::b2MakeBox(half_width, half_height) })
}
#[inline]
pub fn try_box_polygon(half_width: f32, half_height: f32) -> ApiResult<Self> {
check_positive_finite_polygon_scalar(half_width)?;
check_positive_finite_polygon_scalar(half_height)?;
Ok(Self::from_raw(unsafe {
ffi::b2MakeBox(half_width, half_height)
}))
}
#[inline]
pub fn rounded_box_polygon(half_width: f32, half_height: f32, radius: f32) -> Self {
assert_positive_finite_polygon_scalar("half_width", half_width);
assert_positive_finite_polygon_scalar("half_height", half_height);
assert_non_negative_finite_polygon_scalar("radius", radius);
Self::from_raw(unsafe { ffi::b2MakeRoundedBox(half_width, half_height, radius) })
}
#[inline]
pub fn try_rounded_box_polygon(
half_width: f32,
half_height: f32,
radius: f32,
) -> ApiResult<Self> {
check_positive_finite_polygon_scalar(half_width)?;
check_positive_finite_polygon_scalar(half_height)?;
check_non_negative_finite_polygon_scalar(radius)?;
Ok(Self::from_raw(unsafe {
ffi::b2MakeRoundedBox(half_width, half_height, radius)
}))
}
#[inline]
pub fn offset_box_polygon(half_width: f32, half_height: f32, transform: Transform) -> Self {
assert_positive_finite_polygon_scalar("half_width", half_width);
assert_positive_finite_polygon_scalar("half_height", half_height);
assert_transform_valid(transform);
Self::from_raw(unsafe {
ffi::b2MakeOffsetBox(
half_width,
half_height,
transform.position().into_raw(),
transform.rotation().into_raw(),
)
})
}
#[inline]
pub fn try_offset_box_polygon(
half_width: f32,
half_height: f32,
transform: Transform,
) -> ApiResult<Self> {
check_positive_finite_polygon_scalar(half_width)?;
check_positive_finite_polygon_scalar(half_height)?;
check_transform_valid(transform)?;
Ok(Self::from_raw(unsafe {
ffi::b2MakeOffsetBox(
half_width,
half_height,
transform.position().into_raw(),
transform.rotation().into_raw(),
)
}))
}
#[inline]
pub fn offset_rounded_box_polygon(
half_width: f32,
half_height: f32,
radius: f32,
transform: Transform,
) -> Self {
assert_positive_finite_polygon_scalar("half_width", half_width);
assert_positive_finite_polygon_scalar("half_height", half_height);
assert_non_negative_finite_polygon_scalar("radius", radius);
assert_transform_valid(transform);
Self::from_raw(unsafe {
ffi::b2MakeOffsetRoundedBox(
half_width,
half_height,
transform.position().into_raw(),
transform.rotation().into_raw(),
radius,
)
})
}
#[inline]
pub fn try_offset_rounded_box_polygon(
half_width: f32,
half_height: f32,
radius: f32,
transform: Transform,
) -> ApiResult<Self> {
check_positive_finite_polygon_scalar(half_width)?;
check_positive_finite_polygon_scalar(half_height)?;
check_non_negative_finite_polygon_scalar(radius)?;
check_transform_valid(transform)?;
Ok(Self::from_raw(unsafe {
ffi::b2MakeOffsetRoundedBox(
half_width,
half_height,
transform.position().into_raw(),
transform.rotation().into_raw(),
radius,
)
}))
}
#[inline]
pub fn from_points<I, P>(points: I, radius: f32) -> Option<Self>
where
I: IntoIterator<Item = P>,
P: Into<Vec2>,
{
Self::try_from_points(points, radius).ok()
}
#[inline]
pub fn try_from_points<I, P>(points: I, radius: f32) -> ApiResult<Self>
where
I: IntoIterator<Item = P>,
P: Into<Vec2>,
{
check_non_negative_finite_polygon_scalar(radius)?;
let hull = try_compute_hull_from_points(points)?;
Ok(Self::from_raw(unsafe { ffi::b2MakePolygon(&hull, radius) }))
}
#[inline]
pub fn offset_from_points<I, P>(points: I, radius: f32, transform: Transform) -> Option<Self>
where
I: IntoIterator<Item = P>,
P: Into<Vec2>,
{
Self::try_offset_from_points(points, radius, transform).ok()
}
#[inline]
pub fn try_offset_from_points<I, P>(
points: I,
radius: f32,
transform: Transform,
) -> ApiResult<Self>
where
I: IntoIterator<Item = P>,
P: Into<Vec2>,
{
check_non_negative_finite_polygon_scalar(radius)?;
check_transform_valid(transform)?;
let hull = try_compute_hull_from_points(points)?;
Ok(Self::from_raw(unsafe {
if radius == 0.0 {
ffi::b2MakeOffsetPolygon(
&hull,
transform.position().into_raw(),
transform.rotation().into_raw(),
)
} else {
ffi::b2MakeOffsetRoundedPolygon(
&hull,
transform.position().into_raw(),
transform.rotation().into_raw(),
radius,
)
}
}))
}
#[inline]
pub fn hull_is_valid<I, P>(points: I) -> bool
where
I: IntoIterator<Item = P>,
P: Into<Vec2>,
{
compute_hull_from_points(points).is_some_and(|hull| unsafe { ffi::b2ValidateHull(&hull) })
}
#[inline]
pub fn transformed(self, transform: Transform) -> Self {
assert_polygon_helper_geometry_valid(self);
assert_transform_valid(transform);
Self::from_raw(unsafe { ffi::b2TransformPolygon(transform.into_raw(), &self.raw) })
}
#[inline]
pub fn try_transformed(self, transform: Transform) -> ApiResult<Self> {
check_polygon_helper_geometry_valid(self)?;
check_transform_valid(transform)?;
Ok(Self::from_raw(unsafe {
ffi::b2TransformPolygon(transform.into_raw(), &self.raw)
}))
}
#[inline]
pub fn mass_data(self, density: f32) -> MassData {
assert_polygon_helper_geometry_valid(self);
assert_non_negative_finite_density(density);
let raw = self.into_raw();
MassData::from_raw(unsafe { ffi::b2ComputePolygonMass(&raw, density) })
}
#[inline]
pub fn try_mass_data(self, density: f32) -> ApiResult<MassData> {
check_polygon_helper_geometry_valid(self)?;
check_non_negative_finite_density(density)?;
let raw = self.into_raw();
Ok(MassData::from_raw(unsafe {
ffi::b2ComputePolygonMass(&raw, density)
}))
}
#[inline]
pub fn aabb(self, transform: Transform) -> Aabb {
assert_polygon_helper_geometry_valid(self);
assert_transform_valid(transform);
let raw = self.into_raw();
Aabb::from_raw(unsafe { ffi::b2ComputePolygonAABB(&raw, transform.into_raw()) })
}
#[inline]
pub fn try_aabb(self, transform: Transform) -> ApiResult<Aabb> {
check_polygon_helper_geometry_valid(self)?;
check_transform_valid(transform)?;
let raw = self.into_raw();
Ok(Aabb::from_raw(unsafe {
ffi::b2ComputePolygonAABB(&raw, transform.into_raw())
}))
}
#[inline]
pub fn contains_point<P: Into<Vec2>>(self, point: P) -> bool {
assert_polygon_helper_geometry_valid(self);
let point = point.into();
assert_valid_geometry_vec2("point", point);
let raw = self.into_raw();
unsafe { ffi::b2PointInPolygon(&raw, point.into_raw()) }
}
#[inline]
pub fn try_contains_point<P: Into<Vec2>>(self, point: P) -> ApiResult<bool> {
check_polygon_helper_geometry_valid(self)?;
let point = point.into();
check_valid_geometry_vec2(point)?;
let raw = self.into_raw();
Ok(unsafe { ffi::b2PointInPolygon(&raw, point.into_raw()) })
}
#[inline]
pub fn ray_cast<VO: Into<Vec2>, VT: Into<Vec2>>(
self,
origin: VO,
translation: VT,
) -> CastOutput {
assert_polygon_helper_geometry_valid(self);
let raw = self.into_raw();
let input = make_ray_input(origin, translation);
CastOutput::from_raw(unsafe { ffi::b2RayCastPolygon(&raw, &input) })
}
#[inline]
pub fn try_ray_cast<VO: Into<Vec2>, VT: Into<Vec2>>(
self,
origin: VO,
translation: VT,
) -> ApiResult<CastOutput> {
check_polygon_helper_geometry_valid(self)?;
let raw = self.into_raw();
let input = try_make_ray_input(origin, translation)?;
Ok(CastOutput::from_raw(unsafe {
ffi::b2RayCastPolygon(&raw, &input)
}))
}
}
impl fmt::Debug for Polygon {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Polygon")
.field("vertices", &self.vertices())
.field("normals", &self.normals())
.field("centroid", &self.centroid())
.field("radius", &self.radius())
.finish()
}
}