Line data Source code
1 : /* File: geometry_rectangle.inl; Copyright and License: see below */
2 :
3 : #include "u8/u8_trace.h"
4 : #include "u8/u8_log.h"
5 : #include <assert.h>
6 : #include <math.h>
7 :
8 524 : static inline void geometry_rectangle_init ( geometry_rectangle_t *this_, double left, double top, double width, double height )
9 : {
10 524 : (*this_).left = left;
11 524 : (*this_).top = top;
12 524 : (*this_).width = width;
13 524 : (*this_).height = height;
14 524 : }
15 :
16 783 : static inline void geometry_rectangle_reinit ( geometry_rectangle_t *this_, double left, double top, double width, double height )
17 : {
18 783 : (*this_).left = left;
19 783 : (*this_).top = top;
20 783 : (*this_).width = width;
21 783 : (*this_).height = height;
22 783 : }
23 :
24 174 : static inline void geometry_rectangle_copy ( geometry_rectangle_t *this_, const geometry_rectangle_t *original )
25 : {
26 174 : assert( NULL != original );
27 174 : (*this_) = (*original);
28 174 : }
29 :
30 : static inline void geometry_rectangle_move ( geometry_rectangle_t *this_, geometry_rectangle_t *that )
31 : {
32 : assert( NULL != that );
33 : (*this_) = (*that);
34 : }
35 :
36 1085 : static inline void geometry_rectangle_replace ( geometry_rectangle_t *this_, const geometry_rectangle_t *original )
37 : {
38 1085 : assert( NULL != original );
39 1085 : (*this_) = (*original);
40 1085 : }
41 :
42 0 : static inline void geometry_rectangle_replacemove ( geometry_rectangle_t *this_, geometry_rectangle_t *that )
43 : {
44 0 : assert( NULL != that );
45 0 : (*this_) = (*that);
46 0 : }
47 :
48 3481 : static inline void geometry_rectangle_init_empty ( geometry_rectangle_t *this_ )
49 : {
50 3481 : (*this_).left = 0.0;
51 3481 : (*this_).top = 0.0;
52 3481 : (*this_).width = 0.0;
53 3481 : (*this_).height = 0.0;
54 3481 : }
55 :
56 : static inline void geometry_rectangle_reinit_empty ( geometry_rectangle_t *this_ )
57 : {
58 : (*this_).left = 0.0;
59 : (*this_).top = 0.0;
60 : (*this_).width = 0.0;
61 : (*this_).height = 0.0;
62 : }
63 :
64 180 : static inline int geometry_rectangle_init_by_intersect ( geometry_rectangle_t *this_,
65 : const geometry_rectangle_t *rect_a,
66 : const geometry_rectangle_t *rect_b )
67 : {
68 180 : assert( NULL != rect_a );
69 180 : assert( NULL != rect_b );
70 :
71 180 : int result = 0;
72 :
73 180 : const double rect_a_right = (*rect_a).left + (*rect_a).width;
74 180 : const double rect_a_bottom = (*rect_a).top + (*rect_a).height;
75 180 : const double rect_b_right = (*rect_b).left + (*rect_b).width;
76 180 : const double rect_b_bottom = (*rect_b).top + (*rect_b).height;
77 :
78 180 : (*this_).left = fmax( (*rect_a).left, (*rect_b).left );
79 180 : (*this_).top = fmax( (*rect_a).top, (*rect_b).top );
80 180 : (*this_).width = fmin( rect_a_right, rect_b_right ) - (*this_).left;
81 180 : (*this_).height = fmin( rect_a_bottom, rect_b_bottom ) - (*this_).top;
82 180 : if (( (*this_).width < -0.000000001 ) || ( (*this_).height < -0.000000001 ))
83 : {
84 : /* if intersection is empty, result is -1 */
85 25 : (*this_).left = 0.0;
86 25 : (*this_).top = 0.0;
87 25 : (*this_).width = 0.0;
88 25 : (*this_).height = 0.0;
89 25 : result = -1;
90 : }
91 155 : else if (( (*this_).width < 0.0 ) || ( (*this_).height < 0.0 ))
92 : {
93 : /* update rounding error */
94 63 : (*this_).width = 0.0;
95 63 : (*this_).height = 0.0;
96 : }
97 :
98 180 : return result;
99 : }
100 :
101 1537 : static inline int geometry_rectangle_init_by_bounds ( geometry_rectangle_t *this_,
102 : const geometry_rectangle_t *rect_a,
103 : const geometry_rectangle_t *rect_b )
104 : {
105 1537 : assert( NULL != rect_a );
106 1537 : assert( NULL != rect_b );
107 :
108 1537 : int result = 0;
109 :
110 1537 : const double rect_a_right = (*rect_a).left + (*rect_a).width;
111 1537 : const double rect_a_bottom = (*rect_a).top + (*rect_a).height;
112 1537 : const double rect_b_right = (*rect_b).left + (*rect_b).width;
113 1537 : const double rect_b_bottom = (*rect_b).top + (*rect_b).height;
114 :
115 1537 : (*this_).left = fmin( (*rect_a).left, (*rect_b).left );
116 1537 : (*this_).top = fmin( (*rect_a).top, (*rect_b).top );
117 1537 : (*this_).width = fmax( rect_a_right, rect_b_right ) - (*this_).left;
118 1537 : (*this_).height = fmax( rect_a_bottom, rect_b_bottom ) - (*this_).top;
119 :
120 1537 : return result;
121 : }
122 :
123 32 : static inline bool geometry_rectangle_is_intersecting ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
124 : {
125 32 : assert( NULL != that );
126 :
127 : bool result;
128 :
129 32 : const double rect_this_right = (*this_).left + (*this_).width;
130 32 : const double rect_this_bottom = (*this_).top + (*this_).height;
131 32 : const double rect_that_right = (*that).left + (*that).width;
132 32 : const double rect_that_bottom = (*that).top + (*that).height;
133 :
134 32 : if ( ( rect_this_right < (*that).left + 0.000000001 )
135 25 : || ( rect_this_bottom < (*that).top + 0.000000001 )
136 15 : || ( (*this_).left + 0.000000001 > rect_that_right )
137 8 : || ( (*this_).top + 0.000000001 > rect_that_bottom ) )
138 : {
139 28 : result = false;
140 : }
141 : else
142 : {
143 4 : result = true;
144 : }
145 :
146 32 : return result;
147 : }
148 :
149 52 : static inline bool geometry_rectangle_is_contiguous ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
150 : {
151 52 : assert( NULL != that );
152 :
153 : bool result;
154 :
155 52 : const double rect_this_right = (*this_).left + (*this_).width;
156 52 : const double rect_this_bottom = (*this_).top + (*this_).height;
157 52 : const double rect_that_right = (*that).left + (*that).width;
158 52 : const double rect_that_bottom = (*that).top + (*that).height;
159 :
160 52 : if ( ( rect_this_right + 0.000000001 < (*that).left )
161 41 : || ( rect_this_bottom + 0.000000001 < (*that).top )
162 38 : || ( (*this_).left > rect_that_right + 0.000000001 )
163 31 : || ( (*this_).top > rect_that_bottom + 0.000000001 ) )
164 : {
165 25 : result = false;
166 : }
167 : else
168 : {
169 27 : result = true;
170 : }
171 :
172 52 : return result;
173 : }
174 :
175 464 : static inline bool geometry_rectangle_is_containing ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
176 : {
177 464 : assert( NULL != that );
178 :
179 : bool result;
180 :
181 464 : const double rect_this_right = (*this_).left + (*this_).width;
182 464 : const double rect_this_bottom = (*this_).top + (*this_).height;
183 464 : const double rect_that_right = (*that).left + (*that).width;
184 464 : const double rect_that_bottom = (*that).top + (*that).height;
185 :
186 464 : if ( ( (*this_).left < (*that).left + 0.000000001 ) /* touching is containing */
187 399 : && ( (*this_).top < (*that).top + 0.000000001 )
188 398 : && ( rect_this_right + 0.000000001 > rect_that_right )
189 397 : && ( rect_this_bottom + 0.000000001 > rect_that_bottom ) )
190 : {
191 397 : result = true;
192 : }
193 : else
194 : {
195 67 : result = false;
196 : }
197 :
198 464 : return result;
199 : }
200 :
201 72 : static inline void geometry_rectangle_init_by_corners ( geometry_rectangle_t *this_, double x1, double y1, double x2, double y2 )
202 : {
203 72 : if ( x1 < x2 )
204 : {
205 16 : (*this_).left = x1;
206 16 : (*this_).width = x2-x1;
207 : }
208 : else
209 : {
210 56 : (*this_).left = x2;
211 56 : (*this_).width = x1-x2;
212 : }
213 72 : if ( y1 < y2 )
214 : {
215 19 : (*this_).top = y1;
216 19 : (*this_).height = y2-y1;
217 : }
218 : else
219 : {
220 53 : (*this_).top = y2;
221 53 : (*this_).height = y1-y2;
222 : }
223 72 : }
224 :
225 3879 : static inline void geometry_rectangle_destroy ( geometry_rectangle_t *this_ )
226 : {
227 3879 : }
228 :
229 1176 : static inline double geometry_rectangle_get_left ( const geometry_rectangle_t *this_ )
230 : {
231 1176 : return (*this_).left;
232 : }
233 :
234 1368 : static inline double geometry_rectangle_get_top ( const geometry_rectangle_t *this_ )
235 : {
236 1368 : return (*this_).top;
237 : }
238 :
239 184 : static inline double geometry_rectangle_get_right ( const geometry_rectangle_t *this_ )
240 : {
241 184 : return (*this_).left + (*this_).width;
242 : }
243 :
244 312 : static inline double geometry_rectangle_get_bottom ( const geometry_rectangle_t *this_ )
245 : {
246 312 : return (*this_).top + (*this_).height;
247 : }
248 :
249 1694 : static inline double geometry_rectangle_get_width ( const geometry_rectangle_t *this_ )
250 : {
251 1694 : return (*this_).width;
252 : }
253 :
254 1454 : static inline double geometry_rectangle_get_height ( const geometry_rectangle_t *this_ )
255 : {
256 1454 : return (*this_).height;
257 : }
258 :
259 166 : static inline double geometry_rectangle_get_center_x ( const geometry_rectangle_t *this_ )
260 : {
261 166 : return (*this_).left + 0.5*(*this_).width;
262 : }
263 :
264 166 : static inline double geometry_rectangle_get_center_y ( const geometry_rectangle_t *this_ )
265 : {
266 166 : return (*this_).top + 0.5*(*this_).height;
267 : }
268 :
269 0 : static inline geometry_point_t geometry_rectangle_get_center ( const geometry_rectangle_t *this_ )
270 : {
271 : geometry_point_t result;
272 0 : geometry_point_init ( &result, (*this_).left + 0.5*(*this_).width, (*this_).top + 0.5*(*this_).height );
273 0 : return result;
274 : }
275 :
276 0 : static inline geometry_dimensions_t geometry_rectangle_get_dimensions ( const geometry_rectangle_t *this_ )
277 : {
278 : geometry_dimensions_t result;
279 0 : geometry_dimensions_init ( &result, (*this_).width, (*this_).height );
280 0 : return result;
281 : }
282 :
283 218 : static inline double geometry_rectangle_get_area ( const geometry_rectangle_t *this_ )
284 : {
285 218 : return (*this_).width * (*this_).height;
286 : }
287 :
288 2 : static inline bool geometry_rectangle_contains ( const geometry_rectangle_t *this_, double x, double y )
289 : {
290 2 : return (( (*this_).left <= x )&&( x < (*this_).left + (*this_).width )&&( (*this_).top <= y )&&( y < (*this_).top + (*this_).height ));
291 : }
292 :
293 0 : static inline bool geometry_rectangle_contains_point ( const geometry_rectangle_t *this_, const geometry_point_t *point )
294 : {
295 0 : return geometry_rectangle_contains( this_, geometry_point_get_x( point ), geometry_point_get_y( point ) );
296 : }
297 :
298 0 : static inline double geometry_rectangle_calc_chess_distance ( const geometry_rectangle_t *this_, double x, double y )
299 : {
300 0 : double result = 0.0;
301 0 : if ( x < (*this_).left )
302 : {
303 0 : result += ( (*this_).left - x );
304 : }
305 0 : else if ( x > (*this_).left + (*this_).width )
306 : {
307 0 : result += ( x - ((*this_).left + (*this_).width) );
308 : }
309 0 : if ( y < (*this_).top )
310 : {
311 0 : result += ( (*this_).top - y );
312 : }
313 0 : else if ( y > (*this_).top + (*this_).height )
314 : {
315 0 : result += ( y - ((*this_).top + (*this_).height) );
316 : }
317 0 : return result;
318 : }
319 :
320 352 : static inline bool geometry_rectangle_is_empty ( const geometry_rectangle_t *this_ )
321 : {
322 352 : return ( ( (*this_).width < 0.000000001 )||( (*this_).height < 0.000000001 ) );
323 : }
324 :
325 32 : static inline bool geometry_rectangle_is_point ( const geometry_rectangle_t *this_ )
326 : {
327 32 : return ( ( (*this_).width < 0.000000001 )&&( (*this_).height < 0.000000001 ) );
328 : }
329 :
330 146 : static inline double geometry_rectangle_get_intersect_area ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
331 : {
332 : geometry_rectangle_t intersect;
333 146 : geometry_rectangle_init_by_intersect( &intersect, this_, that );
334 146 : return geometry_rectangle_get_area(&intersect);
335 : }
336 :
337 622 : static inline void geometry_rectangle_shift ( geometry_rectangle_t *this_, double delta_x, double delta_y )
338 : {
339 622 : (*this_).left += delta_x;
340 622 : (*this_).top += delta_y;
341 622 : }
342 :
343 302 : static inline void geometry_rectangle_enlarge ( geometry_rectangle_t *this_, double delta_width, double delta_height )
344 : {
345 302 : (*this_).width += delta_width;
346 302 : if ( (*this_).width < 0.0 )
347 : {
348 0 : (*this_).width = 0.0;
349 : }
350 :
351 302 : (*this_).height += delta_height;
352 302 : if ( (*this_).height < 0.0 )
353 : {
354 92 : (*this_).height = 0.0;
355 : }
356 302 : }
357 :
358 163 : static inline void geometry_rectangle_expand_4dir ( geometry_rectangle_t *this_, double delta_width, double delta_height )
359 : {
360 163 : const double double_delta_width = 2.0 * delta_width;
361 163 : (*this_).width += double_delta_width;
362 163 : (*this_).left -= delta_width;
363 163 : if ( (*this_).width < 0.0 )
364 : {
365 2 : (*this_).left += 0.5 * (*this_).width;
366 2 : (*this_).width = 0.0;
367 : }
368 :
369 163 : const double double_delta_height = 2.0 * delta_height;
370 163 : (*this_).height += double_delta_height;
371 163 : (*this_).top -= delta_height;
372 163 : if ( (*this_).height < 0.0 )
373 : {
374 2 : (*this_).top += 0.5 * (*this_).height;
375 2 : (*this_).height = 0.0;
376 : }
377 163 : }
378 :
379 122 : static inline void geometry_rectangle_embrace ( geometry_rectangle_t *this_, double x, double y )
380 : {
381 122 : const double rect_this_right = (*this_).left + (*this_).width;
382 122 : if ( x < (*this_).left )
383 : {
384 13 : const double dx = (*this_).left - x;
385 13 : (*this_).left -= dx;
386 13 : (*this_).width += dx;
387 : }
388 109 : else if ( x > rect_this_right )
389 : {
390 42 : const double dx = x - rect_this_right;
391 42 : (*this_).width += dx;
392 : }
393 122 : const double rect_this_bottom = (*this_).top + (*this_).height;
394 122 : if ( y < (*this_).top )
395 : {
396 11 : const double dy = (*this_).top - y;
397 11 : (*this_).top -= dy;
398 11 : (*this_).height += dy;
399 : }
400 111 : else if ( y > rect_this_bottom )
401 : {
402 40 : const double dy = y - rect_this_bottom;
403 40 : (*this_).height += dy;
404 : }
405 122 : }
406 :
407 0 : static inline void geometry_rectangle_set_left ( geometry_rectangle_t *this_, double left )
408 : {
409 0 : (*this_).left = left;
410 0 : }
411 :
412 384 : static inline void geometry_rectangle_set_top ( geometry_rectangle_t *this_, double top )
413 : {
414 384 : (*this_).top = top;
415 384 : }
416 :
417 0 : static inline void geometry_rectangle_set_width ( geometry_rectangle_t *this_, double width )
418 : {
419 0 : (*this_).width = width;
420 0 : }
421 :
422 0 : static inline void geometry_rectangle_set_height ( geometry_rectangle_t *this_, double height )
423 : {
424 0 : (*this_).height = height;
425 0 : }
426 :
427 960 : static inline void geometry_rectangle_trace ( const geometry_rectangle_t *this_ )
428 : {
429 960 : U8_TRACE_INFO( "geometry_rectangle_t" );
430 960 : U8_TRACE_INFO_INT( "- left:", (*this_).left );
431 960 : U8_TRACE_INFO_INT( "- top:", (*this_).top );
432 960 : U8_TRACE_INFO_INT( "- width:", (*this_).width );
433 960 : U8_TRACE_INFO_INT( "- height:", (*this_).height );
434 960 : }
435 :
436 :
437 : /*
438 : Copyright 2016-2025 Andreas Warnke
439 :
440 : Licensed under the Apache License, Version 2.0 (the "License");
441 : you may not use this file except in compliance with the License.
442 : You may obtain a copy of the License at
443 :
444 : http://www.apache.org/licenses/LICENSE-2.0
445 :
446 : Unless required by applicable law or agreed to in writing, software
447 : distributed under the License is distributed on an "AS IS" BASIS,
448 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
449 : See the License for the specific language governing permissions and
450 : limitations under the License.
451 : */
|