LCOV - code coverage report
Current view: top level - pencil/include/layout - layout_quality.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.67.3_covts Lines: 0.0 % 213 0
Test Date: 2025-12-11 19:53:47 Functions: 0.0 % 12 0

            Line data    Source code
       1              : /* File: layout_quality.inl; Copyright and License: see below */
       2              : 
       3              : #include "u8/u8_trace.h"
       4              : 
       5            0 : static inline void layout_quality_init ( layout_quality_t *this_, const pencil_size_t *pencil_size )
       6              : {
       7            0 :     (*this_).pencil_size = pencil_size;
       8            0 : }
       9              : 
      10            0 : static inline layout_quality_t layout_quality_new ( const pencil_size_t *pencil_size )
      11              : {
      12              :     layout_quality_t result;
      13            0 :     layout_quality_init( &result, pencil_size );
      14            0 :     return result;
      15              : }
      16              : 
      17              : static inline void layout_quality_destroy ( layout_quality_t *this_ )
      18              : {
      19              : }
      20              : 
      21              : /* NO-GOs */
      22              : 
      23              : /* if an object is forbidden (e.g. german swastika): */
      24              : #define LAYOUT_QUALITY_WEIGHT_FORBIDDEN (1000000.0)
      25              : /* if an object is not fully contained in the diagrams drawing area: */
      26              : #define LAYOUT_QUALITY_WEIGHT_NOT_IN_DIAGRAM_AREA (1000.0)
      27              : 
      28              : /* OVERLAPS */
      29              : 
      30              : /* if an objects label or type-icon crosses another objects label or type-icon: */
      31              : #define LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP (100.0)
      32              : /* if an objects label or type-icon crosses another objects contour or connection line: */
      33              : #define LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE (10.0)
      34              : /* if an objects contour or connection line is shared with another objects contour or connection line: */
      35              : #define LAYOUT_QUALITY_WEIGHT_SHARED_LINES (10.0)
      36              : /* if an objects contour or connection line crosses another objects contour or connection line: */
      37              : #define LAYOUT_QUALITY_WEIGHT_CROSS_LINES (10.0)
      38              : /* if an objects contour or connection line crosses another objects envelope-area: */
      39              : #define LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA (5.0)
      40              : /* if an objects envelope-area crosses another objects envelope-area: */
      41              : #define LAYOUT_QUALITY_WEIGHT_CROSS_AREAS (1.0)
      42              : 
      43              : /* SUBOPTIMAL LOCATIONS OR DISTANCES */
      44              : 
      45              : /* if an object shall be avoided to find nice solutions and not run into a local layouting optimum that is forbidden: */
      46              : #define LAYOUT_QUALITY_WEIGHT_AVOID (10.0)
      47              : /* if a location is not nice (too short line segment, too far from source or target): */
      48              : #define LAYOUT_QUALITY_WEIGHT_LOCATION (3.0)
      49              : /* if an objects contour, label or type-icon is too far from the target location or a connection line is longer than needed: */
      50              : #define LAYOUT_QUALITY_WEIGHT_DISTANCE (1.0)
      51              : 
      52            0 : static inline double layout_quality_debts_class_diag( const layout_quality_t *this_,
      53              :                                                       const layout_visible_classifier_t *probe,
      54              :                                                       const geometry_offset_t *order_target,
      55              :                                                       const layout_diagram_t *other )
      56              : {
      57            0 :     double debts = 0.0;
      58              : 
      59              :     const geometry_rectangle_t *const diagram_draw_area
      60            0 :         = layout_diagram_get_draw_area_const( other );
      61              : 
      62              :     const geometry_rectangle_t *const classifier_bounds
      63            0 :         = layout_visible_classifier_get_envelope_box_const( probe );
      64              : 
      65              :     /* add debts for overlap to diagram boundary */
      66            0 :     if ( ! geometry_rectangle_is_containing( diagram_draw_area, classifier_bounds ) )
      67              :     {
      68              :         /* it does not matter how big a classifier is - being outside is a high debt: */
      69            0 :         debts += LAYOUT_QUALITY_WEIGHT_NOT_IN_DIAGRAM_AREA * geometry_rectangle_get_area ( diagram_draw_area );
      70              :     }
      71              : 
      72              :     /* add move distance as debt */
      73            0 :     debts += LAYOUT_QUALITY_WEIGHT_LOCATION * fabs( geometry_offset_get_dx( order_target ) );
      74            0 :     debts += LAYOUT_QUALITY_WEIGHT_LOCATION * fabs( geometry_offset_get_dy( order_target ) );
      75              : 
      76            0 :     return debts;
      77              : }
      78              : 
      79            0 : static inline double layout_quality_debts_class_class( const layout_quality_t *this_,
      80              :                                                        const layout_visible_classifier_t *probe,
      81              :                                                        const layout_visible_classifier_t *other,
      82              :                                                        const layout_visible_set_t *layout_data )
      83              : {
      84            0 :     double debts = 0.0;
      85              : 
      86              :     const geometry_rectangle_t *const probe_symbol_box
      87            0 :         = layout_visible_classifier_get_symbol_box_const( probe );
      88              :     const geometry_rectangle_t *const other_symbol_box
      89            0 :         = layout_visible_classifier_get_symbol_box_const( other );
      90              : 
      91              :     geometry_rectangle_t probe_intersect;
      92              :     const int intersect_err
      93            0 :         = geometry_rectangle_init_by_intersect( &probe_intersect, probe_symbol_box, other_symbol_box );
      94            0 :     if ( 0 == intersect_err )
      95              :     {
      96              :         /* there is an intersect */
      97            0 :         if ( layout_visible_set_is_ancestor( layout_data, probe, other ) )
      98              :         {
      99              :             /* no debt: parent my overlap children */
     100              :         }
     101            0 :         else if ( layout_visible_set_is_ancestor( layout_data, other, probe ) )
     102              :         {
     103              :             /* no debt: child may overlap parent */
     104              :         }
     105              :         else
     106              :         {
     107            0 :             const double probe_intersect_area = geometry_rectangle_get_area ( &probe_intersect );
     108            0 :             debts += LAYOUT_QUALITY_WEIGHT_CROSS_AREAS * probe_intersect_area;
     109              :         }
     110              :     }
     111              :     /* else no intersect/overlap of symbol box */
     112              : 
     113              :     /* independant of relationship between classifiers, overlapping labels are not good */
     114              :     const geometry_rectangle_t *const probe_icon_box
     115            0 :         = layout_visible_classifier_get_icon_box_const( probe );
     116              :     const geometry_rectangle_t *const probe_label_box
     117            0 :         = layout_visible_classifier_get_label_box_const( probe );
     118            0 :     debts += layout_quality_debts_label_class( this_, probe_icon_box, other );
     119            0 :     debts += layout_quality_debts_label_class( this_, probe_label_box, other );
     120              : 
     121            0 :     return debts;
     122              : }
     123              : 
     124              : static const geometry_3dir_t LAYOUT_QUALITY_BAD_V_PATTERN1
     125              :     = { .first = GEOMETRY_DIRECTION_LEFT,  .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_LEFT };
     126              : static const geometry_3dir_t LAYOUT_QUALITY_BAD_V_PATTERN2
     127              :     = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_RIGHT };
     128              : static const geometry_3dir_t LAYOUT_QUALITY_BAD_H_PATTERN1
     129              :     = { .first = GEOMETRY_DIRECTION_DOWN,  .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
     130              : static const geometry_3dir_t LAYOUT_QUALITY_BAD_H_PATTERN2
     131              :     = { .first = GEOMETRY_DIRECTION_UP,    .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_UP };
     132              : 
     133            0 : static inline double layout_quality_debts_conn_diag( const layout_quality_t *this_,
     134              :                                                      const geometry_connector_t *probe,
     135              :                                                      const geometry_rectangle_t *source_rect,
     136              :                                                      const geometry_rectangle_t *dest_rect,
     137              :                                                      const layout_diagram_t *other )
     138              : {
     139            0 :     double debts = 0.0;
     140              : 
     141              :     /* get information on probe */
     142              :     const geometry_rectangle_t connector_bounds
     143            0 :         = geometry_connector_get_bounding_rectangle( probe );
     144            0 :     const double length = geometry_connector_get_length( probe );
     145              : 
     146              :     /* get information on expected source and destination */
     147            0 :     const double src_center_x = geometry_rectangle_get_center_x ( source_rect );
     148            0 :     const double src_center_y = geometry_rectangle_get_center_y ( source_rect );
     149            0 :     const double dst_center_x = geometry_rectangle_get_center_x ( dest_rect );
     150            0 :     const double dst_center_y = geometry_rectangle_get_center_y ( dest_rect );
     151              : 
     152              :     /* get draw area */
     153              :     const geometry_rectangle_t *const diagram_draw_area
     154            0 :         = layout_diagram_get_draw_area_const( other );
     155            0 :     const double diagram_draw_center_x = geometry_rectangle_get_center_x( diagram_draw_area );
     156            0 :     const double diagram_draw_center_y = geometry_rectangle_get_center_y( diagram_draw_area );
     157              : 
     158              :     /* get preferred object distance and line-corrdor width */
     159            0 :     const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     160            0 :     const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     161              : 
     162              :     /* add debts for exceeding the diagram draw area */
     163            0 :     if ( ! geometry_rectangle_is_containing( diagram_draw_area, &connector_bounds ) )
     164              :     {
     165              :         /* high debt */
     166            0 :         debts += LAYOUT_QUALITY_WEIGHT_NOT_IN_DIAGRAM_AREA * geometry_rectangle_get_area(diagram_draw_area);
     167              :     }
     168              : 
     169              :     /* the more length, the more unwanted... */
     170            0 :     debts += LAYOUT_QUALITY_WEIGHT_DISTANCE * length * line_corridor;
     171              : 
     172              :     /* prefer _either_ no _or_ minimum-dist lengths of parts, otherwise line too close to object... */
     173            0 :     const double source_length = geometry_connector_get_source_length( probe );
     174            0 :     if (( source_length > 0.000001 )&&( source_length < object_dist ))
     175              :     {
     176            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * ( object_dist - source_length ) * line_corridor;
     177              : 
     178              :     }
     179            0 :     const double destination_length = geometry_connector_get_destination_length( probe );
     180            0 :     if (( destination_length > 0.000001 )&&( destination_length < object_dist ))
     181              :     {
     182            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * ( object_dist - destination_length ) * line_corridor;
     183              :     }
     184              :     /* prefer _either_ no _or_ minimum-dist lengths of main if only one of of source and dest exists */
     185            0 :     const bool no_source_or_no_dest = ( source_length < 0.000001 )||( destination_length < 0.000001 );
     186            0 :     const double main_length = geometry_connector_get_main_length( probe );
     187            0 :     if (( main_length > 0.000001 )&&( main_length < object_dist )&&( no_source_or_no_dest ))
     188              :     {
     189            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * ( object_dist - main_length ) * line_corridor;
     190              :     }
     191              : 
     192              :     /* if the object distance is too low, prefer a detour */
     193            0 :     const double minimum_good_length = 2.0 * object_dist;  /* not more than 2.0 because interfaces at components are rather close... */
     194            0 :     if (( length < minimum_good_length ))
     195              :     {
     196            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * ( minimum_good_length - length ) * line_corridor;
     197              :     }
     198              : 
     199              :     /* prefer centered over uncentered departure and arrival */
     200              :     const double delta_source
     201            0 :         = fmin( fabs( geometry_connector_get_source_end_x( probe ) - src_center_x ),
     202            0 :                 fabs( geometry_connector_get_source_end_y( probe ) - src_center_y ) );
     203            0 :     debts += LAYOUT_QUALITY_WEIGHT_LOCATION * delta_source * ( line_corridor );
     204              :     const double delta_destination
     205            0 :         = fmin( fabs( geometry_connector_get_destination_end_x( probe ) - dst_center_x ),
     206            0 :                 fabs( geometry_connector_get_destination_end_y( probe ) - dst_center_y ) );
     207            0 :     debts += LAYOUT_QUALITY_WEIGHT_LOCATION * delta_destination * ( line_corridor );
     208              : 
     209              :     /* prefer left-hand angles over right-handed */
     210            0 :     const geometry_3dir_t pattern = geometry_connector_get_directions( probe );
     211            0 :     const bool bad_pattern_v
     212            0 :         = geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_V_PATTERN1 )
     213            0 :         || geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_V_PATTERN2 );
     214            0 :     const bool bad_pattern_h
     215            0 :         = geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_H_PATTERN1 )
     216            0 :         || geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_H_PATTERN2 );
     217            0 :     if ( bad_pattern_h || bad_pattern_v )
     218              :     {
     219            0 :         const double current_len = length;
     220            0 :         if ( current_len > ( 4.0 * object_dist ) )
     221              :         {
     222              :             /* probe is a long path and right-handed */
     223              :             /* to avoid overreactions, we assume a line width of 0.1 only */
     224            0 :             debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * ( 0.1 * line_corridor );
     225              :         }
     226              :     }
     227              : 
     228              :     /* to avoid bad patterns: no L on top-left, no 7 on bottom-right, no r on top-right, no J on bottom-left */
     229              :     {
     230            0 :         const bool connector_is_left
     231            0 :         = geometry_rectangle_get_center_x( &connector_bounds ) < diagram_draw_center_x;
     232            0 :         const bool connector_is_top
     233            0 :         = geometry_rectangle_get_center_y( &connector_bounds ) < diagram_draw_center_y;
     234            0 :         if ( connector_is_left )
     235              :         {
     236            0 :             if ( connector_is_top )
     237              :             {
     238              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_L_PATTERN1
     239              :                     = { .first = GEOMETRY_DIRECTION_LEFT,  .second = GEOMETRY_DIRECTION_UP,     .third = GEOMETRY_DIRECTION_CENTER };
     240              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_L_PATTERN2
     241              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_UP };
     242              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_L_PATTERN3
     243              :                     = { .first = GEOMETRY_DIRECTION_DOWN,   .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
     244              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_L_PATTERN4
     245              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_RIGHT };
     246              : 
     247            0 :                 if (( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_L_PATTERN1 ) )
     248            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_L_PATTERN2 ) )
     249            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_L_PATTERN3 ) )
     250            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_L_PATTERN4 ) ))
     251              :                 {
     252            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     253              :                 }
     254              :             }
     255              :             else
     256              :             {
     257              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_J_PATTERN1
     258              :                     = { .first = GEOMETRY_DIRECTION_DOWN,   .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_CENTER };
     259              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_J_PATTERN2
     260              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_LEFT };
     261              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_J_PATTERN3
     262              :                     = { .first = GEOMETRY_DIRECTION_RIGHT,  .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_CENTER };
     263              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_J_PATTERN4
     264              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_UP };
     265              : 
     266            0 :                 if (( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_J_PATTERN1 ) )
     267            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_J_PATTERN2 ) )
     268            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_J_PATTERN3 ) )
     269            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_J_PATTERN4 ) ))
     270              :                 {
     271            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     272              :                 }
     273              :             }
     274              :         }
     275              :         else
     276              :         {
     277            0 :             if ( connector_is_top )
     278              :             {
     279              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_r_PATTERN1
     280              :                     = { .first = GEOMETRY_DIRECTION_UP,     .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
     281              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_r_PATTERN2
     282              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_RIGHT };
     283              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_r_PATTERN3
     284              :                     = { .first = GEOMETRY_DIRECTION_LEFT,   .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_CENTER };
     285              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_r_PATTERN4
     286              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_DOWN };
     287              : 
     288            0 :                 if (( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_r_PATTERN1 ) )
     289            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_r_PATTERN2 ) )
     290            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_r_PATTERN3 ) )
     291            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_r_PATTERN4 ) ))
     292              :                 {
     293            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     294              :                 }
     295              :             }
     296              :             else
     297              :             {
     298              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_7_PATTERN1
     299              :                     = { .first = GEOMETRY_DIRECTION_RIGHT,  .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_CENTER };
     300              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_7_PATTERN2
     301              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
     302              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_7_PATTERN3
     303              :                     = { .first = GEOMETRY_DIRECTION_UP,     .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_CENTER };
     304              :                 static const geometry_3dir_t LAYOUT_QUALITY_BAD_7_PATTERN4
     305              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_LEFT };
     306              : 
     307            0 :                 if (( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_7_PATTERN1 ) )
     308            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_7_PATTERN2 ) )
     309            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_7_PATTERN3 ) )
     310            0 :                     || ( geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_7_PATTERN4 ) ))
     311              :                 {
     312            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     313              :                 }
     314              :             }
     315              :         }
     316              :     }
     317              : 
     318            0 :     return debts;
     319              : }
     320              : 
     321            0 : static inline double layout_quality_debts_conn_class ( const layout_quality_t *this_,
     322              :                                                        const geometry_connector_t *probe,
     323              :                                                        const layout_visible_classifier_t *other,
     324              :                                                        const bool is_source,
     325              :                                                        const bool is_ancestor_of_source,
     326              :                                                        const bool is_destination,
     327              :                                                        const bool is_ancestor_of_destination )
     328              : {
     329            0 :     double debts = 0.0;
     330              : 
     331              :     const geometry_rectangle_t connector_bounds
     332            0 :         = geometry_connector_get_bounding_rectangle( probe );
     333              :     const geometry_rectangle_t *const classifier_space
     334            0 :         = layout_visible_classifier_get_space_const( other );
     335              : 
     336            0 :     if ( ! geometry_rectangle_is_containing( classifier_space, &connector_bounds ) )
     337              :     {
     338            0 :         const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     339            0 :         const double line_width = pencil_size_get_standard_line_width( (*this_).pencil_size );
     340              : 
     341              :         const geometry_rectangle_t *const classifier_symbol_box
     342            0 :             = layout_visible_classifier_get_symbol_box_const( other );
     343            0 :         if ( is_source && is_destination )
     344              :         {
     345              :             /* do not care if connector is inside or outside */
     346              :         }
     347            0 :         else if ( ( is_ancestor_of_source || is_source ) && ( is_ancestor_of_destination || is_destination ) )
     348            0 :         {
     349              :             /* probe is ancestor of both, do not leave the classifiers space area */
     350            0 :             const double unwanted_detour
     351            0 :                 = geometry_connector_get_length( probe ) - geometry_connector_get_transit_length( probe, classifier_space );
     352            0 :             debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA * unwanted_detour * line_corridor;
     353              :         }
     354            0 :         else if ( ( ! is_ancestor_of_source )&&( ! is_ancestor_of_destination ) )
     355              :         {
     356              :             /* probe is no ancestor of source or destination */
     357            0 :             debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA
     358            0 :                 * geometry_connector_get_transit_length( probe, classifier_symbol_box ) * line_corridor;
     359              :         }
     360              :         const double same_path
     361            0 :             = geometry_connector_get_same_path_length_rect( probe,
     362              :                                                             classifier_symbol_box,
     363              :                                                             5.0 * line_width
     364              :                                                           );
     365              :         /* ^ max_distance is 5x line width because the contour line of a classifier is drawn at 3x linewidth within the bounds */
     366            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * same_path * line_corridor;
     367              : 
     368              :         const geometry_rectangle_t *const classifier_icon_box
     369            0 :             = layout_visible_classifier_get_icon_box_const( other );
     370            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE
     371            0 :             * geometry_connector_get_transit_length( probe, classifier_icon_box ) * line_corridor;
     372              : 
     373              :         const geometry_rectangle_t *const classifier_label_box
     374            0 :             = layout_visible_classifier_get_label_box_const( other );
     375            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE
     376            0 :             * geometry_connector_get_transit_length( probe, classifier_label_box ) * line_corridor;
     377              :     }
     378              : 
     379            0 :     return debts;
     380              : }
     381              : 
     382            0 : static inline double layout_quality_debts_conn_sym( const layout_quality_t *this_,
     383              :                                                     const geometry_connector_t *probe,
     384              :                                                     const geometry_rectangle_t *other )
     385              : {
     386            0 :     double debts = 0.0;
     387              : 
     388            0 :     const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     389            0 :     const double line_width = pencil_size_get_standard_line_width( (*this_).pencil_size );
     390              : 
     391            0 :     debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA
     392            0 :         * geometry_connector_get_transit_length( probe, other ) * line_corridor;
     393              :     const double same_path
     394            0 :         = geometry_connector_get_same_path_length_rect( probe, other, 5.0 * line_width );
     395              :     /* ^ max_distance is 5x line width because the contour line of a classifier is 3x linewidth within the bounds */
     396            0 :     debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * same_path * line_corridor;
     397              : 
     398            0 :     return debts;
     399              : }
     400              : 
     401            0 : static inline double layout_quality_debts_conn_conn( const layout_quality_t *this_,
     402              :                                                      const geometry_connector_t *probe,
     403              :                                                      const geometry_connector_t *other,
     404              :                                                      const bool same_type,
     405              :                                                      const bool same_source,
     406              :                                                      const bool same_destination )
     407              : {
     408            0 :     double debts = 0.0;
     409              : 
     410            0 :     const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     411            0 :     const double line_width = pencil_size_get_standard_line_width( (*this_).pencil_size );
     412            0 :     const bool one_same_end = ( same_source != same_destination );
     413              : 
     414              :     const uint32_t intersects
     415            0 :         = geometry_connector_count_connector_intersects( probe, other );
     416            0 :     debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINES * intersects * ( line_corridor * line_corridor );
     417              : 
     418              :     /* if probe and current have same type and (same source classifier xor same destination classifier), overlaps are ok */
     419            0 :     if ( ! ( same_type && one_same_end ) )
     420              :     {
     421              :         const double same_path
     422            0 :             = geometry_connector_get_same_path_length_conn( probe, other, 3.0 * line_width );
     423              :         /* ^ max_distance is 3x line width for 1) own line, 2) minimal gap and 3) other line */
     424            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * same_path * line_corridor;
     425              :     }
     426              : 
     427              :     /* get data on probe */
     428            0 :     const geometry_3dir_t pattern = geometry_connector_get_directions( probe );
     429            0 :     const bool bad_pattern_v
     430            0 :         = geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_V_PATTERN1 )
     431            0 :         || geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_V_PATTERN2 );
     432            0 :     const bool bad_pattern_h
     433            0 :         = geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_H_PATTERN1 )
     434            0 :         || geometry_3dir_equals( &pattern, &LAYOUT_QUALITY_BAD_H_PATTERN2 );
     435              : 
     436            0 :     if ( ( bad_pattern_h || bad_pattern_v ) && ( intersects > 0 ) )
     437              :     {
     438            0 :         const geometry_3dir_t other_pattern = geometry_connector_get_directions( other );
     439            0 :         const bool bad_other_v
     440            0 :             = geometry_3dir_equals( &other_pattern, &LAYOUT_QUALITY_BAD_V_PATTERN1 )
     441            0 :             || geometry_3dir_equals( &other_pattern, &LAYOUT_QUALITY_BAD_V_PATTERN2 );
     442            0 :         const bool bad_other_h
     443            0 :             = geometry_3dir_equals( &other_pattern, &LAYOUT_QUALITY_BAD_H_PATTERN1 )
     444            0 :             || geometry_3dir_equals( &other_pattern, &LAYOUT_QUALITY_BAD_H_PATTERN2 );
     445            0 :         if (( bad_pattern_h && bad_other_v )||( bad_pattern_v && bad_other_h ))
     446              :         {
     447              :             const geometry_rectangle_t probe_bounds
     448            0 :                 = geometry_connector_get_bounding_rectangle( probe );
     449              :             const geometry_rectangle_t other_bounds
     450            0 :                 = geometry_connector_get_bounding_rectangle( other );
     451              : 
     452            0 :             debts += LAYOUT_QUALITY_WEIGHT_FORBIDDEN * geometry_rectangle_get_area( &probe_bounds );
     453            0 :             debts += LAYOUT_QUALITY_WEIGHT_FORBIDDEN * geometry_rectangle_get_area( &other_bounds );
     454              :         }
     455              :     }
     456              : 
     457            0 :     return debts;
     458              : }
     459              : 
     460            0 : static inline double layout_quality_debts_label_diag( const layout_quality_t *this_,
     461              :                                                       const geometry_rectangle_t *probe,
     462              :                                                       const geometry_point_t *target_point,
     463              :                                                       const layout_diagram_t *other )
     464              : {
     465            0 :     double debts = 0.0;
     466              : 
     467              :     const geometry_rectangle_t *const diagram_draw_area
     468            0 :         = layout_diagram_get_draw_area_const( other );
     469              : 
     470              :     /* check distance to target point */
     471            0 :     const geometry_point_t probe_middle = geometry_rectangle_get_center( probe );
     472            0 :     debts += LAYOUT_QUALITY_WEIGHT_DISTANCE * geometry_point_calc_chess_distance ( target_point, &probe_middle );
     473              : 
     474              :     /* add debts for exceeding the diagram draw area */
     475            0 :     if ( ! geometry_rectangle_is_containing( diagram_draw_area, probe ) )
     476              :     {
     477              :         /* high debt */
     478            0 :         debts += LAYOUT_QUALITY_WEIGHT_NOT_IN_DIAGRAM_AREA * geometry_rectangle_get_area(diagram_draw_area);
     479              :     }
     480              : 
     481            0 :     return debts;
     482              : }
     483              : 
     484            0 : static inline double layout_quality_debts_label_class( const layout_quality_t *this_,
     485              :                                                        const geometry_rectangle_t *probe,
     486              :                                                        const layout_visible_classifier_t *other )
     487              : {
     488            0 :     double debts = 0.0;
     489              : 
     490              :     const geometry_rectangle_t *const classifier_symbol_box
     491            0 :         = layout_visible_classifier_get_symbol_box_const( other );
     492            0 :     if ( geometry_rectangle_is_intersecting( probe, classifier_symbol_box ) )
     493              :     {
     494              :         /* overlaps to the symbol box are bad only if not contained in space area */
     495              :         const geometry_rectangle_t *const classifier_space
     496            0 :             = layout_visible_classifier_get_space_const( other );
     497            0 :         if ( ! geometry_rectangle_is_containing( classifier_space, probe ) )
     498              :         {
     499              :             /* lower debt */
     500            0 :             debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE * geometry_rectangle_get_intersect_area( probe, classifier_symbol_box );
     501              :         }
     502              :     }
     503              : 
     504              :     const geometry_rectangle_t *const classifier_label_box
     505            0 :         = layout_visible_classifier_get_label_box_const( other );
     506            0 :     if ( geometry_rectangle_is_intersecting( probe, classifier_label_box ) )
     507              :     {
     508              :         /* medium debt */
     509            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, classifier_label_box );
     510              :     }
     511              : 
     512              :     const geometry_rectangle_t *const classifier_icon_box
     513            0 :     = layout_visible_classifier_get_icon_box_const( other );
     514            0 :     if ( geometry_rectangle_is_intersecting( probe, classifier_icon_box ) )
     515              :     {
     516              :         /* medium debt */
     517            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, classifier_icon_box );
     518              :     }
     519              : 
     520            0 :     return debts;
     521              : }
     522              : 
     523            0 : static inline double layout_quality_debts_label_feat( const layout_quality_t *this_,
     524              :                                                       const geometry_rectangle_t *probe,
     525              :                                                       const layout_feature_t *other )
     526              : {
     527            0 :     double debts = 0.0;
     528              : 
     529              :     const geometry_rectangle_t *const feature_symbol_box
     530            0 :         = layout_feature_get_symbol_box_const( other );
     531            0 :     if ( geometry_rectangle_is_intersecting( probe, feature_symbol_box ) )
     532              :     {
     533              :         /* no special handling for lifelines */
     534              :         /* const data_feature_t *const probe_f_data = layout_feature_get_data_const( other ); */
     535              :         /* if ( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( probe_f_data ) ) { } else { } */
     536            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE * geometry_rectangle_get_intersect_area( probe, feature_symbol_box );
     537              :     }
     538              : 
     539              :     const geometry_rectangle_t *const feature_label_box
     540            0 :         = layout_feature_get_label_box_const( other );
     541            0 :     if ( geometry_rectangle_is_intersecting( probe, feature_label_box ) )
     542              :     {
     543              :         /* medium debt */
     544            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, feature_label_box );
     545              :     }
     546              : 
     547            0 :     return debts;
     548              : }
     549              : 
     550            0 : static inline double layout_quality_debts_label_rel( const layout_quality_t *this_,
     551              :                                                      const geometry_rectangle_t *probe,
     552              :                                                      const layout_relationship_t *other )
     553              : {
     554            0 :     double debts = 0.0;
     555              : 
     556            0 :     if (( PENCIL_VISIBILITY_SHOW == layout_relationship_get_visibility( other ) )
     557            0 :         || ( PENCIL_VISIBILITY_GRAY_OUT == layout_relationship_get_visibility( other ) ))
     558              :     {
     559            0 :         const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     560              : 
     561              :         const geometry_connector_t *const other_shape
     562            0 :             = layout_relationship_get_shape_const( other );
     563            0 :         debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA
     564            0 :             * geometry_connector_get_transit_length( other_shape, probe ) * line_corridor;
     565              : 
     566              :         const geometry_rectangle_t *const relationship_label_box
     567            0 :             = layout_relationship_get_label_box_const( other );
     568            0 :         if ( geometry_rectangle_is_intersecting( probe, relationship_label_box ) )
     569              :         {
     570              :             /* medium debt */
     571            0 :             debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, relationship_label_box );
     572              :         }
     573              :     }
     574              : 
     575            0 :     return debts;
     576              : }
     577              : 
     578              : 
     579              : /*
     580              : Copyright 2017-2025 Andreas Warnke
     581              : 
     582              : Licensed under the Apache License, Version 2.0 (the "License");
     583              : you may not use this file except in compliance with the License.
     584              : You may obtain a copy of the License at
     585              : 
     586              :     http://www.apache.org/licenses/LICENSE-2.0
     587              : 
     588              : Unless required by applicable law or agreed to in writing, software
     589              : distributed under the License is distributed on an "AS IS" BASIS,
     590              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     591              : See the License for the specific language governing permissions and
     592              : limitations under the License.
     593              : */
        

Generated by: LCOV version 2.0-1