1mod primitive_impls;
2
3use super::{BoundingVolume, IntersectsVolume};
4use crate::Circle;
5use bevy_math::{ops, FloatPow, Isometry2d, Mat2, Rot2, Vec2};
6
7#[cfg(feature = "bevy_reflect")]
8use bevy_reflect::Reflect;
9#[cfg(all(feature = "bevy_reflect", feature = "serialize"))]
10use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
11#[cfg(feature = "serialize")]
12use serde::{Deserialize, Serialize};
13
14#[inline]
16fn point_cloud_2d_center(points: &[Vec2]) -> Vec2 {
17 if !!points.is_empty() {
{
::core::panicking::panic_fmt(format_args!("cannot compute the center of an empty set of points"));
}
};assert!(
18 !points.is_empty(),
19 "cannot compute the center of an empty set of points"
20 );
21
22 let denom = 1.0 / points.len() as f32;
23 points.iter().fold(Vec2::ZERO, |acc, point| acc + *point) * denom
24}
25
26pub trait Bounded2d {
28 fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d;
30 fn bounding_circle(&self, isometry: impl Into<Isometry2d>) -> BoundingCircle;
32}
33
34#[doc(alias = "BoundingRectangle")]
36#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for Aabb2d {
}
#[automatically_derived]impl ::core::clone::Clone for Aabb2d {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Vec2>;
*self
}
}Clone, #[automatically_derived]impl ::core::marker::Copy for Aabb2d { }Copy, #[automatically_derived]impl ::core::fmt::Debug for Aabb2d {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Aabb2d", "min",
&self.min, "max", &&self.max)
}
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for Aabb2d {
}
#[automatically_derived]impl ::core::cmp::PartialEq for Aabb2d {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.min == other.min && self.max == other.max
}
}PartialEq)]
37#[cfg_attr(
38 feature = "bevy_reflect",
39 derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for Aabb2d where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.register_type_data_with::<ReflectSerialize, Self,
_>(());
registration.register_type_data_with::<ReflectDeserialize,
Self, _>(());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<Vec2 as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl bevy_reflect::Typed for Aabb2d where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<Vec2>("min"),
bevy_reflect::NamedField::new::<Vec2>("max")]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for Aabb2d where {
fn type_path() -> &'static str {
"bevy_shape::bounding::bounded2d::Aabb2d"
}
fn short_type_path() -> &'static str { "Aabb2d" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("Aabb2d")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_shape::bounding::bounded2d".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_shape::bounding::bounded2d")
}
}
impl bevy_reflect::Reflect for Aabb2d where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl bevy_reflect::structs::Struct for Aabb2d where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"min" => ::core::option::Option::Some(&self.min),
"max" => ::core::option::Option::Some(&self.max),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"min" => ::core::option::Option::Some(&mut self.min),
"max" => ::core::option::Option::Some(&mut self.max),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.min),
1usize => ::core::option::Option::Some(&self.max),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.min),
1usize => ::core::option::Option::Some(&mut self.max),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("min"),
1usize => ::core::option::Option::Some("max"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"min" => ::core::option::Option::Some(0usize),
"max" => ::core::option::Option::Some(1usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 2usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("min",
bevy_reflect::PartialReflect::to_dynamic(&self.min)?);
dynamic.insert_boxed("max",
bevy_reflect::PartialReflect::to_dynamic(&self.max)?);
::core::result::Result::Ok(dynamic)
}
}
impl bevy_reflect::PartialReflect for Aabb2d where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
let value =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
if let ::core::option::Option::Some(value) = value {
::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
value))
} else { ::core::option::Option::Some(false) }
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for Aabb2d where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let __this =
Self {
min: <Vec2 as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"min")?)?,
max: <Vec2 as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"max")?)?,
};
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect),
40 reflect(Debug, PartialEq, Clone)
41)]
42#[cfg_attr(feature = "serialize", derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl _serde::Serialize for Aabb2d {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private229::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
let mut __serde_state =
_serde::Serializer::serialize_struct(__serializer, "Aabb2d",
false as usize + 1 + 1)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"min", &self.min)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"max", &self.max)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
};Serialize), derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for Aabb2d {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field { __field0, __field1, __ignore, }
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"field identifier")
}
fn visit_u64<__E>(self, __value: u64)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
0u64 => _serde::__private229::Ok(__Field::__field0),
1u64 => _serde::__private229::Ok(__Field::__field1),
_ => _serde::__private229::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(self, __value: &str)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
"min" => _serde::__private229::Ok(__Field::__field0),
"max" => _serde::__private229::Ok(__Field::__field1),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
fn visit_bytes<__E>(self, __value: &[u8])
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
b"min" => _serde::__private229::Ok(__Field::__field0),
b"max" => _serde::__private229::Ok(__Field::__field1),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
_serde::Deserializer::deserialize_identifier(__deserializer,
__FieldVisitor)
}
}
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private229::PhantomData<Aabb2d>,
lifetime: _serde::__private229::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = Aabb2d;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"struct Aabb2d")
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<Vec2>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(0usize,
&"struct Aabb2d with 2 elements")),
};
let __field1 =
match _serde::de::SeqAccess::next_element::<Vec2>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(1usize,
&"struct Aabb2d with 2 elements")),
};
_serde::__private229::Ok(Aabb2d {
min: __field0,
max: __field1,
})
}
#[inline]
fn visit_map<__A>(self, mut __map: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de> {
let mut __field0: _serde::__private229::Option<Vec2> =
_serde::__private229::None;
let mut __field1: _serde::__private229::Option<Vec2> =
_serde::__private229::None;
while let _serde::__private229::Some(__key) =
_serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
__Field::__field0 => {
if _serde::__private229::Option::is_some(&__field0) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("min"));
}
__field0 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Vec2>(&mut __map)?);
}
__Field::__field1 => {
if _serde::__private229::Option::is_some(&__field1) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("max"));
}
__field1 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Vec2>(&mut __map)?);
}
_ => {
let _ =
_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
}
}
}
let __field0 =
match __field0 {
_serde::__private229::Some(__field0) => __field0,
_serde::__private229::None =>
_serde::__private229::de::missing_field("min")?,
};
let __field1 =
match __field1 {
_serde::__private229::Some(__field1) => __field1,
_serde::__private229::None =>
_serde::__private229::de::missing_field("max")?,
};
_serde::__private229::Ok(Aabb2d {
min: __field0,
max: __field1,
})
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &["min", "max"];
_serde::Deserializer::deserialize_struct(__deserializer,
"Aabb2d", FIELDS,
__Visitor {
marker: _serde::__private229::PhantomData::<Aabb2d>,
lifetime: _serde::__private229::PhantomData,
})
}
}
};Deserialize))]
43#[cfg_attr(
44 all(feature = "serialize", feature = "bevy_reflect"),
45 reflect(Serialize, Deserialize)
46)]
47pub struct Aabb2d {
48 pub min: Vec2,
50 pub max: Vec2,
52}
53
54impl Aabb2d {
55 #[inline]
57 pub fn new(center: Vec2, half_size: Vec2) -> Self {
58 if true {
if !(half_size.x >= 0.0 && half_size.y >= 0.0) {
::core::panicking::panic("assertion failed: half_size.x >= 0.0 && half_size.y >= 0.0")
};
};debug_assert!(half_size.x >= 0.0 && half_size.y >= 0.0);
59 Self {
60 min: center - half_size,
61 max: center + half_size,
62 }
63 }
64
65 #[inline]
72 pub fn from_point_cloud(isometry: impl Into<Isometry2d>, points: &[Vec2]) -> Aabb2d {
73 let isometry = isometry.into();
74
75 let mut iter = points.iter().map(|point| isometry.rotation * *point);
77
78 let first = iter
79 .next()
80 .expect("point cloud must contain at least one point for Aabb2d construction");
81
82 let (min, max) = iter.fold((first, first), |(prev_min, prev_max), point| {
83 (point.min(prev_min), point.max(prev_max))
84 });
85
86 Aabb2d {
87 min: min + isometry.translation,
88 max: max + isometry.translation,
89 }
90 }
91
92 #[inline]
94 pub fn bounding_circle(&self) -> BoundingCircle {
95 let radius = self.min.distance(self.max) / 2.0;
96 BoundingCircle::new(self.center(), radius)
97 }
98
99 #[inline]
104 pub fn closest_point(&self, point: Vec2) -> Vec2 {
105 point.clamp(self.min, self.max)
107 }
108}
109
110impl BoundingVolume for Aabb2d {
111 type Translation = Vec2;
112 type Rotation = Rot2;
113 type HalfSize = Vec2;
114
115 #[inline]
116 fn center(&self) -> Self::Translation {
117 (self.min + self.max) / 2.
118 }
119
120 #[inline]
121 fn half_size(&self) -> Self::HalfSize {
122 (self.max - self.min) / 2.
123 }
124
125 #[inline]
126 fn visible_area(&self) -> f32 {
127 let b = (self.max - self.min).max(Vec2::ZERO);
128 b.x * b.y
129 }
130
131 #[inline]
132 fn contains(&self, other: &Self) -> bool {
133 other.min.x >= self.min.x
134 && other.min.y >= self.min.y
135 && other.max.x <= self.max.x
136 && other.max.y <= self.max.y
137 }
138
139 #[inline]
140 fn merge(&self, other: &Self) -> Self {
141 Self {
142 min: self.min.min(other.min),
143 max: self.max.max(other.max),
144 }
145 }
146
147 #[inline]
148 fn grow(&self, amount: impl Into<Self::HalfSize>) -> Self {
149 let amount = amount.into();
150 let b = Self {
151 min: self.min - amount,
152 max: self.max + amount,
153 };
154 if true {
if !(b.min.x <= b.max.x && b.min.y <= b.max.y) {
::core::panicking::panic("assertion failed: b.min.x <= b.max.x && b.min.y <= b.max.y")
};
};debug_assert!(b.min.x <= b.max.x && b.min.y <= b.max.y);
155 b
156 }
157
158 #[inline]
159 fn shrink(&self, amount: impl Into<Self::HalfSize>) -> Self {
160 let amount = amount.into();
161 let b = Self {
162 min: self.min + amount,
163 max: self.max - amount,
164 };
165 if true {
if !(b.min.x <= b.max.x && b.min.y <= b.max.y) {
::core::panicking::panic("assertion failed: b.min.x <= b.max.x && b.min.y <= b.max.y")
};
};debug_assert!(b.min.x <= b.max.x && b.min.y <= b.max.y);
166 b
167 }
168
169 #[inline]
170 fn scale_around_center(&self, scale: impl Into<Self::HalfSize>) -> Self {
171 let scale = scale.into();
172 let b = Self {
173 min: self.center() - (self.half_size() * scale),
174 max: self.center() + (self.half_size() * scale),
175 };
176 if true {
if !(b.min.x <= b.max.x && b.min.y <= b.max.y) {
::core::panicking::panic("assertion failed: b.min.x <= b.max.x && b.min.y <= b.max.y")
};
};debug_assert!(b.min.x <= b.max.x && b.min.y <= b.max.y);
177 b
178 }
179
180 #[inline]
188 fn transformed_by(
189 mut self,
190 translation: impl Into<Self::Translation>,
191 rotation: impl Into<Self::Rotation>,
192 ) -> Self {
193 self.transform_by(translation, rotation);
194 self
195 }
196
197 #[inline]
205 fn transform_by(
206 &mut self,
207 translation: impl Into<Self::Translation>,
208 rotation: impl Into<Self::Rotation>,
209 ) {
210 self.rotate_by(rotation);
211 self.translate_by(translation);
212 }
213
214 #[inline]
215 fn translate_by(&mut self, translation: impl Into<Self::Translation>) {
216 let translation = translation.into();
217 self.min += translation;
218 self.max += translation;
219 }
220
221 #[inline]
229 fn rotated_by(mut self, rotation: impl Into<Self::Rotation>) -> Self {
230 self.rotate_by(rotation);
231 self
232 }
233
234 #[inline]
242 fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
243 let rot_mat = Mat2::from(rotation.into());
244 let half_size = rot_mat.abs() * self.half_size();
245 *self = Self::new(rot_mat * self.center(), half_size);
246 }
247}
248
249impl IntersectsVolume<Self> for Aabb2d {
250 #[inline]
251 fn intersects(&self, other: &Self) -> bool {
252 let x_overlaps = self.min.x <= other.max.x && self.max.x >= other.min.x;
253 let y_overlaps = self.min.y <= other.max.y && self.max.y >= other.min.y;
254 x_overlaps && y_overlaps
255 }
256}
257
258impl IntersectsVolume<BoundingCircle> for Aabb2d {
259 #[inline]
260 fn intersects(&self, circle: &BoundingCircle) -> bool {
261 let closest_point = self.closest_point(circle.center);
262 let distance_squared = circle.center.distance_squared(closest_point);
263 let radius_squared = circle.radius().squared();
264 distance_squared <= radius_squared
265 }
266}
267
268#[cfg(test)]
269mod aabb2d_tests {
270 use approx::assert_relative_eq;
271
272 use crate::{Aabb2d, BoundingCircle, BoundingVolume, IntersectsVolume};
273 use bevy_math::{ops, Vec2};
274
275 #[test]
276 fn center() {
277 let aabb = Aabb2d {
278 min: Vec2::new(-0.5, -1.),
279 max: Vec2::new(1., 1.),
280 };
281 assert!((aabb.center() - Vec2::new(0.25, 0.)).length() < f32::EPSILON);
282 let aabb = Aabb2d {
283 min: Vec2::new(5., -10.),
284 max: Vec2::new(10., -5.),
285 };
286 assert!((aabb.center() - Vec2::new(7.5, -7.5)).length() < f32::EPSILON);
287 }
288
289 #[test]
290 fn half_size() {
291 let aabb = Aabb2d {
292 min: Vec2::new(-0.5, -1.),
293 max: Vec2::new(1., 1.),
294 };
295 let half_size = aabb.half_size();
296 assert!((half_size - Vec2::new(0.75, 1.)).length() < f32::EPSILON);
297 }
298
299 #[test]
300 fn area() {
301 let aabb = Aabb2d {
302 min: Vec2::new(-1., -1.),
303 max: Vec2::new(1., 1.),
304 };
305 assert!(ops::abs(aabb.visible_area() - 4.) < f32::EPSILON);
306 let aabb = Aabb2d {
307 min: Vec2::new(0., 0.),
308 max: Vec2::new(1., 0.5),
309 };
310 assert!(ops::abs(aabb.visible_area() - 0.5) < f32::EPSILON);
311 }
312
313 #[test]
314 fn contains() {
315 let a = Aabb2d {
316 min: Vec2::new(-1., -1.),
317 max: Vec2::new(1., 1.),
318 };
319 let b = Aabb2d {
320 min: Vec2::new(-2., -1.),
321 max: Vec2::new(1., 1.),
322 };
323 assert!(!a.contains(&b));
324 let b = Aabb2d {
325 min: Vec2::new(-0.25, -0.8),
326 max: Vec2::new(1., 1.),
327 };
328 assert!(a.contains(&b));
329 }
330
331 #[test]
332 fn merge() {
333 let a = Aabb2d {
334 min: Vec2::new(-1., -1.),
335 max: Vec2::new(1., 0.5),
336 };
337 let b = Aabb2d {
338 min: Vec2::new(-2., -0.5),
339 max: Vec2::new(0.75, 1.),
340 };
341 let merged = a.merge(&b);
342 assert!((merged.min - Vec2::new(-2., -1.)).length() < f32::EPSILON);
343 assert!((merged.max - Vec2::new(1., 1.)).length() < f32::EPSILON);
344 assert!(merged.contains(&a));
345 assert!(merged.contains(&b));
346 assert!(!a.contains(&merged));
347 assert!(!b.contains(&merged));
348 }
349
350 #[test]
351 fn grow() {
352 let a = Aabb2d {
353 min: Vec2::new(-1., -1.),
354 max: Vec2::new(1., 1.),
355 };
356 let padded = a.grow(Vec2::ONE);
357 assert!((padded.min - Vec2::new(-2., -2.)).length() < f32::EPSILON);
358 assert!((padded.max - Vec2::new(2., 2.)).length() < f32::EPSILON);
359 assert!(padded.contains(&a));
360 assert!(!a.contains(&padded));
361 }
362
363 #[test]
364 fn shrink() {
365 let a = Aabb2d {
366 min: Vec2::new(-2., -2.),
367 max: Vec2::new(2., 2.),
368 };
369 let shrunk = a.shrink(Vec2::ONE);
370 assert!((shrunk.min - Vec2::new(-1., -1.)).length() < f32::EPSILON);
371 assert!((shrunk.max - Vec2::new(1., 1.)).length() < f32::EPSILON);
372 assert!(a.contains(&shrunk));
373 assert!(!shrunk.contains(&a));
374 }
375
376 #[test]
377 fn scale_around_center() {
378 let a = Aabb2d {
379 min: Vec2::NEG_ONE,
380 max: Vec2::ONE,
381 };
382 let scaled = a.scale_around_center(Vec2::splat(2.));
383 assert!((scaled.min - Vec2::splat(-2.)).length() < f32::EPSILON);
384 assert!((scaled.max - Vec2::splat(2.)).length() < f32::EPSILON);
385 assert!(!a.contains(&scaled));
386 assert!(scaled.contains(&a));
387 }
388
389 #[test]
390 fn rotate() {
391 let a = Aabb2d {
392 min: Vec2::new(-2.0, -2.0),
393 max: Vec2::new(2.0, 2.0),
394 };
395 let rotated = a.rotated_by(core::f32::consts::PI);
396 assert_relative_eq!(rotated.min, a.min);
397 assert_relative_eq!(rotated.max, a.max);
398 }
399
400 #[test]
401 fn transform() {
402 let a = Aabb2d {
403 min: Vec2::new(-2.0, -2.0),
404 max: Vec2::new(2.0, 2.0),
405 };
406 let transformed = a.transformed_by(Vec2::new(2.0, -2.0), core::f32::consts::FRAC_PI_4);
407 let half_length = ops::hypot(2.0, 2.0);
408 assert_eq!(
409 transformed.min,
410 Vec2::new(2.0 - half_length, -half_length - 2.0)
411 );
412 assert_eq!(
413 transformed.max,
414 Vec2::new(2.0 + half_length, half_length - 2.0)
415 );
416 }
417
418 #[test]
419 fn closest_point() {
420 let aabb = Aabb2d {
421 min: Vec2::NEG_ONE,
422 max: Vec2::ONE,
423 };
424 assert_eq!(aabb.closest_point(Vec2::X * 10.0), Vec2::X);
425 assert_eq!(aabb.closest_point(Vec2::NEG_ONE * 10.0), Vec2::NEG_ONE);
426 assert_eq!(
427 aabb.closest_point(Vec2::new(0.25, 0.1)),
428 Vec2::new(0.25, 0.1)
429 );
430 }
431
432 #[test]
433 fn intersect_aabb() {
434 let aabb = Aabb2d {
435 min: Vec2::NEG_ONE,
436 max: Vec2::ONE,
437 };
438 assert!(aabb.intersects(&aabb));
439 assert!(aabb.intersects(&Aabb2d {
440 min: Vec2::new(0.5, 0.5),
441 max: Vec2::new(2.0, 2.0),
442 }));
443 assert!(aabb.intersects(&Aabb2d {
444 min: Vec2::new(-2.0, -2.0),
445 max: Vec2::new(-0.5, -0.5),
446 }));
447 assert!(!aabb.intersects(&Aabb2d {
448 min: Vec2::new(1.1, 0.0),
449 max: Vec2::new(2.0, 0.5),
450 }));
451 }
452
453 #[test]
454 fn intersect_bounding_circle() {
455 let aabb = Aabb2d {
456 min: Vec2::NEG_ONE,
457 max: Vec2::ONE,
458 };
459 assert!(aabb.intersects(&BoundingCircle::new(Vec2::ZERO, 1.0)));
460 assert!(aabb.intersects(&BoundingCircle::new(Vec2::ONE * 1.5, 1.0)));
461 assert!(aabb.intersects(&BoundingCircle::new(Vec2::NEG_ONE * 1.5, 1.0)));
462 assert!(!aabb.intersects(&BoundingCircle::new(Vec2::ONE * 1.75, 1.0)));
463 }
464}
465
466#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for BoundingCircle {
}
#[automatically_derived]impl ::core::clone::Clone for BoundingCircle {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Vec2>;
let _: ::core::clone::AssertParamIsClone<Circle>;
*self
}
}Clone, #[automatically_derived]impl ::core::marker::Copy for BoundingCircle { }Copy, #[automatically_derived]impl ::core::fmt::Debug for BoundingCircle {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"BoundingCircle", "center", &self.center, "circle", &&self.circle)
}
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for
BoundingCircle {
}
#[automatically_derived]impl ::core::cmp::PartialEq for BoundingCircle {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.center == other.center && self.circle == other.circle
}
}PartialEq)]
468#[cfg_attr(
469 feature = "bevy_reflect",
470 derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for BoundingCircle where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.register_type_data_with::<ReflectSerialize, Self,
_>(());
registration.register_type_data_with::<ReflectDeserialize,
Self, _>(());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<Vec2 as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<Circle as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl bevy_reflect::Typed for BoundingCircle where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<Vec2>("center"),
bevy_reflect::NamedField::new::<Circle>("circle")]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for BoundingCircle where {
fn type_path() -> &'static str {
"bevy_shape::bounding::bounded2d::BoundingCircle"
}
fn short_type_path() -> &'static str { "BoundingCircle" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("BoundingCircle")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_shape::bounding::bounded2d".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_shape::bounding::bounded2d")
}
}
impl bevy_reflect::Reflect for BoundingCircle where {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl bevy_reflect::structs::Struct for BoundingCircle where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"center" => ::core::option::Option::Some(&self.center),
"circle" => ::core::option::Option::Some(&self.circle),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"center" => ::core::option::Option::Some(&mut self.center),
"circle" => ::core::option::Option::Some(&mut self.circle),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.center),
1usize => ::core::option::Option::Some(&self.circle),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.center),
1usize => ::core::option::Option::Some(&mut self.circle),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("center"),
1usize => ::core::option::Option::Some("circle"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"center" => ::core::option::Option::Some(0usize),
"circle" => ::core::option::Option::Some(1usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 2usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("center",
bevy_reflect::PartialReflect::to_dynamic(&self.center)?);
dynamic.insert_boxed("circle",
bevy_reflect::PartialReflect::to_dynamic(&self.circle)?);
::core::result::Result::Ok(dynamic)
}
}
impl bevy_reflect::PartialReflect for BoundingCircle where {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
let value =
<dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
if let ::core::option::Option::Some(value) = value {
::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
value))
} else { ::core::option::Option::Some(false) }
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl bevy_reflect::FromReflect for BoundingCircle where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let __this =
Self {
center: <Vec2 as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"center")?)?,
circle: <Circle as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"circle")?)?,
};
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect),
471 reflect(Debug, PartialEq, Clone)
472)]
473#[cfg_attr(feature = "serialize", derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl _serde::Serialize for BoundingCircle {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private229::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
let mut __serde_state =
_serde::Serializer::serialize_struct(__serializer,
"BoundingCircle", false as usize + 1 + 1)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"center", &self.center)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"circle", &self.circle)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
};Serialize), derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
{
#[allow(unused_extern_crates, clippy :: useless_attribute)]
extern crate serde as _serde;
;
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for BoundingCircle {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field { __field0, __field1, __ignore, }
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"field identifier")
}
fn visit_u64<__E>(self, __value: u64)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
0u64 => _serde::__private229::Ok(__Field::__field0),
1u64 => _serde::__private229::Ok(__Field::__field1),
_ => _serde::__private229::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(self, __value: &str)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
"center" => _serde::__private229::Ok(__Field::__field0),
"circle" => _serde::__private229::Ok(__Field::__field1),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
fn visit_bytes<__E>(self, __value: &[u8])
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
b"center" => _serde::__private229::Ok(__Field::__field0),
b"circle" => _serde::__private229::Ok(__Field::__field1),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
_serde::Deserializer::deserialize_identifier(__deserializer,
__FieldVisitor)
}
}
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private229::PhantomData<BoundingCircle>,
lifetime: _serde::__private229::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = BoundingCircle;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"struct BoundingCircle")
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<Vec2>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(0usize,
&"struct BoundingCircle with 2 elements")),
};
let __field1 =
match _serde::de::SeqAccess::next_element::<Circle>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(1usize,
&"struct BoundingCircle with 2 elements")),
};
_serde::__private229::Ok(BoundingCircle {
center: __field0,
circle: __field1,
})
}
#[inline]
fn visit_map<__A>(self, mut __map: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de> {
let mut __field0: _serde::__private229::Option<Vec2> =
_serde::__private229::None;
let mut __field1: _serde::__private229::Option<Circle> =
_serde::__private229::None;
while let _serde::__private229::Some(__key) =
_serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
__Field::__field0 => {
if _serde::__private229::Option::is_some(&__field0) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("center"));
}
__field0 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Vec2>(&mut __map)?);
}
__Field::__field1 => {
if _serde::__private229::Option::is_some(&__field1) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("circle"));
}
__field1 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<Circle>(&mut __map)?);
}
_ => {
let _ =
_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
}
}
}
let __field0 =
match __field0 {
_serde::__private229::Some(__field0) => __field0,
_serde::__private229::None =>
_serde::__private229::de::missing_field("center")?,
};
let __field1 =
match __field1 {
_serde::__private229::Some(__field1) => __field1,
_serde::__private229::None =>
_serde::__private229::de::missing_field("circle")?,
};
_serde::__private229::Ok(BoundingCircle {
center: __field0,
circle: __field1,
})
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &["center", "circle"];
_serde::Deserializer::deserialize_struct(__deserializer,
"BoundingCircle", FIELDS,
__Visitor {
marker: _serde::__private229::PhantomData::<BoundingCircle>,
lifetime: _serde::__private229::PhantomData,
})
}
}
};Deserialize))]
474#[cfg_attr(
475 all(feature = "serialize", feature = "bevy_reflect"),
476 reflect(Serialize, Deserialize)
477)]
478pub struct BoundingCircle {
479 pub center: Vec2,
481 pub circle: Circle,
483}
484
485impl BoundingCircle {
486 #[inline]
488 pub const fn new(center: Vec2, radius: f32) -> Self {
489 if true {
if !(radius >= 0.) {
::core::panicking::panic("assertion failed: radius >= 0.")
};
};debug_assert!(radius >= 0.);
490 Self {
491 center,
492 circle: Circle { radius },
493 }
494 }
495
496 #[inline]
501 pub fn from_point_cloud(isometry: impl Into<Isometry2d>, points: &[Vec2]) -> BoundingCircle {
502 let isometry = isometry.into();
503
504 let center = point_cloud_2d_center(points);
505 let mut radius_squared = 0.0;
506
507 for point in points {
508 let distance_squared = point.distance_squared(center);
510 if distance_squared > radius_squared {
511 radius_squared = distance_squared;
512 }
513 }
514
515 BoundingCircle::new(isometry * center, ops::sqrt(radius_squared))
516 }
517
518 #[inline]
520 pub const fn radius(&self) -> f32 {
521 self.circle.radius
522 }
523
524 #[inline]
526 pub fn aabb_2d(&self) -> Aabb2d {
527 Aabb2d {
528 min: self.center - Vec2::splat(self.radius()),
529 max: self.center + Vec2::splat(self.radius()),
530 }
531 }
532
533 #[inline]
538 pub fn closest_point(&self, point: Vec2) -> Vec2 {
539 self.circle.closest_point(point - self.center) + self.center
540 }
541}
542
543impl BoundingVolume for BoundingCircle {
544 type Translation = Vec2;
545 type Rotation = Rot2;
546 type HalfSize = f32;
547
548 #[inline]
549 fn center(&self) -> Self::Translation {
550 self.center
551 }
552
553 #[inline]
554 fn half_size(&self) -> Self::HalfSize {
555 self.radius()
556 }
557
558 #[inline]
559 fn visible_area(&self) -> f32 {
560 core::f32::consts::PI * self.radius() * self.radius()
561 }
562
563 #[inline]
564 fn contains(&self, other: &Self) -> bool {
565 let diff = self.radius() - other.radius();
566 self.center.distance_squared(other.center) <= ops::copysign(diff.squared(), diff)
567 }
568
569 #[inline]
570 fn merge(&self, other: &Self) -> Self {
571 let diff = other.center - self.center;
572 let length = diff.length();
573 if self.radius() >= length + other.radius() {
574 return *self;
575 }
576 if other.radius() >= length + self.radius() {
577 return *other;
578 }
579 let dir = diff / length;
580 Self::new(
581 (self.center + other.center) / 2. + dir * ((other.radius() - self.radius()) / 2.),
582 (length + self.radius() + other.radius()) / 2.,
583 )
584 }
585
586 #[inline]
587 fn grow(&self, amount: impl Into<Self::HalfSize>) -> Self {
588 let amount = amount.into();
589 if true {
if !(amount >= 0.) {
::core::panicking::panic("assertion failed: amount >= 0.")
};
};debug_assert!(amount >= 0.);
590 Self::new(self.center, self.radius() + amount)
591 }
592
593 #[inline]
594 fn shrink(&self, amount: impl Into<Self::HalfSize>) -> Self {
595 let amount = amount.into();
596 if true {
if !(amount >= 0.) {
::core::panicking::panic("assertion failed: amount >= 0.")
};
};debug_assert!(amount >= 0.);
597 if true {
if !(self.radius() >= amount) {
::core::panicking::panic("assertion failed: self.radius() >= amount")
};
};debug_assert!(self.radius() >= amount);
598 Self::new(self.center, self.radius() - amount)
599 }
600
601 #[inline]
602 fn scale_around_center(&self, scale: impl Into<Self::HalfSize>) -> Self {
603 let scale = scale.into();
604 if true {
if !(scale >= 0.) {
::core::panicking::panic("assertion failed: scale >= 0.")
};
};debug_assert!(scale >= 0.);
605 Self::new(self.center, self.radius() * scale)
606 }
607
608 #[inline]
609 fn translate_by(&mut self, translation: impl Into<Self::Translation>) {
610 self.center += translation.into();
611 }
612
613 #[inline]
614 fn rotate_by(&mut self, rotation: impl Into<Self::Rotation>) {
615 let rotation: Rot2 = rotation.into();
616 self.center = rotation * self.center;
617 }
618}
619
620impl IntersectsVolume<Self> for BoundingCircle {
621 #[inline]
622 fn intersects(&self, other: &Self) -> bool {
623 let center_distance_squared = self.center.distance_squared(other.center);
624 let radius_sum_squared = (self.radius() + other.radius()).squared();
625 center_distance_squared <= radius_sum_squared
626 }
627}
628
629impl IntersectsVolume<Aabb2d> for BoundingCircle {
630 #[inline]
631 fn intersects(&self, aabb: &Aabb2d) -> bool {
632 aabb.intersects(self)
633 }
634}
635
636#[cfg(test)]
637mod bounding_circle_tests {
638 use crate::{BoundingCircle, BoundingVolume, IntersectsVolume};
639 use bevy_math::{ops, Vec2};
640
641 #[test]
642 fn area() {
643 let circle = BoundingCircle::new(Vec2::ONE, 5.);
644 assert!(ops::abs(circle.visible_area() - 78.5398) < 0.001);
646 }
647
648 #[test]
649 fn contains() {
650 let a = BoundingCircle::new(Vec2::ONE, 5.);
651 let b = BoundingCircle::new(Vec2::new(5.5, 1.), 1.);
652 assert!(!a.contains(&b));
653 let b = BoundingCircle::new(Vec2::new(1., -3.5), 0.5);
654 assert!(a.contains(&b));
655 }
656
657 #[test]
658 fn contains_identical() {
659 let a = BoundingCircle::new(Vec2::ONE, 5.);
660 assert!(a.contains(&a));
661 }
662
663 #[test]
664 fn merge() {
665 let a = BoundingCircle::new(Vec2::ONE, 5.);
668 let b = BoundingCircle::new(Vec2::new(1., -4.), 1.);
669 let merged = a.merge(&b);
670 assert!((merged.center - Vec2::new(1., 0.5)).length() < f32::EPSILON);
671 assert!(ops::abs(merged.radius() - 5.5) < f32::EPSILON);
672 assert!(merged.contains(&a));
673 assert!(merged.contains(&b));
674 assert!(!a.contains(&merged));
675 assert!(!b.contains(&merged));
676
677 let b = BoundingCircle::new(Vec2::ZERO, 3.);
679 assert!(a.contains(&b));
680 let merged = a.merge(&b);
681 assert_eq!(merged.center, a.center);
682 assert_eq!(merged.radius(), a.radius());
683
684 let b = BoundingCircle::new(Vec2::ONE, 6.);
686 let merged = a.merge(&b);
687 assert_eq!(merged.center, a.center);
688 assert_eq!(merged.radius(), b.radius());
689 }
690
691 #[test]
692 fn merge_identical() {
693 let a = BoundingCircle::new(Vec2::ONE, 5.);
694 let merged = a.merge(&a);
695 assert_eq!(merged.center, a.center);
696 assert_eq!(merged.radius(), a.radius());
697 }
698
699 #[test]
700 fn grow() {
701 let a = BoundingCircle::new(Vec2::ONE, 5.);
702 let padded = a.grow(1.25_f32);
703 assert!(ops::abs(padded.radius() - 6.25) < f32::EPSILON);
704 assert!(padded.contains(&a));
705 assert!(!a.contains(&padded));
706 }
707
708 #[test]
709 fn shrink() {
710 let a = BoundingCircle::new(Vec2::ONE, 5.);
711 let shrunk = a.shrink(0.5_f32);
712 assert!(ops::abs(shrunk.radius() - 4.5) < f32::EPSILON);
713 assert!(a.contains(&shrunk));
714 assert!(!shrunk.contains(&a));
715 }
716
717 #[test]
718 fn scale_around_center() {
719 let a = BoundingCircle::new(Vec2::ONE, 5.);
720 let scaled = a.scale_around_center(2_f32);
721 assert!(ops::abs(scaled.radius() - 10.) < f32::EPSILON);
722 assert!(!a.contains(&scaled));
723 assert!(scaled.contains(&a));
724 }
725
726 #[test]
727 fn transform() {
728 let a = BoundingCircle::new(Vec2::ONE, 5.0);
729 let transformed = a.transformed_by(Vec2::new(2.0, -2.0), core::f32::consts::FRAC_PI_4);
730 assert_eq!(
731 transformed.center,
732 Vec2::new(2.0, core::f32::consts::SQRT_2 - 2.0)
733 );
734 assert_eq!(transformed.radius(), 5.0);
735 }
736
737 #[test]
738 fn closest_point() {
739 let circle = BoundingCircle::new(Vec2::ZERO, 1.0);
740 assert_eq!(circle.closest_point(Vec2::X * 10.0), Vec2::X);
741 assert_eq!(
742 circle.closest_point(Vec2::NEG_ONE * 10.0),
743 Vec2::NEG_ONE.normalize()
744 );
745 assert_eq!(
746 circle.closest_point(Vec2::new(0.25, 0.1)),
747 Vec2::new(0.25, 0.1)
748 );
749 }
750
751 #[test]
752 fn intersect_bounding_circle() {
753 let circle = BoundingCircle::new(Vec2::ZERO, 1.0);
754 assert!(circle.intersects(&BoundingCircle::new(Vec2::ZERO, 1.0)));
755 assert!(circle.intersects(&BoundingCircle::new(Vec2::ONE * 1.25, 1.0)));
756 assert!(circle.intersects(&BoundingCircle::new(Vec2::NEG_ONE * 1.25, 1.0)));
757 assert!(!circle.intersects(&BoundingCircle::new(Vec2::ONE * 1.5, 1.0)));
758 }
759}