LCOV - code coverage report
Current view: top level - pencil/include/layout - layout_quality.inl (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.65.6_covts Lines: 0 201 0.0 %
Date: 2025-09-25 21:07:53 Functions: 0 12 0.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 1.16