Line data Source code
1 : /* File: pencil_classifier_2d_layouter.c; Copyright and License: see below */
2 :
3 : #include "pencil_classifier_2d_layouter.h"
4 : #include "u8/u8_trace.h"
5 : #include <pango/pangocairo.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <math.h>
9 :
10 0 : void pencil_classifier_2d_layouter_init( pencil_classifier_2d_layouter_t *this_,
11 : pencil_layout_data_t *layout_data,
12 : const data_profile_part_t *profile,
13 : const pencil_size_t *pencil_size,
14 : geometry_dimensions_t *default_classifier_size,
15 : geometry_non_linear_scale_t *x_scale,
16 : geometry_non_linear_scale_t *y_scale,
17 : pencil_feature_layouter_t *feature_layouter )
18 : {
19 0 : U8_TRACE_BEGIN();
20 0 : assert( NULL != layout_data );
21 0 : assert( NULL != profile );
22 0 : assert( NULL != pencil_size );
23 0 : assert( NULL != default_classifier_size );
24 0 : assert( NULL != x_scale );
25 0 : assert( NULL != y_scale );
26 0 : assert( NULL != feature_layouter );
27 :
28 0 : (*this_).layout_data = layout_data;
29 0 : (*this_).profile = profile;
30 0 : (*this_).pencil_size = pencil_size;
31 0 : (*this_).default_classifier_size = default_classifier_size;
32 0 : (*this_).x_scale = x_scale;
33 0 : (*this_).y_scale = y_scale;
34 0 : (*this_).feature_layouter = feature_layouter;
35 0 : pencil_classifier_composer_init( &((*this_).classifier_composer) );
36 :
37 : /* get draw area */
38 : {
39 0 : layout_diagram_t *diagram_layout;
40 0 : diagram_layout = pencil_layout_data_get_diagram_ptr( (*this_).layout_data );
41 0 : (*this_).diagram_draw_area = layout_diagram_get_draw_area_const( diagram_layout );
42 : }
43 :
44 0 : U8_TRACE_END();
45 0 : }
46 :
47 0 : void pencil_classifier_2d_layouter_destroy( pencil_classifier_2d_layouter_t *this_ )
48 : {
49 0 : U8_TRACE_BEGIN();
50 :
51 0 : pencil_classifier_composer_destroy( &((*this_).classifier_composer) );
52 :
53 0 : U8_TRACE_END();
54 0 : }
55 :
56 : /* ================================ INITIAL LAYOUT ================================ */
57 :
58 0 : void pencil_classifier_2d_layouter_estimate_bounds( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout )
59 : {
60 0 : U8_TRACE_BEGIN();
61 :
62 : /* store the classifier bounds into input_data_layouter_t */
63 0 : const uint32_t count_clasfy = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data );
64 0 : for ( uint32_t index = 0; index < count_clasfy; index ++ )
65 : {
66 0 : layout_visible_classifier_t *const classifier_layout
67 0 : = pencil_layout_data_get_visible_classifier_ptr ( (*this_).layout_data, index );
68 :
69 : /* set the bounds, space and label_box of the classifier layout */
70 : {
71 0 : const bool shows_contained_children = false; /* if classifier has children, this will be updated later */
72 : /* when calling pencil_classifier_composer_set_space_and_label */
73 :
74 : /* init by default size */
75 : {
76 0 : geometry_rectangle_t envelope;
77 0 : geometry_rectangle_init( &envelope,
78 : 0.0,
79 : 0.0,
80 0 : geometry_dimensions_get_width( (*this_).default_classifier_size ),
81 0 : geometry_dimensions_get_height( (*this_).default_classifier_size ) );
82 :
83 0 : pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer),
84 : &envelope,
85 : shows_contained_children,
86 : (*this_).profile,
87 : (*this_).pencil_size,
88 : font_layout,
89 : classifier_layout
90 : );
91 :
92 0 : geometry_rectangle_destroy( &envelope );
93 : }
94 :
95 : /* check if inner space is big enough for contained features */
96 : {
97 0 : geometry_dimensions_t features_dim;
98 0 : geometry_dimensions_init_empty( &features_dim );
99 0 : pencil_feature_layouter_calculate_features_bounds( (*this_).feature_layouter,
100 : layout_visible_classifier_get_diagramelement_id( classifier_layout ),
101 : font_layout,
102 : &features_dim
103 : );
104 :
105 0 : const geometry_rectangle_t *const space_rect
106 0 : = layout_visible_classifier_get_space_const( classifier_layout );
107 0 : const geometry_dimensions_t space_dim = geometry_rectangle_get_dimensions( space_rect );
108 :
109 0 : if ( ! geometry_dimensions_can_contain( &space_dim, &features_dim ) )
110 : {
111 0 : geometry_rectangle_t new_space;
112 0 : geometry_rectangle_copy( &new_space, space_rect );
113 0 : const double delta_width
114 0 : = geometry_dimensions_get_width( &features_dim ) - geometry_rectangle_get_width( space_rect );
115 0 : const double delta_height
116 0 : = geometry_dimensions_get_height( &features_dim ) - geometry_rectangle_get_height( space_rect );
117 0 : geometry_rectangle_expand_4dir( &new_space,
118 : (delta_width<0.0) ? 0.0 : 0.5*delta_width,
119 : (delta_height<0.0) ? 0.0 : 0.5*delta_height );
120 :
121 0 : pencil_classifier_composer_expand_space( &((*this_).classifier_composer),
122 : &new_space,
123 : shows_contained_children,
124 : (*this_).profile,
125 : (*this_).pencil_size,
126 : font_layout,
127 : classifier_layout
128 : );
129 :
130 0 : geometry_rectangle_destroy( &new_space );
131 : }
132 :
133 0 : geometry_dimensions_destroy( &features_dim );
134 : }
135 : }
136 :
137 : /* move the classifier rectangles to the target location */
138 : {
139 0 : const data_visible_classifier_t *const visible_classifier2
140 0 : = layout_visible_classifier_get_data_const ( classifier_layout );
141 0 : const data_classifier_t *const classifier2
142 0 : = data_visible_classifier_get_classifier_const( visible_classifier2 );
143 0 : const geometry_rectangle_t *const classifier_symbol_box
144 0 : = layout_visible_classifier_get_symbol_box_const( classifier_layout );
145 :
146 0 : const double act_center_x = geometry_rectangle_get_center_x( classifier_symbol_box );
147 0 : const double act_center_y = geometry_rectangle_get_center_y( classifier_symbol_box );
148 0 : const int32_t order_x = data_classifier_get_x_order( classifier2 );
149 0 : const int32_t order_y = data_classifier_get_y_order( classifier2 );
150 0 : const double center_x = geometry_non_linear_scale_get_location( (*this_).x_scale, order_x );
151 0 : const double center_y = geometry_non_linear_scale_get_location( (*this_).y_scale, order_y );
152 0 : layout_visible_classifier_shift( classifier_layout, center_x-act_center_x, center_y-act_center_y );
153 : }
154 : }
155 :
156 0 : U8_TRACE_END();
157 0 : }
158 :
159 : /* ================================ MOVE TO AVOID OVERLAPS ================================ */
160 :
161 0 : void pencil_classifier_2d_layouter_move_to_avoid_overlaps ( pencil_classifier_2d_layouter_t *this_ )
162 : {
163 0 : U8_TRACE_BEGIN();
164 0 : assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS );
165 :
166 0 : universal_array_index_sorter_t sorted;
167 0 : universal_array_index_sorter_init( &sorted );
168 :
169 : /* sort the classifiers by their movement-needs */
170 0 : pencil_classifier_2d_layouter_private_propose_move_processing_order ( this_, &sorted );
171 :
172 : /* move the classifiers */
173 0 : uint32_t count_sorted;
174 0 : count_sorted = universal_array_index_sorter_get_count( &sorted );
175 0 : for ( uint32_t sort_index = 0; sort_index < count_sorted; sort_index ++ )
176 : {
177 : /* declaration of list of options */
178 0 : uint32_t solutions_count = 0;
179 0 : static const uint32_t SOLUTIONS_MAX = 6;
180 0 : double solution_move_dx[6];
181 0 : double solution_move_dy[6];
182 :
183 : /* propose options of moving left/right/up/down */
184 0 : pencil_classifier_2d_layouter_private_propose_4dir_move_solutions( this_,
185 : &sorted,
186 : sort_index,
187 : SOLUTIONS_MAX-1,
188 : solution_move_dx,
189 : solution_move_dy,
190 : &solutions_count
191 : );
192 : /* propose options of moving close at origin-area */
193 0 : pencil_classifier_2d_layouter_private_propose_anchored_solution( this_,
194 : &sorted,
195 : sort_index,
196 0 : &(solution_move_dx[solutions_count]),
197 : &(solution_move_dy[solutions_count])
198 : );
199 0 : solutions_count ++;
200 :
201 : /* select best option */
202 0 : uint32_t index_of_best;
203 0 : if ( 1 == solutions_count )
204 : {
205 0 : index_of_best = 0;
206 : }
207 : else
208 : {
209 0 : pencil_classifier_2d_layouter_private_select_move_solution( this_,
210 : &sorted,
211 : sort_index,
212 : solutions_count,
213 : solution_move_dx,
214 : solution_move_dy,
215 : &index_of_best
216 : );
217 : }
218 :
219 : /* perform best option */
220 0 : uint32_t index;
221 0 : index = universal_array_index_sorter_get_array_index( &sorted, sort_index );
222 : /* move the classifier */
223 0 : layout_visible_classifier_t *the_classifier;
224 0 : the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index );
225 0 : layout_visible_classifier_shift( the_classifier, solution_move_dx[index_of_best], solution_move_dy[index_of_best] );
226 : }
227 :
228 0 : universal_array_index_sorter_destroy( &sorted );
229 :
230 0 : U8_TRACE_END();
231 0 : }
232 :
233 0 : void pencil_classifier_2d_layouter_private_propose_move_processing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
234 : {
235 0 : U8_TRACE_BEGIN();
236 0 : assert ( NULL != out_sorted );
237 0 : assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_CLASSIFIERS );
238 :
239 : /* sort the classifiers by their movement-needs */
240 0 : uint32_t count_clasfy;
241 0 : count_clasfy = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data );
242 0 : for ( uint32_t index = 0; index < count_clasfy; index ++ )
243 : {
244 0 : const layout_visible_classifier_t *const the_classifier
245 0 : = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index );
246 0 : const geometry_rectangle_t *const classifier_envelope_box
247 0 : = layout_visible_classifier_get_envelope_box_const( the_classifier );
248 :
249 0 : int64_t simpleness = 0; /* the lower the number, the ealier the classifier will be processed. Unit is area(=square-length). */
250 :
251 : /* reduce simpleness by area outside the diagram border: the more outside diagram area, the earlier it should be moved */
252 : {
253 0 : geometry_rectangle_t border_intersect;
254 0 : int intersect_error2;
255 0 : intersect_error2 = geometry_rectangle_init_by_intersect( &border_intersect, classifier_envelope_box, (*this_).diagram_draw_area );
256 0 : if ( 0 != intersect_error2 )
257 : {
258 0 : U8_LOG_WARNING( "a rectangle to be drawn is completely outside the diagram area" );
259 : }
260 :
261 0 : simpleness += 16.0 * geometry_rectangle_get_area( &border_intersect );
262 0 : simpleness -= 16.0 * geometry_rectangle_get_area( classifier_envelope_box );
263 :
264 0 : geometry_rectangle_destroy( &border_intersect );
265 : }
266 :
267 : /* reduce simpleness by intersects with other rectangles: the more intersects, the earlier it should be moved */
268 0 : for ( uint32_t probe_index = 0; probe_index < count_clasfy; probe_index ++ )
269 : {
270 0 : layout_visible_classifier_t *probe_classifier;
271 0 : probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, probe_index );
272 0 : const geometry_rectangle_t *const probe_envelope_box
273 0 : = layout_visible_classifier_get_envelope_box_const( probe_classifier );
274 :
275 0 : geometry_rectangle_t intersect;
276 0 : int intersect_error;
277 0 : intersect_error = geometry_rectangle_init_by_intersect( &intersect, classifier_envelope_box, probe_envelope_box );
278 :
279 0 : if ( 0 == intersect_error )
280 : {
281 0 : simpleness -= geometry_rectangle_get_area( &intersect );
282 : }
283 :
284 0 : geometry_rectangle_destroy( &intersect );
285 : }
286 :
287 : /* reduce simpleness by own size: the bigger the object, the earlier it should be moved */
288 : {
289 0 : const double default_classifier_area = geometry_dimensions_get_area( (*this_).default_classifier_size );
290 0 : const double classifier_area = geometry_rectangle_get_area( classifier_envelope_box );
291 0 : if (( default_classifier_area > 0.000000001 )&&( classifier_area > 0.000000001 ))
292 : {
293 0 : simpleness -= default_classifier_area * ( classifier_area / ( classifier_area + default_classifier_area ));
294 : }
295 : }
296 :
297 : /* increase simpleness if contained children: if embracing children later, layouting problems might get solved */
298 : {
299 0 : const double default_classifier_area = geometry_dimensions_get_area( (*this_).default_classifier_size );
300 0 : const uint32_t descendant_count
301 0 : = pencil_layout_data_count_descendants( (*this_).layout_data, the_classifier );
302 0 : if ( descendant_count != 0 )
303 : {
304 0 : simpleness += default_classifier_area;
305 : }
306 : }
307 :
308 0 : int insert_error;
309 0 : insert_error = universal_array_index_sorter_insert( out_sorted, index, simpleness );
310 0 : if ( 0 != insert_error )
311 : {
312 0 : U8_LOG_WARNING( "not all rectangles are moved" );
313 : }
314 : }
315 :
316 0 : U8_TRACE_END();
317 0 : }
318 :
319 : /*!
320 : * \brief constants for directions of moving objects
321 : */
322 : enum pencil_classifier_2d_layouter_private_move_enum {
323 : PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT = 0, /*!< only move to visible arey - nothing more */
324 : PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN = 1, /*!< moves up the minimum distance (up means smaller y-values) */
325 : PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN = 2,
326 : PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN = 3,
327 : PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN = 4,
328 : PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX = 5, /*!< constant defining the total number of available options */
329 : };
330 :
331 0 : void pencil_classifier_2d_layouter_private_propose_4dir_move_solutions( pencil_classifier_2d_layouter_t *this_,
332 : const universal_array_index_sorter_t *sorted,
333 : uint32_t sort_index,
334 : uint32_t solutions_max,
335 : double out_solution_move_dx[],
336 : double out_solution_move_dy[],
337 : uint32_t *out_solutions_count )
338 : {
339 0 : U8_TRACE_BEGIN();
340 0 : assert ( NULL != sorted );
341 0 : assert ( universal_array_index_sorter_get_count( sorted ) > sort_index );
342 0 : assert ( NULL != out_solution_move_dx );
343 0 : assert ( NULL != out_solution_move_dy );
344 0 : assert ( NULL != out_solutions_count );
345 0 : assert ( 1 <= solutions_max ); /* general requirement to report at least one option */
346 0 : assert ( (unsigned int) PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX <= solutions_max ); /* current implementation requires at least 5 options */
347 :
348 : /* get classifier to move */
349 0 : const uint32_t index
350 0 : = universal_array_index_sorter_get_array_index( sorted, sort_index );
351 0 : const layout_visible_classifier_t *const the_classifier
352 0 : = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index );
353 0 : const geometry_rectangle_t *const classifier_envelope_box
354 0 : = layout_visible_classifier_get_envelope_box_const( the_classifier );
355 0 : double top = geometry_rectangle_get_top ( classifier_envelope_box );
356 0 : double bottom = geometry_rectangle_get_bottom ( classifier_envelope_box );
357 0 : double left = geometry_rectangle_get_left ( classifier_envelope_box );
358 0 : double right = geometry_rectangle_get_right ( classifier_envelope_box );
359 :
360 : /* choose distance */
361 0 : double shift_x = 0.0;
362 0 : double shift_y = 0.0;
363 :
364 : /* check overlap to diagram boundary */
365 : {
366 0 : if ( bottom > geometry_rectangle_get_bottom( (*this_).diagram_draw_area ) )
367 : {
368 0 : shift_y = geometry_rectangle_get_bottom( (*this_).diagram_draw_area ) - bottom;
369 : }
370 0 : if ( top < geometry_rectangle_get_top( (*this_).diagram_draw_area ) )
371 : {
372 0 : shift_y = geometry_rectangle_get_top( (*this_).diagram_draw_area ) - top;
373 : }
374 0 : if ( right > geometry_rectangle_get_right( (*this_).diagram_draw_area ) )
375 : {
376 0 : shift_x = geometry_rectangle_get_right( (*this_).diagram_draw_area ) - right;
377 : }
378 0 : if ( left < geometry_rectangle_get_left( (*this_).diagram_draw_area ) )
379 : {
380 0 : shift_x = geometry_rectangle_get_left( (*this_).diagram_draw_area ) - left;
381 : }
382 : }
383 :
384 0 : *out_solutions_count = 1;
385 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT] = shift_x;
386 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_NOT] = shift_y;
387 :
388 : /* determine minimum and comfort distances between classifiers */
389 0 : const double gap = pencil_size_get_standard_object_border( (*this_).pencil_size );
390 :
391 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = shift_x;
392 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = shift_y;
393 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = shift_x;
394 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = shift_y;
395 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = shift_x;
396 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = shift_y;
397 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = shift_x;
398 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = shift_y;
399 :
400 : /* adjust information on current rectangle */
401 0 : top += shift_y;
402 0 : bottom += shift_y;
403 0 : left += shift_x;
404 0 : right += shift_x;
405 :
406 : /* check overlap to already moved classifiers */
407 0 : for ( uint32_t probe_sort_index = 0; probe_sort_index < sort_index; probe_sort_index ++ )
408 : {
409 : /* get classifier to check overlaps */
410 0 : const uint32_t probe_index
411 0 : = universal_array_index_sorter_get_array_index( sorted, probe_sort_index );
412 0 : const layout_visible_classifier_t *const the_probe
413 0 : = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index );
414 0 : const geometry_rectangle_t *const probe_envelope_box
415 0 : = layout_visible_classifier_get_envelope_box_const( the_probe );
416 0 : const double probe_top = geometry_rectangle_get_top ( probe_envelope_box );
417 0 : const double probe_bottom = geometry_rectangle_get_bottom ( probe_envelope_box );
418 0 : const double probe_left = geometry_rectangle_get_left ( probe_envelope_box );
419 0 : const double probe_right = geometry_rectangle_get_right ( probe_envelope_box );
420 :
421 0 : if ( probe_right < left )
422 : {
423 : /* no overlap, finished. */
424 : }
425 0 : else if ( probe_left > right )
426 : {
427 : /* no overlap, finished. */
428 : }
429 0 : else if ( probe_bottom < top )
430 : {
431 : /* no overlap, finished. */
432 : }
433 0 : else if ( probe_top > bottom )
434 : {
435 : /* no overlap, finished. */
436 : }
437 0 : else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_probe, the_classifier ) )
438 : {
439 : /* overlapping the parent is ok, finished */
440 : }
441 0 : else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_classifier, the_probe ) )
442 : {
443 : /* overlapping the child is ok, finished */
444 : }
445 : else
446 : {
447 : /* there is an overlap - at least when considering the comfort zone */
448 :
449 0 : double my_shift_x_left_min;
450 0 : my_shift_x_left_min = probe_left - right - gap;
451 0 : if ( my_shift_x_left_min < out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] )
452 : {
453 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_LEFT_MIN] = my_shift_x_left_min;
454 : }
455 :
456 0 : double my_shift_x_right_min;
457 0 : my_shift_x_right_min = probe_right - left + gap;
458 0 : if ( my_shift_x_right_min > out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] )
459 : {
460 0 : out_solution_move_dx[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_RIGHT_MIN] = my_shift_x_right_min;
461 : }
462 :
463 0 : double my_shift_y_up_min;
464 0 : my_shift_y_up_min = probe_top - bottom - gap;
465 0 : if ( my_shift_y_up_min < out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] )
466 : {
467 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_UP_MIN] = my_shift_y_up_min;
468 : }
469 :
470 0 : double my_shift_y_down_min;
471 0 : my_shift_y_down_min = probe_bottom - top + gap;
472 0 : if ( my_shift_y_down_min > out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] )
473 : {
474 0 : out_solution_move_dy[PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_DOWN_MIN] = my_shift_y_down_min;
475 : }
476 :
477 0 : *out_solutions_count = PENCIL_CLASSIFIER_LAYOUTER_PRIVATE_MOVE_MAX;
478 :
479 : /* trace */
480 0 : const data_visible_classifier_t *visible_classifier_data;
481 0 : visible_classifier_data = layout_visible_classifier_get_data_const ( the_probe );
482 0 : if (( visible_classifier_data != NULL ) && ( data_visible_classifier_is_valid( visible_classifier_data ) ))
483 : {
484 0 : const data_classifier_t *classifier_p;
485 0 : classifier_p = data_visible_classifier_get_classifier_const( visible_classifier_data );
486 0 : U8_TRACE_INFO_STR( "- overlaps:", data_classifier_get_name_const( classifier_p ) );
487 : }
488 : }
489 : }
490 :
491 : /* trace */
492 0 : const data_visible_classifier_t *visible_classifier;
493 0 : visible_classifier = layout_visible_classifier_get_data_const ( the_classifier );
494 0 : const data_classifier_t *classifier;
495 0 : classifier = data_visible_classifier_get_classifier_const( visible_classifier );
496 0 : U8_TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) );
497 :
498 0 : U8_TRACE_END();
499 0 : }
500 :
501 0 : void pencil_classifier_2d_layouter_private_propose_anchored_solution( pencil_classifier_2d_layouter_t *this_,
502 : const universal_array_index_sorter_t *sorted,
503 : uint32_t sort_index,
504 : double * out_solution_move_dx,
505 : double * out_solution_move_dy )
506 : {
507 0 : U8_TRACE_BEGIN();
508 0 : assert ( NULL != sorted );
509 0 : assert ( universal_array_index_sorter_get_count( sorted ) > sort_index );
510 0 : assert ( NULL != out_solution_move_dx );
511 0 : assert ( NULL != out_solution_move_dy );
512 :
513 : /* get classifier to move */
514 0 : const uint32_t index
515 0 : = universal_array_index_sorter_get_array_index( sorted, sort_index );
516 0 : const layout_visible_classifier_t *const the_classifier
517 0 : = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index );
518 :
519 : /* determine the space needed for the solution */
520 0 : const geometry_rectangle_t *const classifier_envelope_box
521 0 : = layout_visible_classifier_get_envelope_box_const( the_classifier );
522 0 : const double width = geometry_rectangle_get_width( classifier_envelope_box );
523 0 : const double height = geometry_rectangle_get_height( classifier_envelope_box );
524 0 : const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
525 :
526 : /* wish a solution area */
527 0 : geometry_rectangle_t classifier_solution_area;
528 0 : geometry_rectangle_init ( &classifier_solution_area,
529 0 : geometry_rectangle_get_left( classifier_envelope_box ) - 0.5*width - gap,
530 0 : geometry_rectangle_get_top( classifier_envelope_box ) - 0.5*height - gap,
531 0 : 2.0*width + 2.0*gap,
532 0 : 2.0*height + 2.0*gap
533 : );
534 :
535 : /* shrink solution area to diagram_draw_area */
536 0 : geometry_rectangle_init_by_intersect( &classifier_solution_area,
537 : &classifier_solution_area,
538 : (*this_).diagram_draw_area
539 : );
540 :
541 : /* check overlap to already moved classifiers */
542 0 : for ( uint32_t probe_sort_index = 0; probe_sort_index < sort_index; probe_sort_index ++ )
543 : {
544 : /* get classifier to check overlaps */
545 0 : const uint32_t probe_index
546 0 : = universal_array_index_sorter_get_array_index( sorted, probe_sort_index );
547 0 : const layout_visible_classifier_t *const the_probe
548 0 : = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index );
549 :
550 0 : geometry_rectangle_t probe_total_bounds;
551 0 : geometry_rectangle_init_by_bounds( &probe_total_bounds,
552 : layout_visible_classifier_get_label_box_const( the_probe ),
553 : layout_visible_classifier_get_envelope_box_const( the_probe )
554 : );
555 :
556 0 : geometry_rectangle_init_by_difference( &classifier_solution_area,
557 : &classifier_solution_area,
558 : &probe_total_bounds
559 : );
560 : }
561 :
562 : /* reduce the biggest free/unoccupied box by gap */
563 0 : geometry_rectangle_shift ( &classifier_solution_area, gap, gap );
564 0 : geometry_rectangle_enlarge ( &classifier_solution_area, -2.0*gap, -2.0*gap );
565 :
566 : /* move - but not to eager - only the minumum distance */
567 0 : const bool is_x_contained
568 0 : = ( geometry_rectangle_get_left( &classifier_solution_area ) < geometry_rectangle_get_left( classifier_envelope_box ) )
569 0 : && ( geometry_rectangle_get_right( classifier_envelope_box ) < geometry_rectangle_get_right( &classifier_solution_area ) );
570 0 : const bool is_y_contained
571 0 : = ( geometry_rectangle_get_top( &classifier_solution_area ) < geometry_rectangle_get_top( classifier_envelope_box ) )
572 0 : && ( geometry_rectangle_get_bottom( classifier_envelope_box ) < geometry_rectangle_get_bottom( &classifier_solution_area ) );
573 0 : if ( is_x_contained )
574 : {
575 0 : *out_solution_move_dx = 0.0;
576 : }
577 : else
578 : {
579 0 : const double sol_center_x = geometry_rectangle_get_center_x( &classifier_solution_area );
580 0 : const double cur_center_x = geometry_rectangle_get_center_x( classifier_envelope_box );
581 0 : *out_solution_move_dx = ( sol_center_x < cur_center_x )
582 0 : ? geometry_rectangle_get_right( &classifier_solution_area )
583 0 : - geometry_rectangle_get_right( classifier_envelope_box )
584 0 : : geometry_rectangle_get_left( &classifier_solution_area )
585 0 : - geometry_rectangle_get_left( classifier_envelope_box );
586 0 : geometry_rectangle_trace( &classifier_solution_area );
587 0 : geometry_rectangle_trace( classifier_envelope_box );
588 : }
589 0 : if ( is_y_contained )
590 : {
591 0 : *out_solution_move_dy = 0.0;
592 : }
593 : else
594 : {
595 0 : const double sol_center_y = geometry_rectangle_get_center_y( &classifier_solution_area );
596 0 : const double cur_center_y = geometry_rectangle_get_center_y( classifier_envelope_box );
597 0 : *out_solution_move_dy = ( sol_center_y < cur_center_y )
598 0 : ? geometry_rectangle_get_bottom( &classifier_solution_area )
599 0 : - geometry_rectangle_get_bottom( classifier_envelope_box )
600 0 : : geometry_rectangle_get_top( &classifier_solution_area )
601 0 : - geometry_rectangle_get_top( classifier_envelope_box );
602 : }
603 :
604 : /* trace */
605 0 : const data_visible_classifier_t *visible_classifier;
606 0 : visible_classifier = layout_visible_classifier_get_data_const ( the_classifier );
607 0 : const data_classifier_t *classifier;
608 0 : classifier = data_visible_classifier_get_classifier_const( visible_classifier );
609 0 : U8_TRACE_INFO_STR( "classifier:", data_classifier_get_name_const( classifier ) );
610 :
611 0 : U8_TRACE_END();
612 0 : }
613 :
614 0 : void pencil_classifier_2d_layouter_private_select_move_solution( pencil_classifier_2d_layouter_t *this_,
615 : const universal_array_index_sorter_t *sorted,
616 : uint32_t sort_index,
617 : uint32_t solutions_count,
618 : const double solution_move_dx[],
619 : const double solution_move_dy[],
620 : uint32_t *out_index_of_best )
621 : {
622 0 : U8_TRACE_BEGIN();
623 0 : assert ( NULL != sorted );
624 0 : assert ( universal_array_index_sorter_get_count( sorted ) > sort_index );
625 0 : assert ( NULL != solution_move_dx );
626 0 : assert ( NULL != solution_move_dy );
627 0 : assert ( NULL != out_index_of_best );
628 0 : assert ( 1 <= solutions_count );
629 :
630 : /* define potential solution and rating */
631 0 : uint32_t index_of_best;
632 0 : double debts_of_best;
633 0 : index_of_best = 0; /* in case of doubts, take the first solution */
634 0 : debts_of_best = 1000000000.0;
635 :
636 : /* get classifier to move */
637 0 : const uint32_t index
638 0 : = universal_array_index_sorter_get_array_index( sorted, sort_index );
639 0 : const layout_visible_classifier_t *const the_classifier
640 0 : = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index );
641 0 : const geometry_rectangle_t *const classifier_envelope_box
642 0 : = layout_visible_classifier_get_envelope_box_const( the_classifier );
643 :
644 : /* check all solutions */
645 0 : for ( uint32_t solution_index = 0; solution_index < solutions_count; solution_index ++ )
646 : {
647 : /* calculate the solution rectangle */
648 0 : geometry_rectangle_t solution_bounds;
649 0 : geometry_rectangle_copy( &solution_bounds, classifier_envelope_box );
650 0 : geometry_rectangle_shift ( &solution_bounds, solution_move_dx[solution_index], solution_move_dy[solution_index] );
651 :
652 : /* evalute the debts of this solution */
653 0 : double debts_of_current;
654 0 : debts_of_current = 0.0;
655 :
656 : /* add move distance as debt */
657 0 : debts_of_current += fabs ( solution_move_dx[solution_index] );
658 0 : debts_of_current += fabs ( solution_move_dy[solution_index] );
659 :
660 : /* add debts for overlap to diagram boundary */
661 : {
662 0 : static const double DIAG_BOUNDS_SEVERITY = 32.0;
663 :
664 0 : double current_area = geometry_rectangle_get_area ( &solution_bounds );
665 0 : geometry_rectangle_t intersect;
666 0 : geometry_rectangle_init_by_intersect( &intersect, &solution_bounds, (*this_).diagram_draw_area );
667 0 : double intersect_area = geometry_rectangle_get_area ( &intersect );
668 :
669 0 : debts_of_current += DIAG_BOUNDS_SEVERITY * ( current_area - intersect_area );
670 : }
671 :
672 : /* check overlap to other classifiers */
673 0 : for ( uint32_t probe_sort_index = 0; probe_sort_index < universal_array_index_sorter_get_count( sorted ); probe_sort_index ++ )
674 : {
675 0 : if ( probe_sort_index != sort_index ) /* skip self */
676 : {
677 : /* get classifier to check overlaps */
678 0 : const uint32_t probe_index
679 0 : = universal_array_index_sorter_get_array_index( sorted, probe_sort_index );
680 :
681 0 : const layout_visible_classifier_t *const the_probe
682 0 : = pencil_layout_data_get_visible_classifier_const( (*this_).layout_data, probe_index );
683 0 : const geometry_rectangle_t *const probe_envelope_box
684 0 : = layout_visible_classifier_get_envelope_box_const( the_probe );
685 :
686 0 : geometry_rectangle_t probe_intersect;
687 0 : const int intersect_err
688 0 : = geometry_rectangle_init_by_intersect( &probe_intersect, &solution_bounds, probe_envelope_box );
689 0 : if ( 0 == intersect_err )
690 : {
691 : /* there is an intersect */
692 0 : if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_classifier, the_probe ) )
693 : {
694 : /* no debt: parent my overlap children */
695 : }
696 0 : else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, the_probe, the_classifier ) )
697 : {
698 : /* no debt: child may overlap parent */
699 : }
700 : else
701 : {
702 : /* already processed classifiers have higher severity because these do not move anymore */
703 0 : const double severity = ( probe_sort_index < sort_index ) ? 4.0 : 1.0;
704 0 : const double probe_intersect_area = geometry_rectangle_get_area ( &probe_intersect );
705 0 : debts_of_current += severity * probe_intersect_area;
706 : }
707 : }
708 : /* else no intersect/overlap */
709 : }
710 : }
711 :
712 : /* finish evaluating this solution */
713 0 : geometry_rectangle_destroy( &solution_bounds );
714 0 : if ( debts_of_current < debts_of_best )
715 : {
716 0 : debts_of_best = debts_of_current;
717 0 : index_of_best = solution_index;
718 : }
719 : }
720 :
721 0 : *out_index_of_best = index_of_best;
722 :
723 0 : U8_TRACE_END();
724 0 : }
725 :
726 : /* ================================ EMBRACE CHILDREN STEP BY STEP ================================ */
727 :
728 0 : void pencil_classifier_2d_layouter_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout )
729 : {
730 0 : U8_TRACE_BEGIN();
731 0 : assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_RELATIONSHIPS );
732 :
733 0 : universal_array_index_sorter_t sorted_relationships;
734 0 : universal_array_index_sorter_init( &sorted_relationships );
735 :
736 : /* sort the relationships by their number of descendants */
737 0 : pencil_classifier_2d_layouter_private_propose_embracing_order ( this_, &sorted_relationships );
738 :
739 : /* init the set of classifiers that has embraced children */
740 0 : data_small_set_t has_embraced_children;
741 0 : data_small_set_init( &has_embraced_children );
742 :
743 : /* move the classifiers */
744 0 : const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted_relationships );
745 0 : for ( uint32_t rel_sort_idx = 0; rel_sort_idx < count_sorted; rel_sort_idx ++ )
746 : {
747 0 : const uint32_t rel_idx
748 0 : = universal_array_index_sorter_get_array_index( &sorted_relationships, rel_sort_idx );
749 0 : layout_relationship_t *const the_relationship
750 0 : = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, rel_idx );
751 0 : assert ( the_relationship != NULL );
752 0 : const data_relationship_t *const rel_data = layout_relationship_get_data_const ( the_relationship );
753 0 : assert ( rel_data != NULL );
754 0 : const data_id_t rel_from_id = data_relationship_get_from_classifier_data_id ( rel_data );
755 :
756 0 : const int failure
757 0 : = pencil_classifier_2d_layouter_private_try_embrace_child( this_,
758 : the_relationship,
759 0 : ! data_small_set_contains( &has_embraced_children, rel_from_id ),
760 : font_layout
761 0 : );
762 0 : if ( ! failure )
763 : {
764 : /* only in case of success, children are counted as embraced */
765 0 : data_small_set_add_obj( &has_embraced_children, rel_from_id );
766 : }
767 : }
768 :
769 0 : data_small_set_destroy( &has_embraced_children );
770 :
771 0 : universal_array_index_sorter_destroy( &sorted_relationships );
772 :
773 0 : U8_TRACE_END();
774 0 : }
775 :
776 0 : void pencil_classifier_2d_layouter_private_propose_embracing_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
777 : {
778 0 : U8_TRACE_BEGIN();
779 0 : assert( NULL != out_sorted );
780 :
781 0 : const uint32_t rel_count = pencil_layout_data_get_relationship_count( (*this_).layout_data );
782 0 : for ( uint32_t rel_idx = 0; rel_idx < rel_count; rel_idx ++ )
783 : {
784 0 : const layout_relationship_t *const the_relationship
785 0 : = pencil_layout_data_get_relationship_ptr( (*this_).layout_data, rel_idx );
786 :
787 : /* count the descendants */
788 0 : const layout_visible_classifier_t *const from_classifier
789 0 : = layout_relationship_get_from_classifier_ptr( the_relationship );
790 0 : const uint32_t from_descendant_count
791 0 : = pencil_layout_data_count_descendants( (*this_).layout_data, from_classifier );
792 :
793 : /* sort it into the array by the number of decendants: */
794 : /* the less descendants the earlier it shall be processed. */
795 0 : const int err
796 0 : = universal_array_index_sorter_insert( out_sorted, rel_idx, (double)from_descendant_count );
797 0 : if ( 0 != err )
798 : {
799 0 : U8_LOG_ERROR ( "universal_array_index_sorter_t list is full." );
800 : }
801 : }
802 :
803 0 : U8_TRACE_END();
804 0 : }
805 :
806 0 : int pencil_classifier_2d_layouter_private_try_embrace_child( pencil_classifier_2d_layouter_t *this_,
807 : layout_relationship_t *the_relationship,
808 : bool move,
809 : PangoLayout *font_layout )
810 : {
811 0 : U8_TRACE_BEGIN();
812 0 : assert( NULL != the_relationship );
813 0 : int result_err = -1;
814 :
815 0 : const data_relationship_type_t the_type
816 0 : = data_relationship_get_main_type ( layout_relationship_get_data_const( the_relationship ));
817 :
818 0 : if ( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type )
819 : {
820 0 : layout_visible_classifier_t *const from_classifier
821 0 : = layout_relationship_get_from_classifier_ptr( the_relationship );
822 0 : const layout_visible_classifier_t *const to_classifier
823 0 : = layout_relationship_get_to_classifier_ptr( the_relationship );
824 0 : if ( from_classifier != to_classifier )
825 : {
826 0 : layout_visible_classifier_t probe_parent_layout;
827 0 : layout_visible_classifier_copy( &probe_parent_layout, from_classifier );
828 0 : const geometry_rectangle_t * parent_space
829 0 : = layout_visible_classifier_get_space_const( &probe_parent_layout );
830 0 : const geometry_rectangle_t child_envelope = layout_visible_classifier_get_envelope_box( to_classifier );
831 0 : geometry_rectangle_t probe_space;
832 0 : if ( move )
833 : {
834 0 : geometry_rectangle_copy( &probe_space, &child_envelope );
835 : }
836 : else
837 : {
838 0 : geometry_rectangle_init_by_bounds( &probe_space, parent_space, &child_envelope );
839 : }
840 :
841 0 : pencil_classifier_composer_expand_space( &((*this_).classifier_composer),
842 : &probe_space,
843 : true, /* = shows_contained_children */
844 : (*this_).profile,
845 : (*this_).pencil_size,
846 : font_layout,
847 : &probe_parent_layout
848 : );
849 :
850 0 : const geometry_rectangle_t probe_parent_envelope
851 0 : = layout_visible_classifier_get_envelope_box( &probe_parent_layout );
852 :
853 : /* check what else would be embraced */
854 0 : bool illegal_overlap = false;
855 0 : const uint32_t count_clasfy
856 0 : = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data );
857 0 : for ( uint32_t c_index = 0; c_index < count_clasfy; c_index ++ )
858 : {
859 0 : layout_visible_classifier_t *probe_classifier;
860 0 : probe_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, c_index );
861 :
862 0 : if (( probe_classifier != from_classifier )&&( probe_classifier != to_classifier ))
863 : {
864 0 : if ( pencil_layout_data_is_ancestor( (*this_).layout_data, from_classifier, probe_classifier ) )
865 : {
866 : /* it is ok to embrace also other children, no illegal_overlap */
867 : }
868 0 : else if ( pencil_layout_data_is_ancestor( (*this_).layout_data, probe_classifier, from_classifier ) )
869 : {
870 : /* it is ok if parent is already contained in grand-parent classifier, no illegal_overlap */
871 : }
872 : else
873 : {
874 0 : const geometry_rectangle_t *const current_envelope_box
875 0 : = layout_visible_classifier_get_envelope_box_const ( probe_classifier );
876 0 : illegal_overlap |= geometry_rectangle_is_intersecting( current_envelope_box, &probe_parent_envelope );
877 : }
878 : }
879 : }
880 : /* check overlap to diagram boundary */
881 0 : if ( ! geometry_rectangle_is_containing ( (*this_).diagram_draw_area, &probe_parent_envelope ) )
882 : {
883 : illegal_overlap = true;
884 : }
885 :
886 : /* cancel or commit */
887 0 : if ( ! illegal_overlap )
888 : {
889 0 : layout_visible_classifier_replacemove( from_classifier, &probe_parent_layout );
890 0 : result_err = 0;
891 : }
892 : else
893 : {
894 0 : layout_visible_classifier_destroy( &probe_parent_layout );
895 : }
896 :
897 : /* cleanup */
898 0 : geometry_rectangle_destroy( &probe_space );
899 : }
900 : else
901 : {
902 0 : U8_TRACE_INFO( "Classifier contains itself" );
903 : }
904 : }
905 : /* else this is not a parent child relationship */
906 :
907 0 : U8_TRACE_END_ERR( result_err );
908 0 : return result_err;
909 : }
910 :
911 : /* ================================ EMBRACE CHILDREN COMMON ================================ */
912 :
913 0 : void pencil_classifier_2d_layouter_hide_relations_of_embraced_children( pencil_classifier_2d_layouter_t *this_ )
914 : {
915 0 : U8_TRACE_BEGIN();
916 :
917 : /* search containment relations */
918 0 : const uint32_t rel_count = pencil_layout_data_get_relationship_count( (*this_).layout_data );
919 0 : for ( uint32_t rel_idx = 0; rel_idx < rel_count; rel_idx ++ )
920 : {
921 0 : const layout_relationship_t *const the_relationship
922 0 : = pencil_layout_data_get_relationship_const( (*this_).layout_data, rel_idx );
923 0 : const data_relationship_t *const the_rel_data
924 0 : = layout_relationship_get_data_const( the_relationship );
925 :
926 0 : const data_relationship_type_t the_type = data_relationship_get_main_type ( the_rel_data );
927 0 : const pencil_visibility_t visibility = layout_relationship_get_visibility( the_relationship );
928 :
929 0 : if (( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type )
930 0 : && (( PENCIL_VISIBILITY_SHOW == visibility )||(PENCIL_VISIBILITY_GRAY_OUT == visibility) ))
931 : {
932 0 : const layout_visible_classifier_t *const from_classifier
933 0 : = layout_relationship_get_from_classifier_ptr( the_relationship );
934 0 : const layout_visible_classifier_t *const to_classifier
935 0 : = layout_relationship_get_to_classifier_ptr( the_relationship );
936 0 : if ( from_classifier != to_classifier )
937 : {
938 0 : const geometry_rectangle_t *const parent_space
939 0 : = layout_visible_classifier_get_space_const ( from_classifier );
940 0 : const geometry_rectangle_t *const child_symbol_box
941 0 : = layout_visible_classifier_get_symbol_box_const ( to_classifier );
942 :
943 : /* hide if parent embraced child(symbol) completely */
944 0 : if ( geometry_rectangle_is_containing( parent_space, child_symbol_box ) )
945 : {
946 0 : pencil_layout_data_set_relationship_visibility( (*this_).layout_data, rel_idx, PENCIL_VISIBILITY_IMPLICIT );
947 0 : U8_TRACE_INFO( "Containment relation is PENCIL_VISIBILITY_IMPLICIT" );
948 : }
949 : }
950 : }
951 : }
952 :
953 0 : U8_TRACE_END();
954 0 : }
955 :
956 : /* ================================ EMBRACE AND MOVE CHILDREN TOGETHER ================================ */
957 :
958 0 : void pencil_classifier_2d_layouter_move_and_embrace_children( pencil_classifier_2d_layouter_t *this_, PangoLayout *font_layout )
959 : {
960 0 : U8_TRACE_BEGIN();
961 0 : assert( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) PENCIL_LAYOUT_DATA_MAX_CLASSIFIERS );
962 :
963 0 : const double TAKE_RATIO = (1.0/3.0);
964 0 : const double LEAVE_RATIO = (1.0-TAKE_RATIO);
965 : /* const double gap = pencil_size_get_preferred_object_distance( (*this_).pencil_size ); */
966 :
967 0 : universal_array_index_sorter_t sorted_classifiers;
968 0 : universal_array_index_sorter_init( &sorted_classifiers );
969 :
970 : /* sort the classifiers by their need to move and to embrace */
971 0 : pencil_classifier_2d_layouter_private_propose_move_embrace_order ( this_, &sorted_classifiers );
972 :
973 : /* small-move and embrace the child classifiers */
974 0 : const uint32_t count_sorted = universal_array_index_sorter_get_count( &sorted_classifiers );
975 0 : for ( uint32_t classifier_sort_idx = 0; classifier_sort_idx < count_sorted; classifier_sort_idx ++ )
976 : {
977 0 : const uint32_t classifier_idx = universal_array_index_sorter_get_array_index( &sorted_classifiers, classifier_sort_idx );
978 0 : layout_visible_classifier_t *const the_classifier
979 0 : = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, classifier_idx );
980 :
981 : /* only if the classifier has children */
982 0 : const uint32_t child_count = pencil_layout_data_count_descendants ( (*this_).layout_data, the_classifier );
983 0 : if ( child_count > 0 )
984 : {
985 : /* get envelope rectangle of all children */
986 0 : const geometry_rectangle_t children_envelope
987 0 : = pencil_classifier_2d_layouter_private_calc_descendant_envelope( this_, the_classifier );
988 :
989 : /* determine outer space around children envelope rectangle */
990 0 : const geometry_rectangle_t outer_space
991 0 : = pencil_classifier_2d_layouter_private_calc_outer_space( this_, &children_envelope, the_classifier );
992 :
993 : /* place the children into the (probe-)parent */
994 0 : layout_visible_classifier_t probe_parent_layout;
995 0 : layout_visible_classifier_copy( &probe_parent_layout, the_classifier );
996 0 : pencil_classifier_composer_expand_space( &((*this_).classifier_composer),
997 : &children_envelope,
998 : true, /* = shows_contained_children */
999 : (*this_).profile,
1000 : (*this_).pencil_size,
1001 : font_layout,
1002 : &probe_parent_layout
1003 : );
1004 0 : const geometry_rectangle_t probe_parent_envelope
1005 0 : = layout_visible_classifier_get_envelope_box( &probe_parent_layout );
1006 :
1007 : /* check if parent fits into into outer_space */
1008 0 : const double outer_border_x
1009 0 : = (geometry_rectangle_get_width( &outer_space ) - geometry_rectangle_get_width(&probe_parent_envelope))/2.0;
1010 0 : const double outer_border_y
1011 0 : = (geometry_rectangle_get_height( &outer_space ) - geometry_rectangle_get_height(&probe_parent_envelope))/2.0;
1012 0 : if (( outer_border_x > 0.0 )&&( outer_border_y > 0.0 ))
1013 : {
1014 : /* prepare to move+expand the parent */
1015 0 : geometry_rectangle_t new_envelope;
1016 0 : geometry_rectangle_copy( &new_envelope, &outer_space );
1017 0 : geometry_rectangle_shift( &new_envelope, (LEAVE_RATIO*outer_border_x), (LEAVE_RATIO*outer_border_y) );
1018 0 : geometry_rectangle_enlarge( &new_envelope, -2.0*(LEAVE_RATIO*outer_border_x), -2.0*(LEAVE_RATIO*outer_border_y) );
1019 :
1020 : /* move+expand the parent */
1021 0 : pencil_classifier_composer_set_envelope_box( &((*this_).classifier_composer),
1022 : &new_envelope,
1023 : true, /* = shows_contained_children */
1024 : (*this_).profile,
1025 : (*this_).pencil_size,
1026 : font_layout,
1027 : the_classifier
1028 : );
1029 :
1030 : /* cleanup move+expand the parent */
1031 0 : geometry_rectangle_destroy( &new_envelope );
1032 :
1033 : /* determine the descendants move deltas */
1034 0 : const geometry_rectangle_t *const parent_new_space = layout_visible_classifier_get_space_const( the_classifier );
1035 0 : const double descendant_add_dx = geometry_rectangle_get_center_x( parent_new_space ) - geometry_rectangle_get_center_x( &children_envelope );
1036 0 : const double descendant_add_dy = geometry_rectangle_get_center_y( parent_new_space ) - geometry_rectangle_get_center_y( &children_envelope );
1037 :
1038 : /* move the descendants */
1039 0 : pencil_classifier_2d_layouter_private_move_descendants( this_, the_classifier, descendant_add_dx, descendant_add_dy );
1040 : }
1041 :
1042 : /* cleanup */
1043 0 : layout_visible_classifier_destroy( &probe_parent_layout );
1044 : }
1045 : }
1046 :
1047 0 : universal_array_index_sorter_destroy( &sorted_classifiers );
1048 :
1049 0 : U8_TRACE_END();
1050 0 : }
1051 :
1052 0 : void pencil_classifier_2d_layouter_private_propose_move_embrace_order ( pencil_classifier_2d_layouter_t *this_, universal_array_index_sorter_t *out_sorted )
1053 : {
1054 0 : U8_TRACE_BEGIN();
1055 0 : assert ( NULL != out_sorted );
1056 0 : assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_CLASSIFIERS );
1057 :
1058 : /* sort the classifiers by their movement-needs */
1059 0 : const uint32_t count_classifiers = pencil_layout_data_get_visible_classifier_count ( (*this_).layout_data );
1060 0 : for ( uint32_t index = 0; index < count_classifiers; index ++ )
1061 : {
1062 0 : const layout_visible_classifier_t *const the_classifier = pencil_layout_data_get_visible_classifier_ptr( (*this_).layout_data, index );
1063 :
1064 0 : int64_t lazy_move = 0;
1065 :
1066 : /* grand-parents must be moved after parents (becasue parents are not yet well layouted) */
1067 0 : const uint32_t child_count = pencil_layout_data_count_descendants ( (*this_).layout_data, the_classifier );
1068 0 : lazy_move = child_count;
1069 :
1070 0 : int insert_error;
1071 0 : insert_error = universal_array_index_sorter_insert( out_sorted, index, lazy_move );
1072 0 : if ( 0 != insert_error )
1073 : {
1074 0 : U8_LOG_WARNING( "not all rectangles are grown" );
1075 : }
1076 : }
1077 :
1078 0 : U8_TRACE_END();
1079 0 : }
1080 :
1081 :
1082 : /*
1083 : Copyright 2017-2024 Andreas Warnke
1084 :
1085 : Licensed under the Apache License, Version 2.0 (the "License");
1086 : you may not use this file except in compliance with the License.
1087 : You may obtain a copy of the License at
1088 :
1089 : http://www.apache.org/licenses/LICENSE-2.0
1090 :
1091 : Unless required by applicable law or agreed to in writing, software
1092 : distributed under the License is distributed on an "AS IS" BASIS,
1093 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1094 : See the License for the specific language governing permissions and
1095 : limitations under the License.
1096 : */
|