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

Generated by: LCOV version 1.16