LCOV - code coverage report
Current view: top level - pencil/include/layout - layout_quality.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 0.0 % 201 0
Test Date: 2025-05-01 10:10:14 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 PENCIL_BAD_V_PATTERN1
     125              :     = { .first = GEOMETRY_DIRECTION_LEFT,  .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_LEFT };
     126              : static const geometry_3dir_t PENCIL_BAD_V_PATTERN2
     127              :     = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_RIGHT };
     128              : static const geometry_3dir_t PENCIL_BAD_H_PATTERN1
     129              :     = { .first = GEOMETRY_DIRECTION_DOWN,  .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
     130              : static const geometry_3dir_t PENCIL_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, &PENCIL_BAD_V_PATTERN1 ) || geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN2 );
     213            0 :     const bool bad_pattern_h
     214            0 :         = geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN1 ) || geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN2 );
     215            0 :     if ( bad_pattern_h || bad_pattern_v )
     216              :     {
     217            0 :         const double current_len = length;
     218            0 :         if ( current_len > ( 4.0 * object_dist ) )
     219              :         {
     220              :             /* probe is a long path and right-handed */
     221              :             /* to avoid overreactions, we assume a line width of 0.1 only */
     222            0 :             debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * ( 0.1 * line_corridor );
     223              :         }
     224              :     }
     225              : 
     226              :     /* to avoid bad patterns: no L on top-left, no 7 on bottom-right, no r on top-right, no J on bottom-left */
     227              :     {
     228            0 :         const bool connector_is_left
     229            0 :         = geometry_rectangle_get_center_x( &connector_bounds ) < diagram_draw_center_x;
     230            0 :         const bool connector_is_top
     231            0 :         = geometry_rectangle_get_center_y( &connector_bounds ) < diagram_draw_center_y;
     232            0 :         if ( connector_is_left )
     233              :         {
     234            0 :             if ( connector_is_top )
     235              :             {
     236              :                 static const geometry_3dir_t PENCIL_BAD_L_PATTERN1
     237              :                     = { .first = GEOMETRY_DIRECTION_LEFT,  .second = GEOMETRY_DIRECTION_UP,     .third = GEOMETRY_DIRECTION_CENTER };
     238              :                 static const geometry_3dir_t PENCIL_BAD_L_PATTERN2
     239              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_UP };
     240              :                 static const geometry_3dir_t PENCIL_BAD_L_PATTERN3
     241              :                     = { .first = GEOMETRY_DIRECTION_DOWN,   .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
     242              :                 static const geometry_3dir_t PENCIL_BAD_L_PATTERN4
     243              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_RIGHT };
     244              : 
     245            0 :                 if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN1 ) )
     246            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN2 ) )
     247            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN3 ) )
     248            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN4 ) ))
     249              :                 {
     250            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     251              :                 }
     252              :             }
     253              :             else
     254              :             {
     255              :                 static const geometry_3dir_t PENCIL_BAD_J_PATTERN1
     256              :                     = { .first = GEOMETRY_DIRECTION_DOWN,   .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_CENTER };
     257              :                 static const geometry_3dir_t PENCIL_BAD_J_PATTERN2
     258              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_LEFT };
     259              :                 static const geometry_3dir_t PENCIL_BAD_J_PATTERN3
     260              :                     = { .first = GEOMETRY_DIRECTION_RIGHT,  .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_CENTER };
     261              :                 static const geometry_3dir_t PENCIL_BAD_J_PATTERN4
     262              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_UP };
     263              : 
     264            0 :                 if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN1 ) )
     265            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN2 ) )
     266            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN3 ) )
     267            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN4 ) ))
     268              :                 {
     269            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     270              :                 }
     271              :             }
     272              :         }
     273              :         else
     274              :         {
     275            0 :             if ( connector_is_top )
     276              :             {
     277              :                 static const geometry_3dir_t PENCIL_BAD_r_PATTERN1
     278              :                     = { .first = GEOMETRY_DIRECTION_UP,     .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
     279              :                 static const geometry_3dir_t PENCIL_BAD_r_PATTERN2
     280              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_RIGHT };
     281              :                 static const geometry_3dir_t PENCIL_BAD_r_PATTERN3
     282              :                     = { .first = GEOMETRY_DIRECTION_LEFT,   .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_CENTER };
     283              :                 static const geometry_3dir_t PENCIL_BAD_r_PATTERN4
     284              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_DOWN };
     285              : 
     286            0 :                 if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN1 ) )
     287            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN2 ) )
     288            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN3 ) )
     289            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN4 ) ))
     290              :                 {
     291            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     292              :                 }
     293              :             }
     294              :             else
     295              :             {
     296              :                 static const geometry_3dir_t PENCIL_BAD_7_PATTERN1
     297              :                     = { .first = GEOMETRY_DIRECTION_RIGHT,  .second = GEOMETRY_DIRECTION_DOWN,  .third = GEOMETRY_DIRECTION_CENTER };
     298              :                 static const geometry_3dir_t PENCIL_BAD_7_PATTERN2
     299              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
     300              :                 static const geometry_3dir_t PENCIL_BAD_7_PATTERN3
     301              :                     = { .first = GEOMETRY_DIRECTION_UP,     .second = GEOMETRY_DIRECTION_LEFT,  .third = GEOMETRY_DIRECTION_CENTER };
     302              :                 static const geometry_3dir_t PENCIL_BAD_7_PATTERN4
     303              :                     = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP,    .third = GEOMETRY_DIRECTION_LEFT };
     304              : 
     305            0 :                 if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN1 ) )
     306            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN2 ) )
     307            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN3 ) )
     308            0 :                     || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN4 ) ))
     309              :                 {
     310            0 :                     debts += LAYOUT_QUALITY_WEIGHT_AVOID * length * line_corridor;
     311              :                 }
     312              :             }
     313              :         }
     314              :     }
     315              : 
     316            0 :     return debts;
     317              : }
     318              : 
     319            0 : static inline double layout_quality_debts_conn_class ( const layout_quality_t *this_,
     320              :                                                        const geometry_connector_t *probe,
     321              :                                                        const layout_visible_classifier_t *other,
     322              :                                                        const bool is_ancestor_of_source,
     323              :                                                        const bool is_ancestor_of_destination )
     324              : {
     325            0 :     double debts = 0.0;
     326              : 
     327              :     const geometry_rectangle_t connector_bounds
     328            0 :         = geometry_connector_get_bounding_rectangle( probe );
     329              :     const geometry_rectangle_t *const classifier_space
     330            0 :         = layout_visible_classifier_get_space_const( other );
     331              : 
     332            0 :     if ( ! geometry_rectangle_is_containing( classifier_space, &connector_bounds ) )
     333              :     {
     334            0 :         const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     335            0 :         const double line_width = pencil_size_get_standard_line_width( (*this_).pencil_size );
     336              : 
     337              :         const geometry_rectangle_t *const classifier_symbol_box
     338            0 :             = layout_visible_classifier_get_symbol_box_const( other );
     339            0 :         if ( is_ancestor_of_source == is_ancestor_of_destination )
     340              :         {
     341              :             /* either probe is no ancestor or ancestor of both */
     342            0 :             debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA
     343            0 :                 * geometry_connector_get_transit_length( probe, classifier_symbol_box ) * line_corridor;
     344              :         }
     345              :         const double same_path
     346            0 :             = geometry_connector_get_same_path_length_rect( probe,
     347              :                                                             classifier_symbol_box,
     348              :                                                             5.0 * line_width
     349              :                                                           );
     350              :         /* ^ max_distance is 5x line width because the contour line of a classifier is drawn at 3x linewidth within the bounds */
     351            0 :         debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * same_path * line_corridor;
     352              : 
     353              :         const geometry_rectangle_t *const classifier_icon_box
     354            0 :             = layout_visible_classifier_get_icon_box_const( other );
     355            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE
     356            0 :             * geometry_connector_get_transit_length( probe, classifier_icon_box ) * line_corridor;
     357              : 
     358              :         const geometry_rectangle_t *const classifier_label_box
     359            0 :             = layout_visible_classifier_get_label_box_const( other );
     360            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE
     361            0 :             * geometry_connector_get_transit_length( probe, classifier_label_box ) * line_corridor;
     362              :     }
     363              : 
     364            0 :     return debts;
     365              : }
     366              : 
     367            0 : static inline double layout_quality_debts_conn_sym( const layout_quality_t *this_,
     368              :                                                     const geometry_connector_t *probe,
     369              :                                                     const geometry_rectangle_t *other )
     370              : {
     371            0 :     double debts = 0.0;
     372              : 
     373            0 :     const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     374            0 :     const double line_width = pencil_size_get_standard_line_width( (*this_).pencil_size );
     375              : 
     376            0 :     debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA
     377            0 :         * geometry_connector_get_transit_length( probe, other ) * line_corridor;
     378              :     const double same_path
     379            0 :         = geometry_connector_get_same_path_length_rect( probe, other, 5.0 * line_width );
     380              :     /* ^ max_distance is 5x line width because the contour line of a classifier is 3x linewidth within the bounds */
     381            0 :     debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * same_path * line_corridor;
     382              : 
     383            0 :     return debts;
     384              : }
     385              : 
     386            0 : static inline double layout_quality_debts_conn_conn( const layout_quality_t *this_,
     387              :                                                      const geometry_connector_t *probe,
     388              :                                                      const geometry_connector_t *other )
     389              : {
     390            0 :     double debts = 0.0;
     391              : 
     392            0 :     const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     393            0 :     const double line_width = pencil_size_get_standard_line_width( (*this_).pencil_size );
     394              : 
     395              :     /* get data on probe */
     396            0 :     const geometry_3dir_t pattern = geometry_connector_get_directions( probe );
     397            0 :     const bool bad_pattern_v
     398            0 :         = geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN1 ) || geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN2 );
     399            0 :     const bool bad_pattern_h
     400            0 :         = geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN1 ) || geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN2 );
     401              : 
     402              :     const uint32_t intersects
     403            0 :         = geometry_connector_count_connector_intersects( probe, other );
     404            0 :     debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINES * intersects * ( line_corridor * line_corridor );
     405              :     const double same_path
     406            0 :         = geometry_connector_get_same_path_length_conn( probe, other, 3.0 * line_width );
     407              :     /* ^ max_distance is 3x line width for 1) own line, 2) minimal gap and 3) other line */
     408            0 :     debts += LAYOUT_QUALITY_WEIGHT_SHARED_LINES * same_path * line_corridor;
     409              : 
     410            0 :     if ( ( bad_pattern_h || bad_pattern_v ) && ( intersects > 0 ) )
     411              :     {
     412            0 :         const geometry_3dir_t other_pattern = geometry_connector_get_directions( other );
     413            0 :         const bool bad_other_v
     414            0 :             = geometry_3dir_equals( &other_pattern, &PENCIL_BAD_V_PATTERN1 )
     415            0 :             || geometry_3dir_equals( &other_pattern, &PENCIL_BAD_V_PATTERN2 );
     416            0 :         const bool bad_other_h
     417            0 :             = geometry_3dir_equals( &other_pattern, &PENCIL_BAD_H_PATTERN1 )
     418            0 :             || geometry_3dir_equals( &other_pattern, &PENCIL_BAD_H_PATTERN2 );
     419            0 :         if (( bad_pattern_h && bad_other_v )||( bad_pattern_v && bad_other_h ))
     420              :         {
     421              :             const geometry_rectangle_t probe_bounds
     422            0 :                 = geometry_connector_get_bounding_rectangle( probe );
     423              :             const geometry_rectangle_t other_bounds
     424            0 :                 = geometry_connector_get_bounding_rectangle( other );
     425              : 
     426            0 :             debts += LAYOUT_QUALITY_WEIGHT_FORBIDDEN * geometry_rectangle_get_area( &probe_bounds );
     427            0 :             debts += LAYOUT_QUALITY_WEIGHT_FORBIDDEN * geometry_rectangle_get_area( &other_bounds );
     428              :         }
     429              :     }
     430              : 
     431            0 :     return debts;
     432              : }
     433              : 
     434            0 : static inline double layout_quality_debts_label_diag( const layout_quality_t *this_,
     435              :                                                       const geometry_rectangle_t *probe,
     436              :                                                       const geometry_point_t *target_point,
     437              :                                                       const layout_diagram_t *other )
     438              : {
     439            0 :     double debts = 0.0;
     440              : 
     441              :     const geometry_rectangle_t *const diagram_draw_area
     442            0 :         = layout_diagram_get_draw_area_const( other );
     443              : 
     444              :     /* check distance to target point */
     445            0 :     const geometry_point_t probe_middle = geometry_rectangle_get_center( probe );
     446            0 :     debts += LAYOUT_QUALITY_WEIGHT_DISTANCE * geometry_point_calc_chess_distance ( target_point, &probe_middle );
     447              : 
     448              :     /* add debts for exceeding the diagram draw area */
     449            0 :     if ( ! geometry_rectangle_is_containing( diagram_draw_area, probe ) )
     450              :     {
     451              :         /* high debt */
     452            0 :         debts += LAYOUT_QUALITY_WEIGHT_NOT_IN_DIAGRAM_AREA * geometry_rectangle_get_area(diagram_draw_area);
     453              :     }
     454              : 
     455            0 :     return debts;
     456              : }
     457              : 
     458            0 : static inline double layout_quality_debts_label_class( const layout_quality_t *this_,
     459              :                                                        const geometry_rectangle_t *probe,
     460              :                                                        const layout_visible_classifier_t *other )
     461              : {
     462            0 :     double debts = 0.0;
     463              : 
     464              :     const geometry_rectangle_t *const classifier_symbol_box
     465            0 :         = layout_visible_classifier_get_symbol_box_const( other );
     466            0 :     if ( geometry_rectangle_is_intersecting( probe, classifier_symbol_box ) )
     467              :     {
     468              :         /* overlaps to the symbol box are bad only if not contained in space area */
     469              :         const geometry_rectangle_t *const classifier_space
     470            0 :             = layout_visible_classifier_get_space_const( other );
     471            0 :         if ( ! geometry_rectangle_is_containing( classifier_space, probe ) )
     472              :         {
     473              :             /* lower debt */
     474            0 :             debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE * geometry_rectangle_get_intersect_area( probe, classifier_symbol_box );
     475              :         }
     476              :     }
     477              : 
     478              :     const geometry_rectangle_t *const classifier_label_box
     479            0 :         = layout_visible_classifier_get_label_box_const( other );
     480            0 :     if ( geometry_rectangle_is_intersecting( probe, classifier_label_box ) )
     481              :     {
     482              :         /* medium debt */
     483            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, classifier_label_box );
     484              :     }
     485              : 
     486              :     const geometry_rectangle_t *const classifier_icon_box
     487            0 :     = layout_visible_classifier_get_icon_box_const( other );
     488            0 :     if ( geometry_rectangle_is_intersecting( probe, classifier_icon_box ) )
     489              :     {
     490              :         /* medium debt */
     491            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, classifier_icon_box );
     492              :     }
     493              : 
     494            0 :     return debts;
     495              : }
     496              : 
     497            0 : static inline double layout_quality_debts_label_feat( const layout_quality_t *this_,
     498              :                                                       const geometry_rectangle_t *probe,
     499              :                                                       const layout_feature_t *other )
     500              : {
     501            0 :     double debts = 0.0;
     502              : 
     503              :     const geometry_rectangle_t *const feature_symbol_box
     504            0 :         = layout_feature_get_symbol_box_const( other );
     505            0 :     if ( geometry_rectangle_is_intersecting( probe, feature_symbol_box ) )
     506              :     {
     507              :         /* no special handling for lifelines */
     508              :         /* const data_feature_t *const probe_f_data = layout_feature_get_data_const( other ); */
     509              :         /* if ( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( probe_f_data ) ) { } else { } */
     510            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_ON_LINE * geometry_rectangle_get_intersect_area( probe, feature_symbol_box );
     511              :     }
     512              : 
     513              :     const geometry_rectangle_t *const feature_label_box
     514            0 :         = layout_feature_get_label_box_const( other );
     515            0 :     if ( geometry_rectangle_is_intersecting( probe, feature_label_box ) )
     516              :     {
     517              :         /* medium debt */
     518            0 :         debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, feature_label_box );
     519              :     }
     520              : 
     521            0 :     return debts;
     522              : }
     523              : 
     524            0 : static inline double layout_quality_debts_label_rel( const layout_quality_t *this_,
     525              :                                                      const geometry_rectangle_t *probe,
     526              :                                                      const layout_relationship_t *other )
     527              : {
     528            0 :     double debts = 0.0;
     529              : 
     530            0 :     if (( PENCIL_VISIBILITY_SHOW == layout_relationship_get_visibility( other ) )
     531            0 :         || ( PENCIL_VISIBILITY_GRAY_OUT == layout_relationship_get_visibility( other ) ))
     532              :     {
     533            0 :         const double line_corridor = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     534              : 
     535              :         const geometry_connector_t *const other_shape
     536            0 :             = layout_relationship_get_shape_const( other );
     537            0 :         debts += LAYOUT_QUALITY_WEIGHT_CROSS_LINE_AREA
     538            0 :             * geometry_connector_get_transit_length( other_shape, probe ) * line_corridor;
     539              : 
     540              :         const geometry_rectangle_t *const relationship_label_box
     541            0 :             = layout_relationship_get_label_box_const( other );
     542            0 :         if ( geometry_rectangle_is_intersecting( probe, relationship_label_box ) )
     543              :         {
     544              :             /* medium debt */
     545            0 :             debts += LAYOUT_QUALITY_WEIGHT_LABEL_OVERLAP * geometry_rectangle_get_intersect_area( probe, relationship_label_box );
     546              :         }
     547              :     }
     548              : 
     549            0 :     return debts;
     550              : }
     551              : 
     552              : 
     553              : /*
     554              : Copyright 2017-2025 Andreas Warnke
     555              : 
     556              : Licensed under the Apache License, Version 2.0 (the "License");
     557              : you may not use this file except in compliance with the License.
     558              : You may obtain a copy of the License at
     559              : 
     560              :     http://www.apache.org/licenses/LICENSE-2.0
     561              : 
     562              : Unless required by applicable law or agreed to in writing, software
     563              : distributed under the License is distributed on an "AS IS" BASIS,
     564              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     565              : See the License for the specific language governing permissions and
     566              : limitations under the License.
     567              : */
        

Generated by: LCOV version 2.0-1