Line data Source code
1 : /* File: geometry_anchor.inl; Copyright and License: see below */
2 :
3 : #include "u8/u8_trace.h"
4 : #include "u8/u8_log.h"
5 : #include "u8/u8_f64.h"
6 : #include <assert.h>
7 : #include <math.h>
8 :
9 3 : static inline void geometry_anchor_init( geometry_anchor_t *this_,
10 : double x,
11 : double y,
12 : geometry_h_align_t x_align,
13 : geometry_v_align_t y_align )
14 : {
15 3 : geometry_point_init( &((*this_).reference_point), x, y );
16 3 : (*this_).x_align = x_align;
17 3 : (*this_).y_align = y_align;
18 3 : }
19 :
20 1 : static inline void geometry_anchor_copy( geometry_anchor_t *this_, const geometry_anchor_t *original )
21 : {
22 1 : assert( NULL != original );
23 1 : (*this_) = (*original);
24 1 : }
25 :
26 1 : static inline void geometry_anchor_replace( geometry_anchor_t *this_, const geometry_anchor_t *original )
27 : {
28 1 : assert( NULL != original );
29 1 : (*this_) = (*original);
30 1 : }
31 :
32 3 : static inline void geometry_anchor_destroy( geometry_anchor_t *this_ )
33 : {
34 3 : geometry_point_destroy( &((*this_).reference_point) );
35 3 : }
36 :
37 1 : static inline double geometry_anchor_get_x( const geometry_anchor_t *this_ )
38 : {
39 1 : return geometry_point_get_x( &((*this_).reference_point) );
40 : }
41 :
42 1 : static inline double geometry_anchor_get_y( const geometry_anchor_t *this_ )
43 : {
44 1 : return geometry_point_get_y( &((*this_).reference_point) );
45 : }
46 :
47 1 : static inline geometry_h_align_t geometry_anchor_get_x_align( const geometry_anchor_t *this_ )
48 : {
49 1 : return (*this_).x_align;
50 : }
51 :
52 1 : static inline geometry_v_align_t geometry_anchor_get_y_align( const geometry_anchor_t *this_ )
53 : {
54 1 : return (*this_).y_align;
55 : }
56 :
57 1 : static inline const geometry_point_t * geometry_anchor_get_point_const( const geometry_anchor_t *this_ )
58 : {
59 1 : return &((*this_).reference_point);
60 : }
61 :
62 1 : static inline geometry_rectangle_t geometry_anchor_align_rect( const geometry_anchor_t *this_,
63 : const geometry_rectangle_t *unaligned )
64 : {
65 1 : assert( unaligned != NULL );
66 :
67 : geometry_rectangle_t result;
68 :
69 1 : const double width = geometry_rectangle_get_width( unaligned );
70 1 : const double height = geometry_rectangle_get_height( unaligned );
71 :
72 1 : const double left = geometry_h_align_get_left( &((*this_).x_align),
73 : width,
74 : geometry_point_get_x( &((*this_).reference_point) ),
75 : 0.0 /* reference_width is zero, the reference is a point */
76 : );
77 1 : const double top = geometry_v_align_get_top( &((*this_).y_align),
78 : height,
79 : geometry_point_get_y( &((*this_).reference_point) ),
80 : 0.0 /* reference_height is zero, the reference is a point */
81 : );
82 :
83 1 : geometry_rectangle_init( &result, left, top, width, height );
84 1 : return result;
85 : }
86 :
87 1 : static inline geometry_rectangle_t geometry_anchor_align_dim ( const geometry_anchor_t *this_,
88 : const geometry_dimensions_t *unaligned )
89 : {
90 1 : assert( unaligned != NULL );
91 :
92 : geometry_rectangle_t result;
93 :
94 1 : const double width = geometry_dimensions_get_width( unaligned );
95 1 : const double height = geometry_dimensions_get_height( unaligned );
96 :
97 1 : const double left = geometry_h_align_get_left( &((*this_).x_align),
98 : width,
99 : geometry_point_get_x( &((*this_).reference_point) ),
100 : 0.0 /* reference_width is zero, the reference is a point */
101 : );
102 1 : const double top = geometry_v_align_get_top( &((*this_).y_align),
103 : height,
104 : geometry_point_get_y( &((*this_).reference_point) ),
105 : 0.0 /* reference_height is zero, the reference is a point */
106 : );
107 :
108 1 : geometry_rectangle_init( &result, left, top, width, height );
109 1 : return result;
110 : }
111 :
112 8 : static inline geometry_rectangle_t geometry_anchor_align_dim_closest( const geometry_anchor_t *this_,
113 : const geometry_dimensions_t *unaligned,
114 : const geometry_rectangle_t *permitted_area )
115 : {
116 8 : assert( unaligned != NULL );
117 8 : assert( permitted_area != NULL );
118 :
119 : geometry_rectangle_t result;
120 :
121 8 : const double width = geometry_dimensions_get_width( unaligned );
122 8 : const double height = geometry_dimensions_get_height( unaligned );
123 :
124 8 : const double left = geometry_h_align_get_left( &((*this_).x_align),
125 : width,
126 : geometry_point_get_x( &((*this_).reference_point) ),
127 : 0.0 /* reference_width is zero, the reference is a point */
128 : );
129 8 : const double top = geometry_v_align_get_top( &((*this_).y_align),
130 : height,
131 : geometry_point_get_y( &((*this_).reference_point) ),
132 : 0.0 /* reference_height is zero, the reference is a point */
133 : );
134 :
135 : /* force the result into permitted_area */
136 8 : const double right = left + width;
137 8 : const double bottom = top + height;
138 8 : const double permitted_left = geometry_rectangle_get_left( permitted_area );
139 8 : const double permitted_top = geometry_rectangle_get_top( permitted_area );
140 8 : const double permitted_right = geometry_rectangle_get_right( permitted_area );
141 8 : const double permitted_bottom = geometry_rectangle_get_bottom( permitted_area );
142 8 : double new_left = left;
143 8 : double new_top = top;
144 8 : if ( left < permitted_left )
145 : {
146 3 : if ( right > permitted_right )
147 : {
148 0 : U8_TRACE_INFO( "geometry_anchor_align_dim_closest cannot fit dim-x into permitted_area" );
149 : }
150 : else
151 : {
152 : /* move the unaligned area either till right side is at limit or till left side is fitting */
153 3 : new_left = u8_f64_min2( permitted_right - width, permitted_left );
154 : }
155 : }
156 : else
157 : {
158 5 : if ( right > permitted_right )
159 : {
160 : /* move the unaligned area either till left side is at limit or till right side is fitting */
161 3 : new_left = u8_f64_max2( permitted_right - width, permitted_left );
162 : }
163 : else
164 : {
165 : /* rectangle is fitting, no move */
166 : }
167 : }
168 8 : if ( top < permitted_top )
169 : {
170 4 : if ( bottom > permitted_bottom )
171 : {
172 0 : U8_TRACE_INFO( "geometry_anchor_align_dim_closest cannot fit dim-y into permitted_area" );
173 : }
174 : else
175 : {
176 : /* move the unaligned area either till bottom side is at limit or till top side is fitting */
177 4 : new_top = u8_f64_min2( permitted_bottom - height, permitted_top );
178 : }
179 : }
180 : else
181 : {
182 4 : if ( bottom > permitted_bottom )
183 : {
184 : /* move the unaligned area either till top side is at limit or till bottom side is fitting */
185 3 : new_top = u8_f64_max2( permitted_bottom - height, permitted_top );
186 : }
187 : else
188 : {
189 : /* rectangle is fitting, no move */
190 : }
191 : }
192 :
193 : #if 0
194 : /* in case of center, allow small moves */
195 : if ( (*this_).x_align == GEOMETRY_H_ALIGN_CENTER )
196 : {
197 : /* if left/top position exceeds preferred_location, then move */
198 : const double min_x = geometry_rectangle_get_left( preferred_location );
199 : const double max_x = geometry_rectangle_get_right( preferred_location );
200 : const double max_width = geometry_rectangle_get_width( preferred_location );
201 : if ( left < min_x )
202 : {
203 : if ( width <= max_width )
204 : {
205 : /* left/top position is too far left, but can fit if moved */
206 : left = min_x;
207 : }
208 : else
209 : {
210 : /* unaligned does not fit to preferred_location, simply center the result */
211 : left = geometry_rectangle_get_center_x( preferred_location ) - 0.5 * width;
212 : }
213 : }
214 : else if ( left + width > max_x )
215 : {
216 : if ( width <= max_width )
217 : {
218 : /* left/top position is too far left, but can fit if moved */
219 : left = max_x - width;
220 : }
221 : else
222 : {
223 : /* unaligned does not fit to preferred_location, simply center the result */
224 : left = geometry_rectangle_get_center_x( preferred_location ) - 0.5 * width;
225 : }
226 : }
227 : /* if result moved too far, pull it back to anchor */
228 : const double reference_x = geometry_point_get_x( &((*this_).reference_point) );
229 : if ( left + width < reference_x )
230 : {
231 : left = reference_x - width;
232 : }
233 : if ( left > reference_x )
234 : {
235 : left = reference_x;
236 : }
237 : }
238 : if ( (*this_).y_align == GEOMETRY_V_ALIGN_CENTER )
239 : {
240 : /* if left/top position exceeds preferred_location, then move */
241 : const double min_y = geometry_rectangle_get_top( preferred_location );
242 : const double max_y = geometry_rectangle_get_bottom( preferred_location );
243 : const double max_height = geometry_rectangle_get_height( preferred_location );
244 : if ( top < min_y )
245 : {
246 : if ( height <= max_height )
247 : {
248 : /* left/top position is too far left, but can fit if moved */
249 : top = min_y;
250 : }
251 : else
252 : {
253 : /* unaligned does not fit to preferred_location, simply center the result */
254 : top = geometry_rectangle_get_center_y( preferred_location ) - 0.5 * height;
255 : }
256 : }
257 : else if ( top + height > max_y )
258 : {
259 : if ( height <= max_height )
260 : {
261 : /* left/top position is too far left, but can fit if moved */
262 : top = max_y - height;
263 : }
264 : else
265 : {
266 : /* unaligned does not fit to preferred_location, simply center the result */
267 : top = geometry_rectangle_get_center_y( preferred_location ) - 0.5 * height;
268 : }
269 : }
270 : /* if result moved too far, pull it back to anchor */
271 : const double reference_y = geometry_point_get_y( &((*this_).reference_point) );
272 : if ( top + height < reference_y )
273 : {
274 : top = reference_y - height;
275 : }
276 : if ( top > reference_y )
277 : {
278 : top = reference_y;
279 : }
280 : }
281 : #endif
282 :
283 8 : geometry_rectangle_init( &result, new_left, new_top, width, height );
284 8 : return result;
285 : }
286 :
287 1 : static inline void geometry_anchor_trace( const geometry_anchor_t *this_ )
288 : {
289 1 : U8_TRACE_INFO( "geometry_anchor_t" );
290 1 : U8_TRACE_INFO_INT( "- x:", geometry_point_get_x( &((*this_).reference_point) ) );
291 1 : U8_TRACE_INFO_INT( "- y:", geometry_point_get_y( &((*this_).reference_point) ) );
292 1 : U8_TRACE_INFO_INT( "- x_align:", (*this_).x_align );
293 1 : U8_TRACE_INFO_INT( "- y_align:", (*this_).y_align );
294 1 : }
295 :
296 :
297 : /*
298 : Copyright 2021-2026 Andreas Warnke
299 :
300 : Licensed under the Apache License, Version 2.0 (the "License");
301 : you may not use this file except in compliance with the License.
302 : You may obtain a copy of the License at
303 :
304 : http://www.apache.org/licenses/LICENSE-2.0
305 :
306 : Unless required by applicable law or agreed to in writing, software
307 : distributed under the License is distributed on an "AS IS" BASIS,
308 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
309 : See the License for the specific language governing permissions and
310 : limitations under the License.
311 : */
|