Line data Source code
1 : /* File: geometry_rectangle.c; Copyright and License: see below */
2 :
3 : #include "geometry/geometry_rectangle.h"
4 : #include "u8/u8_trace.h"
5 : #include "u8/u8_log.h"
6 : #include <assert.h>
7 : #include <math.h>
8 :
9 67 : int geometry_rectangle_init_by_difference_max( geometry_rectangle_t *this_,
10 : const geometry_rectangle_t *rect_a,
11 : const geometry_rectangle_t *rect_b )
12 : {
13 67 : U8_TRACE_BEGIN();
14 67 : assert( NULL != rect_a );
15 67 : assert( NULL != rect_b );
16 :
17 67 : int result = 0;
18 :
19 67 : const double a_left = geometry_rectangle_get_left( rect_a );
20 67 : const double a_right = geometry_rectangle_get_right( rect_a );
21 67 : const double a_top = geometry_rectangle_get_top( rect_a );
22 67 : const double a_bottom = geometry_rectangle_get_bottom( rect_a );
23 67 : const double b_left = geometry_rectangle_get_left( rect_b );
24 67 : const double b_right = geometry_rectangle_get_right( rect_b );
25 67 : const double b_top = geometry_rectangle_get_top( rect_b );
26 67 : const double b_bottom = geometry_rectangle_get_bottom( rect_b );
27 :
28 67 : if ( ( b_right <= a_left )
29 67 : || ( b_bottom <= a_top )
30 67 : || ( b_left >= a_right )
31 66 : || ( b_top >= a_bottom ) )
32 : {
33 : /* no intersection */
34 1 : (*this_) = (*rect_a);
35 : }
36 : else
37 : {
38 : /* determine where to check for a suitable, maximum sub-rectangle */
39 66 : const bool check_top = (( b_top > a_top )&&( b_top < a_bottom ));
40 66 : const bool check_bottom = (( b_bottom > a_top )&&( b_bottom < a_bottom ));
41 66 : const bool check_left = (( b_left > a_left )&&( b_left < a_right ));
42 66 : const bool check_right = (( b_right > a_left )&&( b_right < a_right ));
43 : geometry_direction_t keep;
44 66 : if ( check_top )
45 : {
46 50 : if ( check_bottom )
47 : {
48 39 : if ( check_left )
49 : {
50 30 : if ( check_right )
51 : {
52 24 : U8_TRACE_INFO( "to.bo.le.ri." );
53 : /* 4 possible solutions */
54 24 : const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top );
55 24 : const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom );
56 24 : const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a );
57 24 : const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a );
58 24 : if (area_top>area_bottom)
59 : {
60 12 : if (area_top>area_left)
61 : {
62 8 : if (area_top>area_right)
63 : {
64 6 : keep = GEOMETRY_DIRECTION_UP;
65 : }
66 : else /* area_right is bigger */
67 : {
68 2 : keep = GEOMETRY_DIRECTION_RIGHT;
69 : }
70 : }
71 : else /* area_left is bigger */
72 : {
73 4 : if (area_left>area_right)
74 : {
75 3 : keep = GEOMETRY_DIRECTION_LEFT;
76 : }
77 : else /* area_right is bigger */
78 : {
79 1 : keep = GEOMETRY_DIRECTION_RIGHT;
80 : }
81 : }
82 : }
83 : else /* area_bottom is bigger */
84 : {
85 12 : if (area_bottom>area_left)
86 : {
87 8 : if (area_bottom>area_right)
88 : {
89 6 : keep = GEOMETRY_DIRECTION_DOWN;
90 : }
91 : else /* area_right is bigger */
92 : {
93 2 : keep = GEOMETRY_DIRECTION_RIGHT;
94 : }
95 : }
96 : else /* area_left is bigger */
97 : {
98 4 : if (area_left>area_right)
99 : {
100 3 : keep = GEOMETRY_DIRECTION_LEFT;
101 : }
102 : else /* area_right is bigger */
103 : {
104 1 : keep = GEOMETRY_DIRECTION_RIGHT;
105 : }
106 : }
107 : }
108 : }
109 : else /* ! check_right */
110 : {
111 6 : U8_TRACE_INFO( "to.bo.le." );
112 : /* 3 possible solutions */
113 6 : const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top );
114 6 : const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom );
115 6 : const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a );
116 6 : if (area_top>area_bottom)
117 : {
118 3 : if (area_top>area_left)
119 : {
120 2 : keep = GEOMETRY_DIRECTION_UP;
121 : }
122 : else /* area_left is bigger */
123 : {
124 1 : keep = GEOMETRY_DIRECTION_LEFT;
125 : }
126 : }
127 : else /* area_bottom is bigger */
128 : {
129 3 : if (area_bottom>area_left)
130 : {
131 2 : keep = GEOMETRY_DIRECTION_DOWN;
132 : }
133 : else /* area_left is bigger */
134 : {
135 1 : keep = GEOMETRY_DIRECTION_LEFT;
136 : }
137 : }
138 : }
139 : }
140 : else /* ! check_left */
141 : {
142 9 : if ( check_right )
143 : {
144 7 : U8_TRACE_INFO( "to.bo.ri." );
145 : /* 3 possible solutions */
146 7 : const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top );
147 7 : const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom );
148 7 : const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a );
149 7 : if (area_top>area_bottom)
150 : {
151 3 : if (area_top>area_right)
152 : {
153 2 : keep = GEOMETRY_DIRECTION_UP;
154 : }
155 : else /* area_right is bigger */
156 : {
157 1 : keep = GEOMETRY_DIRECTION_RIGHT;
158 : }
159 : }
160 : else /* area_bottom is bigger */
161 : {
162 4 : if (area_bottom>area_right)
163 : {
164 3 : keep = GEOMETRY_DIRECTION_DOWN;
165 : }
166 : else /* area_right is bigger */
167 : {
168 1 : keep = GEOMETRY_DIRECTION_RIGHT;
169 : }
170 : }
171 : }
172 : else /* ! check_right */
173 : {
174 2 : U8_TRACE_INFO( "to.bo." );
175 : /* 2 possible solutions */
176 2 : if (( b_top-a_top )>( a_bottom-b_bottom ))
177 : {
178 1 : keep = GEOMETRY_DIRECTION_UP;
179 : }
180 : else
181 : {
182 1 : keep = GEOMETRY_DIRECTION_DOWN;
183 : }
184 : }
185 : }
186 : }
187 : else /* ! check_bottom */
188 : {
189 11 : if ( check_left )
190 : {
191 8 : if ( check_right )
192 : {
193 6 : U8_TRACE_INFO( "to.le.ri." );
194 : /* 3 possible solutions */
195 6 : const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top );
196 6 : const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a );
197 6 : const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a );
198 6 : if (area_top>area_left)
199 : {
200 3 : if (area_top>area_right)
201 : {
202 2 : keep = GEOMETRY_DIRECTION_UP;
203 : }
204 : else /* area_right is bigger */
205 : {
206 1 : keep = GEOMETRY_DIRECTION_RIGHT;
207 : }
208 : }
209 : else /* area_left is bigger */
210 : {
211 3 : if (area_left>area_right)
212 : {
213 2 : keep = GEOMETRY_DIRECTION_LEFT;
214 : }
215 : else /* area_right is bigger */
216 : {
217 1 : keep = GEOMETRY_DIRECTION_RIGHT;
218 : }
219 : }
220 : }
221 : else /* ! check_right */
222 : {
223 2 : U8_TRACE_INFO( "to.le." );
224 : /* 2 possible solutions */
225 2 : const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top );
226 2 : const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a );
227 2 : if (area_top>area_left)
228 : {
229 1 : keep = GEOMETRY_DIRECTION_UP;
230 : }
231 : else /* area_left is bigger */
232 : {
233 1 : keep = GEOMETRY_DIRECTION_LEFT;
234 : }
235 : }
236 :
237 : }
238 : else /* ! check_left */
239 : {
240 3 : if ( check_right )
241 : {
242 2 : U8_TRACE_INFO( "to.ri." );
243 : /* 2 possible solutions */
244 2 : const double area_top = geometry_rectangle_get_width( rect_a ) * ( b_top-a_top );
245 2 : const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a );
246 2 : if (area_top>area_right)
247 : {
248 1 : keep = GEOMETRY_DIRECTION_UP;
249 : }
250 : else /* area_right is bigger */
251 : {
252 1 : keep = GEOMETRY_DIRECTION_RIGHT;
253 : }
254 : }
255 : else /* ! check_right */
256 : {
257 1 : U8_TRACE_INFO( "to." );
258 : /* 1 solution */
259 1 : keep = GEOMETRY_DIRECTION_UP;
260 : }
261 : }
262 : }
263 : }
264 : else /* ! check_top */
265 : {
266 16 : if ( check_bottom )
267 : {
268 11 : if ( check_left )
269 : {
270 8 : if ( check_right )
271 : {
272 6 : U8_TRACE_INFO( "bo.le.ri." );
273 : /* 3 possible solutions */
274 6 : const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom );
275 6 : const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a );
276 6 : const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a );
277 6 : if (area_bottom>area_left)
278 : {
279 3 : if (area_bottom>area_right)
280 : {
281 2 : keep = GEOMETRY_DIRECTION_DOWN;
282 : }
283 : else /* area_right is bigger */
284 : {
285 1 : keep = GEOMETRY_DIRECTION_RIGHT;
286 : }
287 : }
288 : else /* area_left is bigger */
289 : {
290 3 : if (area_left>area_right)
291 : {
292 2 : keep = GEOMETRY_DIRECTION_LEFT;
293 : }
294 : else /* area_right is bigger */
295 : {
296 1 : keep = GEOMETRY_DIRECTION_RIGHT;
297 : }
298 : }
299 : }
300 : else /* ! check_right */
301 : {
302 2 : U8_TRACE_INFO( "bo.le." );
303 : /* 2 possible solutions */
304 2 : const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom );
305 2 : const double area_left = ( b_left-a_left ) * geometry_rectangle_get_height( rect_a );
306 2 : if (area_bottom>area_left)
307 : {
308 1 : keep = GEOMETRY_DIRECTION_DOWN;
309 : }
310 : else /* area_left is bigger */
311 : {
312 1 : keep = GEOMETRY_DIRECTION_LEFT;
313 : }
314 : }
315 :
316 : }
317 : else /* ! check_left */
318 : {
319 3 : if ( check_right )
320 : {
321 2 : U8_TRACE_INFO( "bo.ri." );
322 : /* 2 possible solutions */
323 2 : const double area_bottom = geometry_rectangle_get_width( rect_a ) * ( a_bottom-b_bottom );
324 2 : const double area_right = ( a_right-b_right ) * geometry_rectangle_get_height( rect_a );
325 2 : if (area_bottom>area_right)
326 : {
327 1 : keep = GEOMETRY_DIRECTION_DOWN;
328 : }
329 : else /* area_right is bigger */
330 : {
331 1 : keep = GEOMETRY_DIRECTION_RIGHT;
332 : }
333 : }
334 : else /* ! check_right */
335 : {
336 1 : U8_TRACE_INFO( "bo." );
337 : /* 1 solution */
338 1 : keep = GEOMETRY_DIRECTION_DOWN;
339 : }
340 : }
341 : }
342 : else /* ! check_bottom */
343 : {
344 5 : if ( check_left )
345 : {
346 3 : if ( check_right )
347 : {
348 2 : U8_TRACE_INFO( "le.ri." );
349 : /* 2 possible solutions */
350 2 : if (( b_left-a_left )>( a_right-b_right ))
351 : {
352 1 : keep = GEOMETRY_DIRECTION_LEFT;
353 : }
354 : else
355 : {
356 1 : keep = GEOMETRY_DIRECTION_RIGHT;
357 : }
358 : }
359 : else /* ! check_right */
360 : {
361 1 : U8_TRACE_INFO( "le." );
362 : /* 1 solution */
363 1 : keep = GEOMETRY_DIRECTION_LEFT;
364 : }
365 :
366 : }
367 : else /* ! check_left */
368 : {
369 2 : if ( check_right )
370 : {
371 1 : U8_TRACE_INFO( "ri." );
372 : /* 1 solution */
373 1 : keep = GEOMETRY_DIRECTION_RIGHT;
374 : }
375 : else /* ! check_right */
376 : {
377 1 : U8_TRACE_INFO( "0." );
378 : /* rect_b contains rect_a, result is empty */
379 1 : keep = GEOMETRY_DIRECTION_CENTER;
380 : }
381 : }
382 : }
383 : }
384 :
385 66 : if ( keep == GEOMETRY_DIRECTION_UP )
386 : {
387 16 : assert ( check_top );
388 16 : U8_TRACE_INFO( "-top-" );
389 16 : geometry_rectangle_init ( this_, a_left, a_top, geometry_rectangle_get_width( rect_a ), b_top-a_top );
390 : }
391 50 : else if ( keep == GEOMETRY_DIRECTION_DOWN )
392 : {
393 17 : assert ( check_bottom );
394 17 : U8_TRACE_INFO( "-bottom-" );
395 17 : geometry_rectangle_init ( this_, a_left, b_bottom, geometry_rectangle_get_width( rect_a ), a_bottom-b_bottom );
396 : }
397 33 : else if ( keep == GEOMETRY_DIRECTION_LEFT )
398 : {
399 16 : assert ( check_left );
400 16 : U8_TRACE_INFO( "-left-" );
401 16 : geometry_rectangle_init ( this_, a_left, a_top, b_left-a_left, geometry_rectangle_get_height( rect_a ) );
402 : }
403 17 : else if ( keep == GEOMETRY_DIRECTION_RIGHT )
404 : {
405 16 : assert ( check_right );
406 16 : U8_TRACE_INFO( "-right-" );
407 16 : geometry_rectangle_init ( this_, b_right, a_top, a_right-b_right, geometry_rectangle_get_height( rect_a ) );
408 : }
409 : else /* GEOMETRY_DIRECTION_CENTER */
410 : {
411 1 : U8_TRACE_INFO( "-none-" );
412 1 : geometry_rectangle_init ( this_, a_left, a_top, 0.0, 0.0 );
413 : }
414 : }
415 :
416 67 : U8_TRACE_END_ERR( result );
417 67 : return result;
418 : }
419 :
420 18 : int geometry_rectangle_init_by_difference_at_pivot( geometry_rectangle_t *this_,
421 : const geometry_rectangle_t *moon,
422 : const geometry_rectangle_t *shadow,
423 : const geometry_point_t *pivot_point )
424 : {
425 18 : U8_TRACE_BEGIN();
426 18 : assert( NULL != moon );
427 18 : assert( NULL != shadow );
428 18 : assert( NULL != pivot_point );
429 :
430 18 : int result = 0;
431 :
432 18 : const double moon_left = geometry_rectangle_get_left( moon );
433 18 : const double moon_right = geometry_rectangle_get_right( moon );
434 18 : const double moon_top = geometry_rectangle_get_top( moon );
435 18 : const double moon_bottom = geometry_rectangle_get_bottom( moon );
436 18 : const double moon_width = geometry_rectangle_get_width( moon );
437 18 : const double moon_height = geometry_rectangle_get_height( moon );
438 :
439 : geometry_rectangle_t shadow_intersect;
440 18 : const int no_overlap = geometry_rectangle_init_by_intersect( &shadow_intersect, moon, shadow );
441 18 : if ( no_overlap == 0 )
442 : {
443 17 : const double shadow_left = geometry_rectangle_get_left( &shadow_intersect );
444 17 : const double shadow_top = geometry_rectangle_get_top( &shadow_intersect );
445 17 : const double shadow_right = geometry_rectangle_get_right( &shadow_intersect );
446 17 : const double shadow_bottom = geometry_rectangle_get_bottom( &shadow_intersect );
447 17 : const double left_width = shadow_left - moon_left;
448 17 : const double top_height = shadow_top - moon_top;
449 17 : const double right_width = moon_right - shadow_right;
450 17 : const double bottom_height = moon_bottom - shadow_bottom;
451 :
452 : geometry_direction_t keep;
453 17 : if ( geometry_point_get_x( pivot_point ) <= shadow_left )
454 : {
455 4 : if ( geometry_point_get_y( pivot_point ) <= shadow_top )
456 : {
457 1 : keep = ( left_width > top_height ) ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_UP;
458 : }
459 3 : else if ( geometry_point_get_y( pivot_point ) >= shadow_bottom )
460 : {
461 1 : keep = ( left_width > bottom_height ) ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_DOWN;
462 : }
463 : else
464 : {
465 2 : keep = GEOMETRY_DIRECTION_LEFT;
466 : }
467 : }
468 13 : else if ( geometry_point_get_x( pivot_point ) >= shadow_right )
469 : {
470 3 : if ( geometry_point_get_y( pivot_point ) <= shadow_top )
471 : {
472 1 : keep = ( right_width > top_height ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_UP;
473 : }
474 2 : else if ( geometry_point_get_y( pivot_point ) >= shadow_bottom )
475 : {
476 1 : keep = ( right_width > bottom_height ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_DOWN;
477 : }
478 : else
479 : {
480 1 : keep = GEOMETRY_DIRECTION_RIGHT;
481 : }
482 : }
483 : else
484 : {
485 10 : if ( geometry_point_get_y( pivot_point ) <= shadow_top )
486 : {
487 1 : keep = GEOMETRY_DIRECTION_UP;
488 : }
489 9 : else if ( geometry_point_get_y( pivot_point ) >= shadow_bottom )
490 : {
491 1 : keep = GEOMETRY_DIRECTION_DOWN;
492 : }
493 : else
494 : {
495 8 : if ( geometry_point_get_x( pivot_point ) < geometry_rectangle_get_center_x( &shadow_intersect ) )
496 : {
497 4 : if ( geometry_point_get_y( pivot_point ) < geometry_rectangle_get_center_y( &shadow_intersect ) )
498 : {
499 2 : keep = ( left_width > top_height ) ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_UP;
500 : }
501 : else
502 : {
503 2 : keep = ( left_width > bottom_height ) ? GEOMETRY_DIRECTION_LEFT : GEOMETRY_DIRECTION_DOWN;
504 : }
505 : }
506 : else
507 : {
508 4 : if ( geometry_point_get_y( pivot_point ) < geometry_rectangle_get_center_y( &shadow_intersect ) )
509 : {
510 2 : keep = ( right_width > top_height ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_UP;
511 : }
512 : else
513 : {
514 2 : keep = ( right_width > bottom_height ) ? GEOMETRY_DIRECTION_RIGHT : GEOMETRY_DIRECTION_DOWN;
515 : }
516 : }
517 : }
518 : }
519 :
520 17 : if ( keep == GEOMETRY_DIRECTION_LEFT )
521 : {
522 : /* take left side of shadow_intersect */
523 4 : geometry_rectangle_init( this_, moon_left, moon_top, shadow_left - moon_left, moon_height );
524 4 : U8_TRACE_INFO_INT_INT( "left: w*h", left_width, moon_height );
525 : }
526 13 : else if ( keep == GEOMETRY_DIRECTION_RIGHT )
527 : {
528 : /* take right side of shadow_intersect */
529 4 : geometry_rectangle_init( this_, shadow_right, moon_top, moon_right - shadow_right, moon_height );
530 4 : U8_TRACE_INFO_INT_INT( "right: w*h", right_width, moon_height);
531 : }
532 9 : else if ( keep == GEOMETRY_DIRECTION_DOWN )
533 : {
534 : /* take bottom side of shadow_intersect */
535 5 : geometry_rectangle_init( this_, moon_left, shadow_bottom, moon_width, moon_bottom - shadow_bottom );
536 5 : U8_TRACE_INFO_INT_INT( "bottom: w*h", moon_width, bottom_height);
537 : }
538 : else
539 : {
540 : /* take top side of shadow_intersect */
541 4 : geometry_rectangle_init( this_, moon_left, moon_top, moon_width, shadow_top - moon_top );
542 4 : U8_TRACE_INFO_INT_INT( "top: w*h", moon_width, top_height);
543 : }
544 : }
545 : else
546 : {
547 1 : *this_ = *moon;
548 1 : U8_TRACE_INFO_INT_INT( "no intersect: w*h", moon_width, moon_height );
549 : }
550 :
551 18 : U8_TRACE_END_ERR( result );
552 18 : return result;
553 : }
554 :
555 :
556 : /*
557 : Copyright 2020-2025 Andreas Warnke
558 :
559 : Licensed under the Apache License, Version 2.0 (the "License");
560 : you may not use this file except in compliance with the License.
561 : You may obtain a copy of the License at
562 :
563 : http://www.apache.org/licenses/LICENSE-2.0
564 :
565 : Unless required by applicable law or agreed to in writing, software
566 : distributed under the License is distributed on an "AS IS" BASIS,
567 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
568 : See the License for the specific language governing permissions and
569 : limitations under the License.
570 : */
|