1use crate::collision::Polygon;
6use crate::hull::{validate_hull, Hull};
7use crate::math_functions::{
8 add, cross, cross_vs, dot, is_valid_float, mul_add, normalize, rotate_vector, sub,
9 transform_point, Rot, Transform, Vec2, VEC2_ZERO,
10};
11
12pub(crate) fn compute_polygon_centroid(vertices: &[Vec2]) -> Vec2 {
13 let mut center = VEC2_ZERO;
14 let mut area = 0.0f32;
15
16 let origin = vertices[0];
19
20 let inv3 = 1.0 / 3.0;
21
22 let count = vertices.len();
23 for i in 1..count - 1 {
24 let e1 = sub(vertices[i], origin);
26 let e2 = sub(vertices[i + 1], origin);
27 let a = 0.5 * cross(e1, e2);
28
29 center = mul_add(center, a * inv3, add(e1, e2));
31 area += a;
32 }
33
34 debug_assert!(area > f32::EPSILON);
35 let inv_area = 1.0 / area;
36 center.x *= inv_area;
37 center.y *= inv_area;
38
39 add(origin, center)
41}
42
43pub fn make_polygon(hull: &Hull, radius: f32) -> Polygon {
49 debug_assert!(validate_hull(hull));
50
51 if hull.count < 3 {
52 return make_square(0.5);
54 }
55
56 let mut shape = Polygon {
57 count: hull.count,
58 radius,
59 ..Default::default()
60 };
61
62 for i in 0..shape.count as usize {
64 shape.vertices[i] = hull.points[i];
65 }
66
67 for i in 0..shape.count as usize {
69 let i1 = i;
70 let i2 = if i + 1 < shape.count as usize {
71 i + 1
72 } else {
73 0
74 };
75 let edge = sub(shape.vertices[i2], shape.vertices[i1]);
76 debug_assert!(dot(edge, edge) > f32::EPSILON * f32::EPSILON);
77 shape.normals[i] = normalize(cross_vs(edge, 1.0));
78 }
79
80 shape.centroid = compute_polygon_centroid(&shape.vertices[..shape.count as usize]);
81
82 shape
83}
84
85pub fn make_offset_polygon(hull: &Hull, position: Vec2, rotation: Rot) -> Polygon {
88 make_offset_rounded_polygon(hull, position, rotation, 0.0)
89}
90
91pub fn make_offset_rounded_polygon(
94 hull: &Hull,
95 position: Vec2,
96 rotation: Rot,
97 radius: f32,
98) -> Polygon {
99 debug_assert!(validate_hull(hull));
100
101 if hull.count < 3 {
102 return make_square(0.5);
104 }
105
106 let transform = Transform {
107 p: position,
108 q: rotation,
109 };
110
111 let mut shape = Polygon {
112 count: hull.count,
113 radius,
114 ..Default::default()
115 };
116
117 for i in 0..shape.count as usize {
119 shape.vertices[i] = transform_point(transform, hull.points[i]);
120 }
121
122 for i in 0..shape.count as usize {
124 let i1 = i;
125 let i2 = if i + 1 < shape.count as usize {
126 i + 1
127 } else {
128 0
129 };
130 let edge = sub(shape.vertices[i2], shape.vertices[i1]);
131 debug_assert!(dot(edge, edge) > f32::EPSILON * f32::EPSILON);
132 shape.normals[i] = normalize(cross_vs(edge, 1.0));
133 }
134
135 shape.centroid = compute_polygon_centroid(&shape.vertices[..shape.count as usize]);
136
137 shape
138}
139
140pub fn make_square(half_width: f32) -> Polygon {
142 make_box(half_width, half_width)
143}
144
145pub fn make_box(half_width: f32, half_height: f32) -> Polygon {
148 debug_assert!(is_valid_float(half_width) && half_width > 0.0);
149 debug_assert!(is_valid_float(half_height) && half_height > 0.0);
150
151 let mut shape = Polygon {
152 count: 4,
153 ..Default::default()
154 };
155 shape.vertices[0] = Vec2 {
156 x: -half_width,
157 y: -half_height,
158 };
159 shape.vertices[1] = Vec2 {
160 x: half_width,
161 y: -half_height,
162 };
163 shape.vertices[2] = Vec2 {
164 x: half_width,
165 y: half_height,
166 };
167 shape.vertices[3] = Vec2 {
168 x: -half_width,
169 y: half_height,
170 };
171 shape.normals[0] = Vec2 { x: 0.0, y: -1.0 };
172 shape.normals[1] = Vec2 { x: 1.0, y: 0.0 };
173 shape.normals[2] = Vec2 { x: 0.0, y: 1.0 };
174 shape.normals[3] = Vec2 { x: -1.0, y: 0.0 };
175 shape.radius = 0.0;
176 shape.centroid = VEC2_ZERO;
177 shape
178}
179
180pub fn make_rounded_box(half_width: f32, half_height: f32, radius: f32) -> Polygon {
182 debug_assert!(is_valid_float(radius) && radius >= 0.0);
183 let mut shape = make_box(half_width, half_height);
184 shape.radius = radius;
185 shape
186}
187
188pub fn make_offset_box(half_width: f32, half_height: f32, center: Vec2, rotation: Rot) -> Polygon {
190 let xf = Transform {
191 p: center,
192 q: rotation,
193 };
194
195 let mut shape = Polygon {
196 count: 4,
197 ..Default::default()
198 };
199 shape.vertices[0] = transform_point(
200 xf,
201 Vec2 {
202 x: -half_width,
203 y: -half_height,
204 },
205 );
206 shape.vertices[1] = transform_point(
207 xf,
208 Vec2 {
209 x: half_width,
210 y: -half_height,
211 },
212 );
213 shape.vertices[2] = transform_point(
214 xf,
215 Vec2 {
216 x: half_width,
217 y: half_height,
218 },
219 );
220 shape.vertices[3] = transform_point(
221 xf,
222 Vec2 {
223 x: -half_width,
224 y: half_height,
225 },
226 );
227 shape.normals[0] = rotate_vector(xf.q, Vec2 { x: 0.0, y: -1.0 });
228 shape.normals[1] = rotate_vector(xf.q, Vec2 { x: 1.0, y: 0.0 });
229 shape.normals[2] = rotate_vector(xf.q, Vec2 { x: 0.0, y: 1.0 });
230 shape.normals[3] = rotate_vector(xf.q, Vec2 { x: -1.0, y: 0.0 });
231 shape.radius = 0.0;
232 shape.centroid = xf.p;
233 shape
234}
235
236pub fn make_offset_rounded_box(
239 half_width: f32,
240 half_height: f32,
241 center: Vec2,
242 rotation: Rot,
243 radius: f32,
244) -> Polygon {
245 debug_assert!(is_valid_float(radius) && radius >= 0.0);
246 let mut shape = make_offset_box(half_width, half_height, center, rotation);
247 shape.radius = radius;
248 shape
249}
250
251pub fn transform_polygon(transform: Transform, polygon: &Polygon) -> Polygon {
254 let mut p = *polygon;
255
256 for i in 0..p.count as usize {
257 p.vertices[i] = transform_point(transform, p.vertices[i]);
258 p.normals[i] = rotate_vector(transform.q, p.normals[i]);
259 }
260
261 p.centroid = transform_point(transform, p.centroid);
262
263 p
264}