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 380 : static inline void geometry_rectangle_init ( geometry_rectangle_t *this_, double left, double top, double width, double height )
9 : {
10 380 : (*this_).left = left;
11 380 : (*this_).top = top;
12 380 : (*this_).width = width;
13 380 : (*this_).height = height;
14 380 : }
15 :
16 517 : static inline void geometry_rectangle_reinit ( geometry_rectangle_t *this_, double left, double top, double width, double height )
17 : {
18 517 : (*this_).left = left;
19 517 : (*this_).top = top;
20 517 : (*this_).width = width;
21 517 : (*this_).height = height;
22 517 : }
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 893 : static inline void geometry_rectangle_replace ( geometry_rectangle_t *this_, const geometry_rectangle_t *original )
37 : {
38 893 : assert( NULL != original );
39 893 : (*this_) = (*original);
40 893 : }
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 4354 : static inline void geometry_rectangle_init_empty ( geometry_rectangle_t *this_ )
49 : {
50 4354 : (*this_).left = 0.0;
51 4354 : (*this_).top = 0.0;
52 4354 : (*this_).width = 0.0;
53 4354 : (*this_).height = 0.0;
54 4354 : }
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 118 : 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 118 : assert( NULL != rect_a );
69 118 : assert( NULL != rect_b );
70 :
71 118 : int result = 0;
72 :
73 118 : const double rect_a_right = (*rect_a).left + (*rect_a).width;
74 118 : const double rect_a_bottom = (*rect_a).top + (*rect_a).height;
75 118 : const double rect_b_right = (*rect_b).left + (*rect_b).width;
76 118 : const double rect_b_bottom = (*rect_b).top + (*rect_b).height;
77 :
78 118 : (*this_).left = fmax( (*rect_a).left, (*rect_b).left );
79 118 : (*this_).top = fmax( (*rect_a).top, (*rect_b).top );
80 118 : (*this_).width = fmin( rect_a_right, rect_b_right ) - (*this_).left;
81 118 : (*this_).height = fmin( rect_a_bottom, rect_b_bottom ) - (*this_).top;
82 118 : if (( (*this_).width < -0.000000001 ) || ( (*this_).height < -0.000000001 ))
83 : {
84 : /* if intersection is empty, result is -1 */
85 19 : (*this_).left = 0.0;
86 19 : (*this_).top = 0.0;
87 19 : (*this_).width = 0.0;
88 19 : (*this_).height = 0.0;
89 19 : result = -1;
90 : }
91 99 : else if (( (*this_).width < 0.0 ) || ( (*this_).height < 0.0 ))
92 : {
93 : /* update rounding error */
94 0 : (*this_).width = 0.0;
95 0 : (*this_).height = 0.0;
96 : }
97 :
98 118 : return result;
99 : }
100 :
101 1153 : 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 1153 : assert( NULL != rect_a );
106 1153 : assert( NULL != rect_b );
107 :
108 1153 : int result = 0;
109 :
110 1153 : const double rect_a_right = (*rect_a).left + (*rect_a).width;
111 1153 : const double rect_a_bottom = (*rect_a).top + (*rect_a).height;
112 1153 : const double rect_b_right = (*rect_b).left + (*rect_b).width;
113 1153 : const double rect_b_bottom = (*rect_b).top + (*rect_b).height;
114 :
115 1153 : (*this_).left = fmin( (*rect_a).left, (*rect_b).left );
116 1153 : (*this_).top = fmin( (*rect_a).top, (*rect_b).top );
117 1153 : (*this_).width = fmax( rect_a_right, rect_b_right ) - (*this_).left;
118 1153 : (*this_).height = fmax( rect_a_bottom, rect_b_bottom ) - (*this_).top;
119 :
120 1153 : 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 480 : static inline bool geometry_rectangle_is_containing ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
176 : {
177 480 : assert( NULL != that );
178 :
179 : bool result;
180 :
181 480 : const double rect_this_right = (*this_).left + (*this_).width;
182 480 : const double rect_this_bottom = (*this_).top + (*this_).height;
183 480 : const double rect_that_right = (*that).left + (*that).width;
184 480 : const double rect_that_bottom = (*that).top + (*that).height;
185 :
186 480 : if ( ( (*this_).left < (*that).left + 0.000000001 ) /* touching is containing */
187 415 : && ( (*this_).top < (*that).top + 0.000000001 )
188 414 : && ( rect_this_right + 0.000000001 > rect_that_right )
189 413 : && ( rect_this_bottom + 0.000000001 > rect_that_bottom ) )
190 : {
191 413 : result = true;
192 : }
193 : else
194 : {
195 67 : result = false;
196 : }
197 :
198 480 : return result;
199 : }
200 :
201 60 : static inline void geometry_rectangle_init_by_corners ( geometry_rectangle_t *this_, double x1, double y1, double x2, double y2 )
202 : {
203 60 : if ( x1 < x2 )
204 : {
205 12 : (*this_).left = x1;
206 12 : (*this_).width = x2-x1;
207 : }
208 : else
209 : {
210 48 : (*this_).left = x2;
211 48 : (*this_).width = x1-x2;
212 : }
213 60 : if ( y1 < y2 )
214 : {
215 15 : (*this_).top = y1;
216 15 : (*this_).height = y2-y1;
217 : }
218 : else
219 : {
220 45 : (*this_).top = y2;
221 45 : (*this_).height = y1-y2;
222 : }
223 60 : }
224 :
225 4620 : static inline void geometry_rectangle_destroy ( geometry_rectangle_t *this_ )
226 : {
227 4620 : }
228 :
229 995 : static inline double geometry_rectangle_get_left ( const geometry_rectangle_t *this_ )
230 : {
231 995 : return (*this_).left;
232 : }
233 :
234 871 : static inline double geometry_rectangle_get_top ( const geometry_rectangle_t *this_ )
235 : {
236 871 : return (*this_).top;
237 : }
238 :
239 71 : static inline double geometry_rectangle_get_right ( const geometry_rectangle_t *this_ )
240 : {
241 71 : return (*this_).left + (*this_).width;
242 : }
243 :
244 71 : static inline double geometry_rectangle_get_bottom ( const geometry_rectangle_t *this_ )
245 : {
246 71 : return (*this_).top + (*this_).height;
247 : }
248 :
249 1512 : static inline double geometry_rectangle_get_width ( const geometry_rectangle_t *this_ )
250 : {
251 1512 : return (*this_).width;
252 : }
253 :
254 1474 : static inline double geometry_rectangle_get_height ( const geometry_rectangle_t *this_ )
255 : {
256 1474 : return (*this_).height;
257 : }
258 :
259 128 : static inline double geometry_rectangle_get_center_x ( const geometry_rectangle_t *this_ )
260 : {
261 128 : return (*this_).left + 0.5*(*this_).width;
262 : }
263 :
264 128 : static inline double geometry_rectangle_get_center_y ( const geometry_rectangle_t *this_ )
265 : {
266 128 : 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 153 : static inline double geometry_rectangle_get_area ( const geometry_rectangle_t *this_ )
284 : {
285 153 : 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 double geometry_rectangle_calc_chess_distance ( const geometry_rectangle_t *this_, double x, double y )
294 : {
295 0 : double result = 0.0;
296 0 : if ( x < (*this_).left )
297 : {
298 0 : result += ( (*this_).left - x );
299 : }
300 0 : else if ( x > (*this_).left + (*this_).width )
301 : {
302 0 : result += ( x - ((*this_).left + (*this_).width) );
303 : }
304 0 : if ( y < (*this_).top )
305 : {
306 0 : result += ( (*this_).top - y );
307 : }
308 0 : else if ( y > (*this_).top + (*this_).height )
309 : {
310 0 : result += ( y - ((*this_).top + (*this_).height) );
311 : }
312 0 : return result;
313 : }
314 :
315 352 : static inline bool geometry_rectangle_is_empty ( const geometry_rectangle_t *this_ )
316 : {
317 352 : return ( ( (*this_).width < 0.000000001 )||( (*this_).height < 0.000000001 ) );
318 : }
319 :
320 32 : static inline bool geometry_rectangle_is_point ( const geometry_rectangle_t *this_ )
321 : {
322 32 : return ( ( (*this_).width < 0.000000001 )&&( (*this_).height < 0.000000001 ) );
323 : }
324 :
325 114 : static inline double geometry_rectangle_get_intersect_area ( const geometry_rectangle_t *this_, const geometry_rectangle_t *that )
326 : {
327 : geometry_rectangle_t intersect;
328 114 : geometry_rectangle_init_by_intersect( &intersect, this_, that );
329 114 : return geometry_rectangle_get_area(&intersect);
330 : }
331 :
332 558 : static inline void geometry_rectangle_shift ( geometry_rectangle_t *this_, double delta_x, double delta_y )
333 : {
334 558 : (*this_).left += delta_x;
335 558 : (*this_).top += delta_y;
336 558 : }
337 :
338 302 : static inline void geometry_rectangle_enlarge ( geometry_rectangle_t *this_, double delta_width, double delta_height )
339 : {
340 302 : (*this_).width += delta_width;
341 302 : if ( (*this_).width < 0.0 )
342 : {
343 0 : (*this_).width = 0.0;
344 : }
345 :
346 302 : (*this_).height += delta_height;
347 302 : if ( (*this_).height < 0.0 )
348 : {
349 92 : (*this_).height = 0.0;
350 : }
351 302 : }
352 :
353 163 : static inline void geometry_rectangle_expand_4dir ( geometry_rectangle_t *this_, double delta_width, double delta_height )
354 : {
355 163 : const double double_delta_width = 2.0 * delta_width;
356 163 : (*this_).width += double_delta_width;
357 163 : (*this_).left -= delta_width;
358 163 : if ( (*this_).width < 0.0 )
359 : {
360 2 : (*this_).left += 0.5 * (*this_).width;
361 2 : (*this_).width = 0.0;
362 : }
363 :
364 163 : const double double_delta_height = 2.0 * delta_height;
365 163 : (*this_).height += double_delta_height;
366 163 : (*this_).top -= delta_height;
367 163 : if ( (*this_).height < 0.0 )
368 : {
369 2 : (*this_).top += 0.5 * (*this_).height;
370 2 : (*this_).height = 0.0;
371 : }
372 163 : }
373 :
374 122 : static inline void geometry_rectangle_embrace ( geometry_rectangle_t *this_, double x, double y )
375 : {
376 122 : const double rect_this_right = (*this_).left + (*this_).width;
377 122 : if ( x < (*this_).left )
378 : {
379 13 : const double dx = (*this_).left - x;
380 13 : (*this_).left -= dx;
381 13 : (*this_).width += dx;
382 : }
383 109 : else if ( x > rect_this_right )
384 : {
385 42 : const double dx = x - rect_this_right;
386 42 : (*this_).width += dx;
387 : }
388 122 : const double rect_this_bottom = (*this_).top + (*this_).height;
389 122 : if ( y < (*this_).top )
390 : {
391 11 : const double dy = (*this_).top - y;
392 11 : (*this_).top -= dy;
393 11 : (*this_).height += dy;
394 : }
395 111 : else if ( y > rect_this_bottom )
396 : {
397 40 : const double dy = y - rect_this_bottom;
398 40 : (*this_).height += dy;
399 : }
400 122 : }
401 :
402 0 : static inline void geometry_rectangle_set_left ( geometry_rectangle_t *this_, double left )
403 : {
404 0 : (*this_).left = left;
405 0 : }
406 :
407 256 : static inline void geometry_rectangle_set_top ( geometry_rectangle_t *this_, double top )
408 : {
409 256 : (*this_).top = top;
410 256 : }
411 :
412 0 : static inline void geometry_rectangle_set_width ( geometry_rectangle_t *this_, double width )
413 : {
414 0 : (*this_).width = width;
415 0 : }
416 :
417 0 : static inline void geometry_rectangle_set_height ( geometry_rectangle_t *this_, double height )
418 : {
419 0 : (*this_).height = height;
420 0 : }
421 :
422 768 : static inline void geometry_rectangle_trace ( const geometry_rectangle_t *this_ )
423 : {
424 768 : U8_TRACE_INFO( "geometry_rectangle_t" );
425 768 : U8_TRACE_INFO_INT( "- left:", (*this_).left );
426 768 : U8_TRACE_INFO_INT( "- top:", (*this_).top );
427 768 : U8_TRACE_INFO_INT( "- width:", (*this_).width );
428 768 : U8_TRACE_INFO_INT( "- height:", (*this_).height );
429 768 : }
430 :
431 :
432 : /*
433 : Copyright 2016-2024 Andreas Warnke
434 :
435 : Licensed under the Apache License, Version 2.0 (the "License");
436 : you may not use this file except in compliance with the License.
437 : You may obtain a copy of the License at
438 :
439 : http://www.apache.org/licenses/LICENSE-2.0
440 :
441 : Unless required by applicable law or agreed to in writing, software
442 : distributed under the License is distributed on an "AS IS" BASIS,
443 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
444 : See the License for the specific language governing permissions and
445 : limitations under the License.
446 : */
|