LCOV - code coverage report
Current view: top level - pencil/source - pencil_rel_label_layouter.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.57.0_covts Lines: 0 175 0.0 %
Date: 2024-04-07 11:14:42 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /* File: pencil_rel_label_layouter.c; Copyright and License: see below */
       2             : 
       3             : #include "pencil_rel_label_layouter.h"
       4             : #include "geometry/geometry_point.h"
       5             : #include "geometry/geometry_direction.h"
       6             : #include "u8/u8_trace.h"
       7             : #include "utf8stringbuf/utf8string.h"
       8             : 
       9           0 : void pencil_rel_label_layouter_init( pencil_rel_label_layouter_t *this_,
      10             :                                      pencil_layout_data_t *layout_data,
      11             :                                      const data_profile_part_t *profile,
      12             :                                      const pencil_size_t *pencil_size )
      13             : {
      14           0 :     U8_TRACE_BEGIN();
      15           0 :     assert( NULL != layout_data );
      16           0 :     assert( NULL != profile );
      17           0 :     assert( NULL != pencil_size );
      18             : 
      19           0 :     (*this_).layout_data = layout_data;
      20           0 :     (*this_).profile = profile;
      21           0 :     (*this_).pencil_size = pencil_size;
      22           0 :     draw_relationship_label_init( &((*this_).draw_relationship_label) );
      23           0 :     pencil_label_layout_helper_init ( &((*this_).label_layout_helper) );
      24             : 
      25           0 :     U8_TRACE_END();
      26           0 : }
      27             : 
      28           0 : void pencil_rel_label_layouter_reinit( pencil_rel_label_layouter_t *this_,
      29             :                                        pencil_layout_data_t *layout_data,
      30             :                                        const data_profile_part_t *profile,
      31             :                                        const pencil_size_t *pencil_size )
      32             : {
      33           0 :     U8_TRACE_BEGIN();
      34           0 :     assert( NULL != layout_data );
      35           0 :     assert( NULL != profile );
      36           0 :     assert( NULL != pencil_size );
      37             : 
      38           0 :     (*this_).layout_data = layout_data;
      39           0 :     (*this_).profile = profile;
      40           0 :     (*this_).pencil_size = pencil_size;
      41             : 
      42           0 :     U8_TRACE_END();
      43           0 : }
      44             : 
      45           0 : void pencil_rel_label_layouter_destroy( pencil_rel_label_layouter_t *this_ )
      46             : {
      47           0 :     U8_TRACE_BEGIN();
      48             : 
      49           0 :     pencil_label_layout_helper_destroy ( &((*this_).label_layout_helper) );
      50           0 :     draw_relationship_label_destroy( &((*this_).draw_relationship_label) );
      51             : 
      52           0 :     U8_TRACE_END();
      53           0 : }
      54             : 
      55           0 : void pencil_rel_label_layouter_do_layout ( pencil_rel_label_layouter_t *this_, PangoLayout *font_layout )
      56             : {
      57           0 :     U8_TRACE_BEGIN();
      58             :     assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS );
      59           0 :     assert( NULL != font_layout );
      60             : 
      61             :     universal_array_index_sorter_t sorted;
      62           0 :     universal_array_index_sorter_init( &sorted );
      63             : 
      64             :     /* sort the relationships by their label-box layouting needs, drop invisible relations */
      65           0 :     pencil_rel_label_layouter_private_propose_processing_order ( this_, &sorted );
      66             : 
      67             :     /* layout the relationship label-boxes */
      68             :     const uint32_t count_sorted
      69           0 :         = universal_array_index_sorter_get_count( &sorted );
      70           0 :     for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ )
      71             :     {
      72             :         /* determine pointer to relationship */
      73             :         const uint32_t index
      74           0 :             = universal_array_index_sorter_get_array_index( &sorted, sort_index );
      75             :         layout_relationship_t *const current_relation
      76           0 :             = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index );
      77           0 :         geometry_point_t relation_middle = layout_relationship_get_middle ( current_relation );
      78             : 
      79             :         /* declaration of list of options */
      80           0 :         uint32_t solutions_count = 0;
      81             :         static const uint32_t SOLUTIONS_MAX = 16;
      82             :         geometry_rectangle_t solution[16];
      83             : 
      84             :         /* propose options */
      85           0 :         pencil_rel_label_layouter_private_propose_solutions ( this_,
      86             :                                                               current_relation,
      87             :                                                               font_layout,
      88             :                                                               SOLUTIONS_MAX,
      89             :                                                               solution,
      90             :                                                               &solutions_count
      91             :                                                             );
      92             : 
      93             :         /* select best option */
      94             :         uint32_t index_of_best;
      95           0 :         if ( 1 == solutions_count )
      96             :         {
      97           0 :             index_of_best = 0;
      98             :         }
      99             :         else
     100             :         {
     101           0 :             pencil_label_layout_helper_select_solution ( &((*this_).label_layout_helper),
     102             :                                                          (*this_).layout_data,
     103             :                                                          relation_middle,
     104             :                                                          solutions_count,
     105             :                                                          solution,
     106             :                                                          &index_of_best
     107             :                                                        );
     108             :         }
     109             : 
     110             :         /* store best option to (*this_).layout_data */
     111           0 :         layout_relationship_set_label_box( current_relation, &(solution[index_of_best]) );
     112             :     }
     113             : 
     114           0 :     universal_array_index_sorter_destroy( &sorted );
     115             : 
     116           0 :     U8_TRACE_END();
     117           0 : }
     118             : 
     119           0 : void pencil_rel_label_layouter_private_propose_processing_order ( pencil_rel_label_layouter_t *this_,
     120             :                                                                   universal_array_index_sorter_t *out_sorted )
     121             : {
     122           0 :     U8_TRACE_BEGIN();
     123           0 :     assert( NULL != out_sorted );
     124             : 
     125             :     /* sort the relationships by their label-box: the less simple, the earlier it shall be processed */
     126             :     const uint32_t count_relations
     127           0 :         = pencil_layout_data_get_relationship_count ( (*this_).layout_data );
     128           0 :     for ( uint32_t index = 0; index < count_relations; index ++ )
     129             :     {
     130             :         const layout_relationship_t *const current_relation
     131           0 :             = pencil_layout_data_get_relationship_ptr ( (*this_).layout_data, index );
     132             :         const data_relationship_t *const relation_data
     133           0 :             = layout_relationship_get_data_const ( current_relation );
     134           0 :         assert( NULL != relation_data );
     135             : 
     136           0 :         int64_t simpleness = 0;
     137             : 
     138             :         /* determine simpleness by length of label */
     139           0 :         simpleness -= utf8string_get_length( data_relationship_get_name_const( relation_data ) );
     140             : 
     141             :         /* insert relation to sorted array, the simpler the more to the back */
     142           0 :         if ( PENCIL_VISIBILITY_HIDE != layout_relationship_get_visibility ( current_relation ) )
     143             :         {
     144             :             int insert_error;
     145           0 :             insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness );
     146           0 :             if ( 0 != insert_error )
     147             :             {
     148           0 :                 U8_LOG_WARNING( "not all relationship label-boxes are layouted" );
     149             :             }
     150             :         }
     151             :     }
     152             : 
     153           0 :     U8_TRACE_END();
     154           0 : }
     155             : 
     156           0 : void pencil_rel_label_layouter_private_propose_solutions ( pencil_rel_label_layouter_t *this_,
     157             :                                                            layout_relationship_t *current_relation,
     158             :                                                            PangoLayout *font_layout,
     159             :                                                            uint32_t solutions_max,
     160             :                                                            geometry_rectangle_t out_solutions[],
     161             :                                                            uint32_t *out_solutions_count)
     162             : {
     163           0 :     U8_TRACE_BEGIN();
     164           0 :     assert( NULL != current_relation );
     165           0 :     assert( NULL != font_layout );
     166           0 :     assert( NULL != out_solutions );
     167           0 :     assert( NULL != out_solutions_count );
     168             : 
     169           0 :     const data_relationship_t *the_relationship = layout_relationship_get_data_const( current_relation );
     170             :     {
     171             :         /* determine label dimensions */
     172           0 :         const geometry_dimensions_t label_dim_proposal = {
     173           0 :             .width = 15.0 * pencil_size_get_standard_font_size( (*this_).pencil_size ),
     174           0 :             .height = pencil_size_get_standard_font_size( (*this_).pencil_size )
     175             :         };
     176             :         geometry_dimensions_t label_dim;
     177           0 :         draw_relationship_label_get_type_and_name_dimensions( &((*this_).draw_relationship_label),
     178             :                                                               the_relationship,
     179             :                                                               (*this_).profile,
     180             :                                                               &label_dim_proposal,
     181             :                                                               (*this_).pencil_size,
     182             :                                                               font_layout,
     183             :                                                               &label_dim
     184             :                                                             );
     185           0 :         const double text_width = geometry_dimensions_get_width( &label_dim );
     186           0 :         const double text_height = geometry_dimensions_get_height( &label_dim );
     187             : 
     188             :         /* get layout data */
     189           0 :         const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
     190           0 :         const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
     191             : 
     192             :         /* get connector data */
     193           0 :         const geometry_connector_t *const shape = layout_relationship_get_shape_const ( current_relation );
     194           0 :         const double source_end_x = geometry_connector_get_source_end_x ( shape );
     195           0 :         const double source_end_y = geometry_connector_get_source_end_y ( shape );
     196           0 :         const double main_line_source_x = geometry_connector_get_main_line_source_x ( shape );
     197           0 :         const double main_line_source_y = geometry_connector_get_main_line_source_y ( shape );
     198           0 :         const double main_line_destination_x = geometry_connector_get_main_line_destination_x ( shape );
     199           0 :         const double main_line_destination_y = geometry_connector_get_main_line_destination_y ( shape );
     200           0 :         const double destination_end_x = geometry_connector_get_destination_end_x ( shape );
     201           0 :         const double destination_end_y = geometry_connector_get_destination_end_y ( shape );
     202             :         geometry_point_t src_end;
     203             :         geometry_point_t main_src;
     204             :         geometry_point_t main_dst;
     205             :         geometry_point_t dst_end;
     206           0 :         geometry_point_init ( &src_end, source_end_x, source_end_y );
     207           0 :         geometry_point_init ( &main_src, main_line_source_x, main_line_source_y );
     208           0 :         geometry_point_init ( &main_dst, main_line_destination_x, main_line_destination_y );
     209           0 :         geometry_point_init ( &dst_end, destination_end_x, destination_end_y );
     210           0 :         const geometry_direction_t src_dir = geometry_point_get_direction ( &src_end, &main_src );
     211           0 :         const geometry_direction_t dst_dir = geometry_point_get_direction ( &main_dst, &dst_end );
     212             :         geometry_rectangle_t main_line_rect;
     213           0 :         geometry_rectangle_init_by_corners ( &main_line_rect, main_line_source_x, main_line_source_y, main_line_destination_x, main_line_destination_y );
     214             : 
     215             :         /* propose solutions */
     216           0 :         assert( solutions_max >= 16 );
     217           0 :         uint32_t solution_idx = 0;
     218             : 
     219             :         /* there are 0..2 solutions at the src line segment */
     220           0 :         if ( geometry_point_calc_chess_distance( &src_end, &main_src ) > object_dist )
     221             :         {
     222             :             /* this is a noteworthy line segment */
     223           0 :             if ( ( src_dir == GEOMETRY_DIRECTION_UP ) || ( src_dir == GEOMETRY_DIRECTION_DOWN ) )
     224             :             {
     225             :                 /* right */
     226           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     227             :                                          main_line_source_x + gap,
     228           0 :                                          (source_end_y + main_line_source_y - text_height) / 2.0,
     229             :                                          text_width,
     230             :                                          text_height
     231             :                                        );
     232           0 :                 solution_idx ++;
     233             : 
     234             :                 /* left */
     235           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     236           0 :                                          main_line_source_x - text_width - gap,
     237           0 :                                          (source_end_y + main_line_source_y - text_height) / 2.0,
     238             :                                          text_width,
     239             :                                          text_height
     240             :                                        );
     241           0 :                 solution_idx ++;
     242             :             }
     243             :             else
     244             :             {
     245             :                 /* down */
     246           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     247           0 :                                          (source_end_x + main_line_source_x - text_width) / 2.0,
     248             :                                          main_line_source_y + gap,
     249             :                                          text_width,
     250             :                                          text_height
     251             :                                        );
     252           0 :                 solution_idx ++;
     253             : 
     254             :                 /* up */
     255           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     256           0 :                                          (source_end_x + main_line_source_x - text_width) / 2.0,
     257           0 :                                          main_line_source_y - text_height - gap,
     258             :                                          text_width,
     259             :                                          text_height
     260             :                                        );
     261           0 :                 solution_idx ++;
     262             : 
     263             :             }
     264             :         }
     265             : 
     266             :         /* there are 4 solutions at the main line segment */
     267             :         {
     268             :             /* left */
     269           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     270           0 :                                      geometry_rectangle_get_left(&main_line_rect) - text_width - gap,
     271           0 :                                      (main_line_source_y + main_line_destination_y - text_height) / 2.0,
     272             :                                      text_width,
     273             :                                      text_height
     274             :                                    );
     275           0 :             solution_idx ++;
     276             : 
     277             :             /* right */
     278           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     279           0 :                                      geometry_rectangle_get_right(&main_line_rect) + gap,
     280           0 :                                      (main_line_source_y + main_line_destination_y - text_height) / 2.0,
     281             :                                      text_width,
     282             :                                      text_height
     283             :                                    );
     284           0 :             solution_idx ++;
     285             : 
     286             :             /* up */
     287           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     288           0 :                                      (main_line_source_x + main_line_destination_x - text_width) / 2.0,
     289           0 :                                      geometry_rectangle_get_top(&main_line_rect) - text_height - gap,
     290             :                                      text_width,
     291             :                                      text_height
     292             :                                    );
     293           0 :             solution_idx ++;
     294             : 
     295             :             /* down */
     296           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     297           0 :                                      (main_line_source_x + main_line_destination_x - text_width) / 2.0,
     298           0 :                                      geometry_rectangle_get_bottom(&main_line_rect) + gap,
     299             :                                      text_width,
     300             :                                      text_height
     301             :                                    );
     302           0 :             solution_idx ++;
     303             :         }
     304             : 
     305             :         /* there are 0..2 solutions at the dst line segment */
     306           0 :         if ( geometry_point_calc_chess_distance( &main_dst, &dst_end ) > object_dist )
     307             :         {
     308             :             /* this is a noteworthy line segment */
     309           0 :             if ( ( dst_dir == GEOMETRY_DIRECTION_UP ) || ( dst_dir == GEOMETRY_DIRECTION_DOWN ) )
     310             :             {
     311             :                 /* right */
     312           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     313             :                                          main_line_destination_x + gap,
     314           0 :                                          (destination_end_y + main_line_destination_y - text_height) / 2.0,
     315             :                                          text_width,
     316             :                                          text_height
     317             :                                        );
     318           0 :                 solution_idx ++;
     319             : 
     320             :                 /* left */
     321           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     322           0 :                                          main_line_destination_x - text_width - gap,
     323           0 :                                          (destination_end_y + main_line_destination_y - text_height) / 2.0,
     324             :                                          text_width,
     325             :                                          text_height
     326             :                                        );
     327           0 :                 solution_idx ++;
     328             :             }
     329             :             else
     330             :             {
     331             :                 /* down */
     332           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     333           0 :                                          (destination_end_x + main_line_destination_x - text_width) / 2.0,
     334             :                                          main_line_destination_y + gap,
     335             :                                          text_width,
     336             :                                          text_height
     337             :                                        );
     338           0 :                 solution_idx ++;
     339             : 
     340             :                 /* up */
     341           0 :                 geometry_rectangle_init( &(out_solutions[solution_idx]),
     342           0 :                                          (destination_end_x + main_line_destination_x - text_width) / 2.0,
     343           0 :                                          main_line_destination_y - text_height - gap,
     344             :                                          text_width,
     345             :                                          text_height
     346             :                                        );
     347           0 :                 solution_idx ++;
     348             :             }
     349             :         }
     350             : 
     351             :         /* 0..4 at main line source if source end line exists */
     352           0 :         if ( src_dir != GEOMETRY_DIRECTION_CENTER )
     353             :         {
     354           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     355           0 :                                      main_line_source_x - text_width - gap,
     356           0 :                                      main_line_source_y - text_height - gap,
     357             :                                      text_width,
     358             :                                      text_height
     359             :                                    );
     360           0 :             solution_idx ++;
     361           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     362           0 :                                      main_line_source_x - text_width - gap,
     363             :                                      main_line_source_y + gap,
     364             :                                      text_width,
     365             :                                      text_height
     366             :                                    );
     367           0 :             solution_idx ++;
     368           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     369             :                                      main_line_source_x + gap,
     370           0 :                                      main_line_source_y - text_height - gap,
     371             :                                      text_width,
     372             :                                      text_height
     373             :                                    );
     374           0 :             solution_idx ++;
     375           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     376             :                                      main_line_source_x + gap,
     377             :                                      main_line_source_y + gap,
     378             :                                      text_width,
     379             :                                      text_height
     380             :                                    );
     381           0 :             solution_idx ++;
     382             :         }
     383             : 
     384             :         /* 0..4 at main line destination if destination end line exists */
     385           0 :         if ( dst_dir != GEOMETRY_DIRECTION_CENTER )
     386             :         {
     387           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     388           0 :                                      main_line_destination_x - text_width - gap,
     389           0 :                                      main_line_destination_y - text_height - gap,
     390             :                                      text_width,
     391             :                                      text_height
     392             :                                    );
     393           0 :             solution_idx ++;
     394           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     395           0 :                                      main_line_destination_x - text_width - gap,
     396             :                                      main_line_destination_y + gap,
     397             :                                      text_width,
     398             :                                      text_height
     399             :                                    );
     400           0 :             solution_idx ++;
     401           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     402             :                                      main_line_destination_x + gap,
     403           0 :                                      main_line_destination_y - text_height - gap,
     404             :                                      text_width,
     405             :                                      text_height
     406             :                                    );
     407           0 :             solution_idx ++;
     408           0 :             geometry_rectangle_init( &(out_solutions[solution_idx]),
     409             :                                      main_line_destination_x + gap,
     410             :                                      main_line_destination_y + gap,
     411             :                                      text_width,
     412             :                                      text_height
     413             :                                    );
     414           0 :             solution_idx ++;
     415             :         }
     416             : 
     417           0 :         assert( solution_idx > 0 );
     418           0 :         assert( solution_idx <= solutions_max );
     419           0 :         *out_solutions_count = solution_idx;
     420             :     }
     421             : 
     422           0 :     U8_TRACE_END();
     423           0 : }
     424             : 
     425             : 
     426             : /*
     427             : Copyright 2019-2024 Andreas Warnke
     428             : 
     429             : Licensed under the Apache License, Version 2.0 (the "License");
     430             : you may not use this file except in compliance with the License.
     431             : You may obtain a copy of the License at
     432             : 
     433             :     http://www.apache.org/licenses/LICENSE-2.0
     434             : 
     435             : Unless required by applicable law or agreed to in writing, software
     436             : distributed under the License is distributed on an "AS IS" BASIS,
     437             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     438             : See the License for the specific language governing permissions and
     439             : limitations under the License.
     440             : */

Generated by: LCOV version 1.16