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