source: mainline/uspace/lib/gfx/src/coord.c

Last change on this file was 266ec54, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Viewer fullsreen mode

Fullscreen window placement is more of a stopgap. Proper
solution would probably be via maximizing the window.

  • Property mode set to 100644
File size: 9.2 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libgfx
30 * @{
31 */
32/**
33 * @file Coordinates
34 */
35
36#include <gfx/coord.h>
37#include <macros.h>
38#include <stdbool.h>
39#include <stddef.h>
40
41/** Divide @a a by @a b and round towards negative numbers.
42 *
43 * Regular integer division always rounds towards zero. This is not useful
44 * e.g. for scaling down, where we always need to round towards negative
45 * numbers.
46 *
47 * @param a Dividend
48 * @param b Divisor
49 * @return Quotient
50 */
51gfx_coord_t gfx_coord_div_rneg(gfx_coord_t a, gfx_coord_t b)
52{
53 if ((a > 0 && b > 0) || (a < 0 && b < 0)) {
54 /* Result is non-negative, round towards zero */
55 return a / b;
56 } else {
57 /* Result is negative, round away from zero */
58 return (a - b + 1) / b;
59 }
60}
61
62/** Add two vectors.
63 *
64 * @param a First vector
65 * @param b Second vector
66 * @param d Destination
67 */
68void gfx_coord2_add(gfx_coord2_t *a, gfx_coord2_t *b, gfx_coord2_t *d)
69{
70 d->x = a->x + b->x;
71 d->y = a->y + b->y;
72}
73
74/** Subtract two vectors.
75 *
76 * @param a First vector
77 * @param b Second vector
78 * @param d Destination
79 */
80void gfx_coord2_subtract(gfx_coord2_t *a, gfx_coord2_t *b, gfx_coord2_t *d)
81{
82 d->x = a->x - b->x;
83 d->y = a->y - b->y;
84}
85
86/** Clip point coordinates to be within a rectangle.
87 *
88 * @param a Pixel coordinates
89 * @param clip Clipping rectangle
90 * @param d Place to store clipped coordinates
91 */
92void gfx_coord2_clip(gfx_coord2_t *a, gfx_rect_t *clip, gfx_coord2_t *d)
93{
94 gfx_rect_t sclip;
95 gfx_coord2_t t;
96
97 gfx_rect_points_sort(clip, &sclip);
98
99 t.x = min(a->x, clip->p1.x - 1);
100 t.y = min(a->y, clip->p1.y - 1);
101
102 d->x = max(clip->p0.x, t.x);
103 d->y = max(clip->p0.y, t.y);
104}
105
106/** Transform coordinates via rectangle to rectangle projection.
107 *
108 * Transform pixel coordinate via a projection that maps one rectangle
109 * onto another rectangle. The source rectangle must have both dimensions
110 * greater than one.
111 *
112 * @param a Pixel coordinates
113 * @param srect Source rectangle
114 * @param drect Destination rectangle
115 * @param d Place to store resulting coordinates.
116 */
117void gfx_coord2_project(gfx_coord2_t *a, gfx_rect_t *srect, gfx_rect_t *drect,
118 gfx_coord2_t *d)
119{
120 gfx_rect_t sr;
121 gfx_rect_t dr;
122
123 gfx_rect_points_sort(srect, &sr);
124 gfx_rect_points_sort(drect, &dr);
125
126 d->x = dr.p0.x + (a->x - sr.p0.x) * (dr.p1.x - dr.p0.x - 1) /
127 (sr.p1.x - sr.p0.x - 1);
128 d->y = dr.p0.y + (a->y - sr.p0.y) * (dr.p1.y - dr.p0.y - 1) /
129 (sr.p1.y - sr.p0.y - 1);
130}
131
132/** Sort points of a span.
133 *
134 * Sort the begin and end points so that the begin point has the lower
135 * coordinate (i.e. if needed, the span is transposed, if not, it is simply
136 * copied).
137 *
138 * @param s0 Source span start point
139 * @param s1 Source span end point
140 * @param d0 Destination span start point
141 * @param d1 Destination span end point
142 */
143void gfx_span_points_sort(gfx_coord_t s0, gfx_coord_t s1, gfx_coord_t *d0,
144 gfx_coord_t *d1)
145{
146 if (s0 <= s1) {
147 *d0 = s0;
148 *d1 = s1;
149 } else {
150 *d0 = s1 + 1;
151 *d1 = s0 + 1;
152 }
153}
154
155/** Move (translate) rectangle.
156 *
157 * @param trans Translation offset
158 * @param src Source rectangle
159 * @param dest Destination rectangle
160 */
161void gfx_rect_translate(gfx_coord2_t *trans, gfx_rect_t *src, gfx_rect_t *dest)
162{
163 gfx_coord2_add(&src->p0, trans, &dest->p0);
164 gfx_coord2_add(&src->p1, trans, &dest->p1);
165}
166
167/** Reverse move (translate) rectangle.
168 *
169 * @param trans Translation offset
170 * @param src Source rectangle
171 * @param dest Destination rectangle
172 */
173void gfx_rect_rtranslate(gfx_coord2_t *trans, gfx_rect_t *src, gfx_rect_t *dest)
174{
175 gfx_coord2_subtract(&src->p0, trans, &dest->p0);
176 gfx_coord2_subtract(&src->p1, trans, &dest->p1);
177}
178
179/** Compute envelope of two rectangles.
180 *
181 * Envelope is the minimal rectangle covering all pixels of both rectangles.
182 *
183 * @param a First rectangle
184 * @param b Second rectangle
185 * @param dest Place to store enveloping rectangle
186 */
187void gfx_rect_envelope(gfx_rect_t *a, gfx_rect_t *b, gfx_rect_t *dest)
188{
189 gfx_rect_t sa, sb;
190
191 if (gfx_rect_is_empty(a)) {
192 *dest = *b;
193 return;
194 }
195
196 if (gfx_rect_is_empty(b)) {
197 *dest = *a;
198 return;
199 }
200
201 /* a and b are both non-empty */
202
203 gfx_rect_points_sort(a, &sa);
204 gfx_rect_points_sort(b, &sb);
205
206 dest->p0.x = min(sa.p0.x, sb.p0.x);
207 dest->p0.y = min(sa.p0.y, sb.p0.y);
208 dest->p1.x = max(sa.p1.x, sb.p1.x);
209 dest->p1.y = max(sa.p1.y, sb.p1.y);
210}
211
212/** Compute intersection of two rectangles.
213 *
214 * If the two rectangles do not intersect, the result will be an empty
215 * rectangle (check with gfx_rect_is_empty()). The resulting rectangle
216 * is always sorted. If @a clip is NULL, no clipping is performed.
217 *
218 * @param rect Source rectangle
219 * @param clip Clipping rectangle or @c NULL
220 * @param dest Place to store clipped rectangle
221 */
222void gfx_rect_clip(gfx_rect_t *rect, gfx_rect_t *clip, gfx_rect_t *dest)
223{
224 gfx_rect_t srect, sclip;
225
226 if (clip == NULL) {
227 *dest = *rect;
228 return;
229 }
230
231 gfx_rect_points_sort(rect, &srect);
232 gfx_rect_points_sort(clip, &sclip);
233
234 dest->p0.x = min(max(srect.p0.x, sclip.p0.x), sclip.p1.x);
235 dest->p0.y = min(max(srect.p0.y, sclip.p0.y), sclip.p1.y);
236 dest->p1.x = max(sclip.p0.x, min(srect.p1.x, sclip.p1.x));
237 dest->p1.y = max(sclip.p0.y, min(srect.p1.y, sclip.p1.y));
238}
239
240/** Center rectangle on rectangle.
241 *
242 * Translate rectangle @a a so that its center coincides with the
243 * center of rectangle @a b, saving the result in @a dest.
244 *
245 * @param a Rectnagle to translate
246 * @param b Rectangle on which to center
247 * @param dest Place to store resulting rectangle
248 */
249void gfx_rect_ctr_on_rect(gfx_rect_t *a, gfx_rect_t *b, gfx_rect_t *dest)
250{
251 gfx_coord2_t adim;
252 gfx_coord2_t bdim;
253
254 gfx_rect_dims(a, &adim);
255 gfx_rect_dims(b, &bdim);
256
257 dest->p0.x = b->p0.x + bdim.x / 2 - adim.x / 2;
258 dest->p0.y = b->p0.y + bdim.y / 2 - adim.y / 2;
259
260 dest->p1.x = dest->p0.x + adim.x;
261 dest->p1.y = dest->p0.y + adim.y;
262}
263
264/** Sort points of a rectangle.
265 *
266 * Shuffle around coordinates of a rectangle so that p0.x < p1.x and
267 * p0.y < p0.y.
268 *
269 * @param src Source rectangle
270 * @param dest Destination (sorted) rectangle
271 */
272void gfx_rect_points_sort(gfx_rect_t *src, gfx_rect_t *dest)
273{
274 gfx_span_points_sort(src->p0.x, src->p1.x, &dest->p0.x, &dest->p1.x);
275 gfx_span_points_sort(src->p0.y, src->p1.y, &dest->p0.y, &dest->p1.y);
276}
277
278/** Determine if rectangle contains no pixels
279 *
280 * @param rect Rectangle
281 * @return @c true iff rectangle contains no pixels
282 */
283bool gfx_rect_is_empty(gfx_rect_t *rect)
284{
285 return rect->p0.x == rect->p1.x || rect->p0.y == rect->p1.y;
286}
287
288/** Determine if two rectangles share any pixels
289 *
290 * @param a First rectangle
291 * @param b Second rectangle
292 * @return @c true iff rectangles share any pixels
293 */
294bool gfx_rect_is_incident(gfx_rect_t *a, gfx_rect_t *b)
295{
296 gfx_rect_t r;
297
298 gfx_rect_clip(a, b, &r);
299 return !gfx_rect_is_empty(&r);
300}
301
302/** Return true if rectangle @a a is contained in rectangle @a b.
303 *
304 * @param a Inside rectangle
305 * @param b Outside rectangle
306 * @return @c true iff @a a is (non-strictly) inside @a b
307 */
308bool gfx_rect_is_inside(gfx_rect_t *a, gfx_rect_t *b)
309{
310 gfx_rect_t sa;
311 gfx_rect_t sb;
312
313 gfx_rect_points_sort(a, &sa);
314 gfx_rect_points_sort(b, &sb);
315
316 if (sa.p0.x < sb.p0.x || sa.p0.y < sb.p0.y)
317 return false;
318
319 if (sa.p1.x > sb.p1.x || sa.p1.y > sb.p1.y)
320 return false;
321
322 return true;
323}
324
325/** Get rectangle dimensions.
326 *
327 * Get a vector containing the x, y dimensions of a rectangle. These are
328 * always nonnegative.
329 *
330 * @param rect Rectangle
331 * @param dims Place to store dimensions
332 */
333void gfx_rect_dims(gfx_rect_t *rect, gfx_coord2_t *dims)
334{
335 gfx_rect_t srect;
336
337 gfx_rect_points_sort(rect, &srect);
338 gfx_coord2_subtract(&srect.p1, &srect.p0, dims);
339}
340
341/** Return true if pixel at coordinate @a coord lies within rectangle @a rect. */
342bool gfx_pix_inside_rect(gfx_coord2_t *coord, gfx_rect_t *rect)
343{
344 gfx_rect_t sr;
345
346 gfx_rect_points_sort(rect, &sr);
347
348 if (coord->x < sr.p0.x || coord->y < sr.p0.y)
349 return false;
350
351 if (coord->x >= sr.p1.x || coord->y >= sr.p1.y)
352 return false;
353
354 return true;
355}
356
357/** @}
358 */
Note: See TracBrowser for help on using the repository browser.