LCOV - code coverage report
Current view: top level - pencil/source - pencil_layouter.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 0.0 % 338 0
Test Date: 2025-05-01 10:10:14 Functions: 0.0 % 9 0

            Line data    Source code
       1              : /* File: pencil_layouter.c; Copyright and License: see below */
       2              : 
       3              : #include "pencil_layouter.h"
       4              : #include "geometry/geometry_non_linear_scale.h"
       5              : #include "u8/u8_trace.h"
       6              : #include <pango/pangocairo.h>
       7              : #include <stdio.h>
       8              : #include <stdlib.h>
       9              : #include <math.h>
      10              : 
      11            0 : void pencil_layouter_init( pencil_layouter_t *this_,
      12              :                            const data_visible_set_t *input_data,
      13              :                            const data_profile_part_t *profile )
      14              : {
      15            0 :     U8_TRACE_BEGIN();
      16            0 :     assert( NULL != input_data );
      17            0 :     assert( NULL != profile );
      18              : 
      19            0 :     pencil_size_init_empty( &((*this_).pencil_size) );
      20            0 :     geometry_grid_init( &((*this_).grid), GEOMETRY_GRID_KIND_0 );
      21            0 :     geometry_dimensions_init_empty( &((*this_).default_classifier_size) );
      22            0 :     data_rules_init( &((*this_).rules) );
      23              : 
      24              :     /* initialize the layout data objects */
      25            0 :     layout_visible_set_init( &((*this_).layout_data), input_data );
      26            0 :     (*this_).profile = profile;
      27              : 
      28            0 :     pencil_diagram_painter_init( &((*this_).diagram_painter) );
      29              : 
      30            0 :     pencil_feature_layouter_init( &((*this_).feature_layouter),
      31              :                                   &((*this_).layout_data),
      32              :                                   profile,
      33            0 :                                   &((*this_).pencil_size)
      34              :                                 );
      35            0 :     pencil_feat_label_layouter_init( &((*this_).feature_label_layouter),
      36              :                                      &((*this_).layout_data),
      37              :                                      profile,
      38            0 :                                      &((*this_).pencil_size)
      39              :                                    );
      40            0 :     pencil_classifier_2d_layouter_init( &((*this_).pencil_classifier_2d_layouter),
      41              :                                         &((*this_).layout_data),
      42              :                                         profile,
      43            0 :                                         &((*this_).pencil_size),
      44              :                                         &((*this_).default_classifier_size),
      45            0 :                                         &((*this_).grid),
      46              :                                         &((*this_).feature_layouter)
      47              :                                       );
      48            0 :     pencil_classifier_1d_layouter_init( &((*this_).pencil_classifier_1d_layouter),
      49              :                                         &((*this_).layout_data),
      50              :                                         profile,
      51            0 :                                         &((*this_).pencil_size)
      52              :                                       );
      53            0 :     pencil_relationship_2d_layouter_init( &((*this_).pencil_relationship_2d_layouter),
      54              :                                           &((*this_).layout_data),
      55              :                                           profile,
      56            0 :                                           &((*this_).pencil_size)
      57              :                                         );
      58            0 :     pencil_relationship_1d_layouter_init( &((*this_).pencil_relationship_1d_layouter),
      59              :                                           &((*this_).layout_data),
      60              :                                           profile,
      61            0 :                                           &((*this_).pencil_size)
      62              :                                         );
      63            0 :     pencil_rel_label_layouter_init( &((*this_).relationship_label_layouter),
      64              :                                     &((*this_).layout_data),
      65              :                                     profile,
      66            0 :                                     &((*this_).pencil_size)
      67              :                                   );
      68            0 :     U8_TRACE_END();
      69            0 : }
      70              : 
      71            0 : void pencil_layouter_reinit( pencil_layouter_t *this_,
      72              :                              const data_visible_set_t *input_data,
      73              :                              const data_profile_part_t *profile )
      74              : {
      75            0 :     U8_TRACE_BEGIN();
      76            0 :     assert( NULL != input_data );
      77            0 :     assert( NULL != profile );
      78            0 :     pencil_layouter_destroy( this_ );
      79            0 :     pencil_layouter_init( this_, input_data, profile );
      80            0 :     U8_TRACE_END();
      81            0 : }
      82              : 
      83            0 : void pencil_layouter_destroy( pencil_layouter_t *this_ )
      84              : {
      85            0 :     U8_TRACE_BEGIN();
      86              : 
      87            0 :     pencil_rel_label_layouter_destroy( &((*this_).relationship_label_layouter) );
      88            0 :     pencil_relationship_1d_layouter_destroy( &((*this_).pencil_relationship_1d_layouter) );
      89            0 :     pencil_relationship_2d_layouter_destroy( &((*this_).pencil_relationship_2d_layouter) );
      90            0 :     pencil_classifier_1d_layouter_destroy( &((*this_).pencil_classifier_1d_layouter) );
      91            0 :     pencil_classifier_2d_layouter_destroy( &((*this_).pencil_classifier_2d_layouter) );
      92            0 :     pencil_feat_label_layouter_destroy( &((*this_).feature_label_layouter) );
      93            0 :     pencil_feature_layouter_destroy( &((*this_).feature_layouter) );
      94              : 
      95            0 :     pencil_diagram_painter_destroy( &((*this_).diagram_painter) );
      96              : 
      97            0 :     pencil_size_destroy( &((*this_).pencil_size) );
      98            0 :     geometry_grid_destroy( &((*this_).grid) );
      99            0 :     geometry_dimensions_destroy( &((*this_).default_classifier_size) );
     100            0 :     data_rules_destroy( &((*this_).rules) );
     101              : 
     102            0 :     layout_visible_set_destroy( &((*this_).layout_data) );
     103              : 
     104            0 :     U8_TRACE_END();
     105            0 : }
     106              : 
     107            0 : void pencil_layouter_define_grid ( pencil_layouter_t *this_,
     108              :                                    geometry_rectangle_t diagram_bounds,
     109              :                                    PangoLayout *font_layout )
     110              : {
     111            0 :     U8_TRACE_BEGIN();
     112            0 :     geometry_rectangle_trace( &diagram_bounds );
     113              : 
     114              :     /* get the diagram data */
     115              :     layout_diagram_t *the_diagram;
     116            0 :     the_diagram = layout_visible_set_get_diagram_ptr( &((*this_).layout_data) );
     117              :     const data_diagram_t *const diagram_data
     118            0 :         = layout_diagram_get_data_const ( the_diagram );
     119              : 
     120              :     /* calculate the pencil-sizes and the drawing rectangle */
     121            0 :     const double width = geometry_rectangle_get_width( &diagram_bounds );
     122            0 :     const double height = geometry_rectangle_get_height( &diagram_bounds );
     123            0 :     pencil_size_reinit( &((*this_).pencil_size), width, height );
     124              : 
     125            0 :     pencil_diagram_painter_do_layout( &((*this_).diagram_painter),
     126              :                                       diagram_data,
     127              :                                       &diagram_bounds,
     128              :                                       (*this_).profile,
     129            0 :                                       &((*this_).pencil_size),
     130              :                                       font_layout,
     131              :                                       the_diagram
     132              :                                     );
     133              :     const geometry_rectangle_t *const diagram_draw_area
     134            0 :         = layout_diagram_get_draw_area_const( the_diagram );
     135              : 
     136              :     /* calculate the axis scales */
     137            0 :     geometry_rectangle_trace( diagram_draw_area );
     138            0 :     const double draw_left = geometry_rectangle_get_left( diagram_draw_area );
     139            0 :     const double draw_top = geometry_rectangle_get_top( diagram_draw_area );
     140            0 :     const double draw_right = geometry_rectangle_get_right( diagram_draw_area );
     141            0 :     const double draw_bottom = geometry_rectangle_get_bottom( diagram_draw_area );
     142            0 :     geometry_grid_reinit( &((*this_).grid), GEOMETRY_GRID_KIND_XY );
     143            0 :     geometry_non_linear_scale_t *const x_scale = geometry_grid_get_x_scale_ptr( &((*this_).grid) );
     144            0 :     geometry_non_linear_scale_t *const y_scale = geometry_grid_get_y_scale_ptr( &((*this_).grid) );
     145            0 :     geometry_non_linear_scale_reinit( x_scale, draw_left, draw_right );
     146            0 :     geometry_non_linear_scale_reinit( y_scale, draw_top, draw_bottom );
     147              : 
     148              :     /* iterate over all classifiers */
     149              :     const uint32_t count
     150            0 :         = layout_visible_set_get_visible_classifier_count ( &((*this_).layout_data) );
     151            0 :     for ( uint32_t index = 0; index < count; index ++ )
     152              :     {
     153              :         const layout_visible_classifier_t *const visible_classifier
     154            0 :             = layout_visible_set_get_visible_classifier_ptr ( &((*this_).layout_data), index );
     155              :         const data_classifier_t *const classifier_data
     156            0 :             = layout_visible_classifier_get_classifier_const( visible_classifier );
     157              :         const uint32_t visible_descendants
     158            0 :             = layout_visible_set_count_descendants( &((*this_).layout_data), visible_classifier );
     159              : 
     160              :         /* adjust the non-linear scales for this classifier (if no contained descendants) */
     161            0 :         if ( 0 == visible_descendants )
     162              :         {
     163            0 :             geometry_non_linear_scale_add_order( x_scale, data_classifier_get_x_order( classifier_data ) );
     164            0 :             geometry_non_linear_scale_add_order( y_scale, data_classifier_get_y_order( classifier_data ) );
     165              :         }
     166              :     }
     167              : 
     168            0 :     U8_TRACE_END();
     169            0 : }
     170              : 
     171            0 : void pencil_layouter_layout_elements ( pencil_layouter_t *this_, PangoLayout *font_layout )
     172              : {
     173            0 :     U8_TRACE_BEGIN();
     174            0 :     assert( font_layout != NULL );
     175              : 
     176              :     /* get the diagram data */
     177            0 :     const layout_diagram_t *const the_diagram = layout_visible_set_get_diagram_ptr( &((*this_).layout_data) );
     178            0 :     const data_diagram_t *const diagram_data = layout_diagram_get_data_const ( the_diagram );
     179            0 :     const data_diagram_type_t diag_type = data_diagram_get_diagram_type ( diagram_data );
     180              : 
     181              :     /* adjust the default classifier rectangle */
     182            0 :     pencil_layouter_private_propose_default_classifier_size( this_ );
     183              : 
     184              :     /* store the classifier bounds into input_data_layouter_t */
     185            0 :     if ( DATA_DIAGRAM_TYPE_LIST == diag_type )
     186              :     {
     187              :         /* calculate the classifier shapes */
     188            0 :         pencil_classifier_1d_layouter_layout_for_list( &((*this_).pencil_classifier_1d_layouter), font_layout );
     189              : 
     190              :         /* calculate the feature shapes */
     191            0 :         pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout );
     192              : 
     193              :         /* hide relationships in simple list and box diagrams */
     194            0 :         pencil_relationship_2d_layouter_layout_void( &((*this_).pencil_relationship_2d_layouter) );
     195              : 
     196              :         /* layout labels of features */
     197            0 :         pencil_feat_label_layouter_do_layout( &((*this_).feature_label_layouter), font_layout );
     198              :     }
     199            0 :     else if ( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type )
     200              :     {
     201              :         /* calculate the classifier shapes */
     202            0 :         pencil_classifier_1d_layouter_layout_for_sequence( &((*this_).pencil_classifier_1d_layouter), font_layout );
     203              : 
     204              :         /* calculate the feature shapes */
     205            0 :         pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout );
     206              : 
     207              :         /* calculate the relationship shapes for a sequence diagram */
     208            0 :         pencil_relationship_1d_layouter_layout_for_sequence( &((*this_).pencil_relationship_1d_layouter) );
     209              : 
     210              :         /* layout labels of relationships */
     211            0 :         pencil_rel_label_layouter_do_layout( &((*this_).relationship_label_layouter), font_layout );
     212              :     }
     213            0 :     else if ( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type )
     214              :     {
     215              :         /* calculate the classifier shapes */
     216            0 :         pencil_classifier_1d_layouter_layout_for_timing( &((*this_).pencil_classifier_1d_layouter), font_layout );
     217              : 
     218              :         /* calculate the feature shapes */
     219            0 :         pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout );
     220              : 
     221              :         /* calculate the relationship shapes for a timing diagram */
     222            0 :         pencil_relationship_1d_layouter_layout_for_timing( &((*this_).pencil_relationship_1d_layouter) );
     223              : 
     224              :         /* layout labels of relationships */
     225            0 :         pencil_rel_label_layouter_do_layout( &((*this_).relationship_label_layouter), font_layout );
     226              :     }
     227              :     else
     228              :     {
     229              :         /* store the classifier bounds into input_data_layouter_t */
     230            0 :         pencil_classifier_2d_layouter_estimate_bounds( &((*this_).pencil_classifier_2d_layouter), font_layout );
     231              : 
     232              :         /* move the classifiers to avoid overlaps */
     233            0 :         pencil_classifier_2d_layouter_move_to_avoid_overlaps( &((*this_).pencil_classifier_2d_layouter) );
     234              : 
     235              :         /* parent classifiers embrace their children step by step */
     236            0 :         pencil_classifier_2d_layouter_embrace_children( &((*this_).pencil_classifier_2d_layouter), font_layout );
     237              : 
     238              :         /* classifiers embrace all children at once and move them if there is space available */
     239            0 :         pencil_classifier_2d_layouter_move_and_embrace_children( &((*this_).pencil_classifier_2d_layouter), font_layout );
     240              : 
     241              :         /* calculate the feature shapes */
     242            0 :         pencil_feature_layouter_do_layout( &((*this_).feature_layouter), font_layout );
     243              : 
     244            0 :         if ( DATA_DIAGRAM_TYPE_BOX_DIAGRAM == diag_type )
     245              :         {
     246              :             /* hide relationships in simple list and box diagrams */
     247            0 :             pencil_relationship_2d_layouter_layout_void( &((*this_).pencil_relationship_2d_layouter) );
     248              :         }
     249            0 :         else if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diag_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diag_type ))
     250              :         {
     251              :             /* calculate the relationship shapes for a communication diagram or an interaction overview diagram (scenario-relations only) */
     252            0 :             pencil_relationship_2d_layouter_layout_for_communication( &((*this_).pencil_relationship_2d_layouter) );
     253              :         }
     254              :         else
     255              :         {
     256              :             /* calculate the relationship shapes */
     257            0 :             pencil_relationship_2d_layouter_layout_standard( &((*this_).pencil_relationship_2d_layouter) );
     258              :         }
     259              : 
     260              :         /* hide containment relationships if children are embraced */
     261            0 :         pencil_classifier_2d_layouter_hide_relations_of_embraced_children( &((*this_).pencil_classifier_2d_layouter) );
     262              : 
     263              :         /* layout labels of features and relationships */
     264            0 :         pencil_feat_label_layouter_do_layout( &((*this_).feature_label_layouter), font_layout );
     265            0 :         pencil_rel_label_layouter_do_layout( &((*this_).relationship_label_layouter), font_layout );
     266              :     }
     267              : 
     268            0 :     U8_TRACE_END();
     269            0 : }
     270              : 
     271            0 : void pencil_layouter_private_propose_default_classifier_size ( pencil_layouter_t *this_ )
     272              : {
     273            0 :     U8_TRACE_BEGIN();
     274              : 
     275              :     /* determine grid cell size */
     276            0 :     const geometry_non_linear_scale_t *const x_scale = geometry_grid_get_x_scale_const( &((*this_).grid) );
     277            0 :     const geometry_non_linear_scale_t *const y_scale = geometry_grid_get_y_scale_const( &((*this_).grid) );
     278            0 :     const double grid_width = geometry_non_linear_scale_get_grid_distances( x_scale );
     279            0 :     const double grid_height = geometry_non_linear_scale_get_grid_distances( y_scale );
     280            0 :     double cell_width = grid_width;
     281            0 :     double cell_height = grid_height;
     282              : 
     283              :     /* check if the grid has enough points for all classifiers */
     284            0 :     const uint_fast32_t interv_count_x = geometry_non_linear_scale_get_grid_intervals( x_scale );
     285            0 :     const uint_fast32_t interv_count_y = geometry_non_linear_scale_get_grid_intervals( y_scale );
     286            0 :     const uint_fast32_t inner_point_count = (interv_count_x-1)*(interv_count_y-1);
     287            0 :     const uint_fast32_t c_count = layout_visible_set_get_visible_classifier_count ( &((*this_).layout_data) );
     288            0 :     if ( inner_point_count < c_count )
     289              :     {
     290              :         /* many classifiers share the same location */
     291              :         /* default size is calculated based on count and size, not on grid */
     292              :         /* get the diagram data */
     293              :         const layout_diagram_t *const the_diagram
     294            0 :             = layout_visible_set_get_diagram_ptr( &((*this_).layout_data) );
     295              :         const geometry_rectangle_t *const diagram_draw_area
     296            0 :             = layout_diagram_get_draw_area_const( the_diagram );
     297            0 :         const double draw_width = geometry_rectangle_get_width ( diagram_draw_area );
     298            0 :         const double draw_height = geometry_rectangle_get_height ( diagram_draw_area );
     299            0 :         const uint_fast32_t border = 1;
     300              :         uint_fast32_t rows;
     301              :         uint_fast32_t columns;
     302            0 :         if ( c_count <= 6 )
     303              :         {
     304            0 :             columns = 2;
     305            0 :             rows = (c_count+1)/2;
     306              :         }
     307            0 :         else if ( c_count <= 12 )
     308              :         {
     309            0 :             columns = 3;
     310            0 :             rows = (c_count+2)/3;
     311              :         }
     312            0 :         else if ( c_count <= 24 )
     313              :         {
     314            0 :             columns = 4;
     315            0 :             rows = (c_count+3)/4;
     316              :         }
     317              :         else
     318              :         {
     319            0 :             columns = 5;
     320            0 :             rows = (c_count+4)/5;
     321              :         }
     322            0 :         cell_width = draw_width / (columns+border);
     323            0 :         cell_height = draw_height / (rows+border);
     324              :     }
     325              : 
     326              :     /* determine standard gap between objects */
     327            0 :     const double gap = pencil_size_get_preferred_object_distance( &((*this_).pencil_size) );
     328              : 
     329              :     /* set the default size to grid cell minus a gap on each side, minus extra gap on top for containers */
     330            0 :     geometry_dimensions_t *const default_size = &((*this_).default_classifier_size);
     331            0 :     geometry_dimensions_reinit( default_size, cell_width, cell_height );
     332            0 :     const double x_space = 3.0 * gap;  /* space for enclosing parents and for relationships */
     333            0 :     const double y_space = 4.0 * gap;  /* space for enclosing parents (including title-line) and for relationships */
     334            0 :     geometry_dimensions_expand ( default_size, -x_space, -y_space ); /* ensures non-negative values */
     335              : 
     336              :     /* for aesthetic reasons, ensure that the default dimension is more wide than high */
     337            0 :     const double w = geometry_dimensions_get_width( default_size );
     338            0 :     const double h = geometry_dimensions_get_height( default_size );
     339            0 :     if ( w * 0.75 < h )
     340              :     {
     341            0 :         geometry_dimensions_reinit( default_size, w, w * 0.75 );
     342              :     }
     343              : 
     344            0 :     U8_TRACE_END();
     345            0 : }
     346              : 
     347            0 : pencil_error_t pencil_layouter_get_classifier_order_at_pos ( const pencil_layouter_t *this_,
     348              :                                                              data_classifier_type_t c_type,
     349              :                                                              double x,
     350              :                                                              double y,
     351              :                                                              double snap_distance,
     352              :                                                              layout_order_t* out_layout_order )
     353              : {
     354            0 :     U8_TRACE_BEGIN();
     355            0 :     assert ( NULL != out_layout_order );
     356              : 
     357            0 :     pencil_error_t result = PENCIL_ERROR_NONE;
     358              : 
     359              :     /* get the bounding box of the diagram */
     360              :     const layout_diagram_t *const the_diagram
     361            0 :         = layout_visible_set_get_diagram_const( &((*this_).layout_data) );
     362              :     const geometry_rectangle_t *const diagram_bounds
     363            0 :         = layout_diagram_get_bounds_const( the_diagram );
     364              :     const geometry_rectangle_t *const diagram_draw_area
     365            0 :         = layout_diagram_get_draw_area_const( the_diagram );
     366              : 
     367              :     /* get the diagram type */
     368              :     const data_diagram_t *const diagram_data
     369            0 :         = layout_diagram_get_data_const ( the_diagram );
     370              :     const data_diagram_type_t diag_type
     371            0 :         = data_diagram_get_diagram_type ( diagram_data );
     372              : 
     373              :     /* get the classifier type */
     374              :     const bool scenario_semantics
     375            0 :         = data_rules_classifier_has_scenario_semantics( &((*this_).rules),
     376              :                                                         diag_type,
     377              :                                                         c_type
     378              :                                                       );
     379              : 
     380            0 :     if ( ! geometry_rectangle_contains( diagram_bounds, x, y ) )
     381              :     {
     382            0 :         layout_order_init_empty( out_layout_order );
     383            0 :         result = PENCIL_ERROR_OUT_OF_BOUNDS;
     384              :     }
     385              :     else
     386              :     {
     387            0 :         if ((( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type )&& scenario_semantics)
     388            0 :             || (( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type)&&( ! scenario_semantics)))
     389            0 :         {
     390              :             /* classifiers are a horizontal list */
     391            0 :             const double draw_left = geometry_rectangle_get_left(diagram_draw_area);
     392            0 :             const double draw_right = geometry_rectangle_get_right(diagram_draw_area);
     393              :             int32_t list_order;
     394            0 :             if ( x <= draw_left )
     395              :             {
     396            0 :                 list_order = INT32_MIN;
     397              :             }
     398            0 :             else if ( x >= draw_right )
     399              :             {
     400            0 :                 list_order = INT32_MAX;
     401              :             }
     402              :             else
     403              :             {
     404            0 :                 list_order = ((uint32_t)(( x - draw_left ) / ( draw_right - draw_left ) * UINT32_MAX));
     405            0 :                 list_order += INT32_MIN;
     406              :             }
     407            0 :             layout_order_init_list( out_layout_order, list_order );
     408              :         }
     409            0 :         else if ((( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type )&& scenario_semantics)
     410            0 :             || ( DATA_DIAGRAM_TYPE_LIST == diag_type )
     411            0 :             || (( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type)&&( ! scenario_semantics)))
     412            0 :         {
     413              :             /* classifiers are a vertical list */
     414            0 :             const double draw_top = geometry_rectangle_get_top(diagram_draw_area);
     415            0 :             const double draw_bottom = geometry_rectangle_get_bottom(diagram_draw_area);
     416              :             int32_t list_order;
     417            0 :             if ( y <= draw_top )
     418              :             {
     419            0 :                 list_order = INT32_MIN;
     420              :             }
     421            0 :             else if ( y >= draw_bottom )
     422              :             {
     423            0 :                 list_order = INT32_MAX;
     424              :             }
     425              :             else
     426              :             {
     427            0 :                 list_order = ((uint32_t)(( y - draw_top ) / ( draw_bottom - draw_top ) * UINT32_MAX));
     428            0 :                 list_order += INT32_MIN;
     429              :             }
     430            0 :             layout_order_init_list( out_layout_order, list_order );
     431              :         }
     432              :         else
     433              :         {
     434              :             /* classifiers are x/y arranged */
     435              :             const geometry_non_linear_scale_t *const x_scale
     436            0 :                 = geometry_grid_get_x_scale_const( &((*this_).grid) );
     437              :             const geometry_non_linear_scale_t *const y_scale
     438            0 :                 = geometry_grid_get_y_scale_const( &((*this_).grid) );
     439            0 :             const int32_t x_order = geometry_non_linear_scale_get_order( x_scale, x, snap_distance );
     440            0 :             const int32_t y_order = geometry_non_linear_scale_get_order( y_scale, y, snap_distance );
     441            0 :             layout_order_init_x_y( out_layout_order, x_order, y_order );
     442              :         }
     443              :     }
     444              : 
     445            0 :     U8_TRACE_END_ERR( result );
     446            0 :     return result;
     447              : }
     448              : 
     449            0 : pencil_error_t pencil_layouter_get_feature_order_at_pos ( const pencil_layouter_t *this_,
     450              :                                                           const data_feature_t *feature_ptr,
     451              :                                                           double x,
     452              :                                                           double y,
     453              :                                                           layout_order_t* out_layout_order )
     454              : {
     455            0 :     U8_TRACE_BEGIN();
     456            0 :     assert ( NULL != out_layout_order );
     457            0 :     assert ( NULL != feature_ptr );
     458              : 
     459            0 :     pencil_error_t result = PENCIL_ERROR_NONE;
     460              : 
     461              :     /* get data of feature */
     462              :     data_row_t parent_classifier_id;
     463              :     data_feature_type_t feature_type;
     464            0 :     feature_type = data_feature_get_main_type ( feature_ptr );
     465            0 :     parent_classifier_id = data_feature_get_classifier_row_id ( feature_ptr );
     466              : 
     467              :     /* get the bounding box of the diagram */
     468              :     const layout_diagram_t *const the_diagram
     469            0 :         = layout_visible_set_get_diagram_const( &((*this_).layout_data) );
     470              :     const geometry_rectangle_t *const diagram_bounds
     471            0 :         = layout_diagram_get_bounds_const( the_diagram );
     472              : 
     473            0 :     if ( ! geometry_rectangle_contains( diagram_bounds, x, y ) )
     474              :     {
     475            0 :         layout_order_init_empty( out_layout_order );
     476            0 :         result = PENCIL_ERROR_OUT_OF_BOUNDS;
     477              :     }
     478            0 :     else if ( DATA_ROW_VOID == parent_classifier_id ) {
     479            0 :         U8_LOG_WARNING( "feature to move has no parent classifier!" );
     480            0 :         layout_order_init_empty( out_layout_order );
     481            0 :         result = PENCIL_ERROR_UNKNOWN_OBJECT;
     482              :     }
     483              :     else
     484              :     {
     485              :         /* iterate over all classifiers, search the closest_parent_instance */
     486            0 :         const layout_visible_classifier_t *closest_parent_instance = NULL;
     487              :         const uint32_t classfy_count
     488            0 :             = layout_visible_set_get_visible_classifier_count ( &((*this_).layout_data) );
     489            0 :         for ( uint32_t classfy_index = 0; classfy_index < classfy_count; classfy_index ++ )
     490              :         {
     491              :             const layout_visible_classifier_t *const visible_classifier
     492            0 :                 = layout_visible_set_get_visible_classifier_const ( &((*this_).layout_data), classfy_index );
     493              :             const data_row_t classfy_id
     494            0 :                 = layout_visible_classifier_get_classifier_id ( visible_classifier );
     495            0 :             if ( parent_classifier_id == classfy_id )
     496              :             {
     497            0 :                 if ( NULL == closest_parent_instance )
     498              :                 {
     499            0 :                     closest_parent_instance = visible_classifier;
     500              :                 }
     501              :                 else
     502              :                 {
     503              :                     const geometry_rectangle_t *const classfier_symbol_box
     504            0 :                         = layout_visible_classifier_get_symbol_box_const ( visible_classifier );
     505              :                     const geometry_rectangle_t *const closest_parent_symbol_box
     506            0 :                         = layout_visible_classifier_get_symbol_box_const ( closest_parent_instance );
     507            0 :                     const double classfy_distance = geometry_rectangle_calc_chess_distance( classfier_symbol_box, x, y );
     508              :                     const double closest_parent_distance
     509            0 :                         = geometry_rectangle_calc_chess_distance( closest_parent_symbol_box, x, y );
     510            0 :                     if ( classfy_distance < closest_parent_distance )
     511              :                     {
     512            0 :                         closest_parent_instance = visible_classifier;
     513              :                     }
     514              :                 }
     515              :             }
     516              :         }
     517              : 
     518            0 :         if ( NULL != closest_parent_instance )
     519              :         {
     520            0 :             switch (feature_type)
     521              :             {
     522            0 :                 case DATA_FEATURE_TYPE_PROPERTY:  /* or */
     523              :                 case DATA_FEATURE_TYPE_OPERATION:  /* or */
     524              :                 case DATA_FEATURE_TYPE_TAGGED_VALUE:  /* or */
     525              :                 default: /* this may happen if a new database file has been read by an old program version */
     526              :                 {
     527            0 :                     int32_t max_order_above = INT32_MIN;
     528            0 :                     int32_t min_order_below = INT32_MAX;
     529              :                     /* iterate over all contained features */
     530            0 :                     const uint32_t f_count = layout_visible_set_get_feature_count( &((*this_).layout_data) );
     531            0 :                     for ( uint32_t f_idx = 0; f_idx < f_count; f_idx ++ )
     532              :                     {
     533              :                         /* check if feature belongs to same parent classifier */
     534              :                         const layout_feature_t *const the_feature
     535            0 :                             = layout_visible_set_get_feature_const ( &((*this_).layout_data), f_idx );
     536              :                         const layout_visible_classifier_t *const vis_classfy
     537            0 :                             = layout_feature_get_classifier_const ( the_feature );
     538            0 :                         if ( closest_parent_instance == vis_classfy )
     539              :                         {
     540              :                             /* check if feature is not the moved one */
     541              :                             const data_feature_t *const data_feature
     542            0 :                                 = layout_feature_get_data_const ( the_feature );
     543            0 :                             if ( data_feature_get_row_id ( feature_ptr ) != data_feature_get_row_id ( data_feature ) )
     544              :                             {
     545              :                                 const int32_t list_order
     546            0 :                                     = data_feature_get_list_order( data_feature );
     547              :                                 const geometry_rectangle_t *const feature_symbol_box
     548            0 :                                     = layout_feature_get_symbol_box_const ( the_feature );
     549            0 :                                 if ( y < geometry_rectangle_get_center_y( feature_symbol_box ) )
     550              :                                 {
     551            0 :                                     if ( list_order < min_order_below ) { min_order_below = list_order; }
     552              :                                 }
     553              :                                 else
     554              :                                 {
     555            0 :                                     if ( list_order > max_order_above ) { max_order_above = list_order; }
     556              :                                 }
     557              :                             }
     558              :                         }
     559              :                     }
     560              : 
     561            0 :                     if ( max_order_above == INT32_MIN )
     562              :                     {
     563            0 :                         if ( min_order_below == INT32_MAX )
     564              :                         {
     565              :                             /* nothing above, nothing below */
     566            0 :                             layout_order_init_list( out_layout_order, 0 );
     567              :                         }
     568              :                         else
     569              :                         {
     570              :                             /* nothing above */
     571            0 :                             layout_order_init_list( out_layout_order, min_order_below - 32768 );
     572              :                         }
     573              :                     }
     574              :                     else
     575              :                     {
     576            0 :                         if ( min_order_below == INT32_MAX )
     577              :                         {
     578              :                             /* nothing below */
     579            0 :                             layout_order_init_list( out_layout_order, max_order_above + 32768 );
     580              :                         }
     581              :                         else
     582              :                         {
     583              :                             /* regular interval */
     584            0 :                             layout_order_init_list( out_layout_order, (max_order_above + min_order_below)/2 );
     585              :                         }
     586              :                     }
     587              :                 }
     588            0 :                 break;
     589              : 
     590            0 :                 case DATA_FEATURE_TYPE_PORT:  /* or */
     591              :                 case DATA_FEATURE_TYPE_PROVIDED_INTERFACE:  /* or */
     592              :                 case DATA_FEATURE_TYPE_REQUIRED_INTERFACE:  /* or */
     593              :                 case DATA_FEATURE_TYPE_IN_PORT_PIN:  /* or */
     594              :                 case DATA_FEATURE_TYPE_OUT_PORT_PIN:  /* or */
     595              :                 case DATA_FEATURE_TYPE_ENTRY:  /* or */
     596              :                 case DATA_FEATURE_TYPE_EXIT:
     597              :                 {
     598              :                     const geometry_rectangle_t *const closest_parent_symbol_box
     599            0 :                         = layout_visible_classifier_get_symbol_box_const ( closest_parent_instance );
     600            0 :                     const double center_x = geometry_rectangle_get_center_x( closest_parent_symbol_box );
     601            0 :                     const double center_y = geometry_rectangle_get_center_y( closest_parent_symbol_box );
     602            0 :                     const double width = geometry_rectangle_get_width( closest_parent_symbol_box );
     603            0 :                     const double height = geometry_rectangle_get_height( closest_parent_symbol_box );
     604            0 :                     const double delta_x = x - center_x;
     605            0 :                     const double delty_y = y - center_y;
     606            0 :                     const double relative_delta_x = delta_x * height;
     607            0 :                     const double relative_delta_y = delty_y * width;
     608            0 :                     const double distance_x = ( x < center_x ) ? (center_x - x) : (x - center_x);
     609            0 :                     const double distance_y = ( y < center_y ) ? (center_y - y) : (y - center_y);
     610            0 :                     const double relative_dist_x = distance_x * height;
     611            0 :                     const double relative_dist_y = distance_y * width;
     612              :                     int32_t order;
     613            0 :                     if ( relative_dist_x > relative_dist_y )
     614              :                     {
     615            0 :                         if ( x < center_x )
     616              :                         {
     617              :                             /* x,y is on left side, order is between 0 and INT32_MAX/2 */
     618            0 :                             order = INT32_MAX*(relative_delta_y/(relative_dist_x+0.1)*0.25+0.25);
     619              :                         }
     620              :                         else
     621              :                         {
     622              :                             /* x,y is on right side, order is between INT32_MIN and INT32_MIN/2 */
     623            0 :                             order = INT32_MIN*(relative_delta_y/(relative_dist_x+0.1)*0.25+0.75);
     624              :                         }
     625              :                     }
     626              :                     else
     627              :                     {
     628            0 :                         if ( y < center_y )
     629              :                         {
     630              :                             /* x,y is on upper side, order is between INT32_MIN/2 and 0 */
     631            0 :                             order = INT32_MIN*(relative_delta_x/(relative_dist_y+0.1)*0.25+0.25);
     632              :                         }
     633              :                         else
     634              :                         {
     635              :                             /* x,y is on lower side, order is between INT32_MAX/2 and INT32_MAX */
     636            0 :                             order = INT32_MAX*(relative_delta_x/(relative_dist_y+0.1)*0.25+0.75);
     637              :                         }
     638              :                     }
     639            0 :                     layout_order_init_list( out_layout_order, order );
     640              :                 }
     641            0 :                 break;
     642              : 
     643            0 :                 case DATA_FEATURE_TYPE_LIFELINE:
     644              :                 {
     645            0 :                     U8_TRACE_INFO( "feature to move is a lifeline and therefore cannot move." );
     646            0 :                     layout_order_init_empty( out_layout_order );
     647            0 :                     result = PENCIL_ERROR_UNKNOWN_OBJECT;
     648              :                 }
     649            0 :                 break;
     650              :             }
     651              :         }
     652              :         else
     653              :         {
     654            0 :             U8_LOG_WARNING( "parent classifier of feature is not visible; possibly array size too small?" );
     655            0 :             layout_order_init_empty( out_layout_order );
     656            0 :             result = PENCIL_ERROR_UNKNOWN_OBJECT;
     657              :         }
     658              :     }
     659              : 
     660            0 :     U8_TRACE_END_ERR( result );
     661            0 :     return result;
     662              : }
     663              : 
     664            0 : pencil_error_t pencil_layouter_get_relationship_order_at_pos ( const pencil_layouter_t *this_,
     665              :                                                                double x,
     666              :                                                                double y,
     667              :                                                                layout_order_t* out_layout_order )
     668              : {
     669            0 :     U8_TRACE_BEGIN();
     670            0 :     assert ( NULL != out_layout_order );
     671              : 
     672            0 :     pencil_error_t result = PENCIL_ERROR_NONE;
     673              : 
     674              :     /* get the bounding box of the diagram */
     675              :     const layout_diagram_t *const the_diagram
     676            0 :         = layout_visible_set_get_diagram_const( &((*this_).layout_data) );
     677              :     const geometry_rectangle_t *const diagram_bounds
     678            0 :         = layout_diagram_get_bounds_const( the_diagram );
     679              :     const geometry_rectangle_t *const diagram_draw_area
     680            0 :         = layout_diagram_get_draw_area_const( the_diagram );
     681              : 
     682              :     /* get the diagram type */
     683              :     const data_diagram_t *const diagram_data
     684            0 :         = layout_diagram_get_data_const ( the_diagram );
     685              :     const data_diagram_type_t diag_type
     686            0 :         = data_diagram_get_diagram_type ( diagram_data );
     687              : 
     688            0 :     if ( ! geometry_rectangle_contains( diagram_bounds, x, y ) )
     689              :     {
     690            0 :         layout_order_init_empty( out_layout_order );
     691            0 :         result = PENCIL_ERROR_OUT_OF_BOUNDS;
     692              :     }
     693              :     else
     694              :     {
     695            0 :         if (( DATA_DIAGRAM_TYPE_BOX_DIAGRAM == diag_type )
     696            0 :             || ( DATA_DIAGRAM_TYPE_LIST == diag_type ))
     697              :         {
     698              :             /* relationships are hidden in lists and box-diagrams */
     699            0 :             layout_order_init_empty( out_layout_order );
     700            0 :             result = PENCIL_ERROR_OUT_OF_BOUNDS;
     701              :         }
     702            0 :         else if (( DATA_DIAGRAM_TYPE_UML_COMMUNICATION_DIAGRAM == diag_type )||( DATA_DIAGRAM_TYPE_INTERACTION_OVERVIEW_DIAGRAM == diag_type ))
     703              :         {
     704              :             /* communication diagrams and interaction overview diagrams do not care about list_orders of relationships */
     705            0 :             layout_order_init_empty( out_layout_order );
     706              :         }
     707            0 :         else if ( DATA_DIAGRAM_TYPE_UML_SEQUENCE_DIAGRAM == diag_type )
     708              :         {
     709            0 :             const double draw_top = geometry_rectangle_get_top(diagram_draw_area);
     710            0 :             const double draw_bottom = geometry_rectangle_get_bottom(diagram_draw_area);
     711              :             int32_t list_order;
     712            0 :             if ( y <= draw_top )
     713              :             {
     714            0 :                 list_order = INT32_MIN;
     715              :             }
     716            0 :             else if ( y >= draw_bottom )
     717              :             {
     718            0 :                 list_order = INT32_MAX;
     719              :             }
     720              :             else
     721              :             {
     722            0 :                 list_order = ((uint32_t)(( y - draw_top ) / ( draw_bottom - draw_top ) * UINT32_MAX));
     723            0 :                 list_order += INT32_MIN;
     724              :             }
     725            0 :             layout_order_init_list( out_layout_order, list_order );
     726              :         }
     727            0 :         else if ( DATA_DIAGRAM_TYPE_UML_TIMING_DIAGRAM == diag_type )
     728              :         {
     729            0 :             const double draw_left = geometry_rectangle_get_left(diagram_draw_area);
     730            0 :             const double draw_right = geometry_rectangle_get_right(diagram_draw_area);
     731              :             int32_t list_order;
     732            0 :             if ( x <= draw_left )
     733              :             {
     734            0 :                 list_order = INT32_MIN;
     735              :             }
     736            0 :             else if ( x >= draw_right )
     737              :             {
     738            0 :                 list_order = INT32_MAX;
     739              :             }
     740              :             else
     741              :             {
     742            0 :                 list_order = ((uint32_t)(( x - draw_left ) / ( draw_right - draw_left ) * UINT32_MAX));
     743            0 :                 list_order += INT32_MIN;
     744              :             }
     745            0 :             layout_order_init_list( out_layout_order, list_order );
     746              :         }
     747              :         else
     748              :         {
     749              :             /* all other diagram types do not care about list_orders of relationships */
     750            0 :             layout_order_init_empty( out_layout_order );
     751              :         }
     752              :     }
     753              : 
     754            0 :     U8_TRACE_END_ERR( result );
     755            0 :     return result;
     756              : }
     757              : 
     758              : 
     759              : /*
     760              : Copyright 2017-2025 Andreas Warnke
     761              : 
     762              : Licensed under the Apache License, Version 2.0 (the "License");
     763              : you may not use this file except in compliance with the License.
     764              : You may obtain a copy of the License at
     765              : 
     766              :     http://www.apache.org/licenses/LICENSE-2.0
     767              : 
     768              : Unless required by applicable law or agreed to in writing, software
     769              : distributed under the License is distributed on an "AS IS" BASIS,
     770              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     771              : See the License for the specific language governing permissions and
     772              : limitations under the License.
     773              : */
        

Generated by: LCOV version 2.0-1