LCOV - code coverage report
Current view: top level - pencil/source - pencil_relationship_2d_layouter.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 0 903 0.0 %
Date: 2024-10-26 21:44:38 Functions: 0 15 0.0 %

          Line data    Source code
       1             : /* File: pencil_relationship_2d_layouter.c; Copyright and License: see below */
       2             : 
       3             : #include "pencil_relationship_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             : #include <stdint.h>
      10             : 
      11           0 : void pencil_relationship_2d_layouter_init( pencil_relationship_2d_layouter_t *this_,
      12             :                                            layout_visible_set_t *layout_data,
      13             :                                            const data_profile_part_t *profile,
      14             :                                            const pencil_size_t *pencil_size )
      15             : {
      16           0 :     U8_TRACE_BEGIN();
      17           0 :     assert( NULL != layout_data );
      18           0 :     assert( NULL != profile );
      19           0 :     assert( NULL != pencil_size );
      20             : 
      21           0 :     (*this_).layout_data = layout_data;
      22           0 :     (*this_).profile = profile;
      23           0 :     universal_array_index_sorter_init( &((*this_).sorted_relationships) );
      24           0 :     (*this_).sorted_rel_index = 0;
      25             : 
      26           0 :     (*this_).pencil_size = pencil_size;
      27           0 :     pencil_relationship_painter_init( &((*this_).relationship_painter) );
      28             : 
      29           0 :     U8_TRACE_END();
      30           0 : }
      31             : 
      32           0 : void pencil_relationship_2d_layouter_destroy( pencil_relationship_2d_layouter_t *this_ )
      33             : {
      34           0 :     U8_TRACE_BEGIN();
      35             : 
      36           0 :     universal_array_index_sorter_destroy( &((*this_).sorted_relationships) );
      37             : 
      38           0 :     pencil_relationship_painter_destroy( &((*this_).relationship_painter) );
      39             : 
      40           0 :     U8_TRACE_END();
      41           0 : }
      42             : 
      43           0 : void pencil_relationship_2d_layouter_private_do_layout ( pencil_relationship_2d_layouter_t *this_ )
      44             : {
      45           0 :     U8_TRACE_BEGIN();
      46             :     assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS );
      47             : 
      48           0 :     universal_array_index_sorter_reinit( &((*this_).sorted_relationships) );
      49             : 
      50             :     /* sort the relationships by their movement-needs, drop invisible relations */
      51           0 :     pencil_relationship_2d_layouter_private_propose_processing_order ( this_ );
      52             : 
      53             :     /* shape the relationships */
      54             :     const uint32_t count_sorted
      55           0 :         = universal_array_index_sorter_get_count( &((*this_).sorted_relationships) );
      56           0 :     for ( (*this_).sorted_rel_index = 0; (*this_).sorted_rel_index < count_sorted; (*this_).sorted_rel_index ++ )
      57             :     {
      58             :         /* determine pointer to the_relationship */
      59             :         const uint32_t index
      60           0 :             = universal_array_index_sorter_get_array_index ( &((*this_).sorted_relationships),
      61             :                                                              (*this_).sorted_rel_index
      62             :                                                            );
      63             :         layout_relationship_t *const current_relationship
      64           0 :             = layout_visible_set_get_relationship_ptr( (*this_).layout_data, index );
      65             : 
      66             :         /* declaration of list of options */
      67           0 :         uint32_t solutions_count = 0;
      68             :         static const uint32_t SOLUTIONS_MAX = 18;
      69             :         geometry_connector_t solution[18];
      70             : 
      71             :         /* propose options */
      72           0 :         pencil_relationship_2d_layouter_private_propose_solutions ( this_,
      73             :                                                                     SOLUTIONS_MAX,
      74             :                                                                     solution,
      75             :                                                                     &solutions_count
      76             :                                                                   );
      77             : 
      78             :         /* select best option */
      79             :         uint32_t index_of_best;
      80           0 :         if ( 1 == solutions_count )
      81             :         {
      82           0 :             index_of_best = 0;
      83             :         }
      84             :         else
      85             :         {
      86           0 :             pencil_relationship_2d_layouter_private_select_solution ( this_,
      87             :                                                                       solutions_count,
      88             :                                                                       solution,
      89             :                                                                       &index_of_best
      90             :                                                                     );
      91             :         }
      92             : 
      93             :         /* store best option to (*this_).layout_data */
      94           0 :         layout_relationship_set_shape( current_relationship, &(solution[index_of_best]) );
      95             :     }
      96             : 
      97           0 :     universal_array_index_sorter_reinit( &((*this_).sorted_relationships) );
      98             : 
      99           0 :     U8_TRACE_END();
     100           0 : }
     101             : 
     102           0 : void pencil_relationship_2d_layouter_private_propose_processing_order ( pencil_relationship_2d_layouter_t *this_ )
     103             : {
     104           0 :     U8_TRACE_BEGIN();
     105             :     assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_RELATIONSHIPS );
     106             : 
     107             :     /* get draw area */
     108             :     const layout_diagram_t *const diagram_layout
     109           0 :         = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
     110             :     const geometry_rectangle_t *const diagram_draw_area
     111           0 :         = layout_diagram_get_draw_area_const( diagram_layout );
     112             : 
     113             :     /* sort the relationships by their shaping-needs: the less simple, the earlier it shall be processed */
     114             :     const uint32_t count_relations
     115           0 :         = layout_visible_set_get_relationship_count ( (*this_).layout_data );
     116           0 :     for ( uint32_t index = 0; index < count_relations; index ++ )
     117             :     {
     118             :         layout_relationship_t *const current_relation
     119           0 :             = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
     120             : 
     121           0 :         int64_t simpleness = 0;
     122             : 
     123             :         /* determine simpleness by relationship type */
     124             :         {
     125             :             data_relationship_type_t reltype;
     126           0 :             reltype = data_relationship_get_main_type( layout_relationship_get_data_const ( current_relation ));
     127           0 :             if (( DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY == reltype )
     128           0 :                 ||( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == reltype ))
     129             :             {
     130             :                 /* containment may be solved by embracing, mere dependencies are unimportant */
     131           0 :                 simpleness += geometry_rectangle_get_width ( diagram_draw_area );
     132             :             }
     133             :         }
     134             : 
     135             :         /* whatever is not visible is simple */
     136             :         {
     137           0 :             if (( PENCIL_VISIBILITY_SHOW != layout_relationship_get_visibility ( current_relation ) )
     138           0 :                 && ( PENCIL_VISIBILITY_GRAY_OUT != layout_relationship_get_visibility ( current_relation ) ))
     139             :             {
     140           0 :                 simpleness += 2 * geometry_rectangle_get_width ( diagram_draw_area );
     141             :             }
     142             :         }
     143             : 
     144             :         /* determine simpleness by distance between source and destination */
     145             :         {
     146             :             const geometry_rectangle_t *const source_rect
     147           0 :                 = layout_relationship_get_from_symbol_box_const ( current_relation );
     148             :             const geometry_rectangle_t *const dest_rect
     149           0 :                 = layout_relationship_get_to_symbol_box_const ( current_relation );
     150             : 
     151           0 :             simpleness -= fabs ( geometry_rectangle_get_center_x(source_rect) - geometry_rectangle_get_center_x(dest_rect) );
     152           0 :             simpleness -= fabs ( geometry_rectangle_get_center_y(source_rect) - geometry_rectangle_get_center_y(dest_rect) );
     153             :         }
     154             : 
     155             :         /* insert relation to sorted array, the simpler the more to the back */
     156             :         {
     157             :             int insert_error;
     158           0 :             insert_error = universal_array_index_sorter_insert( &((*this_).sorted_relationships), index, simpleness );
     159           0 :             if ( 0 != insert_error )
     160             :             {
     161           0 :                 U8_LOG_WARNING( "not all relationships are shaped" );
     162             :             }
     163             :         }
     164             :     }
     165             : 
     166           0 :     U8_TRACE_END();
     167           0 : }
     168             : 
     169           0 : void pencil_relationship_2d_layouter_private_propose_solutions ( pencil_relationship_2d_layouter_t *this_,
     170             :                                                                  uint32_t solutions_max,
     171             :                                                                  geometry_connector_t out_solutions[],
     172             :                                                                  uint32_t *out_solutions_count )
     173             : {
     174           0 :     U8_TRACE_BEGIN();
     175           0 :     assert ( (*this_).sorted_rel_index < universal_array_index_sorter_get_count( &((*this_).sorted_relationships) ) );
     176           0 :     assert ( NULL != out_solutions );
     177           0 :     assert ( NULL != out_solutions_count );
     178           0 :     assert ( 1 <= solutions_max );  /* general requirement to report at least one option */
     179           0 :     assert ( 18 <= solutions_max );  /* current implementation requires at least 14 options */
     180             : 
     181             :     /* get current relation */
     182             :     const uint32_t index
     183           0 :         = universal_array_index_sorter_get_array_index( &((*this_).sorted_relationships), (*this_).sorted_rel_index );
     184             :     layout_relationship_t *const current_relation
     185           0 :         = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
     186             : 
     187             :     /* propose connections between source and destination */
     188             :     {
     189             :         const geometry_rectangle_t *const source_rect
     190           0 :             = layout_relationship_get_from_symbol_box_const ( current_relation );
     191             :         const geometry_rectangle_t *const dest_rect
     192           0 :             = layout_relationship_get_to_symbol_box_const ( current_relation );
     193             : 
     194             :         uint32_t solutions_by_I;
     195           0 :         pencil_relationship_2d_layouter_private_connect_rectangles_by_I ( this_,
     196             :                                                                           source_rect,
     197             :                                                                           dest_rect,
     198             :                                                                           solutions_max,
     199             :                                                                           &(out_solutions[0]),
     200             :                                                                           &solutions_by_I
     201             :                                                                         );
     202             : 
     203             :         uint32_t solutions_by_ZN;
     204           0 :         pencil_relationship_2d_layouter_private_connect_rectangles_by_ZN ( this_,
     205             :                                                                            source_rect,
     206             :                                                                            dest_rect,
     207             :                                                                            solutions_max - solutions_by_I,
     208           0 :                                                                            &(out_solutions[solutions_by_I]),
     209             :                                                                            &solutions_by_ZN
     210             :                                                                          );
     211             : 
     212             :         uint32_t solutions_by_L7;
     213           0 :         const uint32_t solutions_by_I_ZN = solutions_by_I + solutions_by_ZN;
     214           0 :         pencil_relationship_2d_layouter_private_connect_rectangles_by_L7 ( this_,
     215             :                                                                            source_rect,
     216             :                                                                            dest_rect,
     217             :                                                                            solutions_max - solutions_by_I_ZN,
     218           0 :                                                                            &(out_solutions[solutions_by_I_ZN]),
     219             :                                                                            &solutions_by_L7
     220             :                                                                          );
     221             : 
     222             :         uint32_t solutions_by_UC;
     223           0 :         const uint32_t solutions_by_I_ZN_L7 = solutions_by_I_ZN + solutions_by_L7;
     224           0 :         pencil_relationship_2d_layouter_private_connect_rectangles_by_UC ( this_,
     225             :                                                                            source_rect,
     226             :                                                                            dest_rect,
     227             :                                                                            solutions_max - solutions_by_I_ZN_L7,
     228           0 :                                                                            &(out_solutions[solutions_by_I_ZN_L7]),
     229             :                                                                            &solutions_by_UC
     230             :                                                                          );
     231             : 
     232           0 :         *out_solutions_count = solutions_by_I_ZN_L7 + solutions_by_UC;
     233           0 :         assert ( 1 <= *out_solutions_count );
     234           0 :         assert ( *out_solutions_count <= solutions_max );
     235             :     }
     236             : 
     237           0 :     U8_TRACE_END();
     238           0 : }
     239             : 
     240             : static const geometry_3dir_t PENCIL_BAD_V_PATTERN1
     241             :    = { .first = GEOMETRY_DIRECTION_LEFT,  .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_LEFT };
     242             : static const geometry_3dir_t PENCIL_BAD_V_PATTERN2
     243             :    = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_RIGHT };
     244             : static const geometry_3dir_t PENCIL_BAD_H_PATTERN1
     245             :    = { .first = GEOMETRY_DIRECTION_DOWN,  .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
     246             : static const geometry_3dir_t PENCIL_BAD_H_PATTERN2
     247             :    = { .first = GEOMETRY_DIRECTION_UP,    .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_UP };
     248             : 
     249           0 : void pencil_relationship_2d_layouter_private_select_solution ( pencil_relationship_2d_layouter_t *this_,
     250             :                                                                uint32_t solutions_count,
     251             :                                                                const geometry_connector_t solutions[],
     252             :                                                                uint32_t *out_index_of_best )
     253             : {
     254           0 :     U8_TRACE_BEGIN();
     255           0 :     assert ( (*this_).sorted_rel_index < universal_array_index_sorter_get_count( &((*this_).sorted_relationships) ) );
     256           0 :     assert ( NULL != solutions );
     257           0 :     assert ( NULL != out_index_of_best );
     258           0 :     assert ( 1 <= solutions_count );
     259             : 
     260             :     /* get current relation data */
     261             :     const uint32_t index
     262           0 :         = universal_array_index_sorter_get_array_index ( &((*this_).sorted_relationships), (*this_).sorted_rel_index );
     263             :     const layout_relationship_t *const current_relation
     264           0 :         = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
     265             : #if 0
     266             :     const data_relationship_t *const current_relation_data
     267             :         = layout_relationship_get_data_const ( current_relation );
     268             : #endif
     269             :     const geometry_rectangle_t *const source_rect
     270           0 :         = layout_relationship_get_from_symbol_box_const ( current_relation );
     271             :     const geometry_rectangle_t *const dest_rect
     272           0 :         = layout_relationship_get_to_symbol_box_const ( current_relation );
     273           0 :     const double src_center_x = geometry_rectangle_get_center_x ( source_rect );
     274           0 :     const double src_center_y = geometry_rectangle_get_center_y ( source_rect );
     275           0 :     const double dst_center_x = geometry_rectangle_get_center_x ( dest_rect );
     276           0 :     const double dst_center_y = geometry_rectangle_get_center_y ( dest_rect );
     277             : 
     278             :     /* get draw area */
     279             :     const layout_diagram_t *const diagram_layout
     280           0 :         = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
     281             :     const geometry_rectangle_t *const diagram_draw_area
     282           0 :         = layout_diagram_get_draw_area_const( diagram_layout );
     283           0 :     const double diagram_draw_center_x = geometry_rectangle_get_center_x( diagram_draw_area );
     284           0 :     const double diagram_draw_center_y = geometry_rectangle_get_center_y( diagram_draw_area );
     285             : 
     286             :     /* get preferred object distance */
     287           0 :     const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     288             : 
     289             :     /* define potential solution and rating */
     290           0 :     uint32_t index_of_best = 0;
     291           0 :     double debts_of_best = DBL_MAX;
     292             : 
     293             :     /* evaluate the solutions by their overlaps with classifiers */
     294           0 :     for ( uint32_t solution_idx = 0; solution_idx < solutions_count; solution_idx ++ )
     295             :     {
     296             :         /* evalute the debts of this solution */
     297           0 :         double debts_of_current = 0.0;
     298           0 :         const geometry_connector_t *const current_solution = &(solutions[solution_idx]);
     299             :         const geometry_rectangle_t connector_bounds
     300           0 :             = geometry_connector_get_bounding_rectangle( current_solution );
     301             : 
     302             :         /* avoid alternating solutions in case their debts are identical */
     303           0 :         debts_of_current += 0.1 * solution_idx;
     304             : 
     305             :         /* the more length, the more unwanted... */
     306           0 :         debts_of_current += geometry_connector_get_length( current_solution );
     307             : 
     308             :         /* prefer _either_ no _or_ minimum-dist lengths of parts... */
     309           0 :         const double HEAVIER_THAN_DETOUR = 4.0;
     310           0 :         const double source_length = geometry_connector_get_source_length( current_solution );
     311           0 :         if (( source_length > 0.000001 )&&( source_length < object_dist ))
     312             :         {
     313           0 :             debts_of_current += HEAVIER_THAN_DETOUR * ( object_dist - source_length );
     314             : 
     315             :         }
     316           0 :         const double destination_length = geometry_connector_get_destination_length( current_solution );
     317           0 :         if (( destination_length > 0.000001 )&&( destination_length < object_dist ))
     318             :         {
     319           0 :             debts_of_current += HEAVIER_THAN_DETOUR * ( object_dist - destination_length );
     320             :         }
     321           0 :         const bool no_source_or_no_dest = ( source_length < 0.000001 )||( destination_length < 0.000001 );
     322           0 :         const double main_length = geometry_connector_get_main_length( current_solution );
     323           0 :         if (( main_length > 0.000001 )&&( main_length < object_dist )&&( no_source_or_no_dest ))
     324             :         {
     325           0 :             debts_of_current += HEAVIER_THAN_DETOUR * ( object_dist - main_length );
     326             :         }
     327             : 
     328             :         /* prefer centered over uncentered departure and arrival */
     329           0 :         const double HEAVIER_THAN_CENTERED = 2.0;
     330             :         const double delta_source
     331           0 :             = fmin( fabs( geometry_connector_get_source_end_x( current_solution ) - src_center_x ),
     332           0 :             fabs( geometry_connector_get_source_end_y( current_solution ) - src_center_y ) );
     333           0 :         debts_of_current += delta_source * HEAVIER_THAN_CENTERED;
     334             :         const double delta_destination
     335           0 :             = fmin( fabs( geometry_connector_get_destination_end_x( current_solution ) - dst_center_x ),
     336           0 :             fabs( geometry_connector_get_destination_end_y( current_solution ) - dst_center_y ) );
     337           0 :         debts_of_current += delta_destination * HEAVIER_THAN_CENTERED;
     338             : 
     339             :         /* prefer left-hand angles over right-handed */
     340           0 :         bool bad_pattern_h = false;
     341           0 :         bool bad_pattern_v = false;
     342           0 :         const geometry_3dir_t pattern = geometry_connector_get_directions( current_solution );
     343             :         {
     344             : 
     345           0 :             bad_pattern_v = geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN1 )
     346           0 :                 || geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN2 );
     347           0 :             bad_pattern_h = geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN1 )
     348           0 :                 || geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN2 );
     349           0 :             if ( bad_pattern_h || bad_pattern_v )
     350             :             {
     351           0 :                 const double current_len = geometry_connector_get_length( current_solution );
     352           0 :                 if ( current_len > ( 4.0 * object_dist ) )
     353             :                 {
     354             :                     /* current_solution is a long path and right-handed */
     355           0 :                     debts_of_current += 0.2 * geometry_connector_get_length( current_solution );
     356             :                 }
     357             :             }
     358             :         }
     359             : 
     360             :         /* to avoid bad patterns: no L on top-left, no 7 on bottom-right, no r on top-right, no J on bottom-left */
     361             :         {
     362           0 :             const bool connector_is_left
     363           0 :                 = geometry_rectangle_get_center_x( &connector_bounds ) < diagram_draw_center_x;
     364           0 :             const bool connector_is_top
     365           0 :                 = geometry_rectangle_get_center_y( &connector_bounds ) < diagram_draw_center_y;
     366           0 :             if ( connector_is_left )
     367             :             {
     368           0 :                 if ( connector_is_top )
     369             :                 {
     370             :                     static const geometry_3dir_t PENCIL_BAD_L_PATTERN1
     371             :                          = { .first = GEOMETRY_DIRECTION_LEFT,  .second = GEOMETRY_DIRECTION_UP,     .third = GEOMETRY_DIRECTION_CENTER };
     372             :                     static const geometry_3dir_t PENCIL_BAD_L_PATTERN2
     373             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_UP };
     374             :                     static const geometry_3dir_t PENCIL_BAD_L_PATTERN3
     375             :                          = { .first = GEOMETRY_DIRECTION_DOWN,   .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
     376             :                     static const geometry_3dir_t PENCIL_BAD_L_PATTERN4
     377             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_RIGHT };
     378             : 
     379           0 :                     if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN1 ) )
     380           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN2 ) )
     381           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN3 ) )
     382           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN4 ) ))
     383             :                     {
     384           0 :                         debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
     385             :                     }
     386             :                 }
     387             :                 else
     388             :                 {
     389             :                     static const geometry_3dir_t PENCIL_BAD_J_PATTERN1
     390             :                          = { .first = GEOMETRY_DIRECTION_DOWN,   .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_CENTER };
     391             :                     static const geometry_3dir_t PENCIL_BAD_J_PATTERN2
     392             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_LEFT };
     393             :                     static const geometry_3dir_t PENCIL_BAD_J_PATTERN3
     394             :                          = { .first = GEOMETRY_DIRECTION_RIGHT,  .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_CENTER };
     395             :                     static const geometry_3dir_t PENCIL_BAD_J_PATTERN4
     396             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_UP };
     397             : 
     398           0 :                     if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN1 ) )
     399           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN2 ) )
     400           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN3 ) )
     401           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN4 ) ))
     402             :                     {
     403           0 :                         debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
     404             :                     }
     405             :                 }
     406             :             }
     407             :             else
     408             :             {
     409           0 :                 if ( connector_is_top )
     410             :                 {
     411             :                     static const geometry_3dir_t PENCIL_BAD_r_PATTERN1
     412             :                          = { .first = GEOMETRY_DIRECTION_UP,     .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
     413             :                     static const geometry_3dir_t PENCIL_BAD_r_PATTERN2
     414             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_RIGHT };
     415             :                     static const geometry_3dir_t PENCIL_BAD_r_PATTERN3
     416             :                          = { .first = GEOMETRY_DIRECTION_LEFT,   .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_CENTER };
     417             :                     static const geometry_3dir_t PENCIL_BAD_r_PATTERN4
     418             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_DOWN };
     419             : 
     420           0 :                     if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN1 ) )
     421           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN2 ) )
     422           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN3 ) )
     423           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN4 ) ))
     424             :                     {
     425           0 :                         debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
     426             :                     }
     427             :                 }
     428             :                 else
     429             :                 {
     430             :                     static const geometry_3dir_t PENCIL_BAD_7_PATTERN1
     431             :                          = { .first = GEOMETRY_DIRECTION_RIGHT,  .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_CENTER };
     432             :                     static const geometry_3dir_t PENCIL_BAD_7_PATTERN2
     433             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
     434             :                     static const geometry_3dir_t PENCIL_BAD_7_PATTERN3
     435             :                          = { .first = GEOMETRY_DIRECTION_UP,     .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_CENTER };
     436             :                     static const geometry_3dir_t PENCIL_BAD_7_PATTERN4
     437             :                          = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_LEFT };
     438             : 
     439           0 :                     if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN1 ) )
     440           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN2 ) )
     441           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN3 ) )
     442           0 :                         || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN4 ) ))
     443             :                     {
     444           0 :                         debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
     445             :                     }
     446             :                 }
     447             :             }
     448             :         }
     449             : 
     450             :         /* add debts for overlap to diagram boundary */
     451             :         {
     452           0 :             if ( ! geometry_rectangle_is_containing( diagram_draw_area, &connector_bounds ) )
     453             :             {
     454           0 :                 debts_of_current += 1000000.0;
     455             :             }
     456             :         }
     457             : 
     458             :         /* iterate over all classifiers */
     459             :         const uint32_t count_clasfy
     460           0 :             = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
     461           0 :         for ( uint32_t clasfy_index = 0; clasfy_index < count_clasfy; clasfy_index ++ )
     462             :         {
     463             :             const layout_visible_classifier_t *const probe_classifier
     464           0 :                 = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, clasfy_index );
     465             : 
     466             :             const geometry_rectangle_t *const classifier_space
     467           0 :                 = layout_visible_classifier_get_space_const( probe_classifier );
     468           0 :             if ( ! geometry_rectangle_is_containing( classifier_space, &connector_bounds ) )
     469             :             {
     470             :                 const geometry_rectangle_t *const classifier_symbol_box
     471           0 :                     = layout_visible_classifier_get_symbol_box_const( probe_classifier );
     472           0 :                 if ( geometry_connector_is_intersecting_rectangle( current_solution, classifier_symbol_box ) )
     473             :                 {
     474           0 :                     debts_of_current += 100000.0;
     475             :                 }
     476             : 
     477             :                 const geometry_rectangle_t *const classifier_label_box
     478           0 :                     = layout_visible_classifier_get_label_box_const( probe_classifier );
     479           0 :                 if ( geometry_connector_is_intersecting_rectangle( current_solution, classifier_label_box ) )
     480             :                 {
     481           0 :                     debts_of_current += 10000.0;
     482             :                 }
     483             :             }
     484             :         }
     485             : 
     486             :         /* iterate over all features, check symbol boxes only, label boxes are not yet initialized */
     487             :         const uint32_t count_features
     488           0 :             = layout_visible_set_get_feature_count ( (*this_).layout_data );
     489           0 :         for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
     490             :         {
     491             :             const layout_feature_t *const feature_layout
     492           0 :                 = layout_visible_set_get_feature_ptr ( (*this_).layout_data, f_idx );
     493             : 
     494             :             const geometry_rectangle_t *const feature_symbol_box
     495           0 :                 = layout_feature_get_symbol_box_const( feature_layout );
     496           0 :             if ( geometry_connector_is_intersecting_rectangle( current_solution, feature_symbol_box ) )
     497             :             {
     498           0 :                 debts_of_current += 30000.0;
     499             :             }
     500             :         }
     501             : 
     502             :         /* iterate over the already created connectors (probe_sort_index < (*this_).sorted_rel_index) */
     503           0 :         for ( uint32_t probe_sort_index = 0; probe_sort_index < (*this_).sorted_rel_index; probe_sort_index ++ )
     504             :         {
     505             :             /* add debts if intersects */
     506             :             const uint32_t probe_index
     507           0 :                 = universal_array_index_sorter_get_array_index( &((*this_).sorted_relationships), probe_sort_index );
     508             :             const layout_relationship_t *const probe_relationship
     509           0 :                 = layout_visible_set_get_relationship_ptr( (*this_).layout_data, probe_index );
     510             : #if 0
     511             :             const data_relationship_t *const probe_relation_data
     512             :                 = layout_relationship_get_data_const ( probe_relationship );
     513             :             const bool same_type = ( data_relationship_get_main_type( probe_relation_data )
     514             :                                      == data_relationship_get_main_type( current_relation_data ) );
     515             :             const bool same_from = ( data_relationship_get_from_classifier_row_id( probe_relation_data )
     516             :                                      == data_relationship_get_from_classifier_row_id( current_relation_data ) );
     517             :             const bool same_to = ( data_relationship_get_to_classifier_row_id( probe_relation_data )
     518             :                                      == data_relationship_get_to_classifier_row_id( current_relation_data ) );
     519             :             const bool one_same_end = ( same_from != same_to );
     520             :             /* if probe and current have same type and (same source classifier xor same destination classifier), overlaps are ok */
     521             :             if ( ! ( same_type && one_same_end ) )
     522             : #endif
     523             :             {
     524             :                 const geometry_connector_t *const probe_shape
     525           0 :                     = layout_relationship_get_shape_const( probe_relationship );
     526             :                 const uint32_t intersects
     527           0 :                     = geometry_connector_count_connector_intersects( current_solution, probe_shape );
     528           0 :                 debts_of_current += 1000.0 * intersects;
     529             : 
     530           0 :                 if ( ( bad_pattern_h || bad_pattern_v ) && ( intersects > 0 ) )
     531             :                 {
     532           0 :                     const geometry_3dir_t probe_pattern = geometry_connector_get_directions( probe_shape );
     533           0 :                     const bool bad_probe_v = geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_V_PATTERN1 )
     534           0 :                         || geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_V_PATTERN2 );
     535           0 :                     const bool bad_probe_h = geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_H_PATTERN1 )
     536           0 :                         || geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_H_PATTERN2 );
     537           0 :                     if (( bad_pattern_h && bad_probe_v )||( bad_pattern_v && bad_probe_h ))
     538             :                     {
     539           0 :                          debts_of_current += 1000000.0;
     540             :                     }
     541             :                 }
     542             :             }
     543             :         }
     544             : 
     545             :         /* update best solution */
     546           0 :         if ( debts_of_current < debts_of_best )
     547             :         {
     548           0 :             index_of_best = solution_idx;
     549           0 :             debts_of_best = debts_of_current;
     550             :         }
     551             :     }
     552             : 
     553             :     /* the best */
     554           0 :     *out_index_of_best = index_of_best;
     555           0 :     geometry_connector_trace( &(solutions[index_of_best]) );
     556             : 
     557           0 :     U8_TRACE_END();
     558           0 : }
     559             : 
     560           0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_I ( pencil_relationship_2d_layouter_t *this_,
     561             :                                                                        const geometry_rectangle_t *source_rect,
     562             :                                                                        const geometry_rectangle_t *dest_rect,
     563             :                                                                        uint32_t solutions_max,
     564             :                                                                        geometry_connector_t out_solutions[],
     565             :                                                                        uint32_t *out_solutions_count )
     566             : {
     567           0 :     U8_TRACE_BEGIN();
     568           0 :     assert( NULL != source_rect );
     569           0 :     assert( NULL != dest_rect );
     570           0 :     assert ( NULL != out_solutions );
     571           0 :     assert ( NULL != out_solutions_count );
     572           0 :     assert ( 4 <= solutions_max );  /* current implementation requires at least 4 options */
     573             : 
     574           0 :     uint32_t solutions_count = 0;
     575             : 
     576           0 :     const double src_left = geometry_rectangle_get_left(source_rect);
     577           0 :     const double src_right = geometry_rectangle_get_right(source_rect);
     578           0 :     const double src_top = geometry_rectangle_get_top(source_rect);
     579           0 :     const double src_bottom = geometry_rectangle_get_bottom(source_rect);
     580             : 
     581           0 :     const double dst_left = geometry_rectangle_get_left(dest_rect);
     582           0 :     const double dst_right = geometry_rectangle_get_right(dest_rect);
     583           0 :     const double dst_top = geometry_rectangle_get_top(dest_rect);
     584           0 :     const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
     585             : 
     586           0 :     const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     587           0 :     const double gap_dist = 0.499 * object_dist;  /* half the object distance allows a line to pass between two objects */
     588             : 
     589             :     /* if applicable, add a solution where line is vertical */
     590           0 :     if (( src_right >= dst_left )&&( src_left <= dst_right ))
     591             :     {
     592           0 :         const double min_left = fmax( src_left, dst_left );
     593           0 :         const double max_right = fmin( src_right, dst_right );
     594             : 
     595           0 :         if ( dst_bottom + object_dist < src_top )
     596             :         {
     597             :             /* define defaults */
     598           0 :             double x_value = ( min_left + max_right ) / 2.0;
     599             : 
     600             :             /* optimize coordinates */
     601             :             geometry_rectangle_t search_rect;
     602           0 :             geometry_rectangle_init_by_corners( &search_rect, min_left, dst_bottom, max_right, src_top );
     603           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
     604           0 :             geometry_rectangle_destroy( &search_rect );
     605             : 
     606             :             /* add solution */
     607           0 :             geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
     608             :                                                  x_value,
     609             :                                                  src_top,
     610             :                                                  x_value,
     611             :                                                  dst_bottom,
     612             :                                                  x_value
     613             :                                                );
     614           0 :             solutions_count ++;
     615             :         }
     616           0 :         else if ( dst_top - object_dist > src_bottom )
     617             :         {
     618             :             /* define defaults */
     619           0 :             double x_value = ( min_left + max_right ) / 2.0;
     620             : 
     621             :             /* optimize coordinates */
     622             :             geometry_rectangle_t search_rect;
     623           0 :             geometry_rectangle_init_by_corners( &search_rect, min_left, dst_top, max_right, src_bottom );
     624           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
     625           0 :             geometry_rectangle_destroy( &search_rect );
     626             : 
     627             :             /* add solution */
     628           0 :             geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
     629             :                                                  x_value,
     630             :                                                  src_bottom,
     631             :                                                  x_value,
     632             :                                                  dst_top,
     633             :                                                  x_value
     634             :                                                );
     635           0 :             solutions_count ++;
     636             :         }
     637             :         else
     638             :         {
     639           0 :             if ( fabs( src_top - dst_top ) > object_dist )
     640             :             {
     641             :                 /* define defaults */
     642           0 :                 double x_value = ( min_left + max_right ) / 2.0;
     643             : 
     644             :                 /* optimize coordinates */
     645             :                 geometry_rectangle_t search_rect;
     646           0 :                 geometry_rectangle_init_by_corners( &search_rect, min_left, dst_top, max_right, src_top );
     647           0 :                 pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
     648           0 :                 geometry_rectangle_destroy( &search_rect );
     649             : 
     650             :                 /* add solution */
     651           0 :                 geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
     652             :                                                     x_value,
     653             :                                                     src_top,
     654             :                                                     x_value,
     655             :                                                     dst_top,
     656             :                                                     x_value
     657             :                                                   );
     658           0 :                 solutions_count ++;
     659             :             }
     660             : 
     661           0 :             if ( fabs( src_bottom - dst_bottom ) > object_dist )
     662             :             {
     663             :                 /* define defaults */
     664           0 :                 double x_value = ( min_left + max_right ) / 2.0;
     665             : 
     666             :                 /* optimize coordinates */
     667             :                 geometry_rectangle_t search_rect;
     668           0 :                 geometry_rectangle_init_by_corners( &search_rect, min_left, src_bottom, max_right, dst_bottom );
     669           0 :                 pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
     670           0 :                 geometry_rectangle_destroy( &search_rect );
     671             : 
     672             :                 /* add solution */
     673           0 :                 geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
     674             :                                                     x_value,
     675             :                                                     src_bottom,
     676             :                                                     x_value,
     677             :                                                     dst_bottom,
     678             :                                                     x_value
     679             :                                                   );
     680           0 :                 solutions_count ++;
     681             :             }
     682             :         }
     683             :     }
     684             : 
     685             :     /* if applicable, add a solution where line is horizontal */
     686           0 :     if (( src_bottom >= dst_top )&&( src_top <= dst_bottom ))
     687             :     {
     688           0 :         const double min_top = fmax( src_top, dst_top );
     689           0 :         const double max_bottom = fmin( src_bottom, dst_bottom );
     690             : 
     691           0 :         if ( dst_right + object_dist < src_left )
     692             :         {
     693             :             /* define defaults */
     694           0 :             double y_value = ( min_top + max_bottom ) / 2.0;
     695             : 
     696             :             /* optimize coordinates */
     697             :             geometry_rectangle_t search_rect;
     698           0 :             geometry_rectangle_init_by_corners( &search_rect, dst_right, min_top, src_left, max_bottom );
     699           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
     700           0 :             geometry_rectangle_destroy( &search_rect );
     701             : 
     702             :             /* add solution */
     703           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
     704             :                                                    src_left,
     705             :                                                    y_value,
     706             :                                                    dst_right,
     707             :                                                    y_value,
     708             :                                                    y_value
     709             :                                                  );
     710           0 :             solutions_count ++;
     711             :         }
     712           0 :         else if ( dst_left - object_dist > src_right )
     713             :         {
     714             :             /* define defaults */
     715           0 :             double y_value = ( min_top + max_bottom ) / 2.0;
     716             : 
     717             :             /* optimize coordinates */
     718             :             geometry_rectangle_t search_rect;
     719           0 :             geometry_rectangle_init_by_corners( &search_rect, dst_left, min_top, src_right, max_bottom );
     720           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
     721           0 :             geometry_rectangle_destroy( &search_rect );
     722             : 
     723             :             /* add solution */
     724           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
     725             :                                                    src_right,
     726             :                                                    y_value,
     727             :                                                    dst_left,
     728             :                                                    y_value,
     729             :                                                    y_value
     730             :                                                  );
     731           0 :             solutions_count ++;
     732             :         }
     733             :         else
     734             :         {
     735           0 :             if ( fabs( src_left - dst_left ) > object_dist )
     736             :             {
     737             :                 /* define defaults */
     738           0 :                 double y_value = ( min_top + max_bottom ) / 2.0;
     739             : 
     740             :                 /* optimize coordinates */
     741             :                 geometry_rectangle_t search_rect;
     742           0 :                 geometry_rectangle_init_by_corners( &search_rect, src_left, min_top, dst_left, max_bottom );
     743           0 :                 pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
     744           0 :                 geometry_rectangle_destroy( &search_rect );
     745             : 
     746             :                 /* add solution */
     747           0 :                 geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
     748             :                                                        src_left,
     749             :                                                        y_value,
     750             :                                                        dst_left,
     751             :                                                        y_value,
     752             :                                                        y_value
     753             :                                                      );
     754           0 :                 solutions_count ++;
     755             :             }
     756             : 
     757           0 :             if ( fabs( src_right - dst_right ) > object_dist )
     758             :             {
     759             :                 /* define defaults */
     760           0 :                 double y_value = ( min_top + max_bottom ) / 2.0;
     761             : 
     762             :                 /* optimize coordinates */
     763             :                 geometry_rectangle_t search_rect;
     764           0 :                 geometry_rectangle_init_by_corners( &search_rect, src_right, min_top, dst_right, max_bottom );
     765           0 :                 pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
     766           0 :                 geometry_rectangle_destroy( &search_rect );
     767             : 
     768             :                 /* add solution */
     769           0 :                 geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
     770             :                                                        src_right,
     771             :                                                        y_value,
     772             :                                                        dst_right,
     773             :                                                        y_value,
     774             :                                                        y_value
     775             :                                                      );
     776           0 :                 solutions_count ++;
     777             :             }
     778             :         }
     779             :     }
     780             : 
     781           0 :     *out_solutions_count = solutions_count;
     782             : 
     783           0 :     U8_TRACE_END();
     784           0 : }
     785             : 
     786           0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_ZN ( pencil_relationship_2d_layouter_t *this_,
     787             :                                                                         const geometry_rectangle_t *source_rect,
     788             :                                                                         const geometry_rectangle_t *dest_rect,
     789             :                                                                         uint32_t solutions_max,
     790             :                                                                         geometry_connector_t out_solutions[],
     791             :                                                                         uint32_t *out_solutions_count )
     792             : {
     793           0 :     U8_TRACE_BEGIN();
     794           0 :     assert( NULL != source_rect );
     795           0 :     assert( NULL != dest_rect );
     796           0 :     assert ( NULL != out_solutions );
     797           0 :     assert ( NULL != out_solutions_count );
     798           0 :     assert ( 2 <= solutions_max );  /* current implementation requires at least 2 options */
     799             : 
     800           0 :     uint32_t solutions_count = 0;
     801             : 
     802           0 :     const double src_left = geometry_rectangle_get_left(source_rect);
     803           0 :     const double src_center_x = geometry_rectangle_get_center_x(source_rect);
     804           0 :     const double src_right = geometry_rectangle_get_right(source_rect);
     805           0 :     const double src_top = geometry_rectangle_get_top(source_rect);
     806           0 :     const double src_center_y = geometry_rectangle_get_center_y(source_rect);
     807           0 :     const double src_bottom = geometry_rectangle_get_bottom(source_rect);
     808           0 :     const double src_width = geometry_rectangle_get_width(source_rect);
     809           0 :     const double src_height = geometry_rectangle_get_height(source_rect);
     810             : 
     811           0 :     const double dst_left = geometry_rectangle_get_left(dest_rect);
     812           0 :     const double dst_center_x = geometry_rectangle_get_center_x(dest_rect);
     813           0 :     const double dst_right = geometry_rectangle_get_right(dest_rect);
     814           0 :     const double dst_top = geometry_rectangle_get_top(dest_rect);
     815           0 :     const double dst_center_y = geometry_rectangle_get_center_y(dest_rect);
     816           0 :     const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
     817           0 :     const double dst_width = geometry_rectangle_get_width(dest_rect);
     818           0 :     const double dst_height = geometry_rectangle_get_height(dest_rect);
     819             : 
     820           0 :     const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     821           0 :     const double good_dist = 2.0 * object_dist;  /* duplicate distance: once for each side of the line */
     822           0 :     const double gap_dist = 0.499 * object_dist;  /* half the object distance allows a line to pass between two objects */
     823             : 
     824             :     /* if applicable, add a solution where main line is vertical */
     825             :     {
     826           0 :         if ( dst_right + good_dist < src_left )
     827             :         {
     828             :             /* define defaults */
     829           0 :             double x_value = ( src_left + dst_right ) / 2.0;
     830           0 :             double src_y = src_center_y;
     831           0 :             double dst_y = dst_center_y;
     832             : 
     833             :             /* optimize coordinates */
     834             :             geometry_rectangle_t search_rect;
     835           0 :             geometry_rectangle_init_by_corners( &search_rect, src_left, src_y, dst_right, dst_y );
     836           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
     837           0 :             geometry_rectangle_destroy( &search_rect );
     838             : 
     839           0 :             const geometry_rectangle_t depart_area
     840           0 :                 = { .left=x_value, .top=src_top, .width=(src_left-x_value), .height=src_height};
     841           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
     842             : 
     843           0 :             const geometry_rectangle_t arrive_area
     844           0 :                 = { .left=dst_right, .top=dst_top, .width=(x_value-dst_right), .height=dst_height};
     845           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
     846             : 
     847             :             /* add solution */
     848           0 :             geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
     849             :                                                  src_left,
     850             :                                                  src_y,
     851             :                                                  dst_right,
     852             :                                                  dst_y,
     853             :                                                  x_value
     854             :                                                );
     855           0 :             solutions_count ++;
     856             :         }
     857           0 :         else if ( dst_left - good_dist > src_right )
     858             :         {
     859             :             /* define defaults */
     860           0 :             double x_value = ( src_right + dst_left ) / 2.0;
     861           0 :             double src_y = src_center_y;
     862           0 :             double dst_y = dst_center_y;
     863             : 
     864             :             /* optimize coordinates */
     865             :             geometry_rectangle_t search_rect;
     866           0 :             geometry_rectangle_init_by_corners( &search_rect, src_right, src_y, dst_left, dst_y );
     867           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
     868           0 :             geometry_rectangle_destroy( &search_rect );
     869             : 
     870           0 :             const geometry_rectangle_t depart_area
     871           0 :                 = { .left=src_right, .top=src_top, .width=(x_value-src_right), .height=src_height};
     872           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
     873             : 
     874           0 :             const geometry_rectangle_t arrive_area
     875           0 :                 = { .left=x_value, .top=dst_top, .width=(dst_left-x_value), .height=dst_height};
     876           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
     877             : 
     878             :             /* add solution */
     879           0 :             geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
     880             :                                                  src_right,
     881             :                                                  src_y,
     882             :                                                  dst_left,
     883             :                                                  dst_y,
     884             :                                                  x_value
     885             :                                                );
     886           0 :             solutions_count ++;
     887             :         }
     888             :     }
     889             : 
     890             :     /* if applicable, add a solution where main line is horizontal */
     891             :     {
     892           0 :         if ( dst_bottom + good_dist < src_top )
     893             :         {
     894             :             /* define defaults */
     895           0 :             double y_value = ( src_top + dst_bottom ) / 2.0;
     896           0 :             double src_x = src_center_x;
     897           0 :             double dst_x = dst_center_x;
     898             : 
     899             :             /* optimize coordinates */
     900             :             geometry_rectangle_t search_rect;
     901           0 :             geometry_rectangle_init_by_corners( &search_rect, src_x, src_top, dst_x, dst_bottom );
     902           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
     903           0 :             geometry_rectangle_destroy( &search_rect );
     904             : 
     905           0 :             const geometry_rectangle_t depart_area
     906           0 :                 = { .left=src_left, .top=y_value, .width=src_width, .height=(src_top-y_value)};
     907           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
     908             : 
     909           0 :             const geometry_rectangle_t arrive_area
     910           0 :                 = { .left=dst_left, .top=dst_bottom, .width=dst_width, .height=(y_value-dst_bottom)};
     911           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
     912             : 
     913             :             /* add solution */
     914           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
     915             :                                                    src_x,
     916             :                                                    src_top,
     917             :                                                    dst_x,
     918             :                                                    dst_bottom,
     919             :                                                    y_value
     920             :                                                  );
     921           0 :             solutions_count ++;
     922             :         }
     923           0 :         else if ( dst_top - good_dist > src_bottom )
     924             :         {
     925             :             /* define defaults */
     926           0 :             double y_value = ( src_bottom + dst_top ) / 2.0;
     927           0 :             double src_x = src_center_x;
     928           0 :             double dst_x = dst_center_x;
     929             : 
     930             :             /* optimize coordinates */
     931             :             geometry_rectangle_t search_rect;
     932           0 :             geometry_rectangle_init_by_corners( &search_rect, src_x, src_bottom, dst_x, dst_top );
     933           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
     934           0 :             geometry_rectangle_destroy( &search_rect );
     935             : 
     936           0 :             const geometry_rectangle_t depart_area
     937           0 :                 = { .left=src_left, .top=src_bottom, .width=src_width, .height=(y_value-src_bottom)};
     938           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
     939             : 
     940           0 :             const geometry_rectangle_t arrive_area
     941           0 :                 = { .left=dst_left, .top=y_value, .width=dst_width, .height=(dst_top-y_value)};
     942           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
     943             : 
     944             :             /* add solution */
     945           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
     946             :                                                    src_x,
     947             :                                                    src_bottom,
     948             :                                                    dst_x,
     949             :                                                    dst_top,
     950             :                                                    y_value
     951             :                                                  );
     952           0 :             solutions_count ++;
     953             :         }
     954             :     }
     955             : 
     956           0 :     *out_solutions_count = solutions_count;
     957             : 
     958           0 :     U8_TRACE_END();
     959           0 : }
     960             : 
     961           0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_UC ( pencil_relationship_2d_layouter_t *this_,
     962             :                                                                         const geometry_rectangle_t *source_rect,
     963             :                                                                         const geometry_rectangle_t *dest_rect,
     964             :                                                                         uint32_t solutions_max,
     965             :                                                                         geometry_connector_t out_solutions[],
     966             :                                                                         uint32_t *out_solutions_count )
     967             : {
     968           0 :     U8_TRACE_BEGIN();
     969           0 :     assert( NULL != source_rect );
     970           0 :     assert( NULL != dest_rect );
     971           0 :     assert ( NULL != out_solutions );
     972           0 :     assert ( NULL != out_solutions_count );
     973           0 :     assert ( 4 <= solutions_max );  /* current implementation calculates exactly 4 options */
     974             : 
     975           0 :     uint32_t solutions_count = 0;
     976             : 
     977             :     /* get draw area */
     978             :     const layout_diagram_t *const diagram_layout
     979           0 :         = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
     980             :     const geometry_rectangle_t *const diagram_draw_area
     981           0 :         = layout_diagram_get_draw_area_const( diagram_layout );
     982           0 :     const double draw_left = geometry_rectangle_get_left( diagram_draw_area );
     983           0 :     const double draw_right = geometry_rectangle_get_right( diagram_draw_area );
     984           0 :     const double draw_top = geometry_rectangle_get_top( diagram_draw_area );
     985           0 :     const double draw_bottom = geometry_rectangle_get_bottom( diagram_draw_area );
     986             : 
     987           0 :     const double src_left = geometry_rectangle_get_left(source_rect);
     988           0 :     const double src_center_x = geometry_rectangle_get_center_x(source_rect);
     989           0 :     const double src_right = geometry_rectangle_get_right(source_rect);
     990           0 :     const double src_top = geometry_rectangle_get_top(source_rect);
     991           0 :     const double src_center_y = geometry_rectangle_get_center_y(source_rect);
     992           0 :     const double src_bottom = geometry_rectangle_get_bottom(source_rect);
     993           0 :     const double src_width = geometry_rectangle_get_width(source_rect);
     994           0 :     const double src_height = geometry_rectangle_get_height(source_rect);
     995             : 
     996           0 :     const double dst_left = geometry_rectangle_get_left(dest_rect);
     997           0 :     const double dst_center_x = geometry_rectangle_get_center_x(dest_rect);
     998           0 :     const double dst_right = geometry_rectangle_get_right(dest_rect);
     999           0 :     const double dst_top = geometry_rectangle_get_top(dest_rect);
    1000           0 :     const double dst_center_y = geometry_rectangle_get_center_y(dest_rect);
    1001           0 :     const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
    1002           0 :     const double dst_width = geometry_rectangle_get_width(dest_rect);
    1003           0 :     const double dst_height = geometry_rectangle_get_height(dest_rect);
    1004             : 
    1005           0 :     const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
    1006           0 :     const double gap_dist = 0.499 * object_dist;  /* half the object distance allows a line to pass between two objects */
    1007             :     static const double NO_TOUCH = 0.0001;
    1008             : 
    1009             :     /* connect via left side */
    1010             :     {
    1011             :         /* define defaults */
    1012           0 :         double x_value = fmin( src_left, dst_left ) - object_dist;
    1013           0 :         double src_y = src_center_y;
    1014           0 :         double dst_y = dst_center_y;
    1015           0 :         if ( fabs( src_center_y - dst_center_y ) < NO_TOUCH )
    1016             :         {
    1017             :             /* forward way is identical to retour - may be a relation to self */
    1018           0 :             src_y = fmin( src_center_y + gap_dist, src_bottom );
    1019           0 :             dst_y = fmax( dst_center_y - gap_dist, dst_top );
    1020             :         }
    1021             : 
    1022             :         /* optimize coordinates */
    1023             :         geometry_rectangle_t search_rect;
    1024           0 :         geometry_rectangle_init_by_corners( &search_rect, draw_left, src_y, x_value, dst_y );
    1025           0 :         pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
    1026           0 :         geometry_rectangle_destroy( &search_rect );
    1027             : 
    1028           0 :         const geometry_rectangle_t depart_area
    1029           0 :             = { .left=x_value, .top=src_top, .width=(src_left-x_value), .height=src_height};
    1030           0 :         pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
    1031             : 
    1032           0 :         const geometry_rectangle_t arrive_area
    1033           0 :             = { .left=x_value, .top=dst_top, .width=(dst_left-x_value), .height=dst_height};
    1034           0 :         pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
    1035             : 
    1036             :         /* add solution */
    1037           0 :         geometry_connector_reinit_vertical( &(out_solutions[solutions_count]),
    1038             :                                             src_left,
    1039             :                                             src_y,
    1040             :                                             dst_left,
    1041             :                                             dst_y,
    1042             :                                             x_value
    1043             :                                           );
    1044           0 :         solutions_count ++;
    1045             :     }
    1046             : 
    1047             :     /* connect via right side */
    1048             :     {
    1049             :         /* define defaults */
    1050           0 :         double x_value = fmax( src_right, dst_right ) + object_dist;
    1051           0 :         double src_y = src_center_y;
    1052           0 :         double dst_y = dst_center_y;
    1053           0 :         if ( fabs( src_center_y - dst_center_y ) < NO_TOUCH )
    1054             :         {
    1055             :             /* forward way is identical to retour - may be a relation to self */
    1056           0 :             src_y = fmin( src_center_y + gap_dist, src_bottom );
    1057           0 :             dst_y = fmax( dst_center_y - gap_dist, dst_top );
    1058             :         }
    1059             : 
    1060             :         /* optimize coordinates */
    1061             :         geometry_rectangle_t search_rect;
    1062           0 :         geometry_rectangle_init_by_corners( &search_rect, x_value, src_y, draw_right, dst_y );
    1063           0 :         pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
    1064           0 :         geometry_rectangle_destroy( &search_rect );
    1065             : 
    1066           0 :         const geometry_rectangle_t depart_area
    1067           0 :             = { .left=src_right, .top=src_top, .width=(x_value-src_right), .height=src_height};
    1068           0 :         pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
    1069             : 
    1070           0 :         const geometry_rectangle_t arrive_area
    1071           0 :             = { .left=dst_right, .top=dst_top, .width=(x_value-dst_right), .height=dst_height};
    1072           0 :         pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
    1073             : 
    1074             :         /* add solution */
    1075           0 :         geometry_connector_reinit_vertical( &(out_solutions[solutions_count]),
    1076             :                                             src_right,
    1077             :                                             src_y,
    1078             :                                             dst_right,
    1079             :                                             dst_y,
    1080             :                                             x_value
    1081             :                                           );
    1082           0 :         solutions_count ++;
    1083             :     }
    1084             : 
    1085             :     /* connect via top side */
    1086             :     {
    1087             :         /* define defaults */
    1088           0 :         double y_value = fmin( src_top, dst_top ) - object_dist;
    1089           0 :         double src_x = src_center_x;
    1090           0 :         double dst_x = dst_center_x;
    1091           0 :         if ( fabs( src_center_x - dst_center_x ) < NO_TOUCH )
    1092             :         {
    1093             :             /* forward way is identical to retour - may be a relation to self */
    1094           0 :             src_x = fmax( src_center_x - gap_dist, src_left );
    1095           0 :             dst_x = fmin( dst_center_x + gap_dist, dst_right );
    1096             :         }
    1097             : 
    1098             :         /* optimize coordinates */
    1099             :         geometry_rectangle_t search_rect;
    1100           0 :         geometry_rectangle_init_by_corners( &search_rect, src_x, draw_top, dst_x, y_value );
    1101           0 :         pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
    1102           0 :         geometry_rectangle_destroy( &search_rect );
    1103             : 
    1104           0 :         const geometry_rectangle_t depart_area
    1105           0 :             = { .left=src_left, .top=y_value, .width=src_width, .height=(src_top-y_value)};
    1106           0 :         pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
    1107             : 
    1108           0 :         const geometry_rectangle_t arrive_area
    1109           0 :             = { .left=dst_left, .top=y_value, .width=dst_width, .height=(dst_top-y_value)};
    1110           0 :         pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
    1111             : 
    1112             :         /* add solution */
    1113           0 :         geometry_connector_reinit_horizontal( &(out_solutions[solutions_count]),
    1114             :                                               src_x,
    1115             :                                               src_top,
    1116             :                                               dst_x,
    1117             :                                               dst_top,
    1118             :                                               y_value
    1119             :                                             );
    1120           0 :         solutions_count ++;
    1121             :     }
    1122             : 
    1123             :     /* connect via bottom side */
    1124             :     {
    1125             :         /* define defaults */
    1126           0 :         double y_value = fmax( src_bottom, dst_bottom ) + object_dist;
    1127           0 :         double src_x = src_center_x;
    1128           0 :         double dst_x = dst_center_x;
    1129           0 :         if ( fabs( src_center_x - dst_center_x ) < NO_TOUCH )
    1130             :         {
    1131             :             /* forward way is identical to retour - may be a relation to self */
    1132           0 :             src_x = fmax( src_center_x - gap_dist, src_left );
    1133           0 :             dst_x = fmin( dst_center_x + gap_dist, dst_right );
    1134             :         }
    1135             : 
    1136             :         /* optimize coordinates */
    1137             :         geometry_rectangle_t search_rect;
    1138           0 :         geometry_rectangle_init_by_corners( &search_rect, src_x, y_value, dst_x, draw_bottom );
    1139           0 :         pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
    1140           0 :         geometry_rectangle_destroy( &search_rect );
    1141             : 
    1142           0 :         const geometry_rectangle_t depart_area
    1143           0 :             = { .left=src_left, .top=src_bottom, .width=src_width, .height=(y_value-src_bottom)};
    1144           0 :         pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
    1145             : 
    1146           0 :         const geometry_rectangle_t arrive_area
    1147           0 :             = { .left=dst_left, .top=dst_bottom, .width=dst_width, .height=(y_value-dst_bottom)};
    1148           0 :         pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
    1149             : 
    1150             :         /* add solution */
    1151           0 :         geometry_connector_reinit_horizontal( &(out_solutions[solutions_count]),
    1152             :                                               src_x,
    1153             :                                               src_bottom,
    1154             :                                               dst_x,
    1155             :                                               dst_bottom,
    1156             :                                               y_value
    1157             :                                             );
    1158           0 :         solutions_count ++;
    1159             :     }
    1160             : 
    1161           0 :     *out_solutions_count = solutions_count;
    1162             : 
    1163           0 :     U8_TRACE_END();
    1164           0 : }
    1165             : 
    1166           0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_L7 ( pencil_relationship_2d_layouter_t *this_,
    1167             :                                                                         const geometry_rectangle_t *source_rect,
    1168             :                                                                         const geometry_rectangle_t *dest_rect,
    1169             :                                                                         uint32_t solutions_max,
    1170             :                                                                         geometry_connector_t out_solutions[],
    1171             :                                                                         uint32_t *out_solutions_count )
    1172             : {
    1173           0 :     U8_TRACE_BEGIN();
    1174           0 :     assert( NULL != source_rect );
    1175           0 :     assert( NULL != dest_rect );
    1176           0 :     assert ( NULL != out_solutions );
    1177           0 :     assert ( NULL != out_solutions_count );
    1178           0 :     assert ( 8 <= solutions_max );  /* current implementation requires at least 2 options */
    1179             : 
    1180           0 :     uint32_t solutions_count = 0;
    1181             : 
    1182           0 :     const double src_left = geometry_rectangle_get_left(source_rect);
    1183           0 :     const double src_right = geometry_rectangle_get_right(source_rect);
    1184           0 :     const double src_top = geometry_rectangle_get_top(source_rect);
    1185           0 :     const double src_bottom = geometry_rectangle_get_bottom(source_rect);
    1186             : 
    1187           0 :     const double dst_left = geometry_rectangle_get_left(dest_rect);
    1188           0 :     const double dst_right = geometry_rectangle_get_right(dest_rect);
    1189           0 :     const double dst_top = geometry_rectangle_get_top(dest_rect);
    1190           0 :     const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
    1191             : 
    1192           0 :     const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
    1193           0 :     const double gap_dist = 0.499 * object_dist;  /* half the object distance allows a line to pass between two objects */
    1194             : 
    1195             :     /* pre-calculate some intermediate values on source rect */
    1196           0 :     const bool src_left_to_outside = dst_left < src_left;  /* connector starts towards outside of source rect */
    1197           0 :     const bool src_right_to_outside = dst_right > src_right;  /* connector starts towards outside of source rect */
    1198           0 :     const bool src_top_to_outside = src_top > dst_top;  /* connector arrives from outside at dest rect */
    1199           0 :     const bool src_bottom_to_outside = src_bottom < dst_bottom;  /* connector arrives from outside at dest rect */
    1200             :     /* pre-calculate some intermediate values on destination rect */
    1201           0 :     const bool dst_left_from_outside = src_left < dst_left;  /* connector starts towards outside of source rect */
    1202           0 :     const bool dst_right_from_outside = src_right > dst_right;  /* connector starts towards outside of source rect */
    1203           0 :     const bool dst_top_from_outside = dst_top > src_top;  /* connector arrives from outside at dest rect */
    1204           0 :     const bool dst_bottom_from_outside = dst_bottom < src_bottom;  /* connector arrives from outside at dest rect */
    1205             : 
    1206             :     /* add two solutions from source-left */
    1207             :     {
    1208           0 :         const double search_left = dst_left;
    1209           0 :         const double search_right = src_left_to_outside ? fmin( src_left, dst_right ) : dst_right;
    1210             :         /* add a solution from source-left to destination-bottom */
    1211             :         {
    1212           0 :             const double search_top = dst_bottom_from_outside ? fmax( src_top, dst_bottom ) : src_top;
    1213           0 :             const double search_bottom = src_bottom;
    1214             : 
    1215             :             /* define defaults */
    1216           0 :             double dst_x = ( search_left + search_right ) / 2.0;
    1217           0 :             double src_y = ( search_top + search_bottom ) / 2.0;
    1218             : 
    1219             :             /* optimize coordinates */
    1220             :             geometry_rectangle_t depart_area;
    1221           0 :             geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_left, src_bottom );
    1222           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
    1223           0 :             geometry_rectangle_destroy( &depart_area );
    1224             : 
    1225             :             geometry_rectangle_t arrive_area;
    1226           0 :             geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_bottom );
    1227           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
    1228           0 :             geometry_rectangle_destroy( &arrive_area );
    1229             : 
    1230             :             /* add solution */
    1231           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1232             :                                                    src_left,
    1233             :                                                    src_y,
    1234             :                                                    dst_x,
    1235             :                                                    dst_bottom,
    1236             :                                                    src_y
    1237             :                                                  );
    1238           0 :             solutions_count ++;
    1239             :         }
    1240             :         /* add a solution from source-left to destination-top */
    1241             :         {
    1242           0 :             const double search_top = src_top;
    1243           0 :             const double search_bottom = dst_top_from_outside ? fmin( src_bottom, dst_top ) : src_bottom;
    1244             : 
    1245             :             /* define defaults */
    1246           0 :             double dst_x = ( search_left + search_right ) / 2.0;
    1247           0 :             double src_y = ( search_top + search_bottom ) / 2.0;
    1248             : 
    1249             :             /* optimize coordinates */
    1250             :             geometry_rectangle_t depart_area;
    1251           0 :             geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_left, src_bottom );
    1252           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
    1253           0 :             geometry_rectangle_destroy( &depart_area );
    1254             : 
    1255             :             geometry_rectangle_t arrive_area;
    1256           0 :             geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_top );
    1257           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
    1258           0 :             geometry_rectangle_destroy( &arrive_area );
    1259             : 
    1260             :             /* add solution */
    1261           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1262             :                                                    src_left,
    1263             :                                                    src_y,
    1264             :                                                    dst_x,
    1265             :                                                    dst_top,
    1266             :                                                    src_y
    1267             :                                                  );
    1268           0 :             solutions_count ++;
    1269             :         }
    1270             :     }
    1271             : 
    1272             :     /* add two solutions from source-right */
    1273             :     {
    1274           0 :         const double search_left = src_right_to_outside ? fmax( src_right, dst_left ) : dst_left;
    1275           0 :         const double search_right = dst_right;
    1276             :         /* add a solution from source-right to destination-bottom */
    1277             :         {
    1278           0 :             const double search_top = dst_bottom_from_outside ? fmax( src_top, dst_bottom ) : src_top;
    1279           0 :             const double search_bottom = src_bottom;
    1280             : 
    1281             :             /* define defaults */
    1282           0 :             double dst_x = ( search_left + search_right ) / 2.0;
    1283           0 :             double src_y = ( search_top + search_bottom ) / 2.0;
    1284             : 
    1285             :             /* optimize coordinates */
    1286             :             geometry_rectangle_t depart_area;
    1287           0 :             geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_right, src_bottom );
    1288           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
    1289           0 :             geometry_rectangle_destroy( &depart_area );
    1290             : 
    1291             :             geometry_rectangle_t arrive_area;
    1292           0 :             geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_bottom );
    1293           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
    1294           0 :             geometry_rectangle_destroy( &arrive_area );
    1295             : 
    1296             :             /* add solution */
    1297           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1298             :                                                    src_right,
    1299             :                                                    src_y,
    1300             :                                                    dst_x,
    1301             :                                                    dst_bottom,
    1302             :                                                    src_y
    1303             :                                                  );
    1304           0 :             solutions_count ++;
    1305             :         }
    1306             :         /* add a solution from source-right to destination-top */
    1307             :         {
    1308           0 :             const double search_top = src_top;
    1309           0 :             const double search_bottom = dst_top_from_outside ? fmin( src_bottom, dst_top ) : src_bottom;
    1310             : 
    1311             :             /* define defaults */
    1312           0 :             double dst_x = ( search_left + search_right ) / 2.0;
    1313           0 :             double src_y = ( search_top + search_bottom ) / 2.0;
    1314             : 
    1315             :             /* optimize coordinates */
    1316             :             geometry_rectangle_t depart_area;
    1317           0 :             geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_right, src_bottom );
    1318           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
    1319           0 :             geometry_rectangle_destroy( &depart_area );
    1320             : 
    1321             :             geometry_rectangle_t arrive_area;
    1322           0 :             geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_top );
    1323           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
    1324           0 :             geometry_rectangle_destroy( &arrive_area );
    1325             : 
    1326             :             /* add solution */
    1327           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1328             :                                                    src_right,
    1329             :                                                    src_y,
    1330             :                                                    dst_x,
    1331             :                                                    dst_top,
    1332             :                                                    src_y
    1333             :                                                  );
    1334           0 :             solutions_count ++;
    1335             :         }
    1336             :     }
    1337             : 
    1338             :     /* add two solutions from source-top */
    1339             :     {
    1340           0 :         const double search_top = dst_top;
    1341           0 :         const double search_bottom = src_top_to_outside ? fmin( src_top, dst_bottom ) : dst_bottom;
    1342             :         /* add a solution from source-top to destination-right */
    1343             :         {
    1344           0 :             const double search_left = dst_right_from_outside ? fmax( dst_right, src_left ) : src_left;
    1345           0 :             const double search_right = src_right;
    1346             : 
    1347             :             /* define defaults */
    1348           0 :             double src_x = ( search_left + search_right ) / 2.0;
    1349           0 :             double dst_y = ( search_top + search_bottom ) / 2.0;
    1350             : 
    1351             :             /* optimize coordinates */
    1352             :             geometry_rectangle_t depart_area;
    1353           0 :             geometry_rectangle_init_by_corners( &depart_area, src_left, src_top, src_right, dst_y );
    1354           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
    1355           0 :             geometry_rectangle_destroy( &depart_area );
    1356             : 
    1357             :             geometry_rectangle_t arrive_area;
    1358           0 :             geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_right, dst_bottom );
    1359           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
    1360           0 :             geometry_rectangle_destroy( &arrive_area );
    1361             : 
    1362             :             /* add solution */
    1363           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1364             :                                                    src_x,
    1365             :                                                    src_top,
    1366             :                                                    dst_right,
    1367             :                                                    dst_y,
    1368             :                                                    dst_y
    1369             :                                                  );
    1370           0 :             solutions_count ++;
    1371             :         }
    1372             :         /* add a solution from source-top to destination-left */
    1373             :         {
    1374           0 :             const double search_left = src_left;
    1375           0 :             const double search_right = dst_left_from_outside ? fmin( dst_left, src_right ) : src_right;
    1376             : 
    1377             :             /* define defaults */
    1378           0 :             double src_x = ( search_left + search_right ) / 2.0;
    1379           0 :             double dst_y = ( search_top + search_bottom ) / 2.0;
    1380             : 
    1381             :             /* optimize coordinates */
    1382             :             geometry_rectangle_t depart_area;
    1383           0 :             geometry_rectangle_init_by_corners( &depart_area, src_left, src_top, src_right, dst_y );
    1384           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
    1385           0 :             geometry_rectangle_destroy( &depart_area );
    1386             : 
    1387             :             geometry_rectangle_t arrive_area;
    1388           0 :             geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_left, dst_bottom );
    1389           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
    1390           0 :             geometry_rectangle_destroy( &arrive_area );
    1391             : 
    1392             :             /* add solution */
    1393           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1394             :                                                    src_x,
    1395             :                                                    src_top,
    1396             :                                                    dst_left,
    1397             :                                                    dst_y,
    1398             :                                                    dst_y
    1399             :                                                  );
    1400           0 :             solutions_count ++;
    1401             :         }
    1402             :     }
    1403             : 
    1404             :     /* add two solutions from source-bottom */
    1405             :     {
    1406           0 :         const double search_top = src_bottom_to_outside ? fmax( src_bottom, dst_top ) : dst_top;
    1407           0 :         const double search_bottom = dst_bottom;
    1408             :         /* add a solution from source-bottom to destination-right */
    1409             :         {
    1410           0 :             const double search_left = dst_right_from_outside ? fmax( dst_right, src_left ) : src_left;
    1411           0 :             const double search_right = src_right;
    1412             : 
    1413             :             /* define defaults */
    1414           0 :             double src_x = ( search_left + search_right ) / 2.0;
    1415           0 :             double dst_y = ( search_top + search_bottom ) / 2.0;
    1416             : 
    1417             :             /* optimize coordinates */
    1418             :             geometry_rectangle_t depart_area;
    1419           0 :             geometry_rectangle_init_by_corners( &depart_area, src_left, src_bottom, src_right, dst_y );
    1420           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
    1421           0 :             geometry_rectangle_destroy( &depart_area );
    1422             : 
    1423             :             geometry_rectangle_t arrive_area;
    1424           0 :             geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_right, dst_bottom );
    1425           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
    1426           0 :             geometry_rectangle_destroy( &arrive_area );
    1427             : 
    1428             :             /* add solution */
    1429           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1430             :                                                    src_x,
    1431             :                                                    src_bottom,
    1432             :                                                    dst_right,
    1433             :                                                    dst_y,
    1434             :                                                    dst_y
    1435             :                                                  );
    1436           0 :             solutions_count ++;
    1437             :         }
    1438             :         /* add a solution from source-bottom to destination-left */
    1439             :         {
    1440           0 :             const double search_left = src_left;
    1441           0 :             const double search_right = dst_left_from_outside ? fmin( dst_left, src_right ) : src_right;
    1442             : 
    1443             :             /* define defaults */
    1444           0 :             double src_x = ( search_left + search_right ) / 2.0;
    1445           0 :             double dst_y = ( search_top + search_bottom ) / 2.0;
    1446             : 
    1447             :             /* optimize coordinates */
    1448             :             geometry_rectangle_t depart_area;
    1449           0 :             geometry_rectangle_init_by_corners( &depart_area, src_left, src_bottom, src_right, dst_y );
    1450           0 :             pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
    1451           0 :             geometry_rectangle_destroy( &depart_area );
    1452             : 
    1453             :             geometry_rectangle_t arrive_area;
    1454           0 :             geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_left, dst_bottom );
    1455           0 :             pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
    1456           0 :             geometry_rectangle_destroy( &arrive_area );
    1457             : 
    1458             :             /* add solution */
    1459           0 :             geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
    1460             :                                                    src_x,
    1461             :                                                    src_bottom,
    1462             :                                                    dst_left,
    1463             :                                                    dst_y,
    1464             :                                                    dst_y
    1465             :                                                  );
    1466           0 :             solutions_count ++;
    1467             :         }
    1468             :     }
    1469             : 
    1470           0 :     *out_solutions_count = solutions_count;
    1471             : 
    1472           0 :     U8_TRACE_END();
    1473           0 : }
    1474             : 
    1475           0 : u8_error_t pencil_relationship_2d_layouter_private_find_space_for_line ( pencil_relationship_2d_layouter_t *this_,
    1476             :                                                                          const geometry_rectangle_t *search_rect,
    1477             :                                                                          bool horizontal_line,
    1478             :                                                                          double min_gap,
    1479             :                                                                          double *io_coordinate )
    1480             : {
    1481           0 :     U8_TRACE_BEGIN();
    1482           0 :     assert( (*this_).sorted_rel_index < universal_array_index_sorter_get_count( &((*this_).sorted_relationships) ) );
    1483           0 :     assert ( NULL != search_rect );
    1484           0 :     assert ( NULL != io_coordinate );
    1485           0 :     u8_error_t err = U8_ERROR_NONE;
    1486             : 
    1487             :     /* start two probes at the center and move these to the boundaries when discovering overlaps */
    1488           0 :     const double center = *io_coordinate;
    1489           0 :     if ( horizontal_line )
    1490             :     {
    1491           0 :         assert( center > geometry_rectangle_get_top( search_rect ) - 0.000000001 );
    1492           0 :         assert( center < geometry_rectangle_get_bottom( search_rect ) + 0.000000001 );
    1493             :     }
    1494             :     else
    1495             :     {
    1496           0 :         assert( center > geometry_rectangle_get_left( search_rect ) - 0.000000001 );
    1497           0 :         assert( center < geometry_rectangle_get_right( search_rect ) + 0.000000001 );
    1498             :     }
    1499           0 :     double good_smaller = center;  /* a coordinate top/left of major obstacles */
    1500           0 :     double good_greater = center;  /* a coordinate bottom/right of major obstacles */
    1501           0 :     double best_smaller = center;  /* a coordinate top/left of any obstacle */
    1502           0 :     double best_greater = center;  /* a coordinate bottom/right of any obstacle */
    1503             : 
    1504             :     /* the rectangle where each classifier within is checked for intersections: */
    1505             :     geometry_rectangle_t consider_rect;
    1506           0 :     geometry_rectangle_copy( &consider_rect, search_rect );
    1507           0 :     if ( horizontal_line )
    1508             :     {
    1509           0 :         geometry_rectangle_set_top( &consider_rect, geometry_rectangle_get_top( search_rect ) - min_gap );
    1510           0 :         geometry_rectangle_set_height( &consider_rect, geometry_rectangle_get_height( search_rect ) + 2.0 * min_gap );
    1511             : 
    1512             :     }
    1513             :     else
    1514             :     {
    1515           0 :         geometry_rectangle_set_left( &consider_rect, geometry_rectangle_get_left( search_rect ) - min_gap );
    1516           0 :         geometry_rectangle_set_width( &consider_rect, geometry_rectangle_get_width( search_rect ) + 2.0 * min_gap );
    1517             :     }
    1518           0 :     const double minimum_result
    1519             :         = horizontal_line
    1520           0 :         ? geometry_rectangle_get_top( search_rect )
    1521           0 :         : geometry_rectangle_get_left( search_rect );
    1522           0 :     const double maximum_result
    1523             :         = horizontal_line
    1524           0 :         ? geometry_rectangle_get_bottom( search_rect )
    1525           0 :         : geometry_rectangle_get_right( search_rect );
    1526             : 
    1527             :     /* iterate till no hit anymore */
    1528           0 :     const uint32_t max_list_iteration = 8;  /* in any case, do not iterate ofer the list more than 8 times */
    1529           0 :     bool hit = true;  /* whenever the probes hit a rectangle, hit is set to true */
    1530           0 :     for ( uint32_t list_iteration = 0; (list_iteration < max_list_iteration) && hit; list_iteration ++ )
    1531             :     {
    1532           0 :         hit = false;
    1533             : 
    1534             :         /* move away from classifiers */
    1535           0 :         const uint32_t count_classifiers = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
    1536           0 :         for ( uint32_t classifier_index = 0; classifier_index < count_classifiers; classifier_index ++ )
    1537             :         {
    1538             :             const layout_visible_classifier_t *const the_classifier
    1539           0 :                 = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, classifier_index );
    1540             : 
    1541             :             const geometry_rectangle_t *const classifier_symbol_box
    1542           0 :                 = layout_visible_classifier_get_symbol_box_const( the_classifier );
    1543             :             const geometry_rectangle_t *const classifier_space
    1544           0 :                 = layout_visible_classifier_get_space_const( the_classifier );
    1545             :             /* Note: This algorithm ignores if the current classifier is parent container of source or destination */
    1546           0 :             if ( geometry_rectangle_is_intersecting( &consider_rect, classifier_symbol_box ) )
    1547             :             {
    1548           0 :                 const double clas_symbol_box_smaller
    1549             :                     = horizontal_line /* do vertical search if line is horizontal */
    1550           0 :                     ? ( geometry_rectangle_get_top(classifier_symbol_box) - min_gap )
    1551           0 :                     : ( geometry_rectangle_get_left(classifier_symbol_box) - min_gap );
    1552           0 :                 const double clas_symbol_box_greater
    1553             :                     = horizontal_line /* do vertical search if line is horizontal */
    1554           0 :                     ? ( geometry_rectangle_get_bottom(classifier_symbol_box) + min_gap )
    1555           0 :                     : ( geometry_rectangle_get_right(classifier_symbol_box) + min_gap );
    1556             : 
    1557           0 :                 const double undo_good_smaller = good_smaller;
    1558           0 :                 const double undo_good_greater = good_greater;
    1559           0 :                 const bool undo_hit = hit;
    1560           0 :                 const geometry_rectangle_t good_smaller_rect
    1561           0 :                     = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : good_smaller,
    1562           0 :                         .top = horizontal_line ? good_smaller : geometry_rectangle_get_top( search_rect ),
    1563           0 :                         .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
    1564           0 :                         .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
    1565             :                     };
    1566           0 :                 if ( ( ! geometry_rectangle_is_containing( classifier_space, &good_smaller_rect ) )
    1567           0 :                     && ( clas_symbol_box_smaller < good_smaller ) && ( good_smaller < clas_symbol_box_greater ) )
    1568             :                 {
    1569           0 :                     good_smaller = clas_symbol_box_smaller;
    1570           0 :                     hit = true;
    1571             :                 }
    1572           0 :                 const geometry_rectangle_t good_greater_rect
    1573           0 :                     = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : good_greater,
    1574           0 :                         .top = horizontal_line ? good_greater : geometry_rectangle_get_top( search_rect ),
    1575           0 :                         .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
    1576           0 :                         .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
    1577             :                     };
    1578           0 :                 if ( ( ! geometry_rectangle_is_containing( classifier_space, &good_greater_rect ) )
    1579           0 :                     && ( clas_symbol_box_smaller < good_greater ) && ( good_greater < clas_symbol_box_greater ) )
    1580             :                 {
    1581           0 :                     good_greater = clas_symbol_box_greater;
    1582           0 :                     hit = true;
    1583             :                 }
    1584           0 :                 const bool no_solution_remaining
    1585           0 :                     = ( good_smaller < minimum_result )&&( good_greater > maximum_result );
    1586           0 :                 if ( no_solution_remaining )
    1587             :                 {
    1588             :                     /* restore old values */
    1589           0 :                     good_smaller = undo_good_smaller;
    1590           0 :                     good_greater = undo_good_greater;
    1591           0 :                     hit = undo_hit;
    1592             :                 }
    1593           0 :                 const geometry_rectangle_t best_smaller_rect
    1594           0 :                     = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : best_smaller,
    1595           0 :                         .top = horizontal_line ? best_smaller : geometry_rectangle_get_top( search_rect ),
    1596           0 :                         .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
    1597           0 :                         .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
    1598             :                     };
    1599           0 :                 if ( ( ! geometry_rectangle_is_containing( classifier_space, &best_smaller_rect ) )
    1600           0 :                     && ( clas_symbol_box_smaller < best_smaller ) && ( best_smaller < clas_symbol_box_greater ) )
    1601             :                 {
    1602           0 :                     best_smaller = clas_symbol_box_smaller;
    1603           0 :                     hit = true;
    1604             :                 }
    1605           0 :                 const geometry_rectangle_t best_greater_rect
    1606           0 :                     = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : best_greater,
    1607           0 :                         .top = horizontal_line ? best_greater : geometry_rectangle_get_top( search_rect ),
    1608           0 :                         .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
    1609           0 :                         .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
    1610             :                     };
    1611           0 :                 if ( ( ! geometry_rectangle_is_containing( classifier_space, &best_greater_rect ) )
    1612           0 :                     && ( clas_symbol_box_smaller < best_greater ) && ( best_greater < clas_symbol_box_greater ) )
    1613             :                 {
    1614           0 :                     best_greater = clas_symbol_box_greater;
    1615           0 :                     hit = true;
    1616             :                 }
    1617             :             }
    1618             : 
    1619             :             const geometry_rectangle_t *const classifier_label_box
    1620           0 :                 = layout_visible_classifier_get_label_box_const( the_classifier );
    1621           0 :             if ( geometry_rectangle_is_intersecting( &consider_rect, classifier_label_box ) )
    1622             :             {
    1623           0 :                 const double clas_label_smaller
    1624             :                     = horizontal_line /* do vertical search if line is horizontal */
    1625           0 :                     ? ( geometry_rectangle_get_top(classifier_label_box) - min_gap )
    1626           0 :                     : ( geometry_rectangle_get_left(classifier_label_box) - min_gap );
    1627           0 :                 const double clas_label_greater
    1628             :                     = horizontal_line /* do vertical search if line is horizontal */
    1629           0 :                     ? ( geometry_rectangle_get_bottom(classifier_label_box) + min_gap )
    1630           0 :                     : ( geometry_rectangle_get_right(classifier_label_box) + min_gap );
    1631             : 
    1632           0 :                 if ( ( clas_label_smaller < good_smaller ) && ( good_smaller < clas_label_greater ) )
    1633             :                 {
    1634           0 :                     good_smaller = clas_label_smaller;
    1635           0 :                     hit = true;
    1636             :                 }
    1637           0 :                 if ( ( clas_label_smaller < good_greater ) && ( good_greater < clas_label_greater ) )
    1638             :                 {
    1639           0 :                     good_greater = clas_label_greater;
    1640           0 :                     hit = true;
    1641             :                 }
    1642           0 :                 if ( ( clas_label_smaller < best_smaller ) && ( best_smaller < clas_label_greater ) )
    1643             :                 {
    1644           0 :                     best_smaller = clas_label_smaller;
    1645           0 :                     hit = true;
    1646             :                 }
    1647           0 :                 if ( ( clas_label_smaller < best_greater ) && ( best_greater < clas_label_greater ) )
    1648             :                 {
    1649           0 :                     best_greater = clas_label_greater;
    1650           0 :                     hit = true;
    1651             :                 }
    1652             :             }
    1653             :         }
    1654             : 
    1655             :         /* move away from features, check symbol boxes only, label boxes are not yet initialized */
    1656           0 :         const uint32_t count_features = layout_visible_set_get_feature_count ( (*this_).layout_data );
    1657           0 :         for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
    1658             :         {
    1659             :             const layout_feature_t *const feature_layout
    1660           0 :                 = layout_visible_set_get_feature_ptr ( (*this_).layout_data, f_idx );
    1661             : 
    1662             :             const geometry_rectangle_t *const feature_symbol_box
    1663           0 :                 = layout_feature_get_symbol_box_const( feature_layout );
    1664           0 :             if ( geometry_rectangle_is_intersecting( &consider_rect, feature_symbol_box ) )
    1665             :             {
    1666           0 :                 const double feature_smaller
    1667             :                     = horizontal_line /* do vertical search if line is horizontal */
    1668           0 :                     ? ( geometry_rectangle_get_top(feature_symbol_box) - min_gap )
    1669           0 :                     : ( geometry_rectangle_get_left(feature_symbol_box) - min_gap );
    1670           0 :                 const double feature_greater
    1671             :                     = horizontal_line /* do vertical search if line is horizontal */
    1672           0 :                     ? ( geometry_rectangle_get_bottom(feature_symbol_box) + min_gap )
    1673           0 :                     : ( geometry_rectangle_get_right(feature_symbol_box) + min_gap );
    1674             : 
    1675           0 :                 if ( ( feature_smaller < good_smaller ) && ( good_smaller < feature_greater ) )
    1676             :                 {
    1677           0 :                     good_smaller = feature_smaller;
    1678           0 :                     hit = true;
    1679             :                 }
    1680           0 :                 if ( ( feature_smaller < good_greater ) && ( good_greater < feature_greater ) )
    1681             :                 {
    1682           0 :                     good_greater = feature_greater;
    1683           0 :                     hit = true;
    1684             :                 }
    1685           0 :                 if ( ( feature_smaller < best_smaller ) && ( best_smaller < feature_greater ) )
    1686             :                 {
    1687           0 :                     best_smaller = feature_smaller;
    1688           0 :                     hit = true;
    1689             :                 }
    1690           0 :                 if ( ( feature_smaller < best_greater ) && ( best_greater < feature_greater ) )
    1691             :                 {
    1692           0 :                     best_greater = feature_greater;
    1693           0 :                     hit = true;
    1694             :                 }
    1695             :             }
    1696             :         }
    1697             : 
    1698             :         /* move away from already layed-out parallel relationship-segments; */
    1699             :         /* already done: exist_sort_index < (*this_).sorted_rel_index */
    1700           0 :         for ( uint32_t exist_sort_index = 0; ( exist_sort_index < (*this_).sorted_rel_index ); exist_sort_index ++ )
    1701             :         {
    1702             :             const uint32_t exist_index
    1703           0 :                 = universal_array_index_sorter_get_array_index( &((*this_).sorted_relationships), exist_sort_index );
    1704             :             const layout_relationship_t *const exist_relationship
    1705           0 :                 = layout_visible_set_get_relationship_ptr( (*this_).layout_data, exist_index );
    1706             :             /* Note: This algorithm ignores the relationship types (same_type), sources and destinations (one_same_end) */
    1707             : 
    1708           0 :             const geometry_connector_t *const exist_shape = layout_relationship_get_shape_const( exist_relationship );
    1709           0 :             if ( geometry_connector_is_intersecting_rectangle( exist_shape, &consider_rect ) )
    1710             :             {
    1711             :                 const geometry_rectangle_t seg_1
    1712           0 :                     = geometry_connector_get_segment_bounds( exist_shape, GEOMETRY_CONNECTOR_SEGMENT_SOURCE );
    1713             :                 const bool seg_1_is_intersecting
    1714           0 :                     = geometry_rectangle_is_intersecting( &seg_1, &consider_rect );
    1715           0 :                 const double seg_1_smaller
    1716             :                     = horizontal_line /* do vertical search if line is horizontal */
    1717           0 :                     ? ( geometry_rectangle_get_top( &seg_1 ) - min_gap )
    1718           0 :                     : ( geometry_rectangle_get_left( &seg_1 ) - min_gap );
    1719           0 :                 const double seg_1_greater
    1720             :                     = horizontal_line /* do vertical search if line is horizontal */
    1721           0 :                     ? ( geometry_rectangle_get_bottom( &seg_1 ) + min_gap )
    1722           0 :                     : ( geometry_rectangle_get_right( &seg_1 ) + min_gap );
    1723           0 :                 if ( seg_1_is_intersecting
    1724           0 :                     && ( seg_1_smaller < best_smaller ) && ( best_smaller < seg_1_greater ) )
    1725             :                 {
    1726           0 :                     best_smaller = seg_1_smaller;
    1727           0 :                     hit = true;
    1728             :                 }
    1729           0 :                 if ( seg_1_is_intersecting
    1730           0 :                     && ( seg_1_smaller < best_greater ) && ( best_greater < seg_1_greater ) )
    1731             :                 {
    1732           0 :                     best_greater = seg_1_greater;
    1733           0 :                     hit = true;
    1734             :                 }
    1735             :                 const geometry_rectangle_t seg_2
    1736           0 :                     = geometry_connector_get_segment_bounds( exist_shape, GEOMETRY_CONNECTOR_SEGMENT_MAIN );
    1737             :                 const bool seg_2_is_intersecting
    1738           0 :                     = geometry_rectangle_is_intersecting( &seg_2, &consider_rect );
    1739           0 :                 const double seg_2_smaller
    1740             :                     = horizontal_line /* do vertical search if line is horizontal */
    1741           0 :                     ? ( geometry_rectangle_get_top( &seg_2 ) - min_gap )
    1742           0 :                     : ( geometry_rectangle_get_left( &seg_2 ) - min_gap );
    1743           0 :                 const double seg_2_greater
    1744             :                     = horizontal_line /* do vertical search if line is horizontal */
    1745           0 :                     ? ( geometry_rectangle_get_bottom( &seg_2 ) + min_gap )
    1746           0 :                     : ( geometry_rectangle_get_right( &seg_2 ) + min_gap );
    1747           0 :                 if ( seg_2_is_intersecting
    1748           0 :                     && ( seg_2_smaller < best_smaller ) && ( best_smaller < seg_2_greater ) )
    1749             :                 {
    1750           0 :                     best_smaller = seg_2_smaller;
    1751           0 :                     hit = true;
    1752             :                 }
    1753           0 :                 if ( seg_2_is_intersecting
    1754           0 :                     && ( seg_2_smaller < best_greater ) && ( best_greater < seg_2_greater ) )
    1755             :                 {
    1756           0 :                     best_greater = seg_2_greater;
    1757           0 :                     hit = true;
    1758             :                 }
    1759             :                 const geometry_rectangle_t seg_3
    1760           0 :                     = geometry_connector_get_segment_bounds( exist_shape, GEOMETRY_CONNECTOR_SEGMENT_DESTINATION );
    1761             :                 const bool seg_3_is_intersecting
    1762           0 :                     = geometry_rectangle_is_intersecting( &seg_3, &consider_rect );
    1763           0 :                 const double seg_3_smaller
    1764             :                     = horizontal_line /* do vertical search if line is horizontal */
    1765           0 :                     ? ( geometry_rectangle_get_top( &seg_3 ) - min_gap )
    1766           0 :                     : ( geometry_rectangle_get_left( &seg_3 ) - min_gap );
    1767           0 :                 const double seg_3_greater
    1768             :                     = horizontal_line /* do vertical search if line is horizontal */
    1769           0 :                     ? ( geometry_rectangle_get_bottom( &seg_3 ) + min_gap )
    1770           0 :                     : ( geometry_rectangle_get_right( &seg_3 ) + min_gap );
    1771           0 :                 if ( seg_3_is_intersecting
    1772           0 :                     && ( seg_3_smaller < best_smaller ) && ( best_smaller < seg_3_greater ) )
    1773             :                 {
    1774           0 :                     best_smaller = seg_3_smaller;
    1775           0 :                     hit = true;
    1776             :                 }
    1777           0 :                 if ( seg_3_is_intersecting
    1778           0 :                     && ( seg_3_smaller < best_greater ) && ( best_greater < seg_3_greater ) )
    1779             :                 {
    1780           0 :                     best_greater = seg_3_greater;
    1781           0 :                     hit = true;
    1782             :                 }
    1783             : 
    1784           0 :                 const geometry_3dir_t exist_dirs = geometry_connector_get_directions( exist_shape );
    1785           0 :                 if ( horizontal_line )
    1786             :                 {
    1787           0 :                     const double exist_source_y = geometry_connector_get_main_line_source_y ( exist_shape );
    1788           0 :                     const double exist_destination_y = geometry_connector_get_main_line_destination_y ( exist_shape );
    1789           0 :                     if ( geometry_3dir_is_first_h( &exist_dirs ) || geometry_3dir_is_second_h( &exist_dirs ) )
    1790             :                     {
    1791           0 :                         if (( exist_source_y - min_gap < good_smaller )&&( good_smaller < exist_source_y + min_gap ))
    1792             :                         {
    1793           0 :                             good_smaller = exist_source_y - min_gap;
    1794           0 :                             hit = true;
    1795             :                         }
    1796           0 :                         if (( exist_source_y - min_gap < good_greater )&&( good_greater < exist_source_y + min_gap ))
    1797             :                         {
    1798           0 :                             good_greater = exist_source_y + min_gap;
    1799           0 :                             hit = true;
    1800             :                         }
    1801             :                     }
    1802           0 :                     if ( geometry_3dir_is_third_h( &exist_dirs ) ) /* third segment only, second is already evaluated above */
    1803             :                     {
    1804           0 :                         if (( exist_destination_y - min_gap < good_smaller )&&( good_smaller < exist_destination_y + min_gap ))
    1805             :                         {
    1806           0 :                             good_smaller = exist_destination_y - min_gap;
    1807           0 :                             hit = true;
    1808             :                         }
    1809           0 :                         if (( exist_destination_y - min_gap < good_greater )&&( good_greater < exist_destination_y + min_gap ))
    1810             :                         {
    1811           0 :                             good_greater = exist_destination_y + min_gap;
    1812           0 :                             hit = true;
    1813             :                         }
    1814             :                     }
    1815             :                 }
    1816             :                 else
    1817             :                 {
    1818           0 :                     const double exist_source_x = geometry_connector_get_main_line_source_x ( exist_shape );
    1819           0 :                     const double exist_destination_x = geometry_connector_get_main_line_destination_x ( exist_shape );
    1820           0 :                     if ( geometry_3dir_is_first_v( &exist_dirs ) || geometry_3dir_is_second_v( &exist_dirs ) )
    1821             :                     {
    1822           0 :                         if (( exist_source_x - min_gap < good_smaller )&&( good_smaller < exist_source_x + min_gap ))
    1823             :                         {
    1824           0 :                             good_smaller = exist_source_x - min_gap;
    1825           0 :                             hit = true;
    1826             :                         }
    1827           0 :                         if (( exist_source_x - min_gap < good_greater )&&( good_greater < exist_source_x + min_gap ))
    1828             :                         {
    1829           0 :                             good_greater = exist_source_x + min_gap;
    1830           0 :                             hit = true;
    1831             :                         }
    1832             :                     }
    1833           0 :                     if ( geometry_3dir_is_third_v( &exist_dirs ) ) /* third segment only, second is already evaluated above */
    1834             :                     {
    1835           0 :                         if (( exist_destination_x - min_gap < good_smaller )&&( good_smaller < exist_destination_x + min_gap ))
    1836             :                         {
    1837           0 :                             good_smaller = exist_destination_x - min_gap;
    1838           0 :                             hit = true;
    1839             :                         }
    1840           0 :                         if (( exist_destination_x - min_gap < good_greater )&&( good_greater < exist_destination_x + min_gap ))
    1841             :                         {
    1842           0 :                             good_greater = exist_destination_x + min_gap;
    1843           0 :                             hit = true;
    1844             :                         }
    1845             :                     }
    1846             :                 }
    1847             :             }
    1848             :         }
    1849             :     }
    1850             : 
    1851             :     /* check success */
    1852           0 :     if ( best_greater < maximum_result )
    1853             :     {
    1854           0 :         if ( best_smaller > minimum_result )
    1855             :         {
    1856             :             /* best_greater and best_smaller are both in range; */
    1857             :             /* select the one with smaller distance to the center: */
    1858           0 :             if ( best_greater - center > center - best_smaller )
    1859             :             {
    1860           0 :                 *io_coordinate = best_smaller;
    1861             :             }
    1862             :             else
    1863             :             {
    1864           0 :                 *io_coordinate = best_greater;
    1865             :             }
    1866             :         }
    1867             :         else  /* best_greater is in range */
    1868             :         {
    1869           0 :             *io_coordinate = best_greater;
    1870             :         }
    1871             :     }
    1872             :     else
    1873             :     {
    1874           0 :         if ( best_smaller > minimum_result )
    1875             :         {
    1876             :             /* best_smaller is in range */
    1877           0 :             *io_coordinate = best_smaller;
    1878             :         }
    1879             :         else
    1880             :         {
    1881             :             /* BOTH BEST VALUES ARE OUT OF RANGE */
    1882             :             /* CHECK GOOD VALUES: */
    1883           0 :             if ( good_greater > maximum_result )
    1884             :             {
    1885           0 :                 if ( good_smaller < minimum_result )
    1886             :                 {
    1887           0 :                     err = U8_ERROR_NOT_FOUND;
    1888             :                 }
    1889             :                 else  /* good_smaller is in range */
    1890             :                 {
    1891           0 :                     *io_coordinate = good_smaller;
    1892             :                 }
    1893             :             }
    1894             :             else  /* good_greater is in range */
    1895             :             {
    1896           0 :                 if ( good_smaller < minimum_result )
    1897             :                 {
    1898           0 :                     *io_coordinate = good_greater;
    1899             :                 }
    1900             :                 else
    1901             :                 {
    1902             :                     /* good_smaller and good_greater are both in range; */
    1903             :                     /* select the one with smaller distance to the center: */
    1904           0 :                     if ( good_greater - center > center - good_smaller )
    1905             :                     {
    1906           0 :                         *io_coordinate = good_smaller;
    1907             :                     }
    1908             :                     else
    1909             :                     {
    1910           0 :                         *io_coordinate = good_greater;
    1911             :                     }
    1912             :                 }
    1913             :             }
    1914             :         }
    1915             :     }
    1916             : 
    1917           0 :     geometry_rectangle_destroy( &consider_rect );
    1918             : 
    1919           0 :     U8_TRACE_END_ERR(err);
    1920           0 :     return err;
    1921             : }
    1922             : 
    1923           0 : void pencil_relationship_2d_layouter_private_make_all_visible ( pencil_relationship_2d_layouter_t *this_ )
    1924             : {
    1925           0 :     U8_TRACE_BEGIN();
    1926             : 
    1927             :     /* determine visibility */
    1928           0 :     const uint32_t count_relations = layout_visible_set_get_relationship_count ( (*this_).layout_data );
    1929           0 :     for ( uint32_t index = 0; index < count_relations; index ++ )
    1930             :     {
    1931           0 :         layout_relationship_t *const the_relation = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
    1932           0 :         const layout_visible_classifier_t *const from_layout = layout_relationship_get_from_classifier_ptr ( the_relation );
    1933           0 :         const layout_visible_classifier_t *const to_layout = layout_relationship_get_to_classifier_ptr ( the_relation );
    1934           0 :         assert( from_layout != NULL );
    1935           0 :         assert( to_layout != NULL );
    1936           0 :         const data_visible_classifier_t *const from_data = layout_visible_classifier_get_data_const( from_layout );
    1937           0 :         const data_visible_classifier_t *const to_data = layout_visible_classifier_get_data_const( to_layout );
    1938           0 :         const data_diagramelement_t *const from_diagele = data_visible_classifier_get_diagramelement_const( from_data );
    1939           0 :         const data_diagramelement_t *const to_diagele = data_visible_classifier_get_diagramelement_const( to_data );
    1940           0 :         const data_diagramelement_flag_t from_flags = data_diagramelement_get_display_flags ( from_diagele );
    1941           0 :         const data_diagramelement_flag_t to_flags = data_diagramelement_get_display_flags ( to_diagele );
    1942           0 :         if (( 0 != ( DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT & from_flags ))
    1943           0 :             || ( 0 != ( DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT & to_flags )))
    1944             :         {
    1945           0 :             layout_relationship_set_visibility ( the_relation, PENCIL_VISIBILITY_GRAY_OUT );
    1946             :         }
    1947             :         else
    1948             :         {
    1949           0 :             layout_relationship_set_visibility ( the_relation, PENCIL_VISIBILITY_SHOW );
    1950             :         }
    1951             :     }
    1952             : 
    1953           0 :     U8_TRACE_END();
    1954           0 : }
    1955             : 
    1956           0 : void pencil_relationship_2d_layouter_layout_standard( pencil_relationship_2d_layouter_t *this_ )
    1957             : {
    1958           0 :     U8_TRACE_BEGIN();
    1959             : 
    1960           0 :     pencil_relationship_2d_layouter_private_make_all_visible( this_ );
    1961             : 
    1962           0 :     pencil_relationship_2d_layouter_private_do_layout ( this_ );
    1963             : 
    1964           0 :     U8_TRACE_END();
    1965           0 : }
    1966             : 
    1967           0 : void pencil_relationship_2d_layouter_layout_void( pencil_relationship_2d_layouter_t *this_ )
    1968             : {
    1969           0 :     U8_TRACE_BEGIN();
    1970             : 
    1971             :     /* hide all relationships */
    1972             :     const uint32_t count_relations
    1973           0 :         = layout_visible_set_get_relationship_count ( (*this_).layout_data );
    1974           0 :     for ( uint32_t index = 0; index < count_relations; index ++ )
    1975             :     {
    1976             :         /*
    1977             :         layout_visible_set_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_HIDE );
    1978             :         */
    1979           0 :         layout_visible_set_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT );
    1980             :     }
    1981             : 
    1982             :     /* layout the relationships (needed for PENCIL_VISIBILITY_IMPLICIT) */
    1983           0 :     pencil_relationship_2d_layouter_private_do_layout ( this_ );
    1984             : 
    1985           0 :     U8_TRACE_END();
    1986           0 : }
    1987             : 
    1988           0 : void pencil_relationship_2d_layouter_layout_for_communication( pencil_relationship_2d_layouter_t *this_ )
    1989             : {
    1990           0 :     U8_TRACE_BEGIN();
    1991             : 
    1992           0 :     pencil_relationship_2d_layouter_private_make_all_visible( this_ );
    1993             : 
    1994             :     /* hide some relationships */
    1995             :     const uint32_t count_relations
    1996           0 :         = layout_visible_set_get_relationship_count ( (*this_).layout_data );
    1997           0 :     for ( uint32_t index = 0; index < count_relations; index ++ )
    1998             :     {
    1999             :         layout_relationship_t *const the_relationship
    2000           0 :             = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
    2001             : 
    2002             :         /* adjust visibility */
    2003           0 :         if ( ( NULL == layout_relationship_get_from_feature_ptr ( the_relationship ) )
    2004           0 :             && ( NULL == layout_relationship_get_to_feature_ptr ( the_relationship ) ) )
    2005             :         {
    2006             :             /* this is a globally visible relation, not local/scenario-based */
    2007           0 :             layout_visible_set_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT );
    2008             :         }
    2009             :     }
    2010             : 
    2011             :     /* layout the visible relationships */
    2012           0 :     pencil_relationship_2d_layouter_private_do_layout ( this_ );
    2013             : 
    2014           0 :     U8_TRACE_END();
    2015           0 : }
    2016             : 
    2017             : 
    2018             : /*
    2019             : Copyright 2017-2024 Andreas Warnke
    2020             : 
    2021             : Licensed under the Apache License, Version 2.0 (the "License");
    2022             : you may not use this file except in compliance with the License.
    2023             : You may obtain a copy of the License at
    2024             : 
    2025             :     http://www.apache.org/licenses/LICENSE-2.0
    2026             : 
    2027             : Unless required by applicable law or agreed to in writing, software
    2028             : distributed under the License is distributed on an "AS IS" BASIS,
    2029             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    2030             : See the License for the specific language governing permissions and
    2031             : limitations under the License.
    2032             : */

Generated by: LCOV version 1.16