LCOV - code coverage report
Current view: top level - pencil/source - pencil_classifier_2d_layouter.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.71.2_covts Lines: 0.0 % 435 0
Test Date: 2026-08-22 19:47:36 Functions: 0.0 % 14 0

            Line data    Source code
       1              : /* File: pencil_classifier_2d_layouter.c; Copyright and License: see below */
       2              : 
       3              : #include "pencil_classifier_2d_layouter.h"
       4              : #include "layout/layout_quality.h"
       5              : #include "layout/layout_relationship_iter.h"
       6              : #include "geometry/geometry_non_linear_scale.h"
       7              : #include "u8/u8_trace.h"
       8              : #include "u8/u8_f64.h"
       9              : #include <pango/pangocairo.h>
      10              : #include <stdio.h>
      11              : #include <stdlib.h>
      12              : #include <math.h>
      13              : 
      14            0 : void pencil_classifier_2d_layouter_init( pencil_classifier_2d_layouter_t *this_,
      15              :                                          layout_visible_set_t *layout_data,
      16              :                                          const data_profile_part_t *profile,
      17              :                                          const pencil_size_t *pencil_size,
      18              :                                          geometry_dimensions_t *default_classifier_size,
      19              :                                          const geometry_grid_t *grid,
      20              :                                          pencil_feature_layouter_t *feature_layouter )
      21              : {
      22            0 :     U8_TRACE_BEGIN();
      23            0 :     assert( NULL != layout_data );
      24            0 :     assert( NULL != profile );
      25            0 :     assert( NULL != pencil_size );
      26            0 :     assert( NULL != default_classifier_size );
      27            0 :     assert( NULL != grid );
      28            0 :     assert( NULL != feature_layouter );
      29              : 
      30            0 :     (*this_).layout_data = layout_data;
      31            0 :     (*this_).profile = profile;
      32              : 
      33            0 :     (*this_).pencil_size = pencil_size;
      34            0 :     (*this_).default_classifier_size = default_classifier_size;
      35            0 :     (*this_).grid = grid;
      36            0 :     (*this_).feature_layouter = feature_layouter;
      37            0 :     pencil_classifier_composer_init( &((*this_).classifier_composer) );
      38              : 
      39              :     /* get draw area */
      40              :     {
      41              :         const layout_diagram_t *const diagram_layout
      42            0 :             = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
      43            0 :         (*this_).diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout );
      44              :     }
      45              : 
      46            0 :     U8_TRACE_END();
      47            0 : }
      48              : 
      49            0 : void pencil_classifier_2d_layouter_destroy( pencil_classifier_2d_layouter_t *this_ )
      50              : {
      51            0 :     U8_TRACE_BEGIN();
      52              : 
      53            0 :     pencil_classifier_composer_destroy( &((*this_).classifier_composer) );
      54              : 
      55            0 :     U8_TRACE_END();
      56            0 : }
      57              : 
      58              : /* ================================ INITIAL LAYOUT ================================ */
      59              : 
      60            0 : void pencil_classifier_2d_layouter_estimate_bounds( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout )
      61              : {
      62            0 :     U8_TRACE_BEGIN();
      63              : 
      64              :     /* store the classifier bounds into input_data_layouter_t */
      65            0 :     const uint32_t count_clasfy = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
      66            0 :     for ( uint32_t index = 0; index < count_clasfy; index ++ )
      67              :     {
      68              :         layout_visible_classifier_t *const classifier_layout
      69            0 :             = layout_visible_set_get_visible_classifier_ptr ( (*this_).layout_data, index );
      70              : 
      71              :         /* trace */
      72              :         {
      73              :             const data_visible_classifier_t *const visible_classifier
      74            0 :                 = layout_visible_classifier_get_data_const( classifier_layout );
      75              :             const data_classifier_t *const classifier
      76            0 :                 = data_visible_classifier_get_classifier_const( visible_classifier );
      77            0 :             U8_TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) );
      78              :         }
      79              : 
      80              :         /* set the bounds, space and label_box of the classifier layout */
      81              :         {
      82            0 :             const bool shows_contained_children = false;  /* if classifier has children, this will be updated later */
      83              :                                                           /* when calling pencil_classifier_composer_set_space_and_label */
      84              : 
      85              :             /* determine feature dimensions */
      86            0 :             const double obj_border = pencil_size_get_standard_object_border( (*this_).pencil_size );
      87            0 :             const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
      88              :             geometry_compartments_t features_dim;
      89            0 :             geometry_compartments_init( &features_dim, obj_border, gap );
      90            0 :             pencil_feature_layouter_calculate_features_dimensions( (*this_).feature_layouter,
      91              :                                                                    layout_visible_classifier_get_diagramelement_id( classifier_layout ),
      92              :                                                                    font_layout,
      93              :                                                                    &features_dim
      94              :                                                                  );
      95              : 
      96              : 
      97              :             /* init by default size */
      98              :             {
      99              :                 geometry_rectangle_t envelope;
     100            0 :                 geometry_rectangle_init( &envelope,
     101              :                                          0.0,
     102              :                                          0.0,
     103            0 :                                          geometry_dimensions_get_width( (*this_).default_classifier_size ),
     104            0 :                                          geometry_dimensions_get_height( (*this_).default_classifier_size )
     105              :                                        );
     106              : 
     107            0 :                 pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer),
     108              :                                                              &envelope,
     109              :                                                              shows_contained_children,
     110              :                                                              &features_dim,
     111              :                                                              (*this_).profile,
     112              :                                                              (*this_).pencil_size,
     113              :                                                              font_layout,
     114              :                                                              classifier_layout
     115              :                                                            );
     116              : 
     117            0 :                 geometry_rectangle_destroy( &envelope );
     118              :             }
     119            0 :             geometry_compartments_destroy( &features_dim );
     120              :         }
     121              : 
     122              :         /* move the classifier rectangles to the target location */
     123              :         {
     124              :             const data_visible_classifier_t *const visible_classifier2
     125            0 :                 = layout_visible_classifier_get_data_const( classifier_layout );
     126              :             const data_classifier_t *const classifier2
     127            0 :                 = data_visible_classifier_get_classifier_const( visible_classifier2 );
     128              :             const geometry_rectangle_t *const classifier_symbol_box
     129            0 :                 = layout_visible_classifier_get_symbol_box_const( classifier_layout );
     130              : 
     131            0 :             const double act_center_x = geometry_rectangle_get_center_x( classifier_symbol_box );
     132            0 :             const double act_center_y = geometry_rectangle_get_center_y( classifier_symbol_box );
     133            0 :             const int32_t order_x = data_classifier_get_x_order( classifier2 );
     134            0 :             const int32_t order_y = data_classifier_get_y_order( classifier2 );
     135            0 :             const geometry_non_linear_scale_t *const x_scale = geometry_grid_get_x_scale_const( (*this_).grid );
     136            0 :             const geometry_non_linear_scale_t *const y_scale = geometry_grid_get_y_scale_const( (*this_).grid );
     137            0 :             const double center_x = geometry_non_linear_scale_get_location( x_scale, order_x );
     138            0 :             const double center_y = geometry_non_linear_scale_get_location( y_scale, order_y );
     139            0 :             const geometry_offset_t offset = geometry_offset_new( center_x - act_center_x, center_y - act_center_y );
     140            0 :             layout_visible_classifier_shift( classifier_layout, &offset );
     141              :         }
     142              :     }
     143              : 
     144            0 :     U8_TRACE_END();
     145            0 : }
     146              : 
     147              : /* ================================ MOVE TO AVOID OVERLAPS ================================ */
     148              : 
     149            0 : void pencil_classifier_2d_layouter_move_to_avoid_overlaps ( pencil_classifier_2d_layouter_t *this_ )
     150              : {
     151            0 :     U8_TRACE_BEGIN();
     152              :     assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_CLASSIFIERS );
     153              : 
     154              :     universal_array_index_sorter_t sorted_classifiers;
     155            0 :     universal_array_index_sorter_init( &sorted_classifiers );
     156              : 
     157              :     /* sort the classifiers by their movement-needs */
     158            0 :     pencil_classifier_2d_layouter_private_propose_move_processing_order ( this_, &sorted_classifiers );
     159              : 
     160              :     /* move the classifiers */
     161              :     layout_visible_classifier_iter_t classifier_iterator;
     162            0 :     layout_visible_classifier_iter_init( &classifier_iterator, (*this_).layout_data, &sorted_classifiers );
     163            0 :     while ( layout_visible_classifier_iter_has_next( &classifier_iterator ) )
     164              :     {
     165              :         /* initialize the already processed classifier iterator - it is needed by called methods */
     166              :         layout_visible_classifier_iter_t already_processed;
     167            0 :         layout_visible_classifier_iter_init_from_processed( &already_processed, &classifier_iterator );
     168              : 
     169              :         /* determine pointer to classifier */
     170              :         layout_visible_classifier_t *const layouted_classifier
     171            0 :             = layout_visible_classifier_iter_next_ptr( &classifier_iterator );
     172              : 
     173              :         /* trace */
     174              :         {
     175              :             const data_visible_classifier_t *const visible_classifier
     176            0 :                 = layout_visible_classifier_get_data_const( layouted_classifier );
     177              :             const data_classifier_t *const classifier
     178            0 :                 = data_visible_classifier_get_classifier_const( visible_classifier );
     179            0 :             U8_TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) );
     180              :         }
     181              : 
     182              :         /* declaration of list of options */
     183            0 :         uint32_t solution_count = 0;
     184              :         static const uint32_t SOLUTION_MAX = 6;
     185              :         geometry_offset_t solution[6];
     186              : 
     187              :         /* propose options of moving left/right/up/down */
     188            0 :         pencil_classifier_2d_layouter_private_propose_4dir_move_solutions( this_,
     189              :                                                                            layouted_classifier,
     190              :                                                                            already_processed,  /* copy */
     191              :                                                                            SOLUTION_MAX-1,
     192              :                                                                            &solution,
     193              :                                                                            &solution_count
     194              :                                                                          );
     195            0 :         assert( solution_count < SOLUTION_MAX );
     196              :         /* propose options of moving close at origin-area */
     197            0 :         pencil_classifier_2d_layouter_private_propose_anchored_solution( this_,
     198              :                                                                          layouted_classifier,
     199              :                                                                          already_processed,  /* copy */
     200            0 :                                                                          &(solution[solution_count])
     201              :                                                                        );
     202            0 :         solution_count ++;
     203              : 
     204              :         /* select best option */
     205              :         uint32_t index_of_best;
     206            0 :         if ( 1 == solution_count )
     207              :         {
     208            0 :             index_of_best = 0;
     209              :         }
     210              :         else
     211              :         {
     212            0 :             pencil_classifier_2d_layouter_private_select_move_solution( this_,
     213              :                                                                         layouted_classifier,
     214              :                                                                         &sorted_classifiers,
     215              :                                                                         solution_count,
     216              :                                                                         &solution,
     217              :                                                                         &index_of_best
     218              :                                                                       );
     219              :         }
     220              : 
     221              :         /* move the classifier */
     222            0 :         layout_visible_classifier_shift( layouted_classifier, &(solution[index_of_best]) );
     223            0 :         U8_TRACE_INFO_INT_INT( "classifier moved:",
     224              :                                geometry_offset_get_dx( &(solution[index_of_best]) ),
     225              :                                geometry_offset_get_dy( &(solution[index_of_best]) )
     226              :                              );
     227              : 
     228            0 :         layout_visible_classifier_iter_destroy( &already_processed );
     229              :     }
     230            0 :     layout_visible_classifier_iter_destroy( &classifier_iterator );
     231            0 :     universal_array_index_sorter_destroy( &sorted_classifiers );
     232              : 
     233            0 :     U8_TRACE_END();
     234            0 : }
     235              : 
     236            0 : void pencil_classifier_2d_layouter_private_propose_move_processing_order( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
     237              : {
     238            0 :     U8_TRACE_BEGIN();
     239            0 :     assert ( NULL != out_sorted );
     240              :     assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_CLASSIFIERS );
     241              : 
     242              :     /* sort the classifiers by their movement-needs */
     243              :     uint32_t count_clasfy;
     244            0 :     count_clasfy = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
     245            0 :     for ( uint32_t index = 0; index < count_clasfy; index ++ )
     246              :     {
     247              :         const layout_visible_classifier_t *const the_classifier
     248            0 :             = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, index );
     249              :         const geometry_rectangle_t *const classifier_envelope_box
     250            0 :             = layout_visible_classifier_get_envelope_box_const( the_classifier );
     251              : 
     252            0 :         int64_t simpleness = 0;  /* the lower the number, the ealier the classifier will be processed. Unit is area(=square-length). */
     253              : 
     254              :         /* reduce simpleness by area outside the diagram border: the more outside diagram area, the earlier it should be moved */
     255              :         {
     256              :             geometry_rectangle_t border_intersect;
     257              :             int intersect_error2;
     258            0 :             intersect_error2 = geometry_rectangle_init_by_intersect( &border_intersect, classifier_envelope_box, (*this_).diagram_draw_area );
     259            0 :             if ( 0 != intersect_error2 )
     260              :             {
     261            0 :                 U8_LOG_WARNING( "a rectangle to be drawn is completely outside the diagram area" );
     262              :             }
     263              : 
     264            0 :             simpleness += 16.0 * geometry_rectangle_get_area( &border_intersect );
     265            0 :             simpleness -= 16.0 * geometry_rectangle_get_area( classifier_envelope_box );
     266              : 
     267            0 :             geometry_rectangle_destroy( &border_intersect );
     268              :         }
     269              : 
     270              :         /* reduce simpleness by intersects with other rectangles: the more intersects, the earlier it should be moved */
     271            0 :         for ( uint32_t probe_index = 0; probe_index < count_clasfy; probe_index ++ )
     272              :         {
     273              :             layout_visible_classifier_t *probe_classifier;
     274            0 :             probe_classifier = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, probe_index );
     275              :             const geometry_rectangle_t *const probe_envelope_box
     276            0 :                 = layout_visible_classifier_get_envelope_box_const( probe_classifier );
     277              : 
     278              :             geometry_rectangle_t intersect;
     279              :             const int intersect_error
     280            0 :                 = geometry_rectangle_init_by_intersect( &intersect, classifier_envelope_box, probe_envelope_box );
     281              : 
     282            0 :             if ( 0 == intersect_error )
     283              :             {
     284            0 :                 simpleness -= geometry_rectangle_get_area( &intersect );
     285              :             }
     286              : 
     287            0 :             geometry_rectangle_destroy( &intersect );
     288              :         }
     289              : 
     290              :         /* reduce simpleness by own size: the bigger the object, the earlier it should be moved */
     291              :         {
     292            0 :             const double default_classifier_area = geometry_dimensions_get_area( (*this_).default_classifier_size );
     293            0 :             const double classifier_area = geometry_rectangle_get_area( classifier_envelope_box );
     294            0 :             if (( default_classifier_area > 0.000000001 )&&( classifier_area > 0.000000001 ))
     295              :             {
     296            0 :                 simpleness -= default_classifier_area * ( classifier_area / ( classifier_area + default_classifier_area ));
     297              :             }
     298              :         }
     299              : 
     300              :         /* increase simpleness if contained children: if embracing children later, layouting problems might get solved */
     301              :         {
     302            0 :             const double default_classifier_area = geometry_dimensions_get_area( (*this_).default_classifier_size );
     303              :             const uint32_t descendant_count
     304            0 :                 = layout_visible_set_count_descendants( (*this_).layout_data, the_classifier );
     305            0 :             if ( descendant_count != 0 )
     306              :             {
     307            0 :                 simpleness += default_classifier_area;
     308              :             }
     309              :         }
     310              : 
     311            0 :         const u8_error_t insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness );
     312            0 :         if ( U8_ERROR_NONE != insert_error )
     313              :         {
     314            0 :             U8_LOG_WARNING( "not all rectangles are moved" );
     315              :         }
     316              :     }
     317              : 
     318            0 :     U8_TRACE_END();
     319            0 : }
     320              : 
     321              : /*!
     322              :  *  \brief constants for directions of moving objects
     323              :  */
     324              : enum pencil_classifier_2d_layouter_private_move_enum {
     325              :     PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT = 0,  /*!< only move to visible arey - nothing more */
     326              :     PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN = 1,  /*!< moves up the minimum distance (up means smaller y-values) */
     327              :     PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN = 2,
     328              :     PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN = 3,
     329              :     PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN = 4,
     330              :     PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX = 5,  /*!< constant defining the total number of available options */
     331              : };
     332              : 
     333            0 : void pencil_classifier_2d_layouter_private_propose_4dir_move_solutions( pencil_classifier_2d_layouter_t *this_,
     334              :                                                                         const layout_visible_classifier_t *the_classifier,
     335              :                                                                         layout_visible_classifier_iter_t already_processed,
     336              :                                                                         uint32_t solutions_max,
     337              :                                                                         geometry_offset_t (*out_solution)[],
     338              :                                                                         uint32_t *out_solution_count )
     339              : {
     340            0 :     U8_TRACE_BEGIN();
     341            0 :     assert ( NULL != the_classifier );
     342            0 :     assert ( NULL != out_solution );
     343            0 :     assert ( NULL != out_solution_count );
     344            0 :     assert ( 1 <= solutions_max );  /* general requirement to report at least one option */
     345            0 :     assert ( (unsigned int) PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX <= solutions_max );  /* current implementation requires at least 5 options */
     346              : 
     347              :     /* get classifier to move properties */
     348              :     const geometry_rectangle_t *const classifier_envelope_box
     349            0 :         = layout_visible_classifier_get_envelope_box_const( the_classifier );
     350            0 :     double top = geometry_rectangle_get_top ( classifier_envelope_box );
     351            0 :     double bottom = geometry_rectangle_get_bottom ( classifier_envelope_box );
     352            0 :     double left = geometry_rectangle_get_left ( classifier_envelope_box );
     353            0 :     double right = geometry_rectangle_get_right ( classifier_envelope_box );
     354              : 
     355              :     /* choose distance */
     356            0 :     double shift_x = 0.0;
     357            0 :     double shift_y = 0.0;
     358              : 
     359              :     /* initial check of overlaps to diagram boundary */
     360              :     {
     361            0 :         if ( bottom > geometry_rectangle_get_bottom( (*this_).diagram_draw_area ) )
     362              :         {
     363            0 :             shift_y = geometry_rectangle_get_bottom( (*this_).diagram_draw_area ) - bottom;
     364              :         }
     365            0 :         if ( top < geometry_rectangle_get_top( (*this_).diagram_draw_area ) )
     366              :         {
     367            0 :             shift_y = geometry_rectangle_get_top( (*this_).diagram_draw_area ) - top;
     368              :         }
     369            0 :         if ( right > geometry_rectangle_get_right( (*this_).diagram_draw_area ) )
     370              :         {
     371            0 :             shift_x = geometry_rectangle_get_right( (*this_).diagram_draw_area ) - right;
     372              :         }
     373            0 :         if ( left < geometry_rectangle_get_left( (*this_).diagram_draw_area ) )
     374              :         {
     375            0 :             shift_x = geometry_rectangle_get_left( (*this_).diagram_draw_area ) - left;
     376              :         }
     377              :     }
     378              : 
     379            0 :     *out_solution_count = 1;
     380            0 :     (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT] = geometry_offset_new( shift_x, shift_y );
     381              : 
     382              :     /* determine minimum and comfort distances between classifiers */
     383            0 :     const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
     384              : 
     385            0 :     (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = geometry_offset_new( shift_x, shift_y );
     386            0 :     (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = geometry_offset_new( shift_x, shift_y );
     387            0 :     (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = geometry_offset_new( shift_x, shift_y );
     388            0 :     (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = geometry_offset_new( shift_x, shift_y );
     389              : 
     390              :     /* adjust information on current rectangle */
     391            0 :     top += shift_y;
     392            0 :     bottom += shift_y;
     393            0 :     left += shift_x;
     394            0 :     right += shift_x;
     395              : 
     396              :     /* check overlap to already moved classifiers */
     397            0 :     while ( layout_visible_classifier_iter_has_next( &already_processed ) )
     398              :     {
     399              :         /* get classifier to check overlaps */
     400              :         const layout_visible_classifier_t *const the_probe
     401            0 :             = layout_visible_classifier_iter_next_ptr( &already_processed );
     402              :         const geometry_rectangle_t *const probe_envelope_box
     403            0 :             = layout_visible_classifier_get_envelope_box_const( the_probe );
     404            0 :         const double probe_top = geometry_rectangle_get_top ( probe_envelope_box );
     405            0 :         const double probe_bottom = geometry_rectangle_get_bottom ( probe_envelope_box );
     406            0 :         const double probe_left = geometry_rectangle_get_left ( probe_envelope_box );
     407            0 :         const double probe_right = geometry_rectangle_get_right ( probe_envelope_box );
     408              : 
     409            0 :         if ( probe_right < left )
     410              :         {
     411              :             /* no overlap, finished. */
     412              :         }
     413            0 :         else if ( probe_left > right )
     414              :         {
     415              :             /* no overlap, finished. */
     416              :         }
     417            0 :         else if ( probe_bottom < top )
     418              :         {
     419              :             /* no overlap, finished. */
     420              :         }
     421            0 :         else if ( probe_top > bottom )
     422              :         {
     423              :             /* no overlap, finished. */
     424              :         }
     425            0 :         else if ( layout_visible_set_is_ancestor( (*this_).layout_data, the_probe, the_classifier ) )
     426              :         {
     427              :             /* overlapping the parent is ok, finished */
     428              :         }
     429            0 :         else if ( layout_visible_set_is_ancestor( (*this_).layout_data, the_classifier, the_probe ) )
     430              :         {
     431              :             /* overlapping the child is ok, finished */
     432              :         }
     433              :         else
     434              :         {
     435              :             /* there is an overlap - at least when considering the comfort zone */
     436              : 
     437              :             double my_shift_x_left_min;
     438            0 :             my_shift_x_left_min = probe_left - right - gap;
     439            0 :             if ( my_shift_x_left_min < geometry_offset_get_dx( &((*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN]) ) )
     440              :             {
     441            0 :                 (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = geometry_offset_new( my_shift_x_left_min, shift_y );
     442              :             }
     443              : 
     444              :             double my_shift_x_right_min;
     445            0 :             my_shift_x_right_min = probe_right - left + gap;
     446            0 :             if ( my_shift_x_right_min > geometry_offset_get_dx( &((*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN]) ) )
     447              :             {
     448            0 :                 (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = geometry_offset_new( my_shift_x_right_min, shift_y );
     449              :             }
     450              : 
     451              :             double my_shift_y_up_min;
     452            0 :             my_shift_y_up_min = probe_top - bottom - gap;
     453            0 :             if ( my_shift_y_up_min < geometry_offset_get_dy( &((*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN]) ) )
     454              :             {
     455            0 :                 (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = geometry_offset_new( shift_x, my_shift_y_up_min );
     456              :             }
     457              : 
     458              :             double my_shift_y_down_min;
     459            0 :             my_shift_y_down_min = probe_bottom - top + gap;
     460            0 :             if ( my_shift_y_down_min > geometry_offset_get_dy( &((*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN]) ) )
     461              :             {
     462            0 :                 (*out_solution)[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = geometry_offset_new( shift_x, my_shift_y_down_min );
     463              :             }
     464              : 
     465            0 :             *out_solution_count = PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX;
     466              : 
     467              :             /* trace */
     468              :             const data_visible_classifier_t *visible_classifier_data;
     469            0 :             visible_classifier_data = layout_visible_classifier_get_data_const( the_probe );
     470            0 :             if (( visible_classifier_data != NULL ) && ( data_visible_classifier_is_valid( visible_classifier_data ) ))
     471              :             {
     472              :                 const data_classifier_t *classifier_p;
     473            0 :                 classifier_p = data_visible_classifier_get_classifier_const( visible_classifier_data );
     474            0 :                 U8_TRACE_INFO_STR( "- overlaps:", data_classifier_get_name_const( classifier_p ) );
     475              :             }
     476              :         }
     477              :     }
     478              : 
     479            0 :     U8_TRACE_END();
     480            0 : }
     481              : 
     482            0 : void pencil_classifier_2d_layouter_private_propose_anchored_solution( pencil_classifier_2d_layouter_t *this_,
     483              :                                                                       const layout_visible_classifier_t *the_classifier,
     484              :                                                                       layout_visible_classifier_iter_t already_processed,
     485              :                                                                       geometry_offset_t *out_solution )
     486              : {
     487            0 :     U8_TRACE_BEGIN();
     488            0 :     assert ( NULL != the_classifier );
     489            0 :     assert ( NULL != out_solution );
     490              : 
     491              :     /* determine the space needed for the solution */
     492              :     const geometry_rectangle_t *const classifier_envelope_box
     493            0 :         = layout_visible_classifier_get_envelope_box_const( the_classifier );
     494            0 :     const double width = geometry_rectangle_get_width( classifier_envelope_box );
     495            0 :     const double height = geometry_rectangle_get_height( classifier_envelope_box );
     496            0 :     const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     497              : 
     498              :     /* wish a solution area */
     499              :     geometry_rectangle_t classifier_solution_area;
     500            0 :     geometry_rectangle_init( &classifier_solution_area,
     501            0 :                              geometry_rectangle_get_left( classifier_envelope_box ) - 0.5*width - gap,
     502            0 :                              geometry_rectangle_get_top( classifier_envelope_box ) - 0.5*height - gap,
     503            0 :                              2.0*width + 2.0*gap,
     504            0 :                              2.0*height + 2.0*gap
     505              :                            );
     506              : 
     507              :     /* shrink solution area to diagram_draw_area */
     508            0 :     geometry_rectangle_init_by_intersect( &classifier_solution_area,
     509              :                                           &classifier_solution_area,
     510              :                                           (*this_).diagram_draw_area
     511              :                                         );
     512              : 
     513              :     /* check overlap to already moved classifiers */
     514            0 :     while ( layout_visible_classifier_iter_has_next( &already_processed ) )
     515              :     {
     516              :         /* get classifier to check overlaps */
     517              :         const layout_visible_classifier_t *const the_probe
     518            0 :         = layout_visible_classifier_iter_next_ptr( &already_processed );
     519              : 
     520              :         geometry_rectangle_t probe_total_bounds;
     521            0 :         geometry_rectangle_init_by_bounds( &probe_total_bounds,
     522              :                                            layout_visible_classifier_get_label_box_const( the_probe ),
     523              :                                            layout_visible_classifier_get_envelope_box_const( the_probe )
     524              :                                          );
     525              : 
     526            0 :         geometry_rectangle_init_by_difference_max( &classifier_solution_area,
     527              :                                                    &classifier_solution_area,
     528              :                                                    &probe_total_bounds
     529              :                                                  );
     530              :     }
     531              : 
     532              :     /* reduce the biggest free/unoccupied box by gap */
     533            0 :     geometry_rectangle_shift ( &classifier_solution_area, gap, gap );
     534            0 :     geometry_rectangle_enlarge ( &classifier_solution_area, -2.0*gap, -2.0*gap );
     535              : 
     536              :     /* move - but not to eager - only the minumum distance */
     537            0 :     double solution_move_dx = 0.0;
     538            0 :     double solution_move_dy = 0.0;
     539            0 :     const bool is_x_contained
     540            0 :         = ( geometry_rectangle_get_left( &classifier_solution_area ) < geometry_rectangle_get_left( classifier_envelope_box ) )
     541            0 :         && ( geometry_rectangle_get_right( classifier_envelope_box ) < geometry_rectangle_get_right( &classifier_solution_area ) );
     542            0 :     const bool is_y_contained
     543            0 :         = ( geometry_rectangle_get_top( &classifier_solution_area ) < geometry_rectangle_get_top( classifier_envelope_box ) )
     544            0 :         && ( geometry_rectangle_get_bottom( classifier_envelope_box ) < geometry_rectangle_get_bottom( &classifier_solution_area ) );
     545            0 :     if ( is_x_contained )
     546              :     {
     547            0 :         solution_move_dx = 0.0;
     548              :     }
     549              :     else
     550              :     {
     551            0 :         const double sol_center_x = geometry_rectangle_get_center_x( &classifier_solution_area );
     552            0 :         const double cur_center_x = geometry_rectangle_get_center_x( classifier_envelope_box );
     553            0 :         solution_move_dx = ( sol_center_x < cur_center_x )
     554            0 :             ? geometry_rectangle_get_right( &classifier_solution_area )
     555            0 :             - geometry_rectangle_get_right( classifier_envelope_box )
     556            0 :             : geometry_rectangle_get_left( &classifier_solution_area )
     557            0 :             - geometry_rectangle_get_left( classifier_envelope_box );
     558            0 :         geometry_rectangle_trace( &classifier_solution_area );
     559            0 :         geometry_rectangle_trace( classifier_envelope_box );
     560              :     }
     561            0 :     if ( is_y_contained )
     562              :     {
     563            0 :         solution_move_dy = 0.0;
     564              :     }
     565              :     else
     566              :     {
     567            0 :         const double sol_center_y = geometry_rectangle_get_center_y( &classifier_solution_area );
     568            0 :         const double cur_center_y = geometry_rectangle_get_center_y( classifier_envelope_box );
     569            0 :         solution_move_dy = ( sol_center_y < cur_center_y )
     570            0 :             ? geometry_rectangle_get_bottom( &classifier_solution_area )
     571            0 :             - geometry_rectangle_get_bottom( classifier_envelope_box )
     572            0 :             : geometry_rectangle_get_top( &classifier_solution_area )
     573            0 :             - geometry_rectangle_get_top( classifier_envelope_box );
     574              :     }
     575            0 :     *out_solution = geometry_offset_new( solution_move_dx, solution_move_dy );
     576              : 
     577              :     /* trace */
     578              :     const data_visible_classifier_t *visible_classifier;
     579            0 :     visible_classifier = layout_visible_classifier_get_data_const( the_classifier );
     580              :     const data_classifier_t *classifier;
     581            0 :     classifier = data_visible_classifier_get_classifier_const( visible_classifier );
     582            0 :     U8_TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) );
     583              : 
     584            0 :     U8_TRACE_END();
     585            0 : }
     586              : 
     587            0 : void pencil_classifier_2d_layouter_private_select_move_solution( pencil_classifier_2d_layouter_t *this_,
     588              :                                                                  const layout_visible_classifier_t *the_classifier,
     589              :                                                                  const universal_array_index_sorter_t *sorted,
     590              :                                                                  uint32_t solution_count,
     591              :                                                                  geometry_offset_t (*solution)[],
     592              :                                                                  uint32_t *out_index_of_best )
     593              : {
     594            0 :     U8_TRACE_BEGIN();
     595            0 :     assert ( NULL != sorted );
     596            0 :     assert ( NULL != the_classifier );
     597            0 :     assert ( NULL != solution );
     598            0 :     assert ( NULL != out_index_of_best );
     599            0 :     assert ( 1 <= solution_count );
     600              : 
     601              :     /* define potential solution and rating */
     602            0 :     uint32_t index_of_best = 0;  /* in case of doubts, take the first solution */
     603            0 :     double debts_of_best = DBL_MAX;
     604              : 
     605              :     /* check all solutions */
     606            0 :     for ( uint32_t solution_index = 0; solution_index < solution_count; solution_index ++ )
     607              :     {
     608              :         /* calculate the solution classifier */
     609              :         layout_visible_classifier_t moved_solution;
     610            0 :         layout_visible_classifier_copy( &moved_solution, the_classifier );
     611            0 :         layout_visible_classifier_shift( &moved_solution, &((*solution)[solution_index]) );
     612              : 
     613              :         /* evalute the debts of this solution */
     614            0 :         double debts_of_current = 0.0;
     615              : 
     616              :         const layout_diagram_t *const diagram_layout
     617            0 :             = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
     618              : 
     619            0 :         const layout_quality_t quality = layout_quality_new( (*this_).pencil_size );
     620            0 :         debts_of_current += layout_quality_debts_class_diag( &quality, &moved_solution, &((*solution)[solution_index]), diagram_layout );
     621              : 
     622              :         /* check overlap to other classifiers */
     623            0 :         bool self_passed = false;
     624              :         layout_visible_classifier_iter_t classifer_iterator;
     625            0 :         layout_visible_classifier_iter_init( &classifer_iterator, (*this_).layout_data, sorted );
     626            0 :         while( layout_visible_classifier_iter_has_next( &classifer_iterator ) )
     627              :         {
     628              :             /* get classifier to check overlaps */
     629              :             layout_visible_classifier_t *const the_probe
     630            0 :                 = layout_visible_classifier_iter_next_ptr( &classifer_iterator );
     631              : 
     632            0 :             if ( the_probe != the_classifier )  /* skip self */
     633              :             {
     634              :                 /* already processed classifiers have 4x higher severity because these do not move anymore */
     635            0 :                 const double severity = self_passed ? 0.25 : 1.0;
     636              : 
     637            0 :                 debts_of_current += severity * layout_quality_debts_class_class( &quality, &moved_solution, the_probe, (*this_).layout_data );
     638              :             }
     639              :             else
     640              :             {
     641            0 :                 self_passed = true;
     642              :             }
     643              :         }
     644            0 :         layout_visible_classifier_iter_destroy( &classifer_iterator );
     645              : 
     646              :         /* finish evaluating this solution */
     647            0 :         layout_visible_classifier_destroy( &moved_solution );
     648            0 :         U8_TRACE_INFO_FLT( "classifier solution debts", debts_of_current );
     649            0 :         if ( debts_of_current < debts_of_best )
     650              :         {
     651            0 :             debts_of_best = debts_of_current;
     652            0 :             index_of_best = solution_index;
     653              :         }
     654              :     }
     655              : 
     656            0 :     *out_index_of_best = index_of_best;
     657              : 
     658            0 :     U8_TRACE_END();
     659            0 : }
     660              : 
     661              : /* ================================ EMBRACE CHILDREN STEP BY STEP ================================ */
     662              : 
     663            0 : void pencil_classifier_2d_layouter_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout )
     664              : {
     665            0 :     U8_TRACE_BEGIN();
     666              :     assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS );
     667              : 
     668              :     universal_array_index_sorter_t sorted_relationships;
     669            0 :     universal_array_index_sorter_init( &sorted_relationships );
     670              : 
     671              :     /* sort the relationships by their number of descendants */
     672            0 :     pencil_classifier_2d_layouter_private_propose_embracing_order ( this_, &sorted_relationships );
     673              : 
     674              :     /* init the set of classifiers that has embraced children */
     675              :     data_small_set_t has_embraced_children;
     676            0 :     data_small_set_init( &has_embraced_children );
     677              : 
     678              :     /* move the classifiers */
     679              :     layout_relationship_iter_t relationship_iterator;
     680            0 :     layout_relationship_iter_init( &relationship_iterator, (*this_).layout_data, &sorted_relationships );
     681            0 :     while( layout_relationship_iter_has_next( &relationship_iterator ) )
     682              :     {
     683              :         layout_relationship_t *const the_relationship
     684            0 :             = layout_relationship_iter_next_ptr( &relationship_iterator );
     685            0 :         assert ( the_relationship != NULL );
     686            0 :         const data_relationship_t *const rel_data = layout_relationship_get_data_const ( the_relationship );
     687            0 :         assert ( rel_data != NULL );
     688            0 :         const data_id_t rel_from_id = data_relationship_get_from_classifier_data_id ( rel_data );
     689              : 
     690              :         const pencil_error_t failure
     691            0 :             = pencil_classifier_2d_layouter_private_try_embrace_child( this_,
     692              :                                                                        the_relationship,
     693            0 :                                                                        ! data_small_set_contains( &has_embraced_children, rel_from_id ),
     694              :                                                                        font_layout
     695            0 :                                                                      );
     696            0 :         if ( failure == PENCIL_ERROR_NONE )
     697              :         {
     698              :             /* only in case of success, children are counted as embraced */
     699            0 :             data_small_set_add_obj( &has_embraced_children, rel_from_id );
     700              :         }
     701              :     }
     702              : 
     703            0 :     data_small_set_destroy( &has_embraced_children );
     704              : 
     705            0 :     layout_relationship_iter_destroy( &relationship_iterator );
     706            0 :     universal_array_index_sorter_destroy( &sorted_relationships );
     707              : 
     708            0 :     U8_TRACE_END();
     709            0 : }
     710              : 
     711            0 : void pencil_classifier_2d_layouter_private_propose_embracing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
     712              : {
     713            0 :     U8_TRACE_BEGIN();
     714            0 :     assert( NULL != out_sorted );
     715              : 
     716            0 :     const uint32_t rel_count = layout_visible_set_get_relationship_count( (*this_).layout_data );
     717            0 :     for ( uint32_t rel_idx = 0; rel_idx < rel_count; rel_idx ++ )
     718              :     {
     719              :         const layout_relationship_t *const the_relationship
     720            0 :             = layout_visible_set_get_relationship_ptr( (*this_).layout_data, rel_idx );
     721              : 
     722              :         /* count the descendants */
     723              :         const layout_visible_classifier_t *const from_classifier
     724            0 :             = layout_relationship_get_from_classifier_ptr( the_relationship );
     725              :         const uint32_t from_descendant_count
     726            0 :             = layout_visible_set_count_descendants( (*this_).layout_data, from_classifier );
     727              : 
     728              :         /* sort it into the array by the number of decendants: */
     729              :         /* the less descendants the earlier it shall be processed. */
     730            0 :         const u8_error_t err = universal_array_index_sorter_insert( out_sorted, rel_idx, (double)from_descendant_count );
     731            0 :         if ( U8_ERROR_NONE != err )
     732              :         {
     733            0 :             U8_LOG_ERROR ( "universal_array_index_sorter_t list is full." );
     734              :         }
     735              :     }
     736              : 
     737            0 :     U8_TRACE_END();
     738            0 : }
     739              : 
     740            0 : pencil_error_t pencil_classifier_2d_layouter_private_try_embrace_child( pencil_classifier_2d_layouter_t *this_,
     741              :                                                                         layout_relationship_t *the_relationship,
     742              :                                                                         bool move,
     743              :                                                                         PangoLayout *font_layout )
     744              : {
     745            0 :     U8_TRACE_BEGIN();
     746            0 :     assert( NULL != the_relationship );
     747            0 :     pencil_error_t result_err = PENCIL_ERROR_OUT_OF_BOUNDS;
     748              : 
     749            0 :     const data_relationship_t *const relationship_data = layout_relationship_get_data_const( the_relationship );
     750            0 :     const data_relationship_type_t the_type = data_relationship_get_main_type( relationship_data );
     751            0 :     const data_row_t parent_feature_row = data_relationship_get_from_feature_row ( relationship_data );
     752            0 :     const data_row_t child_feature_row = data_relationship_get_to_feature_row ( relationship_data );
     753            0 :     const bool no_feature_ends = ( parent_feature_row == DATA_ROW_VOID )&&( child_feature_row == DATA_ROW_VOID );
     754              : 
     755            0 :     if ( ( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type ) && no_feature_ends )
     756              :     {
     757              :         layout_visible_classifier_t *const from_classifier
     758            0 :             = layout_relationship_get_from_classifier_ptr( the_relationship );
     759              :         const layout_visible_classifier_t *const to_classifier
     760            0 :             = layout_relationship_get_to_classifier_ptr( the_relationship );
     761            0 :         if ( from_classifier != to_classifier )
     762              :         {
     763              :             layout_visible_classifier_t probe_parent_layout;
     764            0 :             layout_visible_classifier_copy( &probe_parent_layout, from_classifier );
     765              :             const geometry_rectangle_t * parent_space
     766            0 :                 = layout_visible_classifier_get_space_const( &probe_parent_layout );
     767            0 :             const geometry_rectangle_t child_envelope = layout_visible_classifier_get_envelope_box( to_classifier );
     768              :             geometry_rectangle_t probe_space;
     769            0 :             if ( move )
     770              :             {
     771            0 :                 geometry_rectangle_copy( &probe_space, &child_envelope );
     772              :             }
     773              :             else
     774              :             {
     775            0 :                 geometry_rectangle_init_by_bounds( &probe_space, parent_space, &child_envelope );
     776              :             }
     777              : 
     778              :             /* re-estimate the geometry_compartments_t after now knowing the width of the child_envelope. */
     779              :             /* As a first step, simply re-use the layout_visible_classifier_t.compartments and .envelope_box_cache here */
     780              :             const geometry_rectangle_t *const old_compartments
     781            0 :                 = layout_visible_classifier_get_compartments_const( from_classifier );
     782            0 :             geometry_dimensions_t old_compartments_dim = geometry_rectangle_get_dimensions( old_compartments );
     783              :             const geometry_rectangle_t *const old_envelope
     784            0 :                 = layout_visible_classifier_get_envelope_box_const( from_classifier );
     785            0 :             geometry_dimensions_t old_envelope_dim = geometry_rectangle_get_dimensions( old_envelope );
     786              :             const geometry_compartments_t features_dim
     787            0 :                 = geometry_compartments_new( &old_compartments_dim, &old_envelope_dim );
     788              : 
     789            0 :             pencil_classifier_composer_expand_space( &((*this_).classifier_composer),
     790              :                                                      &probe_space,
     791              :                                                      true,  /* = shows_contained_children */
     792              :                                                      &features_dim,
     793              :                                                      (*this_).profile,
     794              :                                                      (*this_).pencil_size,
     795              :                                                      font_layout,
     796              :                                                      &probe_parent_layout
     797              :                                                    );
     798              : 
     799              :             const geometry_rectangle_t probe_parent_envelope
     800            0 :                 = layout_visible_classifier_get_envelope_box( &probe_parent_layout );
     801              : 
     802              :             /* check what else would be embraced */
     803            0 :             bool illegal_overlap = false;
     804              :             const uint32_t count_clasfy
     805            0 :                 = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
     806            0 :             for ( uint32_t c_index = 0; c_index < count_clasfy; c_index ++ )
     807              :             {
     808              :                 layout_visible_classifier_t *probe_classifier;
     809            0 :                 probe_classifier = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, c_index );
     810              : 
     811            0 :                 if (( probe_classifier != from_classifier )&&( probe_classifier != to_classifier ))
     812              :                 {
     813            0 :                     if ( layout_visible_set_is_ancestor( (*this_).layout_data, from_classifier, probe_classifier ) )
     814              :                     {
     815              :                         /* it is ok to embrace also other children, no illegal_overlap */
     816              :                     }
     817            0 :                     else if ( layout_visible_set_is_ancestor( (*this_).layout_data, probe_classifier, from_classifier ) )
     818              :                     {
     819              :                         /* it is ok if parent is already contained in grand-parent classifier, no illegal_overlap */
     820              :                     }
     821              :                     else
     822              :                     {
     823              :                         const geometry_rectangle_t *const current_envelope_box
     824            0 :                             = layout_visible_classifier_get_envelope_box_const ( probe_classifier );
     825            0 :                         illegal_overlap |= geometry_rectangle_is_intersecting( current_envelope_box, &probe_parent_envelope );
     826              :                     }
     827              :                 }
     828              :             }
     829              :             /* check overlap to diagram boundary */
     830            0 :             if ( ! geometry_rectangle_is_containing ( (*this_).diagram_draw_area, &probe_parent_envelope ) )
     831              :             {
     832            0 :                 illegal_overlap = true;
     833              :             }
     834              : 
     835              :             /* cancel or commit */
     836            0 :             if ( ! illegal_overlap )
     837              :             {
     838              :                 /* trace */
     839              :                 {
     840              :                     const data_visible_classifier_t *const visible_classifier
     841            0 :                         = layout_visible_classifier_get_data_const( &probe_parent_layout );
     842              :                     const data_classifier_t *const classifier
     843            0 :                         = data_visible_classifier_get_classifier_const( visible_classifier );
     844            0 :                     U8_TRACE_INFO_STR( "parent classifier:", data_classifier_get_name_const( classifier ) );
     845              :                 }
     846              : 
     847            0 :                 layout_visible_classifier_replacemove( from_classifier, &probe_parent_layout );
     848            0 :                 result_err = PENCIL_ERROR_NONE;
     849              :             }
     850              :             else
     851              :             {
     852            0 :                 layout_visible_classifier_destroy( &probe_parent_layout );
     853              :             }
     854              : 
     855              :             /* cleanup */
     856            0 :             geometry_rectangle_destroy( &probe_space );
     857              :         }
     858              :         else
     859              :         {
     860            0 :             U8_TRACE_INFO( "Classifier contains itself" );
     861              :         }
     862              :     }
     863              :     /* else this is not a parent child relationship */
     864              : 
     865            0 :     U8_TRACE_END_ERR( result_err );
     866            0 :     return result_err;
     867              : }
     868              : 
     869              : /* ================================ EMBRACE CHILDREN COMMON ================================ */
     870              : 
     871            0 : void pencil_classifier_2d_layouter_hide_relations_of_embraced_children( pencil_classifier_2d_layouter_t *this_ )
     872              : {
     873            0 :     U8_TRACE_BEGIN();
     874              : 
     875              :     /* search containment relations */
     876            0 :     const uint32_t rel_count = layout_visible_set_get_relationship_count( (*this_).layout_data );
     877            0 :     for ( uint32_t rel_idx = 0; rel_idx < rel_count; rel_idx ++ )
     878              :     {
     879              :         const layout_relationship_t *const the_relationship
     880            0 :             = layout_visible_set_get_relationship_const( (*this_).layout_data, rel_idx );
     881              :         const data_relationship_t *const the_rel_data
     882            0 :             = layout_relationship_get_data_const( the_relationship );
     883              : 
     884            0 :         const data_relationship_type_t the_type = data_relationship_get_main_type ( the_rel_data );
     885            0 :         const data_row_t parent_feature_row = data_relationship_get_from_feature_row ( the_rel_data );
     886            0 :         const data_row_t child_feature_row = data_relationship_get_to_feature_row ( the_rel_data );
     887            0 :         const bool no_feature_ends = ( parent_feature_row == DATA_ROW_VOID )&&( child_feature_row == DATA_ROW_VOID );
     888            0 :         const pencil_visibility_t visibility = layout_relationship_get_visibility( the_relationship );
     889              : 
     890            0 :         if (( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type ) && no_feature_ends
     891            0 :             && (( PENCIL_VISIBILITY_SHOW == visibility )||(PENCIL_VISIBILITY_GRAY_OUT == visibility) ))
     892              :         {
     893              :             const layout_visible_classifier_t *const from_classifier
     894            0 :                 = layout_relationship_get_from_classifier_ptr( the_relationship );
     895              :             const layout_visible_classifier_t *const to_classifier
     896            0 :                 = layout_relationship_get_to_classifier_ptr( the_relationship );
     897            0 :             if ( from_classifier != to_classifier )
     898              :             {
     899              :                 const geometry_rectangle_t *const parent_space
     900            0 :                     = layout_visible_classifier_get_space_const ( from_classifier );
     901              :                 const geometry_rectangle_t *const child_symbol_box
     902            0 :                     = layout_visible_classifier_get_symbol_box_const ( to_classifier );
     903              : 
     904              :                 /* hide if parent embraced child(symbol) completely */
     905            0 :                 if ( geometry_rectangle_is_containing( parent_space, child_symbol_box ) )
     906              :                 {
     907            0 :                     layout_visible_set_set_relationship_visibility( (*this_).layout_data, rel_idx, PENCIL_VISIBILITY_IMPLICIT );
     908            0 :                     U8_TRACE_INFO( "Containment relation is PENCIL_VISIBILITY_IMPLICIT" );
     909              :                 }
     910              :             }
     911              :         }
     912              :     }
     913              : 
     914            0 :     U8_TRACE_END();
     915            0 : }
     916              : 
     917              : /* ================================ EMBRACE AND MOVE CHILDREN TOGETHER ================================ */
     918              : 
     919            0 : void pencil_classifier_2d_layouter_move_and_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout )
     920              : {
     921            0 :     U8_TRACE_BEGIN();
     922              :     assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_CLASSIFIERS );
     923              : 
     924            0 :     const double TAKE_RATIO = (1.0/3.0);
     925            0 :     const double LEAVE_RATIO = (1.0-TAKE_RATIO);
     926              :     /* const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); */
     927              : 
     928              :     universal_array_index_sorter_t sorted_classifiers;
     929            0 :     universal_array_index_sorter_init( &sorted_classifiers );
     930              : 
     931              :     /* sort the classifiers by their need to move and to embrace */
     932            0 :     pencil_classifier_2d_layouter_private_propose_move_embrace_order ( this_, &sorted_classifiers );
     933              : 
     934              :     /* small-move and embrace the child classifiers */
     935              :     layout_visible_classifier_iter_t classifer_iterator;
     936            0 :     layout_visible_classifier_iter_init( &classifer_iterator, (*this_).layout_data, &sorted_classifiers );
     937            0 :     while( layout_visible_classifier_iter_has_next( &classifer_iterator ) )
     938              :     {
     939              :         layout_visible_classifier_t *const the_classifier
     940            0 :             = layout_visible_classifier_iter_next_ptr( &classifer_iterator );
     941              : 
     942              :         /* only if the classifier has children */
     943            0 :         const uint32_t child_count = layout_visible_set_count_descendants( (*this_).layout_data, the_classifier );
     944            0 :         if ( child_count > 0 )
     945              :         {
     946              :             /* trace */
     947              :             {
     948              :                 const data_visible_classifier_t *const visible_classifier
     949            0 :                     = layout_visible_classifier_get_data_const( the_classifier );
     950              :                 const data_classifier_t *const classifier
     951            0 :                     = data_visible_classifier_get_classifier_const( visible_classifier );
     952            0 :                 U8_TRACE_INFO_STR( "parent classifier:", data_classifier_get_name_const( classifier ) );
     953              :             }
     954              : 
     955              :             /* get envelope rectangle of all children */
     956              :             const geometry_rectangle_t children_envelope
     957            0 :                 = pencil_classifier_2d_layouter_private_calc_descendant_envelope( this_, the_classifier );
     958              : 
     959              :             /* determine outer space around children envelope rectangle */
     960              :             const geometry_rectangle_t outer_space
     961            0 :                 = pencil_classifier_2d_layouter_private_calc_outer_space( this_, &children_envelope, the_classifier );
     962              : 
     963              :             /* re-estimate the geometry_compartments_t after now knowing the width of the children_envelope. */
     964              :             /* As a first step, simply re-use the layout_visible_classifier_t.compartments and .envelope_box_cache here: */
     965              :             const geometry_rectangle_t *const old_compartments
     966            0 :                 = layout_visible_classifier_get_compartments_const( the_classifier );
     967            0 :             geometry_dimensions_t old_compartments_dim = geometry_rectangle_get_dimensions( old_compartments );
     968              :             const geometry_rectangle_t *const old_envelope
     969            0 :                 = layout_visible_classifier_get_envelope_box_const( the_classifier );
     970            0 :             geometry_dimensions_t old_envelope_dim = geometry_rectangle_get_dimensions( old_envelope );
     971              :             const geometry_compartments_t features_dim
     972            0 :                 = geometry_compartments_new( &old_compartments_dim, &old_envelope_dim );
     973              : 
     974              :             /* place the children into the (probe-)parent */
     975              :             layout_visible_classifier_t probe_parent_layout;
     976            0 :             layout_visible_classifier_copy( &probe_parent_layout, the_classifier );
     977            0 :             pencil_classifier_composer_expand_space( &((*this_).classifier_composer),
     978              :                                                      &children_envelope,
     979              :                                                      true,  /* = shows_contained_children */
     980              :                                                      &features_dim,
     981              :                                                      (*this_).profile,
     982              :                                                      (*this_).pencil_size,
     983              :                                                      font_layout,
     984              :                                                      &probe_parent_layout
     985              :                                                    );
     986              :             const geometry_rectangle_t probe_parent_envelope
     987            0 :                 = layout_visible_classifier_get_envelope_box( &probe_parent_layout );
     988              : 
     989              :             /* check if parent fits into into outer_space */
     990            0 :             const double outer_border_x
     991            0 :                 = (geometry_rectangle_get_width( &outer_space ) - geometry_rectangle_get_width(&probe_parent_envelope))/2.0;
     992            0 :             const double outer_border_y
     993            0 :                 = (geometry_rectangle_get_height( &outer_space ) - geometry_rectangle_get_height(&probe_parent_envelope))/2.0;
     994            0 :             if (( outer_border_x > 0.0 )&&( outer_border_y > 0.0 ))
     995              :             {
     996              :                 /* prepare to move+expand the parent */
     997              :                 geometry_rectangle_t new_envelope;
     998            0 :                 geometry_rectangle_copy( &new_envelope, &outer_space );
     999            0 :                 geometry_rectangle_shift( &new_envelope, (LEAVE_RATIO*outer_border_x), (LEAVE_RATIO*outer_border_y) );
    1000            0 :                 geometry_rectangle_enlarge( &new_envelope, -2.0*(LEAVE_RATIO*outer_border_x), -2.0*(LEAVE_RATIO*outer_border_y) );
    1001              : 
    1002              :                 /* move+expand the parent */
    1003            0 :                 pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer),
    1004              :                                                              &new_envelope,
    1005              :                                                              true,  /* = shows_contained_children */
    1006              :                                                              &features_dim,
    1007              :                                                              (*this_).profile,
    1008              :                                                              (*this_).pencil_size,
    1009              :                                                              font_layout,
    1010              :                                                              the_classifier
    1011              :                                                            );
    1012              : 
    1013              :                 /* cleanup move+expand the parent */
    1014            0 :                 geometry_rectangle_destroy( &new_envelope );
    1015              : 
    1016              :                 /* determine the descendants move deltas */
    1017            0 :                 const geometry_rectangle_t *const parent_new_space = layout_visible_classifier_get_space_const( the_classifier );
    1018            0 :                 const double descendant_add_dx = geometry_rectangle_get_center_x( parent_new_space ) - geometry_rectangle_get_center_x( &children_envelope );
    1019            0 :                 const double descendant_add_dy = geometry_rectangle_get_center_y( parent_new_space ) - geometry_rectangle_get_center_y( &children_envelope );
    1020            0 :                 const geometry_offset_t offset = geometry_offset_new( descendant_add_dx, descendant_add_dy );
    1021              : 
    1022              :                 /* move the descendants */
    1023            0 :                 pencil_classifier_2d_layouter_private_move_descendants( this_, the_classifier, &offset );
    1024              :             }
    1025              : 
    1026              :             /* cleanup */
    1027            0 :             layout_visible_classifier_destroy( &probe_parent_layout );
    1028              :         }
    1029              :     }
    1030              : 
    1031            0 :     layout_visible_classifier_iter_destroy( &classifer_iterator );
    1032            0 :     universal_array_index_sorter_destroy( &sorted_classifiers );
    1033              : 
    1034            0 :     U8_TRACE_END();
    1035            0 : }
    1036              : 
    1037            0 : void pencil_classifier_2d_layouter_private_propose_move_embrace_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
    1038              : {
    1039            0 :     U8_TRACE_BEGIN();
    1040            0 :     assert ( NULL != out_sorted );
    1041              :     assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_CLASSIFIERS );
    1042              : 
    1043              :     /* sort the classifiers by their movement-needs */
    1044            0 :     const uint32_t count_classifiers = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
    1045            0 :     for ( uint32_t index = 0; index < count_classifiers; index ++ )
    1046              :     {
    1047            0 :         const layout_visible_classifier_t *const the_classifier = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, index );
    1048              : 
    1049            0 :         int64_t lazy_move = 0;
    1050              : 
    1051              :         /* grand-parents must be moved after parents (becasue parents are not yet well layouted) */
    1052            0 :         const uint32_t child_count = layout_visible_set_count_descendants ( (*this_).layout_data, the_classifier );
    1053            0 :         lazy_move = child_count;
    1054              : 
    1055            0 :         const u8_error_t insert_error = universal_array_index_sorter_insert( out_sorted, index, lazy_move );
    1056            0 :         if ( U8_ERROR_NONE != insert_error )
    1057              :         {
    1058            0 :             U8_LOG_WARNING( "not all rectangles are grown" );
    1059              :         }
    1060              :     }
    1061              : 
    1062            0 :     U8_TRACE_END();
    1063            0 : }
    1064              : 
    1065              : 
    1066              : /*
    1067              : Copyright 2017-2026 Andreas Warnke
    1068              : 
    1069              : Licensed under the Apache License, Version 2.0 (the "License");
    1070              : you may not use this file except in compliance with the License.
    1071              : You may obtain a copy of the License at
    1072              : 
    1073              :     http://www.apache.org/licenses/LICENSE-2.0
    1074              : 
    1075              : Unless required by applicable law or agreed to in writing, software
    1076              : distributed under the License is distributed on an "AS IS" BASIS,
    1077              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1078              : See the License for the specific language governing permissions and
    1079              : limitations under the License.
    1080              : */
        

Generated by: LCOV version 2.0-1