Line data Source code
1 : /* File: layout_visible_set.c; Copyright and License: see below */
2 :
3 : #include "layout/layout_visible_set.h"
4 : #include "filter/pencil_rules.h"
5 : #include "u8/u8_trace.h"
6 : #include "u8/u8_log.h"
7 : #include <assert.h>
8 :
9 5 : void layout_visible_set_init( layout_visible_set_t *this_, const data_visible_set_t *input_data )
10 : {
11 5 : U8_TRACE_BEGIN();
12 5 : assert ( NULL != input_data );
13 5 : U8_TRACE_INFO_INT( "sizeof(layout_visible_set_t):", sizeof(layout_visible_set_t) );
14 :
15 5 : data_rules_init ( &((*this_).filter_rules) );
16 :
17 : /* init input data */
18 5 : (*this_).input_data = input_data;
19 :
20 : /* initialite the layout data objects */
21 5 : layout_visible_set_private_init_diagram( this_ );
22 5 : layout_visible_set_private_init_classifiers( this_ );
23 5 : layout_visible_set_private_init_features( this_ );
24 5 : layout_visible_set_private_init_relationships( this_ );
25 :
26 5 : if ( data_visible_set_is_valid( input_data ) )
27 : {
28 4 : assert ( layout_visible_set_is_consistent( this_ ) );
29 : }
30 5 : U8_TRACE_END();
31 5 : }
32 :
33 5 : void layout_visible_set_private_init_diagram( layout_visible_set_t *this_ )
34 : {
35 5 : U8_TRACE_BEGIN();
36 5 : assert ( NULL != (*this_).input_data );
37 :
38 5 : layout_diagram_init ( &((*this_).diagram_layout),
39 : data_visible_set_get_diagram_const( (*this_).input_data )
40 : );
41 5 : (*this_).diagram_valid = layout_diagram_is_valid( &((*this_).diagram_layout) );
42 :
43 5 : U8_TRACE_INFO_INT ( "diagram data objects:", 1 );
44 5 : U8_TRACE_INFO_INT ( "diagram ignored objects:", 0 ); /* we do not ignore diagram objects */
45 5 : U8_TRACE_INFO_INT ( "layout_diagram objects:", 1 );
46 :
47 5 : U8_TRACE_END();
48 5 : }
49 :
50 5 : void layout_visible_set_private_init_classifiers( layout_visible_set_t *this_ )
51 : {
52 5 : U8_TRACE_BEGIN();
53 5 : assert ( NULL != (*this_).input_data );
54 :
55 5 : const uint_fast32_t data_classifier_count = data_visible_set_get_visible_classifier_count( (*this_).input_data );
56 5 : (*this_).visible_classifier_count = 0;
57 5 : assert ( data_classifier_count <= LAYOUT_VISIBLE_SET_MAX_CLASSIFIERS );
58 :
59 153 : for ( uint_fast32_t c_idx = 0; c_idx < data_classifier_count; c_idx ++ )
60 : {
61 : const data_visible_classifier_t *const classifier_data
62 148 : = data_visible_set_get_visible_classifier_const( (*this_).input_data, c_idx );
63 :
64 148 : if ( ( NULL != classifier_data ) && data_visible_classifier_is_valid( classifier_data ) )
65 : {
66 148 : layout_visible_classifier_init( &((*this_).visible_classifier_layout[(*this_).visible_classifier_count]),
67 : classifier_data
68 : );
69 148 : (*this_).visible_classifier_count ++;
70 : }
71 : else
72 : {
73 0 : U8_LOG_ERROR("error in input_data: illegal classifier.");
74 0 : assert(false);
75 : }
76 : } /* end for all classifier_data */
77 :
78 5 : U8_TRACE_INFO_INT ( "classifier data objects:", data_classifier_count );
79 5 : U8_TRACE_INFO_INT ( "classifier ignored objects:", data_classifier_count - (*this_).visible_classifier_count );
80 5 : U8_TRACE_INFO_INT ( "layout_v._classifier objects:", (*this_).visible_classifier_count );
81 :
82 5 : U8_TRACE_END();
83 5 : }
84 :
85 5 : void layout_visible_set_private_init_features( layout_visible_set_t *this_ )
86 : {
87 5 : U8_TRACE_BEGIN();
88 5 : assert ( NULL != (*this_).input_data );
89 :
90 5 : const uint_fast32_t data_feature_count = data_visible_set_get_feature_count( (*this_).input_data );
91 : uint_fast32_t debug_dropped_features;
92 5 : debug_dropped_features = 0;
93 : uint_fast32_t warn_dropped_features;
94 5 : warn_dropped_features = 0;
95 5 : (*this_).feature_count = 0;
96 :
97 306 : for ( uint_fast32_t f_idx = 0; f_idx < data_feature_count; f_idx ++ )
98 : {
99 : const data_feature_t *const feature_data
100 301 : = data_visible_set_get_feature_const( (*this_).input_data, f_idx );
101 301 : uint_fast32_t layout_feature_count = 0;
102 :
103 301 : if ( ( NULL != feature_data ) && data_feature_is_valid( feature_data ) )
104 301 : {
105 301 : const data_row_id_t feature_id = data_feature_get_row_id( feature_data );
106 301 : const bool show = data_rules_diagram_shows_feature ( &((*this_).filter_rules),
107 : (*this_).input_data,
108 : feature_id
109 : );
110 :
111 301 : if ( show )
112 : {
113 33528 : for ( uint_fast32_t c_idx2 = 0; c_idx2 < (*this_).visible_classifier_count; c_idx2 ++ )
114 : {
115 33238 : layout_visible_classifier_t *const parent_classifier
116 : = &((*this_).visible_classifier_layout[c_idx2]);
117 :
118 33238 : const bool one_parent_found = data_rules_vis_classifier_has_feature ( &((*this_).filter_rules),
119 : layout_visible_classifier_get_data_const( parent_classifier ),
120 : feature_data );
121 33238 : if ( one_parent_found )
122 : {
123 580 : if ( (*this_).feature_count < LAYOUT_VISIBLE_SET_MAX_FEATURES )
124 : {
125 356 : layout_feature_init( &((*this_).feature_layout[(*this_).feature_count]),
126 : feature_data,
127 : parent_classifier
128 : );
129 356 : (*this_).feature_count ++;
130 356 : layout_feature_count ++;
131 : }
132 : else
133 : {
134 224 : warn_dropped_features ++;
135 : }
136 : } /* one_parent_found */
137 : } /* end search-for parent_classifier */
138 : }
139 : }
140 : else
141 : {
142 0 : U8_LOG_ERROR("error in input_data: illegal feature.");
143 0 : assert(false);
144 : }
145 :
146 301 : if ( layout_feature_count == 0 )
147 : {
148 : /* no warning here, dropping features - e.g. lifelines for other diagrams - is ok */
149 123 : debug_dropped_features ++;
150 : }
151 : } /* end for all feature_data */
152 :
153 5 : U8_TRACE_INFO_INT ( "feature data objects:", data_feature_count );
154 5 : U8_TRACE_INFO_INT ( "feature ignored objects:", debug_dropped_features );
155 5 : U8_TRACE_INFO_INT ( "layout_feature objects:", (*this_).feature_count );
156 5 : if ( 0 != warn_dropped_features )
157 : {
158 1 : U8_LOG_WARNING_INT( "LAYOUT_VISIBLE_SET_MAX_FEATURES exceeded, layout_features not visible:", warn_dropped_features );
159 : }
160 :
161 5 : U8_TRACE_END();
162 5 : }
163 :
164 5 : void layout_visible_set_private_init_relationships( layout_visible_set_t *this_ )
165 : {
166 5 : U8_TRACE_BEGIN();
167 5 : assert ( NULL != (*this_).input_data );
168 :
169 5 : const uint32_t data_relationship_count = data_visible_set_get_relationship_count( (*this_).input_data );
170 : uint32_t debug_dropped_relationships;
171 5 : debug_dropped_relationships = 0;
172 : uint32_t warn_dropped_relationships;
173 5 : warn_dropped_relationships = 0;
174 5 : (*this_).relationship_count = 0;
175 :
176 1064 : for ( uint32_t r_idx = 0; r_idx < data_relationship_count; r_idx ++ )
177 : {
178 : const data_relationship_t *relationship_data;
179 1059 : relationship_data = data_visible_set_get_relationship_const( (*this_).input_data, r_idx );
180 :
181 1059 : uint32_t layout_relationship_count = 0;
182 1059 : if ( ( NULL != relationship_data ) && data_relationship_is_valid( relationship_data ) )
183 1059 : {
184 1059 : const bool show = data_rules_diagram_shows_relationship ( &((*this_).filter_rules),
185 : (*this_).input_data,
186 : data_relationship_get_row_id( relationship_data )
187 : );
188 :
189 1059 : if ( show )
190 : {
191 1047 : layout_relationship_count = layout_visible_set_private_init_relationship( this_,
192 : relationship_data,
193 : &warn_dropped_relationships
194 : );
195 : }
196 : }
197 : else
198 : {
199 0 : U8_LOG_ERROR("error in input_data: illegal relationship.");
200 0 : assert(false);
201 : }
202 :
203 1059 : if ( layout_relationship_count == 0 )
204 : {
205 : /* no warning here, dropping relationships - e.g. only one end-object visible in current diagram - is ok */
206 525 : debug_dropped_relationships ++;
207 : }
208 : } /* end for all relationship_data */
209 :
210 5 : U8_TRACE_INFO_INT ( "relationship data objects:", data_relationship_count );
211 5 : U8_TRACE_INFO_INT ( "relationship ignored objects:", debug_dropped_relationships );
212 5 : U8_TRACE_INFO_INT ( "layout_relationship objects:", (*this_).relationship_count );
213 5 : if ( 0 != warn_dropped_relationships )
214 : {
215 1 : U8_LOG_WARNING_INT( "LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS exceeded, layout_relationships not visible:", warn_dropped_relationships );
216 : }
217 :
218 5 : U8_TRACE_END();
219 5 : }
220 :
221 1047 : uint32_t layout_visible_set_private_init_relationship( layout_visible_set_t *this_,
222 : const data_relationship_t *relationship_data,
223 : uint32_t *io_dropped_relationships )
224 : {
225 1047 : U8_TRACE_BEGIN();
226 1047 : assert ( NULL != (*this_).input_data );
227 1047 : assert ( NULL != relationship_data );
228 1047 : assert ( NULL != io_dropped_relationships );
229 1047 : uint32_t layout_relationship_count = 0;
230 :
231 1047 : const data_row_id_t from_classifier_id = data_relationship_get_from_classifier_row_id( relationship_data );
232 1047 : const data_row_id_t to_classifier_id = data_relationship_get_to_classifier_row_id( relationship_data );
233 1047 : const data_row_id_t from_feature_id = data_relationship_get_from_feature_row_id( relationship_data );
234 1047 : const data_row_id_t to_feature_id = data_relationship_get_to_feature_row_id( relationship_data );
235 :
236 1047 : if ( DATA_ROW_ID_VOID == from_feature_id ) /* search source(from) in classifiers */
237 : {
238 132412 : for ( uint32_t c_idx3 = 0; c_idx3 < (*this_).visible_classifier_count; c_idx3 ++ )
239 : {
240 131367 : layout_visible_classifier_t *const probe3_classifier
241 : = &((*this_).visible_classifier_layout[c_idx3]);
242 :
243 131367 : const bool one_from_classifier_found = ( from_classifier_id == layout_visible_classifier_get_classifier_id( probe3_classifier ) );
244 131367 : if ( one_from_classifier_found )
245 : {
246 2090 : if ( DATA_ROW_ID_VOID == to_feature_id ) /* search destination(to) in classifiers */
247 : {
248 264824 : for ( uint32_t c_idx4 = 0; c_idx4 < (*this_).visible_classifier_count; c_idx4 ++ )
249 : {
250 : layout_visible_classifier_t *probe4_classifier;
251 262734 : probe4_classifier = &((*this_).visible_classifier_layout[c_idx4]);
252 :
253 262734 : const bool one_to_classifier_found = ( to_classifier_id == layout_visible_classifier_get_classifier_id( probe4_classifier ) );
254 262734 : if ( one_to_classifier_found )
255 : {
256 4180 : if ( (*this_).relationship_count < LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS )
257 : {
258 2132 : layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]),
259 : relationship_data,
260 : probe3_classifier,
261 : probe4_classifier,
262 : NULL,
263 : NULL
264 : );
265 2132 : (*this_).relationship_count ++;
266 2132 : layout_relationship_count ++;
267 : }
268 : else
269 : {
270 2048 : (*io_dropped_relationships) ++;
271 : }
272 : } /* one_to_classifier_found */
273 : } /* end search-for to_classifier */
274 : }
275 : else /* search destination(to) in features */
276 : {
277 0 : for ( uint32_t f_idx4 = 0; f_idx4 < (*this_).feature_count; f_idx4 ++ )
278 : {
279 0 : layout_feature_t *const probe4_feature = &((*this_).feature_layout[f_idx4]);
280 :
281 0 : const bool one_to_feature_found = ( to_feature_id == layout_feature_get_feature_id( probe4_feature ) );
282 0 : if ( one_to_feature_found )
283 : {
284 0 : const bool to_feature_ok
285 0 : = ( to_classifier_id == data_feature_get_classifier_row_id(layout_feature_get_data_const( probe4_feature )) );
286 0 : if ( to_feature_ok )
287 : {
288 0 : if ( (*this_).relationship_count < LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS )
289 : {
290 0 : layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]),
291 : relationship_data,
292 : probe3_classifier,
293 : layout_feature_get_classifier_ptr( probe4_feature ),
294 : NULL,
295 : probe4_feature
296 : );
297 0 : (*this_).relationship_count ++;
298 0 : layout_relationship_count ++;
299 : }
300 : else
301 : {
302 0 : (*io_dropped_relationships) ++;
303 : }
304 : }
305 : else
306 : {
307 0 : U8_LOG_ERROR("error in input_data: relationship links to feature and inconsistent classifier.");
308 : }
309 : } /* one_to_feature_found */
310 : } /* end search-for to_feature */
311 : }
312 : } /* one_from_classifier_found */
313 : } /* end search-for from_classifier */
314 : }
315 : else /* search source(from) in features */
316 : {
317 70 : for ( uint32_t f_idx3 = 0; f_idx3 < (*this_).feature_count; f_idx3 ++ )
318 : {
319 : layout_feature_t *probe3_feature;
320 68 : probe3_feature = &((*this_).feature_layout[f_idx3]);
321 :
322 68 : const bool one_from_feature_found = ( from_feature_id == layout_feature_get_feature_id( probe3_feature ) );
323 68 : if ( one_from_feature_found )
324 : {
325 4 : const bool from_feature_ok = ( from_classifier_id == data_feature_get_classifier_row_id(layout_feature_get_data_const( probe3_feature )) );
326 4 : if ( from_feature_ok )
327 : {
328 2 : if ( DATA_ROW_ID_VOID == to_feature_id ) /* search destination(to) in classifiers */
329 : {
330 0 : for ( uint32_t c_idx5 = 0; c_idx5 < (*this_).visible_classifier_count; c_idx5 ++ )
331 : {
332 0 : layout_visible_classifier_t *const probe5_classifier
333 : = &((*this_).visible_classifier_layout[c_idx5]);
334 :
335 0 : const bool one_to_classifier_found
336 0 : = ( to_classifier_id == layout_visible_classifier_get_classifier_id( probe5_classifier ) );
337 0 : if ( one_to_classifier_found )
338 : {
339 0 : if ( (*this_).relationship_count < LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS )
340 : {
341 0 : layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]),
342 : relationship_data,
343 : layout_feature_get_classifier_ptr( probe3_feature ),
344 : probe5_classifier,
345 : probe3_feature,
346 : NULL
347 : );
348 0 : (*this_).relationship_count ++;
349 0 : layout_relationship_count ++;
350 : }
351 : else
352 : {
353 0 : (*io_dropped_relationships) ++;
354 : }
355 : } /* one_to_classifier_found */
356 : } /* end search-for to_classifier */
357 : }
358 : else /* search destination(to) in features */
359 : {
360 122 : for ( uint32_t f_idx5 = 0; f_idx5 < (*this_).feature_count; f_idx5 ++ )
361 : {
362 120 : layout_feature_t *const probe5_feature
363 : = &((*this_).feature_layout[f_idx5]);
364 :
365 120 : const bool one_to_feature_found = ( to_feature_id == layout_feature_get_feature_id( probe5_feature ) );
366 120 : if ( one_to_feature_found )
367 : {
368 4 : const bool to_feature_ok = ( to_classifier_id == data_feature_get_classifier_row_id(layout_feature_get_data_const( probe5_feature )) );
369 4 : if ( to_feature_ok )
370 : {
371 4 : if ( (*this_).relationship_count < LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS )
372 : {
373 4 : layout_relationship_init( &((*this_).relationship_layout[(*this_).relationship_count]),
374 : relationship_data,
375 : layout_feature_get_classifier_ptr( probe3_feature ),
376 : layout_feature_get_classifier_ptr( probe5_feature ),
377 : probe3_feature,
378 : probe5_feature
379 : );
380 4 : (*this_).relationship_count ++;
381 4 : layout_relationship_count ++;
382 : }
383 : else
384 : {
385 0 : (*io_dropped_relationships) ++;
386 : }
387 : }
388 : else
389 : {
390 0 : U8_LOG_ERROR("error in input_data: relationship links to feature and inconsistent classifier.");
391 : }
392 : } /* one_to_feature_found */
393 : } /* end search-for to_feature */
394 : }
395 : }
396 : else
397 : {
398 2 : U8_LOG_ERROR("error in input_data: relationship links from feature and inconsistent classifier.");
399 : }
400 : } /* one_from_feature_found */
401 : } /* end search-for from_feature */
402 : } /* endif: search source(from) */
403 :
404 1047 : U8_TRACE_END();
405 1047 : return layout_relationship_count;
406 : }
407 :
408 5 : void layout_visible_set_destroy( layout_visible_set_t *this_ )
409 : {
410 5 : U8_TRACE_BEGIN();
411 5 : assert( (*this_).visible_classifier_count <= LAYOUT_VISIBLE_SET_MAX_CLASSIFIERS );
412 5 : assert( (*this_).feature_count <= LAYOUT_VISIBLE_SET_MAX_FEATURES );
413 5 : assert( (*this_).relationship_count <= LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS );
414 :
415 5 : data_rules_destroy ( &((*this_).filter_rules) );
416 :
417 5 : if ( (*this_).diagram_valid )
418 : {
419 4 : layout_diagram_destroy ( &((*this_).diagram_layout) );
420 : }
421 :
422 153 : for ( uint_fast32_t c_idx = 0; c_idx < (*this_).visible_classifier_count; c_idx ++ )
423 : {
424 148 : layout_visible_classifier_destroy( &((*this_).visible_classifier_layout[c_idx]) );
425 : }
426 :
427 361 : for ( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ )
428 : {
429 356 : layout_feature_destroy( &((*this_).feature_layout[f_idx]) );
430 : }
431 :
432 2141 : for ( uint_fast32_t r_idx = 0; r_idx < (*this_).relationship_count; r_idx ++ )
433 : {
434 2136 : layout_relationship_destroy( &((*this_).relationship_layout[r_idx]) );
435 : }
436 :
437 5 : U8_TRACE_END();
438 5 : }
439 :
440 : /* ================================ misc ================================ */
441 :
442 9 : bool layout_visible_set_is_consistent ( const layout_visible_set_t *this_ )
443 : {
444 9 : bool result = true;
445 :
446 : /* check input data */
447 9 : if ( NULL == (*this_).input_data )
448 : {
449 0 : result = false;
450 : }
451 : else
452 : {
453 9 : if ( ! data_visible_set_is_valid( (*this_).input_data ) )
454 : {
455 1 : result = false;
456 : }
457 : }
458 :
459 : /* check diagram */
460 9 : if ( ! (*this_).diagram_valid )
461 : {
462 1 : result = false;
463 : }
464 : else
465 : {
466 8 : if ( ! layout_diagram_is_valid( &((*this_).diagram_layout) ) )
467 : {
468 0 : result = false;
469 : }
470 : }
471 :
472 : /* check classifiers */
473 9 : if ( (*this_).visible_classifier_count > LAYOUT_VISIBLE_SET_MAX_CLASSIFIERS )
474 : {
475 : /* if the object is already initialized, this is a severe error */
476 0 : result = false;
477 : }
478 : else
479 : {
480 305 : for ( uint_fast32_t c_idx = 0; c_idx < (*this_).visible_classifier_count; c_idx ++ )
481 : {
482 296 : const layout_visible_classifier_t *current = &((*this_).visible_classifier_layout[c_idx]);
483 296 : if ( ! layout_visible_classifier_is_valid( current ) )
484 : {
485 0 : result = false;
486 : }
487 : }
488 : }
489 :
490 : /* check features */
491 9 : if ( (*this_).feature_count > LAYOUT_VISIBLE_SET_MAX_FEATURES )
492 : {
493 : /* if the object is already initialized, this is a severe error */
494 0 : result = false;
495 : }
496 : else
497 : {
498 721 : for ( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ )
499 : {
500 712 : const layout_feature_t *current = &((*this_).feature_layout[f_idx]);
501 712 : if ( ! layout_feature_is_valid( current ) )
502 : {
503 0 : result = false;
504 : }
505 : }
506 : }
507 :
508 : /* check relationships */
509 9 : if ( (*this_).relationship_count > LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS )
510 : {
511 : /* if the object is already initialized, this is a severe error */
512 0 : result = false;
513 : }
514 : else
515 : {
516 4281 : for ( uint_fast32_t r_idx = 0; r_idx < (*this_).relationship_count; r_idx ++ )
517 : {
518 4272 : const layout_relationship_t *current = &((*this_).relationship_layout[r_idx]);
519 4272 : if ( ! layout_relationship_is_valid( current ) )
520 : {
521 0 : result = false;
522 : }
523 : }
524 : }
525 :
526 9 : return result;
527 : }
528 :
529 : #ifndef NDEBUG
530 : #define LAYOUT_VISIBLE_SET_STATS_WITH_WARNINGS
531 : #else
532 : /* no layouting warnings to user in release mode */
533 : #endif
534 :
535 0 : void layout_visible_set_private_analyze_nothing_callback ( void *data,
536 : const geometry_rectangle_t *rect_a,
537 : const geometry_rectangle_t *rect_b )
538 : {
539 0 : }
540 :
541 0 : void layout_visible_set_get_statistics ( const layout_visible_set_t *this_, data_stat_t *io_layout_stat )
542 : {
543 0 : U8_TRACE_BEGIN();
544 0 : layout_visible_set_analyze( this_, io_layout_stat, layout_visible_set_private_analyze_nothing_callback, NULL );
545 0 : U8_TRACE_END();
546 0 : }
547 :
548 0 : void layout_visible_set_analyze ( const layout_visible_set_t *this_,
549 : data_stat_t *io_layout_stat,
550 : void (*overlap_callback)(void *data, const geometry_rectangle_t *a, const geometry_rectangle_t *b),
551 : void *data )
552 : {
553 0 : U8_TRACE_BEGIN();
554 0 : assert( (*this_).visible_classifier_count <= LAYOUT_VISIBLE_SET_MAX_CLASSIFIERS );
555 0 : assert( (*this_).feature_count <= LAYOUT_VISIBLE_SET_MAX_FEATURES );
556 0 : assert( (*this_).relationship_count <= LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS );
557 0 : assert( io_layout_stat != NULL );
558 : pencil_rules_t pencil_rules;
559 0 : pencil_rules_init( &pencil_rules );
560 :
561 : /* check if diagram is valid */
562 :
563 0 : if ( (*this_).diagram_valid )
564 : {
565 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_EXPORTED );
566 :
567 0 : const geometry_rectangle_t *const diag_bounds = layout_diagram_get_bounds_const( &((*this_).diagram_layout) );
568 0 : const geometry_rectangle_t *const diag_space = layout_diagram_get_draw_area_const( &((*this_).diagram_layout) );
569 : #ifdef LAYOUT_VISIBLE_SET_STATS_WITH_WARNINGS
570 0 : const data_diagram_t *const diag_data = layout_diagram_get_data_const ( &((*this_).diagram_layout) );
571 0 : const data_diagram_type_t diag_type = data_diagram_get_diagram_type ( diag_data );
572 : #endif
573 :
574 : /* check classifiers against diagram */
575 :
576 0 : for ( uint_fast32_t c_idx = 0; c_idx < (*this_).visible_classifier_count; c_idx ++ )
577 : {
578 0 : const layout_visible_classifier_t *const classifier = &((*this_).visible_classifier_layout[c_idx]);
579 : const geometry_rectangle_t *const c_symbox
580 0 : = layout_visible_classifier_get_symbol_box_const( classifier );
581 : const geometry_rectangle_t *const c_label
582 0 : = layout_visible_classifier_get_label_box_const( classifier );
583 : #ifdef LAYOUT_VISIBLE_SET_STATS_WITH_WARNINGS
584 : const geometry_rectangle_t *const c_space
585 0 : = layout_visible_classifier_get_space_const( classifier );
586 : #endif
587 :
588 0 : if ( geometry_rectangle_is_containing( diag_space, c_symbox )
589 0 : && geometry_rectangle_is_containing( diag_space, c_label ) )
590 : {
591 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_EXPORTED );
592 :
593 : #ifdef LAYOUT_VISIBLE_SET_STATS_WITH_WARNINGS
594 : /* check current classifier against already processed classifiers */
595 :
596 0 : for ( uint_fast32_t probe_idx = 0; probe_idx < c_idx; probe_idx ++ )
597 : {
598 0 : const layout_visible_classifier_t *const probe = &((*this_).visible_classifier_layout[probe_idx]);
599 : const geometry_rectangle_t *const probe_symbox
600 0 : = layout_visible_classifier_get_symbol_box_const( probe );
601 : const geometry_rectangle_t *const probe_label
602 0 : = layout_visible_classifier_get_label_box_const( probe );
603 : const geometry_rectangle_t *const probe_space
604 0 : = layout_visible_classifier_get_space_const( probe );
605 :
606 : const bool symbox_overlaps
607 0 : = geometry_rectangle_is_intersecting( c_symbox, probe_symbox );
608 0 : const bool mixed_overlaps
609 0 : = ( geometry_rectangle_is_intersecting( c_symbox, probe_label )
610 0 : || geometry_rectangle_is_intersecting( c_label, probe_symbox ) );
611 : const bool label_overlaps
612 0 : = geometry_rectangle_is_intersecting( c_label, probe_label );
613 :
614 0 : if ( symbox_overlaps || mixed_overlaps || label_overlaps )
615 : {
616 : const bool probe_is_ancestor
617 0 : = layout_visible_set_is_ancestor( this_,
618 : probe, /* ancestor */
619 : classifier /* descendant */
620 : );
621 : const bool probe_is_descendant
622 0 : = layout_visible_set_is_ancestor( this_,
623 : classifier, /* ancestor */
624 : probe /* descendant */
625 : );
626 0 : const bool probe_contains_c
627 0 : = ( geometry_rectangle_is_containing( probe_space, c_symbox )
628 0 : && geometry_rectangle_is_containing( probe_space, c_label ) );
629 0 : const bool c_contains_probe
630 0 : = ( geometry_rectangle_is_containing( c_space, probe_symbox )
631 0 : && geometry_rectangle_is_containing( c_space, probe_label ) );
632 0 : if ( probe_is_ancestor && probe_contains_c )
633 : {
634 : /* ok */
635 : }
636 0 : else if ( probe_is_descendant && c_contains_probe )
637 : {
638 : /* ok */
639 : }
640 : else
641 : {
642 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING );
643 0 : (*overlap_callback)( data, probe_space, c_symbox );
644 0 : (*overlap_callback)( data, probe_space, c_label );
645 0 : (*overlap_callback)( data, c_space, probe_symbox );
646 0 : (*overlap_callback)( data, c_space, probe_label );
647 : }
648 : }
649 : }
650 : #endif
651 :
652 : }
653 0 : else if ( geometry_rectangle_is_containing( diag_bounds, c_symbox )
654 0 : && geometry_rectangle_is_containing( diag_bounds, c_label ) )
655 : {
656 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_EXPORTED );
657 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING );
658 0 : (*overlap_callback)( data, diag_bounds, c_symbox );
659 0 : (*overlap_callback)( data, diag_bounds, c_label );
660 : }
661 : else
662 : {
663 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_ERROR );
664 0 : (*overlap_callback)( data, diag_space, diag_space );
665 : }
666 :
667 : }
668 :
669 : /* check features against diagram */
670 :
671 0 : for ( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ )
672 : {
673 0 : const layout_feature_t *const feature = &((*this_).feature_layout[f_idx]);
674 0 : const data_feature_t *const feature_data = layout_feature_get_data_const( feature );
675 0 : const data_feature_type_t feature_type = data_feature_get_main_type( feature_data );
676 0 : const data_row_id_t feature_id = layout_feature_get_feature_id( feature );
677 : const bool feature_visible
678 0 : = data_rules_diagram_shows_feature( &((*this_).filter_rules),
679 0 : (*this_).input_data,
680 : feature_id
681 : );
682 0 : const data_stat_table_t feat_or_lifeline
683 0 : = ( feature_type == DATA_FEATURE_TYPE_LIFELINE ) ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE;
684 :
685 : const geometry_rectangle_t *const f_symbox
686 0 : = layout_feature_get_symbol_box_const( feature );
687 : const geometry_rectangle_t *const f_label
688 0 : = layout_feature_get_label_box_const( feature );
689 :
690 0 : if ( ! feature_visible )
691 : {
692 : /* nothing to do, feature is not visible in this diagram */
693 : }
694 0 : else if ( ( geometry_rectangle_is_empty( f_symbox )
695 0 : || geometry_rectangle_is_containing( diag_space, f_symbox ))
696 0 : && geometry_rectangle_is_containing( diag_space, f_label ) )
697 : {
698 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_EXPORTED );
699 :
700 : #ifdef LAYOUT_VISIBLE_SET_STATS_WITH_WARNINGS
701 : /* check features against classifiers */
702 :
703 0 : for ( uint_fast32_t probe_idx = 0; probe_idx < (*this_).visible_classifier_count; probe_idx ++ )
704 : {
705 0 : const layout_visible_classifier_t *const probe = &((*this_).visible_classifier_layout[probe_idx]);
706 0 : const data_classifier_t *const probe_data = layout_visible_classifier_get_classifier_const( probe );
707 0 : const data_classifier_type_t probe_type = data_classifier_get_main_type( probe_data );
708 : /* determine if this probe classifier shall be drawn in the same rectangle as the lifeline */
709 : const bool feature_is_proxy_for_probe
710 0 : = pencil_rules_feature_is_implicit_proxy( &pencil_rules, feature_type, probe_type, diag_type );
711 : const geometry_rectangle_t *const probe_symbox
712 0 : = layout_visible_classifier_get_symbol_box_const( probe );
713 : const geometry_rectangle_t *const probe_label
714 0 : = layout_visible_classifier_get_label_box_const( probe );
715 : const geometry_rectangle_t *const c_space
716 0 : = layout_visible_classifier_get_space_const( probe );
717 :
718 0 : const bool symbox_overlaps
719 0 : = geometry_rectangle_is_intersecting( f_symbox, probe_symbox )
720 0 : && ( ! geometry_rectangle_is_containing( c_space, f_symbox ) );
721 : const bool f_sym_overlaps_c_label
722 0 : = geometry_rectangle_is_intersecting( f_symbox, probe_label );
723 0 : const bool f_label_overlaps_c_sym
724 0 : = geometry_rectangle_is_intersecting( f_label, probe_symbox )
725 0 : && ( ! geometry_rectangle_is_containing( c_space, f_label ) );
726 : const bool label_overlaps
727 0 : = geometry_rectangle_is_intersecting( f_label, probe_label );
728 :
729 0 : if ( ! feature_is_proxy_for_probe )
730 : {
731 0 : if ( f_sym_overlaps_c_label || f_label_overlaps_c_sym || label_overlaps )
732 : {
733 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_WARNING );
734 0 : (*overlap_callback)( data, f_symbox, probe_label );
735 0 : (*overlap_callback)( data, f_label, probe_symbox );
736 0 : (*overlap_callback)( data, f_label, probe_label );
737 : }
738 0 : else if ( symbox_overlaps )
739 : {
740 : const layout_visible_classifier_t *const f_parent
741 0 : = layout_feature_get_classifier_const ( feature );
742 : const bool probe_is_parent
743 0 : = layout_visible_classifier_is_equal_diagramelement_id( f_parent, probe );
744 0 : if ( probe_is_parent )
745 : {
746 : /* ok: a feature may overlap its own parent classifier */
747 : }
748 : else
749 : {
750 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_WARNING );
751 0 : (*overlap_callback)( data, f_symbox, probe_symbox );
752 : }
753 : }
754 : }
755 : }
756 :
757 : /* check current feature against already processed features */
758 :
759 0 : for ( uint_fast32_t probe_idx = 0; probe_idx < f_idx; probe_idx ++ )
760 : {
761 0 : const layout_feature_t *const probe = &((*this_).feature_layout[probe_idx]);
762 0 : const data_row_id_t probe_id = layout_feature_get_feature_id( probe );
763 : const bool probe_visible
764 0 : = data_rules_diagram_shows_feature( &((*this_).filter_rules),
765 0 : (*this_).input_data,
766 : probe_id
767 : );
768 : const geometry_rectangle_t *const probe_symbox
769 0 : = layout_feature_get_symbol_box_const( probe );
770 : const geometry_rectangle_t *const probe_label
771 0 : = layout_feature_get_label_box_const( probe );
772 :
773 0 : if ( probe_visible )
774 : {
775 : const bool symbox_overlaps
776 0 : = geometry_rectangle_is_intersecting( f_symbox, probe_symbox );
777 0 : const bool mixed_overlaps
778 0 : = ( geometry_rectangle_is_intersecting( f_symbox, probe_label )
779 0 : || geometry_rectangle_is_intersecting( f_label, probe_symbox ) );
780 : const bool label_overlaps
781 0 : = geometry_rectangle_is_intersecting( f_label, probe_label );
782 :
783 0 : if ( mixed_overlaps || label_overlaps )
784 : {
785 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_WARNING );
786 0 : (*overlap_callback)( data, f_symbox, probe_label );
787 0 : (*overlap_callback)( data, f_label, probe_symbox );
788 0 : (*overlap_callback)( data, f_label, probe_label );
789 : }
790 0 : else if ( symbox_overlaps )
791 : {
792 : const layout_visible_classifier_t *const f_parent
793 0 : = layout_feature_get_classifier_const ( feature );
794 : const layout_visible_classifier_t *const probe_parent
795 0 : = layout_feature_get_classifier_const ( probe );
796 :
797 : const bool same_parent
798 0 : = layout_visible_classifier_is_equal_diagramelement_id( f_parent, probe_parent );
799 0 : if ( same_parent )
800 : {
801 : /* ok, not a layouting issue */
802 : }
803 : else
804 : {
805 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_WARNING );
806 0 : (*overlap_callback)( data, f_symbox, probe_symbox );
807 : }
808 : }
809 : }
810 : }
811 : #endif
812 : }
813 0 : else if ( geometry_rectangle_is_containing( diag_bounds, f_symbox )
814 0 : && geometry_rectangle_is_containing( diag_bounds, f_label ) )
815 : {
816 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_EXPORTED );
817 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_WARNING );
818 0 : (*overlap_callback)( data, diag_bounds, f_symbox );
819 0 : (*overlap_callback)( data, diag_bounds, f_label );
820 : }
821 : else
822 : {
823 0 : data_stat_inc_count( io_layout_stat, feat_or_lifeline, DATA_STAT_SERIES_ERROR );
824 0 : (*overlap_callback)( data, diag_space, diag_space );
825 : }
826 : }
827 :
828 : /* check relationships against diagram */
829 :
830 0 : for ( uint_fast32_t r_idx = 0; r_idx < (*this_).relationship_count; r_idx ++ )
831 : {
832 0 : const layout_relationship_t *const relationship = &((*this_).relationship_layout[r_idx]);
833 0 : const data_row_id_t relationship_id = layout_relationship_get_relationship_id( relationship );
834 : const bool relationship_visible
835 0 : = data_rules_diagram_shows_relationship( &((*this_).filter_rules),
836 0 : (*this_).input_data,
837 : relationship_id
838 : );
839 : const geometry_rectangle_t *const r_label
840 0 : = layout_relationship_get_label_box_const( relationship );
841 : const geometry_connector_t *const r_shape
842 0 : = layout_relationship_get_shape_const( relationship );
843 0 : const geometry_rectangle_t r_bounds = geometry_connector_get_bounding_rectangle( r_shape );
844 :
845 0 : if ( ! relationship_visible )
846 : {
847 : /* nothing to do, relationship is not visible in this diagram */
848 : }
849 0 : else if ( geometry_rectangle_is_containing( diag_space, &r_bounds )
850 0 : && geometry_rectangle_is_containing( diag_space, r_label ) )
851 : {
852 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED );
853 :
854 : #ifdef LAYOUT_VISIBLE_SET_STATS_WITH_WARNINGS
855 : /* check relationships against classifiers */
856 :
857 0 : for ( uint_fast32_t probe_idx = 0; probe_idx < (*this_).visible_classifier_count; probe_idx ++ )
858 : {
859 0 : const layout_visible_classifier_t *const probe = &((*this_).visible_classifier_layout[probe_idx]);
860 : const geometry_rectangle_t *const probe_symbox
861 0 : = layout_visible_classifier_get_symbol_box_const( probe );
862 : const geometry_rectangle_t *const probe_label
863 0 : = layout_visible_classifier_get_label_box_const( probe );
864 : const geometry_rectangle_t *const probe_space
865 0 : = layout_visible_classifier_get_space_const( probe );
866 :
867 : const bool label_overlaps_label
868 0 : = geometry_rectangle_is_intersecting( r_label, probe_label );
869 0 : const bool label_overlaps_symbox
870 0 : = ( geometry_rectangle_is_intersecting( r_label, probe_symbox )
871 0 : && ! geometry_rectangle_is_containing( probe_space, r_label ) );
872 : const bool shape_overlaps_label
873 0 : = geometry_connector_is_intersecting_rectangle( r_shape, probe_label );
874 :
875 0 : if ( label_overlaps_label || label_overlaps_symbox || shape_overlaps_label )
876 : {
877 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING );
878 0 : (*overlap_callback)( data, r_label, probe_label );
879 0 : (*overlap_callback)( data, r_label, probe_symbox );
880 0 : (*overlap_callback)( data, &r_bounds, probe_label );
881 : }
882 : }
883 :
884 : /* check relationships against features */
885 :
886 0 : for ( uint_fast32_t probe_idx = 0; probe_idx < (*this_).feature_count; probe_idx ++ )
887 : {
888 0 : const layout_feature_t *const probe = &((*this_).feature_layout[probe_idx]);
889 0 : const data_feature_t *const probe_data = layout_feature_get_data_const( probe );
890 0 : const data_feature_type_t probe_type = data_feature_get_main_type( probe_data );
891 0 : const data_row_id_t probe_id = layout_feature_get_feature_id( probe );
892 : const bool probe_visible
893 0 : = data_rules_diagram_shows_feature( &((*this_).filter_rules),
894 0 : (*this_).input_data,
895 : probe_id
896 : );
897 : const geometry_rectangle_t *const probe_symbox
898 0 : = layout_feature_get_symbol_box_const( probe );
899 : const geometry_rectangle_t *const probe_label
900 0 : = layout_feature_get_label_box_const( probe );
901 :
902 0 : if ( probe_visible && ( DATA_FEATURE_TYPE_LIFELINE != probe_type ) )
903 : {
904 : const bool label_overlaps_label
905 0 : = geometry_rectangle_is_intersecting( r_label, probe_label );
906 : const bool label_overlaps_symbox
907 0 : = geometry_rectangle_is_intersecting( r_label, probe_symbox );
908 : const bool shape_overlaps_label
909 0 : = geometry_connector_is_intersecting_rectangle( r_shape, probe_label );
910 :
911 0 : if ( label_overlaps_label || label_overlaps_symbox || shape_overlaps_label )
912 : {
913 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING );
914 0 : (*overlap_callback)( data, r_label, probe_label );
915 0 : (*overlap_callback)( data, r_label, probe_symbox );
916 0 : (*overlap_callback)( data, &r_bounds, probe_label );
917 : }
918 : }
919 : }
920 :
921 : /* check current relationship against already processed relationships */
922 :
923 0 : for ( uint_fast32_t probe_idx = 0; probe_idx < r_idx; probe_idx ++ )
924 : {
925 0 : const layout_relationship_t *const probe = &((*this_).relationship_layout[probe_idx]);
926 0 : const data_row_id_t probe_id = layout_relationship_get_relationship_id( probe );
927 : const bool probe_visible
928 0 : = data_rules_diagram_shows_relationship( &((*this_).filter_rules),
929 0 : (*this_).input_data,
930 : probe_id
931 : );
932 : const geometry_rectangle_t *const probe_label
933 0 : = layout_relationship_get_label_box_const( probe );
934 : const geometry_connector_t *const probe_shape
935 0 : = layout_relationship_get_shape_const( probe );
936 :
937 0 : if ( probe_visible )
938 : {
939 : const bool label_overlaps
940 0 : = geometry_rectangle_is_intersecting( r_label, probe_label );
941 0 : const bool mixed_overlaps
942 0 : = ( geometry_connector_is_intersecting_rectangle( r_shape, probe_label )
943 0 : || geometry_connector_is_intersecting_rectangle( probe_shape, r_label ) );
944 :
945 0 : if ( label_overlaps || mixed_overlaps )
946 : {
947 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING );
948 0 : (*overlap_callback)( data, r_label, probe_label );
949 0 : (*overlap_callback)( data, &r_bounds, probe_label );
950 : const geometry_rectangle_t probe_bounds
951 0 : = geometry_connector_get_bounding_rectangle( probe_shape );
952 0 : (*overlap_callback)( data, &probe_bounds, r_label );
953 : }
954 : }
955 : }
956 : #endif
957 :
958 : }
959 0 : else if ( geometry_rectangle_is_containing( diag_bounds, &r_bounds )
960 0 : && geometry_rectangle_is_containing( diag_bounds, r_label ) )
961 : {
962 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_EXPORTED );
963 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING );
964 0 : (*overlap_callback)( data, diag_bounds, &r_bounds );
965 0 : (*overlap_callback)( data, diag_bounds, r_label );
966 : }
967 : else
968 : {
969 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR );
970 0 : (*overlap_callback)( data, diag_space, diag_space );
971 : }
972 : }
973 : }
974 : else
975 : {
976 0 : data_stat_inc_count( io_layout_stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_ERROR );
977 : }
978 :
979 0 : pencil_rules_destroy( &pencil_rules );
980 0 : U8_TRACE_END();
981 0 : }
982 :
983 :
984 : /*
985 : Copyright 2017-2024 Andreas Warnke
986 :
987 : Licensed under the Apache License, Version 2.0 (the "License");
988 : you may not use this file except in compliance with the License.
989 : You may obtain a copy of the License at
990 :
991 : http://www.apache.org/licenses/LICENSE-2.0
992 :
993 : Unless required by applicable law or agreed to in writing, software
994 : distributed under the License is distributed on an "AS IS" BASIS,
995 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
996 : See the License for the specific language governing permissions and
997 : limitations under the License.
998 : */
|