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