Line data Source code
1 : /* File: pencil_relationship_2d_layouter.c; Copyright and License: see below */
2 :
3 : #include "pencil_relationship_2d_layouter.h"
4 : #include "u8/u8_trace.h"
5 : #include <pango/pangocairo.h>
6 : #include <stdio.h>
7 : #include <stdlib.h>
8 : #include <math.h>
9 : #include <stdint.h>
10 :
11 0 : void pencil_relationship_2d_layouter_init( pencil_relationship_2d_layouter_t *this_,
12 : layout_visible_set_t *layout_data,
13 : const data_profile_part_t *profile,
14 : const pencil_size_t *pencil_size )
15 : {
16 0 : U8_TRACE_BEGIN();
17 0 : assert( NULL != layout_data );
18 0 : assert( NULL != profile );
19 0 : assert( NULL != pencil_size );
20 :
21 0 : (*this_).layout_data = layout_data;
22 0 : (*this_).profile = profile;
23 0 : universal_array_index_sorter_init( &((*this_).sorted_relationships) );
24 0 : (*this_).sorted_rel_index = 0;
25 :
26 0 : (*this_).pencil_size = pencil_size;
27 0 : pencil_relationship_painter_init( &((*this_).relationship_painter) );
28 :
29 0 : U8_TRACE_END();
30 0 : }
31 :
32 0 : void pencil_relationship_2d_layouter_destroy( pencil_relationship_2d_layouter_t *this_ )
33 : {
34 0 : U8_TRACE_BEGIN();
35 :
36 0 : universal_array_index_sorter_destroy( &((*this_).sorted_relationships) );
37 :
38 0 : pencil_relationship_painter_destroy( &((*this_).relationship_painter) );
39 :
40 0 : U8_TRACE_END();
41 0 : }
42 :
43 0 : void pencil_relationship_2d_layouter_private_do_layout ( pencil_relationship_2d_layouter_t *this_ )
44 : {
45 0 : U8_TRACE_BEGIN();
46 : assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) LAYOUT_VISIBLE_SET_MAX_RELATIONSHIPS );
47 :
48 0 : universal_array_index_sorter_reinit( &((*this_).sorted_relationships) );
49 :
50 : /* sort the relationships by their movement-needs, drop invisible relations */
51 0 : pencil_relationship_2d_layouter_private_propose_processing_order ( this_ );
52 :
53 : /* shape the relationships */
54 : const uint32_t count_sorted
55 0 : = universal_array_index_sorter_get_count( &((*this_).sorted_relationships) );
56 0 : for ( (*this_).sorted_rel_index = 0; (*this_).sorted_rel_index < count_sorted; (*this_).sorted_rel_index ++ )
57 : {
58 : /* determine pointer to the_relationship */
59 : const uint32_t index
60 0 : = universal_array_index_sorter_get_array_index ( &((*this_).sorted_relationships),
61 : (*this_).sorted_rel_index
62 : );
63 : layout_relationship_t *const current_relationship
64 0 : = layout_visible_set_get_relationship_ptr( (*this_).layout_data, index );
65 :
66 : /* declaration of list of options */
67 0 : uint32_t solutions_count = 0;
68 : static const uint32_t SOLUTIONS_MAX = 18;
69 : geometry_connector_t solution[18];
70 :
71 : /* propose options */
72 0 : pencil_relationship_2d_layouter_private_propose_solutions ( this_,
73 : SOLUTIONS_MAX,
74 : solution,
75 : &solutions_count
76 : );
77 :
78 : /* select best option */
79 : uint32_t index_of_best;
80 0 : if ( 1 == solutions_count )
81 : {
82 0 : index_of_best = 0;
83 : }
84 : else
85 : {
86 0 : pencil_relationship_2d_layouter_private_select_solution ( this_,
87 : solutions_count,
88 : solution,
89 : &index_of_best
90 : );
91 : }
92 :
93 : /* store best option to (*this_).layout_data */
94 0 : layout_relationship_set_shape( current_relationship, &(solution[index_of_best]) );
95 : }
96 :
97 0 : universal_array_index_sorter_reinit( &((*this_).sorted_relationships) );
98 :
99 0 : U8_TRACE_END();
100 0 : }
101 :
102 0 : void pencil_relationship_2d_layouter_private_propose_processing_order ( pencil_relationship_2d_layouter_t *this_ )
103 : {
104 0 : U8_TRACE_BEGIN();
105 : assert ( (unsigned int) UNIVERSAL_ARRAY_INDEX_SORTER_MAX_ARRAY_SIZE >= (unsigned int) DATA_VISIBLE_SET_MAX_RELATIONSHIPS );
106 :
107 : /* get draw area */
108 : const layout_diagram_t *const diagram_layout
109 0 : = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
110 : const geometry_rectangle_t *const diagram_draw_area
111 0 : = layout_diagram_get_draw_area_const( diagram_layout );
112 :
113 : /* sort the relationships by their shaping-needs: the less simple, the earlier it shall be processed */
114 : const uint32_t count_relations
115 0 : = layout_visible_set_get_relationship_count ( (*this_).layout_data );
116 0 : for ( uint32_t index = 0; index < count_relations; index ++ )
117 : {
118 : layout_relationship_t *const current_relation
119 0 : = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
120 :
121 0 : int64_t simpleness = 0;
122 :
123 : /* determine simpleness by relationship type */
124 : {
125 : data_relationship_type_t reltype;
126 0 : reltype = data_relationship_get_main_type( layout_relationship_get_data_const ( current_relation ));
127 0 : if (( DATA_RELATIONSHIP_TYPE_UML_DEPENDENCY == reltype )
128 0 : ||( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == reltype ))
129 : {
130 : /* containment may be solved by embracing, mere dependencies are unimportant */
131 0 : simpleness += geometry_rectangle_get_width ( diagram_draw_area );
132 : }
133 : }
134 :
135 : /* whatever is not visible is simple */
136 : {
137 0 : if (( PENCIL_VISIBILITY_SHOW != layout_relationship_get_visibility ( current_relation ) )
138 0 : && ( PENCIL_VISIBILITY_GRAY_OUT != layout_relationship_get_visibility ( current_relation ) ))
139 : {
140 0 : simpleness += 2 * geometry_rectangle_get_width ( diagram_draw_area );
141 : }
142 : }
143 :
144 : /* determine simpleness by distance between source and destination */
145 : {
146 : const geometry_rectangle_t *const source_rect
147 0 : = layout_relationship_get_from_symbol_box_const ( current_relation );
148 : const geometry_rectangle_t *const dest_rect
149 0 : = layout_relationship_get_to_symbol_box_const ( current_relation );
150 :
151 0 : simpleness -= fabs ( geometry_rectangle_get_center_x(source_rect) - geometry_rectangle_get_center_x(dest_rect) );
152 0 : simpleness -= fabs ( geometry_rectangle_get_center_y(source_rect) - geometry_rectangle_get_center_y(dest_rect) );
153 : }
154 :
155 : /* insert relation to sorted array, the simpler the more to the back */
156 : {
157 : int insert_error;
158 0 : insert_error = universal_array_index_sorter_insert( &((*this_).sorted_relationships), index, simpleness );
159 0 : if ( 0 != insert_error )
160 : {
161 0 : U8_LOG_WARNING( "not all relationships are shaped" );
162 : }
163 : }
164 : }
165 :
166 0 : U8_TRACE_END();
167 0 : }
168 :
169 0 : void pencil_relationship_2d_layouter_private_propose_solutions ( pencil_relationship_2d_layouter_t *this_,
170 : uint32_t solutions_max,
171 : geometry_connector_t out_solutions[],
172 : uint32_t *out_solutions_count )
173 : {
174 0 : U8_TRACE_BEGIN();
175 0 : assert ( (*this_).sorted_rel_index < universal_array_index_sorter_get_count( &((*this_).sorted_relationships) ) );
176 0 : assert ( NULL != out_solutions );
177 0 : assert ( NULL != out_solutions_count );
178 0 : assert ( 1 <= solutions_max ); /* general requirement to report at least one option */
179 0 : assert ( 18 <= solutions_max ); /* current implementation requires at least 14 options */
180 :
181 : /* get current relation */
182 : const uint32_t index
183 0 : = universal_array_index_sorter_get_array_index( &((*this_).sorted_relationships), (*this_).sorted_rel_index );
184 : layout_relationship_t *const current_relation
185 0 : = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
186 :
187 : /* propose connections between source and destination */
188 : {
189 : const geometry_rectangle_t *const source_rect
190 0 : = layout_relationship_get_from_symbol_box_const ( current_relation );
191 : const geometry_rectangle_t *const dest_rect
192 0 : = layout_relationship_get_to_symbol_box_const ( current_relation );
193 :
194 : uint32_t solutions_by_I;
195 0 : pencil_relationship_2d_layouter_private_connect_rectangles_by_I ( this_,
196 : source_rect,
197 : dest_rect,
198 : solutions_max,
199 : &(out_solutions[0]),
200 : &solutions_by_I
201 : );
202 :
203 : uint32_t solutions_by_ZN;
204 0 : pencil_relationship_2d_layouter_private_connect_rectangles_by_ZN ( this_,
205 : source_rect,
206 : dest_rect,
207 : solutions_max - solutions_by_I,
208 0 : &(out_solutions[solutions_by_I]),
209 : &solutions_by_ZN
210 : );
211 :
212 : uint32_t solutions_by_L7;
213 0 : const uint32_t solutions_by_I_ZN = solutions_by_I + solutions_by_ZN;
214 0 : pencil_relationship_2d_layouter_private_connect_rectangles_by_L7 ( this_,
215 : source_rect,
216 : dest_rect,
217 : solutions_max - solutions_by_I_ZN,
218 0 : &(out_solutions[solutions_by_I_ZN]),
219 : &solutions_by_L7
220 : );
221 :
222 : uint32_t solutions_by_UC;
223 0 : const uint32_t solutions_by_I_ZN_L7 = solutions_by_I_ZN + solutions_by_L7;
224 0 : pencil_relationship_2d_layouter_private_connect_rectangles_by_UC ( this_,
225 : source_rect,
226 : dest_rect,
227 : solutions_max - solutions_by_I_ZN_L7,
228 0 : &(out_solutions[solutions_by_I_ZN_L7]),
229 : &solutions_by_UC
230 : );
231 :
232 0 : *out_solutions_count = solutions_by_I_ZN_L7 + solutions_by_UC;
233 0 : assert ( 1 <= *out_solutions_count );
234 0 : assert ( *out_solutions_count <= solutions_max );
235 : }
236 :
237 0 : U8_TRACE_END();
238 0 : }
239 :
240 : static const geometry_3dir_t PENCIL_BAD_V_PATTERN1
241 : = { .first = GEOMETRY_DIRECTION_LEFT, .second = GEOMETRY_DIRECTION_DOWN, .third = GEOMETRY_DIRECTION_LEFT };
242 : static const geometry_3dir_t PENCIL_BAD_V_PATTERN2
243 : = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_UP, .third = GEOMETRY_DIRECTION_RIGHT };
244 : static const geometry_3dir_t PENCIL_BAD_H_PATTERN1
245 : = { .first = GEOMETRY_DIRECTION_DOWN, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
246 : static const geometry_3dir_t PENCIL_BAD_H_PATTERN2
247 : = { .first = GEOMETRY_DIRECTION_UP, .second = GEOMETRY_DIRECTION_LEFT, .third = GEOMETRY_DIRECTION_UP };
248 :
249 0 : void pencil_relationship_2d_layouter_private_select_solution ( pencil_relationship_2d_layouter_t *this_,
250 : uint32_t solutions_count,
251 : const geometry_connector_t solutions[],
252 : uint32_t *out_index_of_best )
253 : {
254 0 : U8_TRACE_BEGIN();
255 0 : assert ( (*this_).sorted_rel_index < universal_array_index_sorter_get_count( &((*this_).sorted_relationships) ) );
256 0 : assert ( NULL != solutions );
257 0 : assert ( NULL != out_index_of_best );
258 0 : assert ( 1 <= solutions_count );
259 :
260 : /* get current relation data */
261 : const uint32_t index
262 0 : = universal_array_index_sorter_get_array_index ( &((*this_).sorted_relationships), (*this_).sorted_rel_index );
263 : const layout_relationship_t *const current_relation
264 0 : = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
265 : #if 0
266 : const data_relationship_t *const current_relation_data
267 : = layout_relationship_get_data_const ( current_relation );
268 : #endif
269 : const geometry_rectangle_t *const source_rect
270 0 : = layout_relationship_get_from_symbol_box_const ( current_relation );
271 : const geometry_rectangle_t *const dest_rect
272 0 : = layout_relationship_get_to_symbol_box_const ( current_relation );
273 0 : const double src_center_x = geometry_rectangle_get_center_x ( source_rect );
274 0 : const double src_center_y = geometry_rectangle_get_center_y ( source_rect );
275 0 : const double dst_center_x = geometry_rectangle_get_center_x ( dest_rect );
276 0 : const double dst_center_y = geometry_rectangle_get_center_y ( dest_rect );
277 :
278 : /* get draw area */
279 : const layout_diagram_t *const diagram_layout
280 0 : = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
281 : const geometry_rectangle_t *const diagram_draw_area
282 0 : = layout_diagram_get_draw_area_const( diagram_layout );
283 0 : const double diagram_draw_center_x = geometry_rectangle_get_center_x( diagram_draw_area );
284 0 : const double diagram_draw_center_y = geometry_rectangle_get_center_y( diagram_draw_area );
285 :
286 : /* get preferred object distance */
287 0 : const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
288 :
289 : /* define potential solution and rating */
290 0 : uint32_t index_of_best = 0;
291 0 : double debts_of_best = DBL_MAX;
292 :
293 : /* evaluate the solutions by their overlaps with classifiers */
294 0 : for ( uint32_t solution_idx = 0; solution_idx < solutions_count; solution_idx ++ )
295 : {
296 : /* evalute the debts of this solution */
297 0 : double debts_of_current = 0.0;
298 0 : const geometry_connector_t *const current_solution = &(solutions[solution_idx]);
299 : const geometry_rectangle_t connector_bounds
300 0 : = geometry_connector_get_bounding_rectangle( current_solution );
301 :
302 : /* avoid alternating solutions in case their debts are identical */
303 0 : debts_of_current += 0.1 * solution_idx;
304 :
305 : /* the more length, the more unwanted... */
306 0 : debts_of_current += geometry_connector_get_length( current_solution );
307 :
308 : /* prefer _either_ no _or_ minimum-dist lengths of parts... */
309 0 : const double HEAVIER_THAN_DETOUR = 4.0;
310 0 : const double source_length = geometry_connector_get_source_length( current_solution );
311 0 : if (( source_length > 0.000001 )&&( source_length < object_dist ))
312 : {
313 0 : debts_of_current += HEAVIER_THAN_DETOUR * ( object_dist - source_length );
314 :
315 : }
316 0 : const double destination_length = geometry_connector_get_destination_length( current_solution );
317 0 : if (( destination_length > 0.000001 )&&( destination_length < object_dist ))
318 : {
319 0 : debts_of_current += HEAVIER_THAN_DETOUR * ( object_dist - destination_length );
320 : }
321 0 : const bool no_source_or_no_dest = ( source_length < 0.000001 )||( destination_length < 0.000001 );
322 0 : const double main_length = geometry_connector_get_main_length( current_solution );
323 0 : if (( main_length > 0.000001 )&&( main_length < object_dist )&&( no_source_or_no_dest ))
324 : {
325 0 : debts_of_current += HEAVIER_THAN_DETOUR * ( object_dist - main_length );
326 : }
327 :
328 : /* prefer centered over uncentered departure and arrival */
329 0 : const double HEAVIER_THAN_CENTERED = 2.0;
330 : const double delta_source
331 0 : = fmin( fabs( geometry_connector_get_source_end_x( current_solution ) - src_center_x ),
332 0 : fabs( geometry_connector_get_source_end_y( current_solution ) - src_center_y ) );
333 0 : debts_of_current += delta_source * HEAVIER_THAN_CENTERED;
334 : const double delta_destination
335 0 : = fmin( fabs( geometry_connector_get_destination_end_x( current_solution ) - dst_center_x ),
336 0 : fabs( geometry_connector_get_destination_end_y( current_solution ) - dst_center_y ) );
337 0 : debts_of_current += delta_destination * HEAVIER_THAN_CENTERED;
338 :
339 : /* prefer left-hand angles over right-handed */
340 0 : bool bad_pattern_h = false;
341 0 : bool bad_pattern_v = false;
342 0 : const geometry_3dir_t pattern = geometry_connector_get_directions( current_solution );
343 : {
344 :
345 0 : bad_pattern_v = geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN1 )
346 0 : || geometry_3dir_equals( &pattern, &PENCIL_BAD_V_PATTERN2 );
347 0 : bad_pattern_h = geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN1 )
348 0 : || geometry_3dir_equals( &pattern, &PENCIL_BAD_H_PATTERN2 );
349 0 : if ( bad_pattern_h || bad_pattern_v )
350 : {
351 0 : const double current_len = geometry_connector_get_length( current_solution );
352 0 : if ( current_len > ( 4.0 * object_dist ) )
353 : {
354 : /* current_solution is a long path and right-handed */
355 0 : debts_of_current += 0.2 * geometry_connector_get_length( current_solution );
356 : }
357 : }
358 : }
359 :
360 : /* to avoid bad patterns: no L on top-left, no 7 on bottom-right, no r on top-right, no J on bottom-left */
361 : {
362 0 : const bool connector_is_left
363 0 : = geometry_rectangle_get_center_x( &connector_bounds ) < diagram_draw_center_x;
364 0 : const bool connector_is_top
365 0 : = geometry_rectangle_get_center_y( &connector_bounds ) < diagram_draw_center_y;
366 0 : if ( connector_is_left )
367 : {
368 0 : if ( connector_is_top )
369 : {
370 : static const geometry_3dir_t PENCIL_BAD_L_PATTERN1
371 : = { .first = GEOMETRY_DIRECTION_LEFT, .second = GEOMETRY_DIRECTION_UP, .third = GEOMETRY_DIRECTION_CENTER };
372 : static const geometry_3dir_t PENCIL_BAD_L_PATTERN2
373 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT, .third = GEOMETRY_DIRECTION_UP };
374 : static const geometry_3dir_t PENCIL_BAD_L_PATTERN3
375 : = { .first = GEOMETRY_DIRECTION_DOWN, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
376 : static const geometry_3dir_t PENCIL_BAD_L_PATTERN4
377 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN, .third = GEOMETRY_DIRECTION_RIGHT };
378 :
379 0 : if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN1 ) )
380 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN2 ) )
381 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN3 ) )
382 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_L_PATTERN4 ) ))
383 : {
384 0 : debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
385 : }
386 : }
387 : else
388 : {
389 : static const geometry_3dir_t PENCIL_BAD_J_PATTERN1
390 : = { .first = GEOMETRY_DIRECTION_DOWN, .second = GEOMETRY_DIRECTION_LEFT, .third = GEOMETRY_DIRECTION_CENTER };
391 : static const geometry_3dir_t PENCIL_BAD_J_PATTERN2
392 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_DOWN, .third = GEOMETRY_DIRECTION_LEFT };
393 : static const geometry_3dir_t PENCIL_BAD_J_PATTERN3
394 : = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_UP, .third = GEOMETRY_DIRECTION_CENTER };
395 : static const geometry_3dir_t PENCIL_BAD_J_PATTERN4
396 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_UP };
397 :
398 0 : if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN1 ) )
399 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN2 ) )
400 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN3 ) )
401 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_J_PATTERN4 ) ))
402 : {
403 0 : debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
404 : }
405 : }
406 : }
407 : else
408 : {
409 0 : if ( connector_is_top )
410 : {
411 : static const geometry_3dir_t PENCIL_BAD_r_PATTERN1
412 : = { .first = GEOMETRY_DIRECTION_UP, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_CENTER };
413 : static const geometry_3dir_t PENCIL_BAD_r_PATTERN2
414 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP, .third = GEOMETRY_DIRECTION_RIGHT };
415 : static const geometry_3dir_t PENCIL_BAD_r_PATTERN3
416 : = { .first = GEOMETRY_DIRECTION_LEFT, .second = GEOMETRY_DIRECTION_DOWN, .third = GEOMETRY_DIRECTION_CENTER };
417 : static const geometry_3dir_t PENCIL_BAD_r_PATTERN4
418 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_LEFT, .third = GEOMETRY_DIRECTION_DOWN };
419 :
420 0 : if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN1 ) )
421 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN2 ) )
422 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN3 ) )
423 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_r_PATTERN4 ) ))
424 : {
425 0 : debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
426 : }
427 : }
428 : else
429 : {
430 : static const geometry_3dir_t PENCIL_BAD_7_PATTERN1
431 : = { .first = GEOMETRY_DIRECTION_RIGHT, .second = GEOMETRY_DIRECTION_DOWN, .third = GEOMETRY_DIRECTION_CENTER };
432 : static const geometry_3dir_t PENCIL_BAD_7_PATTERN2
433 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_RIGHT, .third = GEOMETRY_DIRECTION_DOWN };
434 : static const geometry_3dir_t PENCIL_BAD_7_PATTERN3
435 : = { .first = GEOMETRY_DIRECTION_UP, .second = GEOMETRY_DIRECTION_LEFT, .third = GEOMETRY_DIRECTION_CENTER };
436 : static const geometry_3dir_t PENCIL_BAD_7_PATTERN4
437 : = { .first = GEOMETRY_DIRECTION_CENTER, .second = GEOMETRY_DIRECTION_UP, .third = GEOMETRY_DIRECTION_LEFT };
438 :
439 0 : if (( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN1 ) )
440 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN2 ) )
441 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN3 ) )
442 0 : || ( geometry_3dir_equals( &pattern, &PENCIL_BAD_7_PATTERN4 ) ))
443 : {
444 0 : debts_of_current += 4.0 * geometry_connector_get_length( current_solution );
445 : }
446 : }
447 : }
448 : }
449 :
450 : /* add debts for overlap to diagram boundary */
451 : {
452 0 : if ( ! geometry_rectangle_is_containing( diagram_draw_area, &connector_bounds ) )
453 : {
454 0 : debts_of_current += 1000000.0;
455 : }
456 : }
457 :
458 : /* iterate over all classifiers */
459 : const uint32_t count_clasfy
460 0 : = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
461 0 : for ( uint32_t clasfy_index = 0; clasfy_index < count_clasfy; clasfy_index ++ )
462 : {
463 : const layout_visible_classifier_t *const probe_classifier
464 0 : = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, clasfy_index );
465 :
466 : const geometry_rectangle_t *const classifier_space
467 0 : = layout_visible_classifier_get_space_const( probe_classifier );
468 0 : if ( ! geometry_rectangle_is_containing( classifier_space, &connector_bounds ) )
469 : {
470 : const geometry_rectangle_t *const classifier_symbol_box
471 0 : = layout_visible_classifier_get_symbol_box_const( probe_classifier );
472 0 : if ( geometry_connector_is_intersecting_rectangle( current_solution, classifier_symbol_box ) )
473 : {
474 0 : debts_of_current += 100000.0;
475 : }
476 :
477 : const geometry_rectangle_t *const classifier_label_box
478 0 : = layout_visible_classifier_get_label_box_const( probe_classifier );
479 0 : if ( geometry_connector_is_intersecting_rectangle( current_solution, classifier_label_box ) )
480 : {
481 0 : debts_of_current += 10000.0;
482 : }
483 : }
484 : }
485 :
486 : /* iterate over all features, check symbol boxes only, label boxes are not yet initialized */
487 : const uint32_t count_features
488 0 : = layout_visible_set_get_feature_count ( (*this_).layout_data );
489 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
490 : {
491 : const layout_feature_t *const feature_layout
492 0 : = layout_visible_set_get_feature_ptr ( (*this_).layout_data, f_idx );
493 :
494 : const geometry_rectangle_t *const feature_symbol_box
495 0 : = layout_feature_get_symbol_box_const( feature_layout );
496 0 : if ( geometry_connector_is_intersecting_rectangle( current_solution, feature_symbol_box ) )
497 : {
498 0 : debts_of_current += 30000.0;
499 : }
500 : }
501 :
502 : /* iterate over the already created connectors (probe_sort_index < (*this_).sorted_rel_index) */
503 0 : for ( uint32_t probe_sort_index = 0; probe_sort_index < (*this_).sorted_rel_index; probe_sort_index ++ )
504 : {
505 : /* add debts if intersects */
506 : const uint32_t probe_index
507 0 : = universal_array_index_sorter_get_array_index( &((*this_).sorted_relationships), probe_sort_index );
508 : const layout_relationship_t *const probe_relationship
509 0 : = layout_visible_set_get_relationship_ptr( (*this_).layout_data, probe_index );
510 : #if 0
511 : const data_relationship_t *const probe_relation_data
512 : = layout_relationship_get_data_const ( probe_relationship );
513 : const bool same_type = ( data_relationship_get_main_type( probe_relation_data )
514 : == data_relationship_get_main_type( current_relation_data ) );
515 : const bool same_from = ( data_relationship_get_from_classifier_row_id( probe_relation_data )
516 : == data_relationship_get_from_classifier_row_id( current_relation_data ) );
517 : const bool same_to = ( data_relationship_get_to_classifier_row_id( probe_relation_data )
518 : == data_relationship_get_to_classifier_row_id( current_relation_data ) );
519 : const bool one_same_end = ( same_from != same_to );
520 : /* if probe and current have same type and (same source classifier xor same destination classifier), overlaps are ok */
521 : if ( ! ( same_type && one_same_end ) )
522 : #endif
523 : {
524 : const geometry_connector_t *const probe_shape
525 0 : = layout_relationship_get_shape_const( probe_relationship );
526 : const uint32_t intersects
527 0 : = geometry_connector_count_connector_intersects( current_solution, probe_shape );
528 0 : debts_of_current += 1000.0 * intersects;
529 :
530 0 : if ( ( bad_pattern_h || bad_pattern_v ) && ( intersects > 0 ) )
531 : {
532 0 : const geometry_3dir_t probe_pattern = geometry_connector_get_directions( probe_shape );
533 0 : const bool bad_probe_v = geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_V_PATTERN1 )
534 0 : || geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_V_PATTERN2 );
535 0 : const bool bad_probe_h = geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_H_PATTERN1 )
536 0 : || geometry_3dir_equals( &probe_pattern, &PENCIL_BAD_H_PATTERN2 );
537 0 : if (( bad_pattern_h && bad_probe_v )||( bad_pattern_v && bad_probe_h ))
538 : {
539 0 : debts_of_current += 1000000.0;
540 : }
541 : }
542 : }
543 : }
544 :
545 : /* update best solution */
546 0 : if ( debts_of_current < debts_of_best )
547 : {
548 0 : index_of_best = solution_idx;
549 0 : debts_of_best = debts_of_current;
550 : }
551 : }
552 :
553 : /* the best */
554 0 : *out_index_of_best = index_of_best;
555 0 : geometry_connector_trace( &(solutions[index_of_best]) );
556 :
557 0 : U8_TRACE_END();
558 0 : }
559 :
560 0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_I ( pencil_relationship_2d_layouter_t *this_,
561 : const geometry_rectangle_t *source_rect,
562 : const geometry_rectangle_t *dest_rect,
563 : uint32_t solutions_max,
564 : geometry_connector_t out_solutions[],
565 : uint32_t *out_solutions_count )
566 : {
567 0 : U8_TRACE_BEGIN();
568 0 : assert( NULL != source_rect );
569 0 : assert( NULL != dest_rect );
570 0 : assert ( NULL != out_solutions );
571 0 : assert ( NULL != out_solutions_count );
572 0 : assert ( 4 <= solutions_max ); /* current implementation requires at least 4 options */
573 :
574 0 : uint32_t solutions_count = 0;
575 :
576 0 : const double src_left = geometry_rectangle_get_left(source_rect);
577 0 : const double src_right = geometry_rectangle_get_right(source_rect);
578 0 : const double src_top = geometry_rectangle_get_top(source_rect);
579 0 : const double src_bottom = geometry_rectangle_get_bottom(source_rect);
580 :
581 0 : const double dst_left = geometry_rectangle_get_left(dest_rect);
582 0 : const double dst_right = geometry_rectangle_get_right(dest_rect);
583 0 : const double dst_top = geometry_rectangle_get_top(dest_rect);
584 0 : const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
585 :
586 0 : const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
587 0 : const double gap_dist = 0.499 * object_dist; /* half the object distance allows a line to pass between two objects */
588 :
589 : /* if applicable, add a solution where line is vertical */
590 0 : if (( src_right >= dst_left )&&( src_left <= dst_right ))
591 : {
592 0 : const double min_left = fmax( src_left, dst_left );
593 0 : const double max_right = fmin( src_right, dst_right );
594 :
595 0 : if ( dst_bottom + object_dist < src_top )
596 : {
597 : /* define defaults */
598 0 : double x_value = ( min_left + max_right ) / 2.0;
599 :
600 : /* optimize coordinates */
601 : geometry_rectangle_t search_rect;
602 0 : geometry_rectangle_init_by_corners( &search_rect, min_left, dst_bottom, max_right, src_top );
603 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
604 0 : geometry_rectangle_destroy( &search_rect );
605 :
606 : /* add solution */
607 0 : geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
608 : x_value,
609 : src_top,
610 : x_value,
611 : dst_bottom,
612 : x_value
613 : );
614 0 : solutions_count ++;
615 : }
616 0 : else if ( dst_top - object_dist > src_bottom )
617 : {
618 : /* define defaults */
619 0 : double x_value = ( min_left + max_right ) / 2.0;
620 :
621 : /* optimize coordinates */
622 : geometry_rectangle_t search_rect;
623 0 : geometry_rectangle_init_by_corners( &search_rect, min_left, dst_top, max_right, src_bottom );
624 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
625 0 : geometry_rectangle_destroy( &search_rect );
626 :
627 : /* add solution */
628 0 : geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
629 : x_value,
630 : src_bottom,
631 : x_value,
632 : dst_top,
633 : x_value
634 : );
635 0 : solutions_count ++;
636 : }
637 : else
638 : {
639 0 : if ( fabs( src_top - dst_top ) > object_dist )
640 : {
641 : /* define defaults */
642 0 : double x_value = ( min_left + max_right ) / 2.0;
643 :
644 : /* optimize coordinates */
645 : geometry_rectangle_t search_rect;
646 0 : geometry_rectangle_init_by_corners( &search_rect, min_left, dst_top, max_right, src_top );
647 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
648 0 : geometry_rectangle_destroy( &search_rect );
649 :
650 : /* add solution */
651 0 : geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
652 : x_value,
653 : src_top,
654 : x_value,
655 : dst_top,
656 : x_value
657 : );
658 0 : solutions_count ++;
659 : }
660 :
661 0 : if ( fabs( src_bottom - dst_bottom ) > object_dist )
662 : {
663 : /* define defaults */
664 0 : double x_value = ( min_left + max_right ) / 2.0;
665 :
666 : /* optimize coordinates */
667 : geometry_rectangle_t search_rect;
668 0 : geometry_rectangle_init_by_corners( &search_rect, min_left, src_bottom, max_right, dst_bottom );
669 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
670 0 : geometry_rectangle_destroy( &search_rect );
671 :
672 : /* add solution */
673 0 : geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
674 : x_value,
675 : src_bottom,
676 : x_value,
677 : dst_bottom,
678 : x_value
679 : );
680 0 : solutions_count ++;
681 : }
682 : }
683 : }
684 :
685 : /* if applicable, add a solution where line is horizontal */
686 0 : if (( src_bottom >= dst_top )&&( src_top <= dst_bottom ))
687 : {
688 0 : const double min_top = fmax( src_top, dst_top );
689 0 : const double max_bottom = fmin( src_bottom, dst_bottom );
690 :
691 0 : if ( dst_right + object_dist < src_left )
692 : {
693 : /* define defaults */
694 0 : double y_value = ( min_top + max_bottom ) / 2.0;
695 :
696 : /* optimize coordinates */
697 : geometry_rectangle_t search_rect;
698 0 : geometry_rectangle_init_by_corners( &search_rect, dst_right, min_top, src_left, max_bottom );
699 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
700 0 : geometry_rectangle_destroy( &search_rect );
701 :
702 : /* add solution */
703 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
704 : src_left,
705 : y_value,
706 : dst_right,
707 : y_value,
708 : y_value
709 : );
710 0 : solutions_count ++;
711 : }
712 0 : else if ( dst_left - object_dist > src_right )
713 : {
714 : /* define defaults */
715 0 : double y_value = ( min_top + max_bottom ) / 2.0;
716 :
717 : /* optimize coordinates */
718 : geometry_rectangle_t search_rect;
719 0 : geometry_rectangle_init_by_corners( &search_rect, dst_left, min_top, src_right, max_bottom );
720 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
721 0 : geometry_rectangle_destroy( &search_rect );
722 :
723 : /* add solution */
724 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
725 : src_right,
726 : y_value,
727 : dst_left,
728 : y_value,
729 : y_value
730 : );
731 0 : solutions_count ++;
732 : }
733 : else
734 : {
735 0 : if ( fabs( src_left - dst_left ) > object_dist )
736 : {
737 : /* define defaults */
738 0 : double y_value = ( min_top + max_bottom ) / 2.0;
739 :
740 : /* optimize coordinates */
741 : geometry_rectangle_t search_rect;
742 0 : geometry_rectangle_init_by_corners( &search_rect, src_left, min_top, dst_left, max_bottom );
743 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
744 0 : geometry_rectangle_destroy( &search_rect );
745 :
746 : /* add solution */
747 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
748 : src_left,
749 : y_value,
750 : dst_left,
751 : y_value,
752 : y_value
753 : );
754 0 : solutions_count ++;
755 : }
756 :
757 0 : if ( fabs( src_right - dst_right ) > object_dist )
758 : {
759 : /* define defaults */
760 0 : double y_value = ( min_top + max_bottom ) / 2.0;
761 :
762 : /* optimize coordinates */
763 : geometry_rectangle_t search_rect;
764 0 : geometry_rectangle_init_by_corners( &search_rect, src_right, min_top, dst_right, max_bottom );
765 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
766 0 : geometry_rectangle_destroy( &search_rect );
767 :
768 : /* add solution */
769 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
770 : src_right,
771 : y_value,
772 : dst_right,
773 : y_value,
774 : y_value
775 : );
776 0 : solutions_count ++;
777 : }
778 : }
779 : }
780 :
781 0 : *out_solutions_count = solutions_count;
782 :
783 0 : U8_TRACE_END();
784 0 : }
785 :
786 0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_ZN ( pencil_relationship_2d_layouter_t *this_,
787 : const geometry_rectangle_t *source_rect,
788 : const geometry_rectangle_t *dest_rect,
789 : uint32_t solutions_max,
790 : geometry_connector_t out_solutions[],
791 : uint32_t *out_solutions_count )
792 : {
793 0 : U8_TRACE_BEGIN();
794 0 : assert( NULL != source_rect );
795 0 : assert( NULL != dest_rect );
796 0 : assert ( NULL != out_solutions );
797 0 : assert ( NULL != out_solutions_count );
798 0 : assert ( 2 <= solutions_max ); /* current implementation requires at least 2 options */
799 :
800 0 : uint32_t solutions_count = 0;
801 :
802 0 : const double src_left = geometry_rectangle_get_left(source_rect);
803 0 : const double src_center_x = geometry_rectangle_get_center_x(source_rect);
804 0 : const double src_right = geometry_rectangle_get_right(source_rect);
805 0 : const double src_top = geometry_rectangle_get_top(source_rect);
806 0 : const double src_center_y = geometry_rectangle_get_center_y(source_rect);
807 0 : const double src_bottom = geometry_rectangle_get_bottom(source_rect);
808 0 : const double src_width = geometry_rectangle_get_width(source_rect);
809 0 : const double src_height = geometry_rectangle_get_height(source_rect);
810 :
811 0 : const double dst_left = geometry_rectangle_get_left(dest_rect);
812 0 : const double dst_center_x = geometry_rectangle_get_center_x(dest_rect);
813 0 : const double dst_right = geometry_rectangle_get_right(dest_rect);
814 0 : const double dst_top = geometry_rectangle_get_top(dest_rect);
815 0 : const double dst_center_y = geometry_rectangle_get_center_y(dest_rect);
816 0 : const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
817 0 : const double dst_width = geometry_rectangle_get_width(dest_rect);
818 0 : const double dst_height = geometry_rectangle_get_height(dest_rect);
819 :
820 0 : const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
821 0 : const double good_dist = 2.0 * object_dist; /* duplicate distance: once for each side of the line */
822 0 : const double gap_dist = 0.499 * object_dist; /* half the object distance allows a line to pass between two objects */
823 :
824 : /* if applicable, add a solution where main line is vertical */
825 : {
826 0 : if ( dst_right + good_dist < src_left )
827 : {
828 : /* define defaults */
829 0 : double x_value = ( src_left + dst_right ) / 2.0;
830 0 : double src_y = src_center_y;
831 0 : double dst_y = dst_center_y;
832 :
833 : /* optimize coordinates */
834 : geometry_rectangle_t search_rect;
835 0 : geometry_rectangle_init_by_corners( &search_rect, src_left, src_y, dst_right, dst_y );
836 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
837 0 : geometry_rectangle_destroy( &search_rect );
838 :
839 0 : const geometry_rectangle_t depart_area
840 0 : = { .left=x_value, .top=src_top, .width=(src_left-x_value), .height=src_height};
841 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
842 :
843 0 : const geometry_rectangle_t arrive_area
844 0 : = { .left=dst_right, .top=dst_top, .width=(x_value-dst_right), .height=dst_height};
845 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
846 :
847 : /* add solution */
848 0 : geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
849 : src_left,
850 : src_y,
851 : dst_right,
852 : dst_y,
853 : x_value
854 : );
855 0 : solutions_count ++;
856 : }
857 0 : else if ( dst_left - good_dist > src_right )
858 : {
859 : /* define defaults */
860 0 : double x_value = ( src_right + dst_left ) / 2.0;
861 0 : double src_y = src_center_y;
862 0 : double dst_y = dst_center_y;
863 :
864 : /* optimize coordinates */
865 : geometry_rectangle_t search_rect;
866 0 : geometry_rectangle_init_by_corners( &search_rect, src_right, src_y, dst_left, dst_y );
867 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
868 0 : geometry_rectangle_destroy( &search_rect );
869 :
870 0 : const geometry_rectangle_t depart_area
871 0 : = { .left=src_right, .top=src_top, .width=(x_value-src_right), .height=src_height};
872 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
873 :
874 0 : const geometry_rectangle_t arrive_area
875 0 : = { .left=x_value, .top=dst_top, .width=(dst_left-x_value), .height=dst_height};
876 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
877 :
878 : /* add solution */
879 0 : geometry_connector_reinit_vertical ( &(out_solutions[solutions_count]),
880 : src_right,
881 : src_y,
882 : dst_left,
883 : dst_y,
884 : x_value
885 : );
886 0 : solutions_count ++;
887 : }
888 : }
889 :
890 : /* if applicable, add a solution where main line is horizontal */
891 : {
892 0 : if ( dst_bottom + good_dist < src_top )
893 : {
894 : /* define defaults */
895 0 : double y_value = ( src_top + dst_bottom ) / 2.0;
896 0 : double src_x = src_center_x;
897 0 : double dst_x = dst_center_x;
898 :
899 : /* optimize coordinates */
900 : geometry_rectangle_t search_rect;
901 0 : geometry_rectangle_init_by_corners( &search_rect, src_x, src_top, dst_x, dst_bottom );
902 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
903 0 : geometry_rectangle_destroy( &search_rect );
904 :
905 0 : const geometry_rectangle_t depart_area
906 0 : = { .left=src_left, .top=y_value, .width=src_width, .height=(src_top-y_value)};
907 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
908 :
909 0 : const geometry_rectangle_t arrive_area
910 0 : = { .left=dst_left, .top=dst_bottom, .width=dst_width, .height=(y_value-dst_bottom)};
911 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
912 :
913 : /* add solution */
914 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
915 : src_x,
916 : src_top,
917 : dst_x,
918 : dst_bottom,
919 : y_value
920 : );
921 0 : solutions_count ++;
922 : }
923 0 : else if ( dst_top - good_dist > src_bottom )
924 : {
925 : /* define defaults */
926 0 : double y_value = ( src_bottom + dst_top ) / 2.0;
927 0 : double src_x = src_center_x;
928 0 : double dst_x = dst_center_x;
929 :
930 : /* optimize coordinates */
931 : geometry_rectangle_t search_rect;
932 0 : geometry_rectangle_init_by_corners( &search_rect, src_x, src_bottom, dst_x, dst_top );
933 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
934 0 : geometry_rectangle_destroy( &search_rect );
935 :
936 0 : const geometry_rectangle_t depart_area
937 0 : = { .left=src_left, .top=src_bottom, .width=src_width, .height=(y_value-src_bottom)};
938 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
939 :
940 0 : const geometry_rectangle_t arrive_area
941 0 : = { .left=dst_left, .top=y_value, .width=dst_width, .height=(dst_top-y_value)};
942 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
943 :
944 : /* add solution */
945 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
946 : src_x,
947 : src_bottom,
948 : dst_x,
949 : dst_top,
950 : y_value
951 : );
952 0 : solutions_count ++;
953 : }
954 : }
955 :
956 0 : *out_solutions_count = solutions_count;
957 :
958 0 : U8_TRACE_END();
959 0 : }
960 :
961 0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_UC ( pencil_relationship_2d_layouter_t *this_,
962 : const geometry_rectangle_t *source_rect,
963 : const geometry_rectangle_t *dest_rect,
964 : uint32_t solutions_max,
965 : geometry_connector_t out_solutions[],
966 : uint32_t *out_solutions_count )
967 : {
968 0 : U8_TRACE_BEGIN();
969 0 : assert( NULL != source_rect );
970 0 : assert( NULL != dest_rect );
971 0 : assert ( NULL != out_solutions );
972 0 : assert ( NULL != out_solutions_count );
973 0 : assert ( 4 <= solutions_max ); /* current implementation calculates exactly 4 options */
974 :
975 0 : uint32_t solutions_count = 0;
976 :
977 : /* get draw area */
978 : const layout_diagram_t *const diagram_layout
979 0 : = layout_visible_set_get_diagram_ptr( (*this_).layout_data );
980 : const geometry_rectangle_t *const diagram_draw_area
981 0 : = layout_diagram_get_draw_area_const( diagram_layout );
982 0 : const double draw_left = geometry_rectangle_get_left( diagram_draw_area );
983 0 : const double draw_right = geometry_rectangle_get_right( diagram_draw_area );
984 0 : const double draw_top = geometry_rectangle_get_top( diagram_draw_area );
985 0 : const double draw_bottom = geometry_rectangle_get_bottom( diagram_draw_area );
986 :
987 0 : const double src_left = geometry_rectangle_get_left(source_rect);
988 0 : const double src_center_x = geometry_rectangle_get_center_x(source_rect);
989 0 : const double src_right = geometry_rectangle_get_right(source_rect);
990 0 : const double src_top = geometry_rectangle_get_top(source_rect);
991 0 : const double src_center_y = geometry_rectangle_get_center_y(source_rect);
992 0 : const double src_bottom = geometry_rectangle_get_bottom(source_rect);
993 0 : const double src_width = geometry_rectangle_get_width(source_rect);
994 0 : const double src_height = geometry_rectangle_get_height(source_rect);
995 :
996 0 : const double dst_left = geometry_rectangle_get_left(dest_rect);
997 0 : const double dst_center_x = geometry_rectangle_get_center_x(dest_rect);
998 0 : const double dst_right = geometry_rectangle_get_right(dest_rect);
999 0 : const double dst_top = geometry_rectangle_get_top(dest_rect);
1000 0 : const double dst_center_y = geometry_rectangle_get_center_y(dest_rect);
1001 0 : const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
1002 0 : const double dst_width = geometry_rectangle_get_width(dest_rect);
1003 0 : const double dst_height = geometry_rectangle_get_height(dest_rect);
1004 :
1005 0 : const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
1006 0 : const double gap_dist = 0.499 * object_dist; /* half the object distance allows a line to pass between two objects */
1007 : static const double NO_TOUCH = 0.0001;
1008 :
1009 : /* connect via left side */
1010 : {
1011 : /* define defaults */
1012 0 : double x_value = fmin( src_left, dst_left ) - object_dist;
1013 0 : double src_y = src_center_y;
1014 0 : double dst_y = dst_center_y;
1015 0 : if ( fabs( src_center_y - dst_center_y ) < NO_TOUCH )
1016 : {
1017 : /* forward way is identical to retour - may be a relation to self */
1018 0 : src_y = fmin( src_center_y + gap_dist, src_bottom );
1019 0 : dst_y = fmax( dst_center_y - gap_dist, dst_top );
1020 : }
1021 :
1022 : /* optimize coordinates */
1023 : geometry_rectangle_t search_rect;
1024 0 : geometry_rectangle_init_by_corners( &search_rect, draw_left, src_y, x_value, dst_y );
1025 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
1026 0 : geometry_rectangle_destroy( &search_rect );
1027 :
1028 0 : const geometry_rectangle_t depart_area
1029 0 : = { .left=x_value, .top=src_top, .width=(src_left-x_value), .height=src_height};
1030 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
1031 :
1032 0 : const geometry_rectangle_t arrive_area
1033 0 : = { .left=x_value, .top=dst_top, .width=(dst_left-x_value), .height=dst_height};
1034 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
1035 :
1036 : /* add solution */
1037 0 : geometry_connector_reinit_vertical( &(out_solutions[solutions_count]),
1038 : src_left,
1039 : src_y,
1040 : dst_left,
1041 : dst_y,
1042 : x_value
1043 : );
1044 0 : solutions_count ++;
1045 : }
1046 :
1047 : /* connect via right side */
1048 : {
1049 : /* define defaults */
1050 0 : double x_value = fmax( src_right, dst_right ) + object_dist;
1051 0 : double src_y = src_center_y;
1052 0 : double dst_y = dst_center_y;
1053 0 : if ( fabs( src_center_y - dst_center_y ) < NO_TOUCH )
1054 : {
1055 : /* forward way is identical to retour - may be a relation to self */
1056 0 : src_y = fmin( src_center_y + gap_dist, src_bottom );
1057 0 : dst_y = fmax( dst_center_y - gap_dist, dst_top );
1058 : }
1059 :
1060 : /* optimize coordinates */
1061 : geometry_rectangle_t search_rect;
1062 0 : geometry_rectangle_init_by_corners( &search_rect, x_value, src_y, draw_right, dst_y );
1063 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &search_rect, gap_dist, &x_value );
1064 0 : geometry_rectangle_destroy( &search_rect );
1065 :
1066 0 : const geometry_rectangle_t depart_area
1067 0 : = { .left=src_right, .top=src_top, .width=(x_value-src_right), .height=src_height};
1068 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
1069 :
1070 0 : const geometry_rectangle_t arrive_area
1071 0 : = { .left=dst_right, .top=dst_top, .width=(x_value-dst_right), .height=dst_height};
1072 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
1073 :
1074 : /* add solution */
1075 0 : geometry_connector_reinit_vertical( &(out_solutions[solutions_count]),
1076 : src_right,
1077 : src_y,
1078 : dst_right,
1079 : dst_y,
1080 : x_value
1081 : );
1082 0 : solutions_count ++;
1083 : }
1084 :
1085 : /* connect via top side */
1086 : {
1087 : /* define defaults */
1088 0 : double y_value = fmin( src_top, dst_top ) - object_dist;
1089 0 : double src_x = src_center_x;
1090 0 : double dst_x = dst_center_x;
1091 0 : if ( fabs( src_center_x - dst_center_x ) < NO_TOUCH )
1092 : {
1093 : /* forward way is identical to retour - may be a relation to self */
1094 0 : src_x = fmax( src_center_x - gap_dist, src_left );
1095 0 : dst_x = fmin( dst_center_x + gap_dist, dst_right );
1096 : }
1097 :
1098 : /* optimize coordinates */
1099 : geometry_rectangle_t search_rect;
1100 0 : geometry_rectangle_init_by_corners( &search_rect, src_x, draw_top, dst_x, y_value );
1101 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
1102 0 : geometry_rectangle_destroy( &search_rect );
1103 :
1104 0 : const geometry_rectangle_t depart_area
1105 0 : = { .left=src_left, .top=y_value, .width=src_width, .height=(src_top-y_value)};
1106 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
1107 :
1108 0 : const geometry_rectangle_t arrive_area
1109 0 : = { .left=dst_left, .top=y_value, .width=dst_width, .height=(dst_top-y_value)};
1110 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
1111 :
1112 : /* add solution */
1113 0 : geometry_connector_reinit_horizontal( &(out_solutions[solutions_count]),
1114 : src_x,
1115 : src_top,
1116 : dst_x,
1117 : dst_top,
1118 : y_value
1119 : );
1120 0 : solutions_count ++;
1121 : }
1122 :
1123 : /* connect via bottom side */
1124 : {
1125 : /* define defaults */
1126 0 : double y_value = fmax( src_bottom, dst_bottom ) + object_dist;
1127 0 : double src_x = src_center_x;
1128 0 : double dst_x = dst_center_x;
1129 0 : if ( fabs( src_center_x - dst_center_x ) < NO_TOUCH )
1130 : {
1131 : /* forward way is identical to retour - may be a relation to self */
1132 0 : src_x = fmax( src_center_x - gap_dist, src_left );
1133 0 : dst_x = fmin( dst_center_x + gap_dist, dst_right );
1134 : }
1135 :
1136 : /* optimize coordinates */
1137 : geometry_rectangle_t search_rect;
1138 0 : geometry_rectangle_init_by_corners( &search_rect, src_x, y_value, dst_x, draw_bottom );
1139 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &search_rect, gap_dist, &y_value );
1140 0 : geometry_rectangle_destroy( &search_rect );
1141 :
1142 0 : const geometry_rectangle_t depart_area
1143 0 : = { .left=src_left, .top=src_bottom, .width=src_width, .height=(y_value-src_bottom)};
1144 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
1145 :
1146 0 : const geometry_rectangle_t arrive_area
1147 0 : = { .left=dst_left, .top=dst_bottom, .width=dst_width, .height=(y_value-dst_bottom)};
1148 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
1149 :
1150 : /* add solution */
1151 0 : geometry_connector_reinit_horizontal( &(out_solutions[solutions_count]),
1152 : src_x,
1153 : src_bottom,
1154 : dst_x,
1155 : dst_bottom,
1156 : y_value
1157 : );
1158 0 : solutions_count ++;
1159 : }
1160 :
1161 0 : *out_solutions_count = solutions_count;
1162 :
1163 0 : U8_TRACE_END();
1164 0 : }
1165 :
1166 0 : void pencil_relationship_2d_layouter_private_connect_rectangles_by_L7 ( pencil_relationship_2d_layouter_t *this_,
1167 : const geometry_rectangle_t *source_rect,
1168 : const geometry_rectangle_t *dest_rect,
1169 : uint32_t solutions_max,
1170 : geometry_connector_t out_solutions[],
1171 : uint32_t *out_solutions_count )
1172 : {
1173 0 : U8_TRACE_BEGIN();
1174 0 : assert( NULL != source_rect );
1175 0 : assert( NULL != dest_rect );
1176 0 : assert ( NULL != out_solutions );
1177 0 : assert ( NULL != out_solutions_count );
1178 0 : assert ( 8 <= solutions_max ); /* current implementation requires at least 2 options */
1179 :
1180 0 : uint32_t solutions_count = 0;
1181 :
1182 0 : const double src_left = geometry_rectangle_get_left(source_rect);
1183 0 : const double src_right = geometry_rectangle_get_right(source_rect);
1184 0 : const double src_top = geometry_rectangle_get_top(source_rect);
1185 0 : const double src_bottom = geometry_rectangle_get_bottom(source_rect);
1186 :
1187 0 : const double dst_left = geometry_rectangle_get_left(dest_rect);
1188 0 : const double dst_right = geometry_rectangle_get_right(dest_rect);
1189 0 : const double dst_top = geometry_rectangle_get_top(dest_rect);
1190 0 : const double dst_bottom = geometry_rectangle_get_bottom(dest_rect);
1191 :
1192 0 : const double object_dist = pencil_size_get_preferred_object_distance( (*this_).pencil_size );
1193 0 : const double gap_dist = 0.499 * object_dist; /* half the object distance allows a line to pass between two objects */
1194 :
1195 : /* pre-calculate some intermediate values on source rect */
1196 0 : const bool src_left_to_outside = dst_left < src_left; /* connector starts towards outside of source rect */
1197 0 : const bool src_right_to_outside = dst_right > src_right; /* connector starts towards outside of source rect */
1198 0 : const bool src_top_to_outside = src_top > dst_top; /* connector arrives from outside at dest rect */
1199 0 : const bool src_bottom_to_outside = src_bottom < dst_bottom; /* connector arrives from outside at dest rect */
1200 : /* pre-calculate some intermediate values on destination rect */
1201 0 : const bool dst_left_from_outside = src_left < dst_left; /* connector starts towards outside of source rect */
1202 0 : const bool dst_right_from_outside = src_right > dst_right; /* connector starts towards outside of source rect */
1203 0 : const bool dst_top_from_outside = dst_top > src_top; /* connector arrives from outside at dest rect */
1204 0 : const bool dst_bottom_from_outside = dst_bottom < src_bottom; /* connector arrives from outside at dest rect */
1205 :
1206 : /* add two solutions from source-left */
1207 : {
1208 0 : const double search_left = dst_left;
1209 0 : const double search_right = src_left_to_outside ? fmin( src_left, dst_right ) : dst_right;
1210 : /* add a solution from source-left to destination-bottom */
1211 : {
1212 0 : const double search_top = dst_bottom_from_outside ? fmax( src_top, dst_bottom ) : src_top;
1213 0 : const double search_bottom = src_bottom;
1214 :
1215 : /* define defaults */
1216 0 : double dst_x = ( search_left + search_right ) / 2.0;
1217 0 : double src_y = ( search_top + search_bottom ) / 2.0;
1218 :
1219 : /* optimize coordinates */
1220 : geometry_rectangle_t depart_area;
1221 0 : geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_left, src_bottom );
1222 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
1223 0 : geometry_rectangle_destroy( &depart_area );
1224 :
1225 : geometry_rectangle_t arrive_area;
1226 0 : geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_bottom );
1227 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
1228 0 : geometry_rectangle_destroy( &arrive_area );
1229 :
1230 : /* add solution */
1231 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1232 : src_left,
1233 : src_y,
1234 : dst_x,
1235 : dst_bottom,
1236 : src_y
1237 : );
1238 0 : solutions_count ++;
1239 : }
1240 : /* add a solution from source-left to destination-top */
1241 : {
1242 0 : const double search_top = src_top;
1243 0 : const double search_bottom = dst_top_from_outside ? fmin( src_bottom, dst_top ) : src_bottom;
1244 :
1245 : /* define defaults */
1246 0 : double dst_x = ( search_left + search_right ) / 2.0;
1247 0 : double src_y = ( search_top + search_bottom ) / 2.0;
1248 :
1249 : /* optimize coordinates */
1250 : geometry_rectangle_t depart_area;
1251 0 : geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_left, src_bottom );
1252 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
1253 0 : geometry_rectangle_destroy( &depart_area );
1254 :
1255 : geometry_rectangle_t arrive_area;
1256 0 : geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_top );
1257 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
1258 0 : geometry_rectangle_destroy( &arrive_area );
1259 :
1260 : /* add solution */
1261 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1262 : src_left,
1263 : src_y,
1264 : dst_x,
1265 : dst_top,
1266 : src_y
1267 : );
1268 0 : solutions_count ++;
1269 : }
1270 : }
1271 :
1272 : /* add two solutions from source-right */
1273 : {
1274 0 : const double search_left = src_right_to_outside ? fmax( src_right, dst_left ) : dst_left;
1275 0 : const double search_right = dst_right;
1276 : /* add a solution from source-right to destination-bottom */
1277 : {
1278 0 : const double search_top = dst_bottom_from_outside ? fmax( src_top, dst_bottom ) : src_top;
1279 0 : const double search_bottom = src_bottom;
1280 :
1281 : /* define defaults */
1282 0 : double dst_x = ( search_left + search_right ) / 2.0;
1283 0 : double src_y = ( search_top + search_bottom ) / 2.0;
1284 :
1285 : /* optimize coordinates */
1286 : geometry_rectangle_t depart_area;
1287 0 : geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_right, src_bottom );
1288 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
1289 0 : geometry_rectangle_destroy( &depart_area );
1290 :
1291 : geometry_rectangle_t arrive_area;
1292 0 : geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_bottom );
1293 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
1294 0 : geometry_rectangle_destroy( &arrive_area );
1295 :
1296 : /* add solution */
1297 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1298 : src_right,
1299 : src_y,
1300 : dst_x,
1301 : dst_bottom,
1302 : src_y
1303 : );
1304 0 : solutions_count ++;
1305 : }
1306 : /* add a solution from source-right to destination-top */
1307 : {
1308 0 : const double search_top = src_top;
1309 0 : const double search_bottom = dst_top_from_outside ? fmin( src_bottom, dst_top ) : src_bottom;
1310 :
1311 : /* define defaults */
1312 0 : double dst_x = ( search_left + search_right ) / 2.0;
1313 0 : double src_y = ( search_top + search_bottom ) / 2.0;
1314 :
1315 : /* optimize coordinates */
1316 : geometry_rectangle_t depart_area;
1317 0 : geometry_rectangle_init_by_corners( &depart_area, dst_x, src_top, src_right, src_bottom );
1318 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &depart_area, gap_dist, &src_y );
1319 0 : geometry_rectangle_destroy( &depart_area );
1320 :
1321 : geometry_rectangle_t arrive_area;
1322 0 : geometry_rectangle_init_by_corners( &arrive_area, dst_left, src_y, dst_right, dst_top );
1323 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &arrive_area, gap_dist, &dst_x );
1324 0 : geometry_rectangle_destroy( &arrive_area );
1325 :
1326 : /* add solution */
1327 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1328 : src_right,
1329 : src_y,
1330 : dst_x,
1331 : dst_top,
1332 : src_y
1333 : );
1334 0 : solutions_count ++;
1335 : }
1336 : }
1337 :
1338 : /* add two solutions from source-top */
1339 : {
1340 0 : const double search_top = dst_top;
1341 0 : const double search_bottom = src_top_to_outside ? fmin( src_top, dst_bottom ) : dst_bottom;
1342 : /* add a solution from source-top to destination-right */
1343 : {
1344 0 : const double search_left = dst_right_from_outside ? fmax( dst_right, src_left ) : src_left;
1345 0 : const double search_right = src_right;
1346 :
1347 : /* define defaults */
1348 0 : double src_x = ( search_left + search_right ) / 2.0;
1349 0 : double dst_y = ( search_top + search_bottom ) / 2.0;
1350 :
1351 : /* optimize coordinates */
1352 : geometry_rectangle_t depart_area;
1353 0 : geometry_rectangle_init_by_corners( &depart_area, src_left, src_top, src_right, dst_y );
1354 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
1355 0 : geometry_rectangle_destroy( &depart_area );
1356 :
1357 : geometry_rectangle_t arrive_area;
1358 0 : geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_right, dst_bottom );
1359 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
1360 0 : geometry_rectangle_destroy( &arrive_area );
1361 :
1362 : /* add solution */
1363 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1364 : src_x,
1365 : src_top,
1366 : dst_right,
1367 : dst_y,
1368 : dst_y
1369 : );
1370 0 : solutions_count ++;
1371 : }
1372 : /* add a solution from source-top to destination-left */
1373 : {
1374 0 : const double search_left = src_left;
1375 0 : const double search_right = dst_left_from_outside ? fmin( dst_left, src_right ) : src_right;
1376 :
1377 : /* define defaults */
1378 0 : double src_x = ( search_left + search_right ) / 2.0;
1379 0 : double dst_y = ( search_top + search_bottom ) / 2.0;
1380 :
1381 : /* optimize coordinates */
1382 : geometry_rectangle_t depart_area;
1383 0 : geometry_rectangle_init_by_corners( &depart_area, src_left, src_top, src_right, dst_y );
1384 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
1385 0 : geometry_rectangle_destroy( &depart_area );
1386 :
1387 : geometry_rectangle_t arrive_area;
1388 0 : geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_left, dst_bottom );
1389 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
1390 0 : geometry_rectangle_destroy( &arrive_area );
1391 :
1392 : /* add solution */
1393 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1394 : src_x,
1395 : src_top,
1396 : dst_left,
1397 : dst_y,
1398 : dst_y
1399 : );
1400 0 : solutions_count ++;
1401 : }
1402 : }
1403 :
1404 : /* add two solutions from source-bottom */
1405 : {
1406 0 : const double search_top = src_bottom_to_outside ? fmax( src_bottom, dst_top ) : dst_top;
1407 0 : const double search_bottom = dst_bottom;
1408 : /* add a solution from source-bottom to destination-right */
1409 : {
1410 0 : const double search_left = dst_right_from_outside ? fmax( dst_right, src_left ) : src_left;
1411 0 : const double search_right = src_right;
1412 :
1413 : /* define defaults */
1414 0 : double src_x = ( search_left + search_right ) / 2.0;
1415 0 : double dst_y = ( search_top + search_bottom ) / 2.0;
1416 :
1417 : /* optimize coordinates */
1418 : geometry_rectangle_t depart_area;
1419 0 : geometry_rectangle_init_by_corners( &depart_area, src_left, src_bottom, src_right, dst_y );
1420 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
1421 0 : geometry_rectangle_destroy( &depart_area );
1422 :
1423 : geometry_rectangle_t arrive_area;
1424 0 : geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_right, dst_bottom );
1425 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
1426 0 : geometry_rectangle_destroy( &arrive_area );
1427 :
1428 : /* add solution */
1429 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1430 : src_x,
1431 : src_bottom,
1432 : dst_right,
1433 : dst_y,
1434 : dst_y
1435 : );
1436 0 : solutions_count ++;
1437 : }
1438 : /* add a solution from source-bottom to destination-left */
1439 : {
1440 0 : const double search_left = src_left;
1441 0 : const double search_right = dst_left_from_outside ? fmin( dst_left, src_right ) : src_right;
1442 :
1443 : /* define defaults */
1444 0 : double src_x = ( search_left + search_right ) / 2.0;
1445 0 : double dst_y = ( search_top + search_bottom ) / 2.0;
1446 :
1447 : /* optimize coordinates */
1448 : geometry_rectangle_t depart_area;
1449 0 : geometry_rectangle_init_by_corners( &depart_area, src_left, src_bottom, src_right, dst_y );
1450 0 : pencil_relationship_2d_layouter_private_find_space_for_v_line ( this_, &depart_area, gap_dist, &src_x );
1451 0 : geometry_rectangle_destroy( &depart_area );
1452 :
1453 : geometry_rectangle_t arrive_area;
1454 0 : geometry_rectangle_init_by_corners( &arrive_area, src_x, dst_top, dst_left, dst_bottom );
1455 0 : pencil_relationship_2d_layouter_private_find_space_for_h_line ( this_, &arrive_area, gap_dist, &dst_y );
1456 0 : geometry_rectangle_destroy( &arrive_area );
1457 :
1458 : /* add solution */
1459 0 : geometry_connector_reinit_horizontal ( &(out_solutions[solutions_count]),
1460 : src_x,
1461 : src_bottom,
1462 : dst_left,
1463 : dst_y,
1464 : dst_y
1465 : );
1466 0 : solutions_count ++;
1467 : }
1468 : }
1469 :
1470 0 : *out_solutions_count = solutions_count;
1471 :
1472 0 : U8_TRACE_END();
1473 0 : }
1474 :
1475 0 : u8_error_t pencil_relationship_2d_layouter_private_find_space_for_line ( pencil_relationship_2d_layouter_t *this_,
1476 : const geometry_rectangle_t *search_rect,
1477 : bool horizontal_line,
1478 : double min_gap,
1479 : double *io_coordinate )
1480 : {
1481 0 : U8_TRACE_BEGIN();
1482 0 : assert( (*this_).sorted_rel_index < universal_array_index_sorter_get_count( &((*this_).sorted_relationships) ) );
1483 0 : assert ( NULL != search_rect );
1484 0 : assert ( NULL != io_coordinate );
1485 0 : u8_error_t err = U8_ERROR_NONE;
1486 :
1487 : /* start two probes at the center and move these to the boundaries when discovering overlaps */
1488 0 : const double center = *io_coordinate;
1489 0 : if ( horizontal_line )
1490 : {
1491 0 : assert( center > geometry_rectangle_get_top( search_rect ) - 0.000000001 );
1492 0 : assert( center < geometry_rectangle_get_bottom( search_rect ) + 0.000000001 );
1493 : }
1494 : else
1495 : {
1496 0 : assert( center > geometry_rectangle_get_left( search_rect ) - 0.000000001 );
1497 0 : assert( center < geometry_rectangle_get_right( search_rect ) + 0.000000001 );
1498 : }
1499 0 : double good_smaller = center; /* a coordinate top/left of major obstacles */
1500 0 : double good_greater = center; /* a coordinate bottom/right of major obstacles */
1501 0 : double best_smaller = center; /* a coordinate top/left of any obstacle */
1502 0 : double best_greater = center; /* a coordinate bottom/right of any obstacle */
1503 :
1504 : /* the rectangle where each classifier within is checked for intersections: */
1505 : geometry_rectangle_t consider_rect;
1506 0 : geometry_rectangle_copy( &consider_rect, search_rect );
1507 0 : if ( horizontal_line )
1508 : {
1509 0 : geometry_rectangle_set_top( &consider_rect, geometry_rectangle_get_top( search_rect ) - min_gap );
1510 0 : geometry_rectangle_set_height( &consider_rect, geometry_rectangle_get_height( search_rect ) + 2.0 * min_gap );
1511 :
1512 : }
1513 : else
1514 : {
1515 0 : geometry_rectangle_set_left( &consider_rect, geometry_rectangle_get_left( search_rect ) - min_gap );
1516 0 : geometry_rectangle_set_width( &consider_rect, geometry_rectangle_get_width( search_rect ) + 2.0 * min_gap );
1517 : }
1518 0 : const double minimum_result
1519 : = horizontal_line
1520 0 : ? geometry_rectangle_get_top( search_rect )
1521 0 : : geometry_rectangle_get_left( search_rect );
1522 0 : const double maximum_result
1523 : = horizontal_line
1524 0 : ? geometry_rectangle_get_bottom( search_rect )
1525 0 : : geometry_rectangle_get_right( search_rect );
1526 :
1527 : /* iterate till no hit anymore */
1528 0 : const uint32_t max_list_iteration = 8; /* in any case, do not iterate ofer the list more than 8 times */
1529 0 : bool hit = true; /* whenever the probes hit a rectangle, hit is set to true */
1530 0 : for ( uint32_t list_iteration = 0; (list_iteration < max_list_iteration) && hit; list_iteration ++ )
1531 : {
1532 0 : hit = false;
1533 :
1534 : /* move away from classifiers */
1535 0 : const uint32_t count_classifiers = layout_visible_set_get_visible_classifier_count ( (*this_).layout_data );
1536 0 : for ( uint32_t classifier_index = 0; classifier_index < count_classifiers; classifier_index ++ )
1537 : {
1538 : const layout_visible_classifier_t *const the_classifier
1539 0 : = layout_visible_set_get_visible_classifier_ptr( (*this_).layout_data, classifier_index );
1540 :
1541 : const geometry_rectangle_t *const classifier_symbol_box
1542 0 : = layout_visible_classifier_get_symbol_box_const( the_classifier );
1543 : const geometry_rectangle_t *const classifier_space
1544 0 : = layout_visible_classifier_get_space_const( the_classifier );
1545 : /* Note: This algorithm ignores if the current classifier is parent container of source or destination */
1546 0 : if ( geometry_rectangle_is_intersecting( &consider_rect, classifier_symbol_box ) )
1547 : {
1548 0 : const double clas_symbol_box_smaller
1549 : = horizontal_line /* do vertical search if line is horizontal */
1550 0 : ? ( geometry_rectangle_get_top(classifier_symbol_box) - min_gap )
1551 0 : : ( geometry_rectangle_get_left(classifier_symbol_box) - min_gap );
1552 0 : const double clas_symbol_box_greater
1553 : = horizontal_line /* do vertical search if line is horizontal */
1554 0 : ? ( geometry_rectangle_get_bottom(classifier_symbol_box) + min_gap )
1555 0 : : ( geometry_rectangle_get_right(classifier_symbol_box) + min_gap );
1556 :
1557 0 : const double undo_good_smaller = good_smaller;
1558 0 : const double undo_good_greater = good_greater;
1559 0 : const bool undo_hit = hit;
1560 0 : const geometry_rectangle_t good_smaller_rect
1561 0 : = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : good_smaller,
1562 0 : .top = horizontal_line ? good_smaller : geometry_rectangle_get_top( search_rect ),
1563 0 : .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
1564 0 : .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
1565 : };
1566 0 : if ( ( ! geometry_rectangle_is_containing( classifier_space, &good_smaller_rect ) )
1567 0 : && ( clas_symbol_box_smaller < good_smaller ) && ( good_smaller < clas_symbol_box_greater ) )
1568 : {
1569 0 : good_smaller = clas_symbol_box_smaller;
1570 0 : hit = true;
1571 : }
1572 0 : const geometry_rectangle_t good_greater_rect
1573 0 : = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : good_greater,
1574 0 : .top = horizontal_line ? good_greater : geometry_rectangle_get_top( search_rect ),
1575 0 : .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
1576 0 : .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
1577 : };
1578 0 : if ( ( ! geometry_rectangle_is_containing( classifier_space, &good_greater_rect ) )
1579 0 : && ( clas_symbol_box_smaller < good_greater ) && ( good_greater < clas_symbol_box_greater ) )
1580 : {
1581 0 : good_greater = clas_symbol_box_greater;
1582 0 : hit = true;
1583 : }
1584 0 : const bool no_solution_remaining
1585 0 : = ( good_smaller < minimum_result )&&( good_greater > maximum_result );
1586 0 : if ( no_solution_remaining )
1587 : {
1588 : /* restore old values */
1589 0 : good_smaller = undo_good_smaller;
1590 0 : good_greater = undo_good_greater;
1591 0 : hit = undo_hit;
1592 : }
1593 0 : const geometry_rectangle_t best_smaller_rect
1594 0 : = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : best_smaller,
1595 0 : .top = horizontal_line ? best_smaller : geometry_rectangle_get_top( search_rect ),
1596 0 : .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
1597 0 : .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
1598 : };
1599 0 : if ( ( ! geometry_rectangle_is_containing( classifier_space, &best_smaller_rect ) )
1600 0 : && ( clas_symbol_box_smaller < best_smaller ) && ( best_smaller < clas_symbol_box_greater ) )
1601 : {
1602 0 : best_smaller = clas_symbol_box_smaller;
1603 0 : hit = true;
1604 : }
1605 0 : const geometry_rectangle_t best_greater_rect
1606 0 : = { .left = horizontal_line ? geometry_rectangle_get_left( search_rect ) : best_greater,
1607 0 : .top = horizontal_line ? best_greater : geometry_rectangle_get_top( search_rect ),
1608 0 : .width = horizontal_line ? geometry_rectangle_get_width( search_rect ) : 0.0,
1609 0 : .height = horizontal_line ? 0.0 : geometry_rectangle_get_height( search_rect )
1610 : };
1611 0 : if ( ( ! geometry_rectangle_is_containing( classifier_space, &best_greater_rect ) )
1612 0 : && ( clas_symbol_box_smaller < best_greater ) && ( best_greater < clas_symbol_box_greater ) )
1613 : {
1614 0 : best_greater = clas_symbol_box_greater;
1615 0 : hit = true;
1616 : }
1617 : }
1618 :
1619 : const geometry_rectangle_t *const classifier_label_box
1620 0 : = layout_visible_classifier_get_label_box_const( the_classifier );
1621 0 : if ( geometry_rectangle_is_intersecting( &consider_rect, classifier_label_box ) )
1622 : {
1623 0 : const double clas_label_smaller
1624 : = horizontal_line /* do vertical search if line is horizontal */
1625 0 : ? ( geometry_rectangle_get_top(classifier_label_box) - min_gap )
1626 0 : : ( geometry_rectangle_get_left(classifier_label_box) - min_gap );
1627 0 : const double clas_label_greater
1628 : = horizontal_line /* do vertical search if line is horizontal */
1629 0 : ? ( geometry_rectangle_get_bottom(classifier_label_box) + min_gap )
1630 0 : : ( geometry_rectangle_get_right(classifier_label_box) + min_gap );
1631 :
1632 0 : if ( ( clas_label_smaller < good_smaller ) && ( good_smaller < clas_label_greater ) )
1633 : {
1634 0 : good_smaller = clas_label_smaller;
1635 0 : hit = true;
1636 : }
1637 0 : if ( ( clas_label_smaller < good_greater ) && ( good_greater < clas_label_greater ) )
1638 : {
1639 0 : good_greater = clas_label_greater;
1640 0 : hit = true;
1641 : }
1642 0 : if ( ( clas_label_smaller < best_smaller ) && ( best_smaller < clas_label_greater ) )
1643 : {
1644 0 : best_smaller = clas_label_smaller;
1645 0 : hit = true;
1646 : }
1647 0 : if ( ( clas_label_smaller < best_greater ) && ( best_greater < clas_label_greater ) )
1648 : {
1649 0 : best_greater = clas_label_greater;
1650 0 : hit = true;
1651 : }
1652 : }
1653 : }
1654 :
1655 : /* move away from features, check symbol boxes only, label boxes are not yet initialized */
1656 0 : const uint32_t count_features = layout_visible_set_get_feature_count ( (*this_).layout_data );
1657 0 : for ( uint32_t f_idx = 0; f_idx < count_features; f_idx ++ )
1658 : {
1659 : const layout_feature_t *const feature_layout
1660 0 : = layout_visible_set_get_feature_ptr ( (*this_).layout_data, f_idx );
1661 :
1662 : const geometry_rectangle_t *const feature_symbol_box
1663 0 : = layout_feature_get_symbol_box_const( feature_layout );
1664 0 : if ( geometry_rectangle_is_intersecting( &consider_rect, feature_symbol_box ) )
1665 : {
1666 0 : const double feature_smaller
1667 : = horizontal_line /* do vertical search if line is horizontal */
1668 0 : ? ( geometry_rectangle_get_top(feature_symbol_box) - min_gap )
1669 0 : : ( geometry_rectangle_get_left(feature_symbol_box) - min_gap );
1670 0 : const double feature_greater
1671 : = horizontal_line /* do vertical search if line is horizontal */
1672 0 : ? ( geometry_rectangle_get_bottom(feature_symbol_box) + min_gap )
1673 0 : : ( geometry_rectangle_get_right(feature_symbol_box) + min_gap );
1674 :
1675 0 : if ( ( feature_smaller < good_smaller ) && ( good_smaller < feature_greater ) )
1676 : {
1677 0 : good_smaller = feature_smaller;
1678 0 : hit = true;
1679 : }
1680 0 : if ( ( feature_smaller < good_greater ) && ( good_greater < feature_greater ) )
1681 : {
1682 0 : good_greater = feature_greater;
1683 0 : hit = true;
1684 : }
1685 0 : if ( ( feature_smaller < best_smaller ) && ( best_smaller < feature_greater ) )
1686 : {
1687 0 : best_smaller = feature_smaller;
1688 0 : hit = true;
1689 : }
1690 0 : if ( ( feature_smaller < best_greater ) && ( best_greater < feature_greater ) )
1691 : {
1692 0 : best_greater = feature_greater;
1693 0 : hit = true;
1694 : }
1695 : }
1696 : }
1697 :
1698 : /* move away from already layed-out parallel relationship-segments; */
1699 : /* already done: exist_sort_index < (*this_).sorted_rel_index */
1700 0 : for ( uint32_t exist_sort_index = 0; ( exist_sort_index < (*this_).sorted_rel_index ); exist_sort_index ++ )
1701 : {
1702 : const uint32_t exist_index
1703 0 : = universal_array_index_sorter_get_array_index( &((*this_).sorted_relationships), exist_sort_index );
1704 : const layout_relationship_t *const exist_relationship
1705 0 : = layout_visible_set_get_relationship_ptr( (*this_).layout_data, exist_index );
1706 : /* Note: This algorithm ignores the relationship types (same_type), sources and destinations (one_same_end) */
1707 :
1708 0 : const geometry_connector_t *const exist_shape = layout_relationship_get_shape_const( exist_relationship );
1709 0 : if ( geometry_connector_is_intersecting_rectangle( exist_shape, &consider_rect ) )
1710 : {
1711 : const geometry_rectangle_t seg_1
1712 0 : = geometry_connector_get_segment_bounds( exist_shape, GEOMETRY_CONNECTOR_SEGMENT_SOURCE );
1713 : const bool seg_1_is_intersecting
1714 0 : = geometry_rectangle_is_intersecting( &seg_1, &consider_rect );
1715 0 : const double seg_1_smaller
1716 : = horizontal_line /* do vertical search if line is horizontal */
1717 0 : ? ( geometry_rectangle_get_top( &seg_1 ) - min_gap )
1718 0 : : ( geometry_rectangle_get_left( &seg_1 ) - min_gap );
1719 0 : const double seg_1_greater
1720 : = horizontal_line /* do vertical search if line is horizontal */
1721 0 : ? ( geometry_rectangle_get_bottom( &seg_1 ) + min_gap )
1722 0 : : ( geometry_rectangle_get_right( &seg_1 ) + min_gap );
1723 0 : if ( seg_1_is_intersecting
1724 0 : && ( seg_1_smaller < best_smaller ) && ( best_smaller < seg_1_greater ) )
1725 : {
1726 0 : best_smaller = seg_1_smaller;
1727 0 : hit = true;
1728 : }
1729 0 : if ( seg_1_is_intersecting
1730 0 : && ( seg_1_smaller < best_greater ) && ( best_greater < seg_1_greater ) )
1731 : {
1732 0 : best_greater = seg_1_greater;
1733 0 : hit = true;
1734 : }
1735 : const geometry_rectangle_t seg_2
1736 0 : = geometry_connector_get_segment_bounds( exist_shape, GEOMETRY_CONNECTOR_SEGMENT_MAIN );
1737 : const bool seg_2_is_intersecting
1738 0 : = geometry_rectangle_is_intersecting( &seg_2, &consider_rect );
1739 0 : const double seg_2_smaller
1740 : = horizontal_line /* do vertical search if line is horizontal */
1741 0 : ? ( geometry_rectangle_get_top( &seg_2 ) - min_gap )
1742 0 : : ( geometry_rectangle_get_left( &seg_2 ) - min_gap );
1743 0 : const double seg_2_greater
1744 : = horizontal_line /* do vertical search if line is horizontal */
1745 0 : ? ( geometry_rectangle_get_bottom( &seg_2 ) + min_gap )
1746 0 : : ( geometry_rectangle_get_right( &seg_2 ) + min_gap );
1747 0 : if ( seg_2_is_intersecting
1748 0 : && ( seg_2_smaller < best_smaller ) && ( best_smaller < seg_2_greater ) )
1749 : {
1750 0 : best_smaller = seg_2_smaller;
1751 0 : hit = true;
1752 : }
1753 0 : if ( seg_2_is_intersecting
1754 0 : && ( seg_2_smaller < best_greater ) && ( best_greater < seg_2_greater ) )
1755 : {
1756 0 : best_greater = seg_2_greater;
1757 0 : hit = true;
1758 : }
1759 : const geometry_rectangle_t seg_3
1760 0 : = geometry_connector_get_segment_bounds( exist_shape, GEOMETRY_CONNECTOR_SEGMENT_DESTINATION );
1761 : const bool seg_3_is_intersecting
1762 0 : = geometry_rectangle_is_intersecting( &seg_3, &consider_rect );
1763 0 : const double seg_3_smaller
1764 : = horizontal_line /* do vertical search if line is horizontal */
1765 0 : ? ( geometry_rectangle_get_top( &seg_3 ) - min_gap )
1766 0 : : ( geometry_rectangle_get_left( &seg_3 ) - min_gap );
1767 0 : const double seg_3_greater
1768 : = horizontal_line /* do vertical search if line is horizontal */
1769 0 : ? ( geometry_rectangle_get_bottom( &seg_3 ) + min_gap )
1770 0 : : ( geometry_rectangle_get_right( &seg_3 ) + min_gap );
1771 0 : if ( seg_3_is_intersecting
1772 0 : && ( seg_3_smaller < best_smaller ) && ( best_smaller < seg_3_greater ) )
1773 : {
1774 0 : best_smaller = seg_3_smaller;
1775 0 : hit = true;
1776 : }
1777 0 : if ( seg_3_is_intersecting
1778 0 : && ( seg_3_smaller < best_greater ) && ( best_greater < seg_3_greater ) )
1779 : {
1780 0 : best_greater = seg_3_greater;
1781 0 : hit = true;
1782 : }
1783 :
1784 0 : const geometry_3dir_t exist_dirs = geometry_connector_get_directions( exist_shape );
1785 0 : if ( horizontal_line )
1786 : {
1787 0 : const double exist_source_y = geometry_connector_get_main_line_source_y ( exist_shape );
1788 0 : const double exist_destination_y = geometry_connector_get_main_line_destination_y ( exist_shape );
1789 0 : if ( geometry_3dir_is_first_h( &exist_dirs ) || geometry_3dir_is_second_h( &exist_dirs ) )
1790 : {
1791 0 : if (( exist_source_y - min_gap < good_smaller )&&( good_smaller < exist_source_y + min_gap ))
1792 : {
1793 0 : good_smaller = exist_source_y - min_gap;
1794 0 : hit = true;
1795 : }
1796 0 : if (( exist_source_y - min_gap < good_greater )&&( good_greater < exist_source_y + min_gap ))
1797 : {
1798 0 : good_greater = exist_source_y + min_gap;
1799 0 : hit = true;
1800 : }
1801 : }
1802 0 : if ( geometry_3dir_is_third_h( &exist_dirs ) ) /* third segment only, second is already evaluated above */
1803 : {
1804 0 : if (( exist_destination_y - min_gap < good_smaller )&&( good_smaller < exist_destination_y + min_gap ))
1805 : {
1806 0 : good_smaller = exist_destination_y - min_gap;
1807 0 : hit = true;
1808 : }
1809 0 : if (( exist_destination_y - min_gap < good_greater )&&( good_greater < exist_destination_y + min_gap ))
1810 : {
1811 0 : good_greater = exist_destination_y + min_gap;
1812 0 : hit = true;
1813 : }
1814 : }
1815 : }
1816 : else
1817 : {
1818 0 : const double exist_source_x = geometry_connector_get_main_line_source_x ( exist_shape );
1819 0 : const double exist_destination_x = geometry_connector_get_main_line_destination_x ( exist_shape );
1820 0 : if ( geometry_3dir_is_first_v( &exist_dirs ) || geometry_3dir_is_second_v( &exist_dirs ) )
1821 : {
1822 0 : if (( exist_source_x - min_gap < good_smaller )&&( good_smaller < exist_source_x + min_gap ))
1823 : {
1824 0 : good_smaller = exist_source_x - min_gap;
1825 0 : hit = true;
1826 : }
1827 0 : if (( exist_source_x - min_gap < good_greater )&&( good_greater < exist_source_x + min_gap ))
1828 : {
1829 0 : good_greater = exist_source_x + min_gap;
1830 0 : hit = true;
1831 : }
1832 : }
1833 0 : if ( geometry_3dir_is_third_v( &exist_dirs ) ) /* third segment only, second is already evaluated above */
1834 : {
1835 0 : if (( exist_destination_x - min_gap < good_smaller )&&( good_smaller < exist_destination_x + min_gap ))
1836 : {
1837 0 : good_smaller = exist_destination_x - min_gap;
1838 0 : hit = true;
1839 : }
1840 0 : if (( exist_destination_x - min_gap < good_greater )&&( good_greater < exist_destination_x + min_gap ))
1841 : {
1842 0 : good_greater = exist_destination_x + min_gap;
1843 0 : hit = true;
1844 : }
1845 : }
1846 : }
1847 : }
1848 : }
1849 : }
1850 :
1851 : /* check success */
1852 0 : if ( best_greater < maximum_result )
1853 : {
1854 0 : if ( best_smaller > minimum_result )
1855 : {
1856 : /* best_greater and best_smaller are both in range; */
1857 : /* select the one with smaller distance to the center: */
1858 0 : if ( best_greater - center > center - best_smaller )
1859 : {
1860 0 : *io_coordinate = best_smaller;
1861 : }
1862 : else
1863 : {
1864 0 : *io_coordinate = best_greater;
1865 : }
1866 : }
1867 : else /* best_greater is in range */
1868 : {
1869 0 : *io_coordinate = best_greater;
1870 : }
1871 : }
1872 : else
1873 : {
1874 0 : if ( best_smaller > minimum_result )
1875 : {
1876 : /* best_smaller is in range */
1877 0 : *io_coordinate = best_smaller;
1878 : }
1879 : else
1880 : {
1881 : /* BOTH BEST VALUES ARE OUT OF RANGE */
1882 : /* CHECK GOOD VALUES: */
1883 0 : if ( good_greater > maximum_result )
1884 : {
1885 0 : if ( good_smaller < minimum_result )
1886 : {
1887 0 : err = U8_ERROR_NOT_FOUND;
1888 : }
1889 : else /* good_smaller is in range */
1890 : {
1891 0 : *io_coordinate = good_smaller;
1892 : }
1893 : }
1894 : else /* good_greater is in range */
1895 : {
1896 0 : if ( good_smaller < minimum_result )
1897 : {
1898 0 : *io_coordinate = good_greater;
1899 : }
1900 : else
1901 : {
1902 : /* good_smaller and good_greater are both in range; */
1903 : /* select the one with smaller distance to the center: */
1904 0 : if ( good_greater - center > center - good_smaller )
1905 : {
1906 0 : *io_coordinate = good_smaller;
1907 : }
1908 : else
1909 : {
1910 0 : *io_coordinate = good_greater;
1911 : }
1912 : }
1913 : }
1914 : }
1915 : }
1916 :
1917 0 : geometry_rectangle_destroy( &consider_rect );
1918 :
1919 0 : U8_TRACE_END_ERR(err);
1920 0 : return err;
1921 : }
1922 :
1923 0 : void pencil_relationship_2d_layouter_private_make_all_visible ( pencil_relationship_2d_layouter_t *this_ )
1924 : {
1925 0 : U8_TRACE_BEGIN();
1926 :
1927 : /* determine visibility */
1928 0 : const uint32_t count_relations = layout_visible_set_get_relationship_count ( (*this_).layout_data );
1929 0 : for ( uint32_t index = 0; index < count_relations; index ++ )
1930 : {
1931 0 : layout_relationship_t *const the_relation = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
1932 0 : const layout_visible_classifier_t *const from_layout = layout_relationship_get_from_classifier_ptr ( the_relation );
1933 0 : const layout_visible_classifier_t *const to_layout = layout_relationship_get_to_classifier_ptr ( the_relation );
1934 0 : assert( from_layout != NULL );
1935 0 : assert( to_layout != NULL );
1936 0 : const data_visible_classifier_t *const from_data = layout_visible_classifier_get_data_const( from_layout );
1937 0 : const data_visible_classifier_t *const to_data = layout_visible_classifier_get_data_const( to_layout );
1938 0 : const data_diagramelement_t *const from_diagele = data_visible_classifier_get_diagramelement_const( from_data );
1939 0 : const data_diagramelement_t *const to_diagele = data_visible_classifier_get_diagramelement_const( to_data );
1940 0 : const data_diagramelement_flag_t from_flags = data_diagramelement_get_display_flags ( from_diagele );
1941 0 : const data_diagramelement_flag_t to_flags = data_diagramelement_get_display_flags ( to_diagele );
1942 0 : if (( 0 != ( DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT & from_flags ))
1943 0 : || ( 0 != ( DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT & to_flags )))
1944 : {
1945 0 : layout_relationship_set_visibility ( the_relation, PENCIL_VISIBILITY_GRAY_OUT );
1946 : }
1947 : else
1948 : {
1949 0 : layout_relationship_set_visibility ( the_relation, PENCIL_VISIBILITY_SHOW );
1950 : }
1951 : }
1952 :
1953 0 : U8_TRACE_END();
1954 0 : }
1955 :
1956 0 : void pencil_relationship_2d_layouter_layout_standard( pencil_relationship_2d_layouter_t *this_ )
1957 : {
1958 0 : U8_TRACE_BEGIN();
1959 :
1960 0 : pencil_relationship_2d_layouter_private_make_all_visible( this_ );
1961 :
1962 0 : pencil_relationship_2d_layouter_private_do_layout ( this_ );
1963 :
1964 0 : U8_TRACE_END();
1965 0 : }
1966 :
1967 0 : void pencil_relationship_2d_layouter_layout_void( pencil_relationship_2d_layouter_t *this_ )
1968 : {
1969 0 : U8_TRACE_BEGIN();
1970 :
1971 : /* hide all relationships */
1972 : const uint32_t count_relations
1973 0 : = layout_visible_set_get_relationship_count ( (*this_).layout_data );
1974 0 : for ( uint32_t index = 0; index < count_relations; index ++ )
1975 : {
1976 : /*
1977 : layout_visible_set_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_HIDE );
1978 : */
1979 0 : layout_visible_set_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT );
1980 : }
1981 :
1982 : /* layout the relationships (needed for PENCIL_VISIBILITY_IMPLICIT) */
1983 0 : pencil_relationship_2d_layouter_private_do_layout ( this_ );
1984 :
1985 0 : U8_TRACE_END();
1986 0 : }
1987 :
1988 0 : void pencil_relationship_2d_layouter_layout_for_communication( pencil_relationship_2d_layouter_t *this_ )
1989 : {
1990 0 : U8_TRACE_BEGIN();
1991 :
1992 0 : pencil_relationship_2d_layouter_private_make_all_visible( this_ );
1993 :
1994 : /* hide some relationships */
1995 : const uint32_t count_relations
1996 0 : = layout_visible_set_get_relationship_count ( (*this_).layout_data );
1997 0 : for ( uint32_t index = 0; index < count_relations; index ++ )
1998 : {
1999 : layout_relationship_t *const the_relationship
2000 0 : = layout_visible_set_get_relationship_ptr ( (*this_).layout_data, index );
2001 :
2002 : /* adjust visibility */
2003 0 : if ( ( NULL == layout_relationship_get_from_feature_ptr ( the_relationship ) )
2004 0 : && ( NULL == layout_relationship_get_to_feature_ptr ( the_relationship ) ) )
2005 : {
2006 : /* this is a globally visible relation, not local/scenario-based */
2007 0 : layout_visible_set_set_relationship_visibility ( (*this_).layout_data, index, PENCIL_VISIBILITY_IMPLICIT );
2008 : }
2009 : }
2010 :
2011 : /* layout the visible relationships */
2012 0 : pencil_relationship_2d_layouter_private_do_layout ( this_ );
2013 :
2014 0 : U8_TRACE_END();
2015 0 : }
2016 :
2017 :
2018 : /*
2019 : Copyright 2017-2024 Andreas Warnke
2020 :
2021 : Licensed under the Apache License, Version 2.0 (the "License");
2022 : you may not use this file except in compliance with the License.
2023 : You may obtain a copy of the License at
2024 :
2025 : http://www.apache.org/licenses/LICENSE-2.0
2026 :
2027 : Unless required by applicable law or agreed to in writing, software
2028 : distributed under the License is distributed on an "AS IS" BASIS,
2029 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2030 : See the License for the specific language governing permissions and
2031 : limitations under the License.
2032 : */
|