Line data Source code
1 : /* File: pencil_floating_label_layouter.inl; Copyright and License: see below */
2 :
3 : #include <assert.h>
4 :
5 0 : static inline void pencil_floating_label_layouter_private_propose_solution( const pencil_floating_label_layouter_t *this_,
6 : const geometry_anchor_t *anchor,
7 : const geometry_dimensions_t *preferred_dim,
8 : draw_feature_label_t *draw_estimator_feat,
9 : const data_feature_t *feature,
10 : draw_relationship_label_t *draw_estimator_rel,
11 : const data_relationship_t *relation,
12 : geometry_rectangle_t *out_solution )
13 : {
14 0 : U8_TRACE_BEGIN();
15 0 : assert( (*this_).pencil_size != NULL );
16 0 : assert( (*this_).layout_data != NULL );
17 0 : assert( (*this_).profile != NULL );
18 0 : assert( (*this_).font_layout != NULL );
19 0 : assert( anchor != NULL );
20 0 : assert( preferred_dim != NULL );
21 0 : if ( draw_estimator_feat == NULL )
22 : {
23 0 : assert( feature == NULL );
24 0 : assert( draw_estimator_rel != NULL );
25 0 : assert( relation != NULL );
26 : }
27 : else
28 : {
29 0 : assert( feature != NULL );
30 0 : assert( draw_estimator_rel == NULL );
31 0 : assert( relation == NULL );
32 : }
33 0 : assert( out_solution != NULL );
34 :
35 : /* get draw area */
36 0 : const layout_diagram_t *const diagram_layout = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
37 0 : const geometry_rectangle_t *const diagram_draw_rect = layout_diagram_get_draw_area_const( diagram_layout );
38 :
39 : /* Start shrinking the available solution space to anchor-alignment and diagram space. */
40 : /* To not accidentially shrink to wrong width/height by taking into account far-away elements, */
41 : /* start with a smaller rectagle of 3..5 * preferred_dim: This allows for moving by +/- 0.5 and re-sizing by factor 2..4 */
42 : geometry_dimensions_t search_area; /* limit the search area to avoid that far-away elements limit width or height */
43 0 : geometry_dimensions_init( &search_area, 3.0 * geometry_dimensions_get_width( preferred_dim ), 5.0 * geometry_dimensions_get_height( preferred_dim ) );
44 0 : geometry_rectangle_t available = geometry_anchor_align_dim( anchor, &search_area );
45 0 : geometry_rectangle_init_by_intersect( &available, &available, diagram_draw_rect );
46 :
47 : /* iterate over all classifiers */
48 0 : const uint32_t count_classifiers = layout_visible_set_get_visible_classifier_count( (*this_).layout_data );
49 0 : for ( uint32_t classifier_index = 0; classifier_index < count_classifiers; classifier_index ++ )
50 : {
51 : const layout_visible_classifier_t *const probe_classifier
52 0 : = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, classifier_index );
53 0 : const geometry_rectangle_t *const probe_space = layout_visible_classifier_get_space_const( probe_classifier );
54 0 : if ( geometry_rectangle_contains_point( probe_space, geometry_anchor_get_point_const( anchor ) ) )
55 : {
56 : /* reference point is inside the space of probe_classifier */
57 : /* shrink the available solution space to the classifier space */
58 0 : geometry_rectangle_init_by_intersect( &available, &available, probe_space );
59 : }
60 : else
61 : {
62 0 : geometry_rectangle_init_by_difference_at_pivot( &available,
63 : &available,
64 : layout_visible_classifier_get_symbol_box_const( probe_classifier ),
65 : geometry_anchor_get_point_const( anchor )
66 : );
67 0 : geometry_rectangle_init_by_difference_at_pivot( &available,
68 : &available,
69 : layout_visible_classifier_get_label_box_const( probe_classifier ),
70 : geometry_anchor_get_point_const( anchor )
71 : );
72 : /*
73 : icon_box is covered by symbol_box
74 : geometry_rectangle_init_by_difference_at_pivot( &available,
75 : &available,
76 : layout_visible_classifier_get_icon_box_const( probe_classifier ),
77 : geometry_anchor_get_point_const( anchor )
78 : );
79 : */
80 : }
81 : }
82 :
83 : /* iterate over all features */
84 0 : const uint32_t count_features = layout_visible_set_get_feature_count( (*this_).layout_data );
85 0 : for ( uint32_t feature_index = 0; feature_index < count_features; feature_index ++ )
86 : {
87 : const layout_feature_t *const probe_feature
88 0 : = layout_visible_set_get_feature_ptr( (*this_).layout_data, feature_index );
89 0 : const data_feature_t *const probe_feature_data = layout_feature_get_data_const( probe_feature );
90 0 : if ( DATA_FEATURE_TYPE_LIFELINE != data_feature_get_main_type( probe_feature_data ) )
91 : {
92 0 : geometry_rectangle_init_by_difference_at_pivot( &available,
93 : &available,
94 : layout_feature_get_symbol_box_const( probe_feature ),
95 : geometry_anchor_get_point_const( anchor )
96 : );
97 : /* note: the label_box may not yet have been initialized in all cases */
98 : }
99 : else
100 : {
101 : /* ignore lifelines - otherwise the labels are shrinked to fit between lielines which looks ugly */
102 : }
103 : }
104 :
105 : /* iterate over all relationships */
106 0 : const uint32_t count_relationships = layout_visible_set_get_relationship_count( (*this_).layout_data );
107 0 : for ( uint32_t relationship_index = 0; relationship_index < count_relationships; relationship_index ++ )
108 : {
109 : const layout_relationship_t *const probe_relationship
110 0 : = layout_visible_set_get_relationship_ptr( (*this_).layout_data, relationship_index );
111 0 : const geometry_connector_t *const conn = layout_relationship_get_shape_const( probe_relationship );
112 0 : const geometry_rectangle_t source = geometry_connector_get_segment_bounds( conn, GEOMETRY_CONNECTOR_SEGMENT_SOURCE );
113 0 : const geometry_rectangle_t middle = geometry_connector_get_segment_bounds( conn, GEOMETRY_CONNECTOR_SEGMENT_MAIN );
114 0 : const geometry_rectangle_t dest = geometry_connector_get_segment_bounds( conn, GEOMETRY_CONNECTOR_SEGMENT_DESTINATION );
115 0 : geometry_rectangle_init_by_difference_at_pivot( &available,
116 : &available,
117 : &source,
118 : geometry_anchor_get_point_const( anchor )
119 : );
120 0 : geometry_rectangle_init_by_difference_at_pivot( &available,
121 : &available,
122 : &middle,
123 : geometry_anchor_get_point_const( anchor )
124 : );
125 0 : geometry_rectangle_init_by_difference_at_pivot( &available,
126 : &available,
127 : &dest,
128 : geometry_anchor_get_point_const( anchor )
129 : );
130 : /* note: the label_box may not yet have been initialized in all cases */
131 : }
132 :
133 : /* if the available solution space has a positive width, layout the label */
134 0 : const double available_width = geometry_rectangle_get_width( &available );
135 0 : const geometry_dimensions_t available_dim = geometry_rectangle_get_dimensions( &available );
136 0 : bool preferred_fits = geometry_dimensions_can_contain( &available_dim, preferred_dim )
137 0 : || ( geometry_dimensions_get_width( preferred_dim ) < 0.000000001 );
138 0 : if ( preferred_fits )
139 : {
140 : /* no need to re-calculate, just shift */
141 0 : *out_solution = geometry_anchor_align_biased_dim( anchor, preferred_dim, &available );
142 : }
143 0 : else if ( available_width > pencil_size_get_standard_font_size( (*this_).pencil_size ) )
144 : {
145 : /* try to fit the label into the available space */
146 : geometry_dimensions_t label_dim;
147 0 : if ( draw_estimator_feat != NULL )
148 : {
149 0 : draw_feature_label_get_key_and_value_dimensions( draw_estimator_feat,
150 : feature,
151 0 : (*this_).profile,
152 : &available_dim,
153 0 : (*this_).pencil_size,
154 0 : (*this_).font_layout,
155 : &label_dim
156 : );
157 : }
158 : else
159 : {
160 0 : draw_relationship_label_get_type_and_name_dimensions( draw_estimator_rel,
161 : relation,
162 0 : (*this_).profile,
163 : &available_dim,
164 0 : (*this_).pencil_size,
165 0 : (*this_).font_layout,
166 : &label_dim
167 : );
168 : }
169 :
170 0 : *out_solution = geometry_anchor_align_biased_dim( anchor, &label_dim, &available );
171 :
172 0 : U8_TRACE_INFO_INT_INT("pencil_floating_label: label does not fit to available space", (int) geometry_dimensions_get_width( preferred_dim ), (int) available_width );
173 0 : U8_TRACE_INFO_INT("pencil_floating_label: suitable label width found:", (int) geometry_dimensions_get_width( &label_dim ) );
174 : }
175 : else
176 : {
177 : /* there is no space, accept any overlap */
178 0 : *out_solution = geometry_anchor_align_dim( anchor, preferred_dim );
179 : }
180 :
181 0 : U8_TRACE_END();
182 0 : }
183 :
184 :
185 : /*
186 : Copyright 2025-2025 Andreas Warnke
187 :
188 : Licensed under the Apache License, Version 2.0 (the "License");
189 : you may not use this file except in compliance with the License.
190 : You may obtain a copy of the License at
191 :
192 : http://www.apache.org/licenses/LICENSE-2.0
193 :
194 : Unless required by applicable law or agreed to in writing, software
195 : distributed under the License is distributed on an "AS IS" BASIS,
196 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
197 : See the License for the specific language governing permissions and
198 : limitations under the License.
199 : */
|