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

Generated by: LCOV version 1.16