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