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 1087 : static inline void geometry_rectangle_init ( geometry_rectangle_t *this_, double left, double top, double width, double height )
9 : {
10 1087 : (*this_).left = left;
11 1087 : (*this_).top = top;
12 1087 : (*this_).width = width;
13 1087 : (*this_).height = height;
14 1087 : }
15 :
16 592 : static inline void geometry_rectangle_reinit ( geometry_rectangle_t *this_, double left, double top, double width, double height )
17 : {
18 592 : (*this_).left = left;
19 592 : (*this_).top = top;
20 592 : (*this_).width = width;
21 592 : (*this_).height = height;
22 592 : }
23 :
24 1 : static inline void geometry_rectangle_copy ( geometry_rectangle_t *this_, const geometry_rectangle_t *original )
25 : {
26 1 : assert( NULL != original );
27 1 : (*this_) = (*original);
28 1 : }
29 :
30 1 : static inline void geometry_rectangle_move ( geometry_rectangle_t *this_, geometry_rectangle_t *that )
31 : {
32 1 : assert( NULL != that );
33 1 : (*this_) = (*that);
34 1 : }
35 :
36 1387 : static inline void geometry_rectangle_replace ( geometry_rectangle_t *this_, const geometry_rectangle_t *original )
37 : {
38 1387 : assert( NULL != original );
39 1387 : (*this_) = (*original);
40 1387 : }
41 :
42 1 : static inline void geometry_rectangle_replacemove ( geometry_rectangle_t *this_, geometry_rectangle_t *that )
43 : {
44 1 : assert( NULL != that );
45 1 : (*this_) = (*that);
46 1 : }
47 :
48 3552 : static inline void geometry_rectangle_init_empty ( geometry_rectangle_t *this_ )
49 : {
50 3552 : (*this_).left = 0.0;
51 3552 : (*this_).top = 0.0;
52 3552 : (*this_).width = 0.0;
53 3552 : (*this_).height = 0.0;
54 3552 : }
55 :
56 1 : static inline void geometry_rectangle_reinit_empty ( geometry_rectangle_t *this_ )
57 : {
58 1 : (*this_).left = 0.0;
59 1 : (*this_).top = 0.0;
60 1 : (*this_).width = 0.0;
61 1 : (*this_).height = 0.0;
62 1 : }
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 2881 : 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 2881 : assert( NULL != rect_a );
106 2881 : assert( NULL != rect_b );
107 :
108 2881 : int result = 0;
109 :
110 2881 : const double rect_a_right = (*rect_a).left + (*rect_a).width;
111 2881 : const double rect_a_bottom = (*rect_a).top + (*rect_a).height;
112 2881 : const double rect_b_right = (*rect_b).left + (*rect_b).width;
113 2881 : const double rect_b_bottom = (*rect_b).top + (*rect_b).height;
114 :
115 2881 : (*this_).left = fmin( (*rect_a).left, (*rect_b).left );
116 2881 : (*this_).top = fmin( (*rect_a).top, (*rect_b).top );
117 2881 : (*this_).width = fmax( rect_a_right, rect_b_right ) - (*this_).left;
118 2881 : (*this_).height = fmax( rect_a_bottom, rect_b_bottom ) - (*this_).top;
119 :
120 2881 : 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 3442 : static inline void geometry_rectangle_destroy ( geometry_rectangle_t *this_ )
226 : {
227 3442 : }
228 :
229 787 : static inline geometry_rectangle_t geometry_rectangle_new ( double left, double top, double width, double height )
230 : {
231 : geometry_rectangle_t result;
232 787 : geometry_rectangle_init( &result, left, top, width, height );
233 787 : return result;
234 : }
235 :
236 1572 : static inline double geometry_rectangle_get_left ( const geometry_rectangle_t *this_ )
237 : {
238 1572 : return (*this_).left;
239 : }
240 :
241 1424 : static inline double geometry_rectangle_get_top ( const geometry_rectangle_t *this_ )
242 : {
243 1424 : return (*this_).top;
244 : }
245 :
246 185 : static inline double geometry_rectangle_get_right ( const geometry_rectangle_t *this_ )
247 : {
248 185 : return (*this_).left + (*this_).width;
249 : }
250 :
251 441 : static inline double geometry_rectangle_get_bottom ( const geometry_rectangle_t *this_ )
252 : {
253 441 : return (*this_).top + (*this_).height;
254 : }
255 :
256 2438 : static inline double geometry_rectangle_get_width ( const geometry_rectangle_t *this_ )
257 : {
258 2438 : return (*this_).width;
259 : }
260 :
261 2167 : static inline double geometry_rectangle_get_height ( const geometry_rectangle_t *this_ )
262 : {
263 2167 : return (*this_).height;
264 : }
265 :
266 166 : static inline double geometry_rectangle_get_center_x ( const geometry_rectangle_t *this_ )
267 : {
268 166 : return (*this_).left + 0.5*(*this_).width;
269 : }
270 :
271 166 : static inline double geometry_rectangle_get_center_y ( const geometry_rectangle_t *this_ )
272 : {
273 166 : return (*this_).top + 0.5*(*this_).height;
274 : }
275 :
276 1 : static inline geometry_point_t geometry_rectangle_get_center ( const geometry_rectangle_t *this_ )
277 : {
278 : geometry_point_t result;
279 1 : geometry_point_init ( &result, (*this_).left + 0.5*(*this_).width, (*this_).top + 0.5*(*this_).height );
280 1 : return result;
281 : }
282 :
283 1 : static inline geometry_dimensions_t geometry_rectangle_get_dimensions ( const geometry_rectangle_t *this_ )
284 : {
285 : geometry_dimensions_t result;
286 1 : geometry_dimensions_init ( &result, (*this_).width, (*this_).height );
287 1 : return result;
288 : }
289 :
290 218 : static inline double geometry_rectangle_get_area ( const geometry_rectangle_t *this_ )
291 : {
292 218 : return (*this_).width * (*this_).height;
293 : }
294 :
295 3 : static inline bool geometry_rectangle_contains ( const geometry_rectangle_t *this_, double x, double y )
296 : {
297 3 : return (( (*this_).left <= x )&&( x < (*this_).left + (*this_).width )&&( (*this_).top <= y )&&( y < (*this_).top + (*this_).height ));
298 : }
299 :
300 1 : static inline bool geometry_rectangle_contains_point ( const geometry_rectangle_t *this_, const geometry_point_t *point )
301 : {
302 1 : return geometry_rectangle_contains( this_, geometry_point_get_x( point ), geometry_point_get_y( point ) );
303 : }
304 :
305 4 : static inline double geometry_rectangle_calc_chess_distance ( const geometry_rectangle_t *this_, double x, double y )
306 : {
307 4 : double result = 0.0;
308 4 : if ( x < (*this_).left )
309 : {
310 1 : result += ( (*this_).left - x );
311 : }
312 3 : else if ( x > (*this_).left + (*this_).width )
313 : {
314 1 : result += ( x - ((*this_).left + (*this_).width) );
315 : }
316 4 : if ( y < (*this_).top )
317 : {
318 1 : result += ( (*this_).top - y );
319 : }
320 3 : else if ( y > (*this_).top + (*this_).height )
321 : {
322 1 : result += ( y - ((*this_).top + (*this_).height) );
323 : }
324 4 : return result;
325 : }
326 :
327 352 : static inline bool geometry_rectangle_is_empty ( const geometry_rectangle_t *this_ )
328 : {
329 352 : return ( ( (*this_).width < 0.000000001 )||( (*this_).height < 0.000000001 ) );
330 : }
331 :
332 32 : static inline bool geometry_rectangle_is_point ( const geometry_rectangle_t *this_ )
333 : {
334 32 : return ( ( (*this_).width < 0.000000001 )&&( (*this_).height < 0.000000001 ) );
335 : }
336 :
337 146 : static inline double geometry_rectangle_get_intersect_area ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
338 : {
339 : geometry_rectangle_t intersect;
340 146 : geometry_rectangle_init_by_intersect( &intersect, this_, that );
341 146 : return geometry_rectangle_get_area(&intersect);
342 : }
343 :
344 557 : static inline void geometry_rectangle_shift ( geometry_rectangle_t *this_, double delta_x, double delta_y )
345 : {
346 557 : (*this_).left += delta_x;
347 557 : (*this_).top += delta_y;
348 557 : }
349 :
350 175 : static inline void geometry_rectangle_enlarge ( geometry_rectangle_t *this_, double delta_width, double delta_height )
351 : {
352 175 : (*this_).width += delta_width;
353 175 : if ( (*this_).width < 0.0 )
354 : {
355 1 : (*this_).width = 0.0;
356 : }
357 :
358 175 : (*this_).height += delta_height;
359 175 : if ( (*this_).height < 0.0 )
360 : {
361 29 : (*this_).height = 0.0;
362 : }
363 175 : }
364 :
365 227 : static inline void geometry_rectangle_expand_4dir ( geometry_rectangle_t *this_, double delta_width, double delta_height )
366 : {
367 227 : const double double_delta_width = 2.0 * delta_width;
368 227 : (*this_).width += double_delta_width;
369 227 : (*this_).left -= delta_width;
370 227 : if ( (*this_).width < 0.0 )
371 : {
372 2 : (*this_).left += 0.5 * (*this_).width;
373 2 : (*this_).width = 0.0;
374 : }
375 :
376 227 : const double double_delta_height = 2.0 * delta_height;
377 227 : (*this_).height += double_delta_height;
378 227 : (*this_).top -= delta_height;
379 227 : if ( (*this_).height < 0.0 )
380 : {
381 2 : (*this_).top += 0.5 * (*this_).height;
382 2 : (*this_).height = 0.0;
383 : }
384 227 : }
385 :
386 122 : static inline void geometry_rectangle_embrace ( geometry_rectangle_t *this_, double x, double y )
387 : {
388 122 : const double rect_this_right = (*this_).left + (*this_).width;
389 122 : if ( x < (*this_).left )
390 : {
391 13 : const double dx = (*this_).left - x;
392 13 : (*this_).left -= dx;
393 13 : (*this_).width += dx;
394 : }
395 109 : else if ( x > rect_this_right )
396 : {
397 42 : const double dx = x - rect_this_right;
398 42 : (*this_).width += dx;
399 : }
400 122 : const double rect_this_bottom = (*this_).top + (*this_).height;
401 122 : if ( y < (*this_).top )
402 : {
403 11 : const double dy = (*this_).top - y;
404 11 : (*this_).top -= dy;
405 11 : (*this_).height += dy;
406 : }
407 111 : else if ( y > rect_this_bottom )
408 : {
409 40 : const double dy = y - rect_this_bottom;
410 40 : (*this_).height += dy;
411 : }
412 122 : }
413 :
414 1 : static inline void geometry_rectangle_set_left ( geometry_rectangle_t *this_, double left )
415 : {
416 1 : (*this_).left = left;
417 1 : }
418 :
419 193 : static inline void geometry_rectangle_set_top ( geometry_rectangle_t *this_, double top )
420 : {
421 193 : (*this_).top = top;
422 193 : }
423 :
424 1 : static inline void geometry_rectangle_set_width ( geometry_rectangle_t *this_, double width )
425 : {
426 1 : (*this_).width = width;
427 1 : }
428 :
429 1 : static inline void geometry_rectangle_set_height ( geometry_rectangle_t *this_, double height )
430 : {
431 1 : (*this_).height = height;
432 1 : }
433 :
434 1280 : static inline void geometry_rectangle_trace ( const geometry_rectangle_t *this_ )
435 : {
436 1280 : U8_TRACE_INFO( "geometry_rectangle_t" );
437 1280 : U8_TRACE_INFO_INT( "- left:", (*this_).left );
438 1280 : U8_TRACE_INFO_INT( "- top:", (*this_).top );
439 1280 : U8_TRACE_INFO_INT( "- width:", (*this_).width );
440 1280 : U8_TRACE_INFO_INT( "- height:", (*this_).height );
441 1280 : }
442 :
443 :
444 : /*
445 : Copyright 2016-2026 Andreas Warnke
446 :
447 : Licensed under the Apache License, Version 2.0 (the "License");
448 : you may not use this file except in compliance with the License.
449 : You may obtain a copy of the License at
450 :
451 : http://www.apache.org/licenses/LICENSE-2.0
452 :
453 : Unless required by applicable law or agreed to in writing, software
454 : distributed under the License is distributed on an "AS IS" BASIS,
455 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
456 : See the License for the specific language governing permissions and
457 : limitations under the License.
458 : */
|