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