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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since afcf704 was afcf704, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Allow GUI direct access to window buffer

  • Property mode set to 100644
File size: 8.0 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/** Add two vectors.
42 *
43 * @param a First vector
44 * @param b Second vector
45 * @param d Destination
46 */
47void gfx_coord2_add(gfx_coord2_t *a, gfx_coord2_t *b, gfx_coord2_t *d)
48{
49 d->x = a->x + b->x;
50 d->y = a->y + b->y;
51}
52
53/** Subtract two vectors.
54 *
55 * @param a First vector
56 * @param b Second vector
57 * @param d Destination
58 */
59void gfx_coord2_subtract(gfx_coord2_t *a, gfx_coord2_t *b, gfx_coord2_t *d)
60{
61 d->x = a->x - b->x;
62 d->y = a->y - b->y;
63}
64
65/** Clip point coordinates to be within a rectangle.
66 *
67 * @param a Pixel coordinates
68 * @param clip Clipping rectangle
69 * @param d Place to store clipped coordinates
70 */
71void gfx_coord2_clip(gfx_coord2_t *a, gfx_rect_t *clip, gfx_coord2_t *d)
72{
73 gfx_rect_t sclip;
74 gfx_coord2_t t;
75
76 gfx_rect_points_sort(clip, &sclip);
77
78 t.x = min(a->x, clip->p1.x - 1);
79 t.y = min(a->y, clip->p1.y - 1);
80
81 d->x = max(clip->p0.x, t.x);
82 d->y = max(clip->p0.y, t.y);
83}
84
85/** Transform coordinates via rectangle to rectangle projection.
86 *
87 * Transform pixel coordinate via a projection that maps one rectangle
88 * onto another rectangle. The source rectangle must have both dimensions
89 * greater than one.
90 *
91 * @param a Pixel coordinates
92 * @param srect Source rectangle
93 * @param drect Destination rectangle
94 * @param d Place to store resulting coordinates.
95 */
96void gfx_coord2_project(gfx_coord2_t *a, gfx_rect_t *srect, gfx_rect_t *drect,
97 gfx_coord2_t *d)
98{
99 gfx_rect_t sr;
100 gfx_rect_t dr;
101
102 gfx_rect_points_sort(srect, &sr);
103 gfx_rect_points_sort(drect, &dr);
104
105 d->x = dr.p0.x + (a->x - sr.p0.x) * (dr.p1.x - dr.p0.x - 1) /
106 (sr.p1.x - sr.p0.x - 1);
107 d->y = dr.p0.y + (a->y - sr.p0.y) * (dr.p1.y - dr.p0.y - 1) /
108 (sr.p1.y - sr.p0.y - 1);
109}
110
111/** Sort points of a span.
112 *
113 * Sort the begin and end points so that the begin point has the lower
114 * coordinate (i.e. if needed, the span is transposed, if not, it is simply
115 * copied).
116 *
117 * @param s0 Source span start point
118 * @param s1 Source span end point
119 * @param d0 Destination span start point
120 * @param d1 Destination span end point
121 */
122void gfx_span_points_sort(gfx_coord_t s0, gfx_coord_t s1, gfx_coord_t *d0,
123 gfx_coord_t *d1)
124{
125 if (s0 <= s1) {
126 *d0 = s0;
127 *d1 = s1;
128 } else {
129 *d0 = s1 + 1;
130 *d1 = s0 + 1;
131 }
132}
133
134/** Move (translate) rectangle.
135 *
136 * @param trans Translation offset
137 * @param src Source rectangle
138 * @param dest Destination rectangle
139 */
140void gfx_rect_translate(gfx_coord2_t *trans, gfx_rect_t *src, gfx_rect_t *dest)
141{
142 gfx_coord2_add(&src->p0, trans, &dest->p0);
143 gfx_coord2_add(&src->p1, trans, &dest->p1);
144}
145
146/** Reverse move (translate) rectangle.
147 *
148 * @param trans Translation offset
149 * @param src Source rectangle
150 * @param dest Destination rectangle
151 */
152void gfx_rect_rtranslate(gfx_coord2_t *trans, gfx_rect_t *src, gfx_rect_t *dest)
153{
154 gfx_coord2_subtract(&src->p0, trans, &dest->p0);
155 gfx_coord2_subtract(&src->p1, trans, &dest->p1);
156}
157
158/** Compute envelope of two rectangles.
159 *
160 * Envelope is the minimal rectangle covering all pixels of both rectangles.
161 *
162 * @param a First rectangle
163 * @param b Second rectangle
164 * @param dest Place to store enveloping rectangle
165 */
166void gfx_rect_envelope(gfx_rect_t *a, gfx_rect_t *b, gfx_rect_t *dest)
167{
168 gfx_rect_t sa, sb;
169
170 if (gfx_rect_is_empty(a)) {
171 *dest = *b;
172 return;
173 }
174
175 if (gfx_rect_is_empty(b)) {
176 *dest = *a;
177 return;
178 }
179
180 /* a and b are both non-empty */
181
182 gfx_rect_points_sort(a, &sa);
183 gfx_rect_points_sort(b, &sb);
184
185 dest->p0.x = min(sa.p0.x, sb.p0.x);
186 dest->p0.y = min(sa.p0.y, sb.p0.y);
187 dest->p1.x = max(sa.p1.x, sb.p1.x);
188 dest->p1.y = max(sa.p1.y, sb.p1.y);
189}
190
191/** Compute intersection of two rectangles.
192 *
193 * If the two rectangles do not intersect, the result will be an empty
194 * rectangle (check with gfx_rect_is_empty()). The resulting rectangle
195 * is always sorted. If @a clip is NULL, no clipping is performed.
196 *
197 * @param rect Source rectangle
198 * @param clip Clipping rectangle or @c NULL
199 * @param dest Place to store clipped rectangle
200 */
201void gfx_rect_clip(gfx_rect_t *rect, gfx_rect_t *clip, gfx_rect_t *dest)
202{
203 gfx_rect_t srect, sclip;
204
205 if (clip == NULL) {
206 *dest = *rect;
207 return;
208 }
209
210 gfx_rect_points_sort(rect, &srect);
211 gfx_rect_points_sort(clip, &sclip);
212
213 dest->p0.x = min(max(srect.p0.x, sclip.p0.x), sclip.p1.x);
214 dest->p0.y = min(max(srect.p0.y, sclip.p0.y), sclip.p1.y);
215 dest->p1.x = max(sclip.p0.x, min(srect.p1.x, sclip.p1.x));
216 dest->p1.y = max(sclip.p0.y, min(srect.p1.y, sclip.p1.y));
217}
218
219/** Sort points of a rectangle.
220 *
221 * Shuffle around coordinates of a rectangle so that p0.x < p1.x and
222 * p0.y < p0.y.
223 *
224 * @param src Source rectangle
225 * @param dest Destination (sorted) rectangle
226 */
227void gfx_rect_points_sort(gfx_rect_t *src, gfx_rect_t *dest)
228{
229 gfx_span_points_sort(src->p0.x, src->p1.x, &dest->p0.x, &dest->p1.x);
230 gfx_span_points_sort(src->p0.y, src->p1.y, &dest->p0.y, &dest->p1.y);
231}
232
233/** Determine if rectangle contains no pixels
234 *
235 * @param rect Rectangle
236 * @return @c true iff rectangle contains no pixels
237 */
238bool gfx_rect_is_empty(gfx_rect_t *rect)
239{
240 return rect->p0.x == rect->p1.x || rect->p0.y == rect->p1.y;
241}
242
243/** Determine if two rectangles share any pixels
244 *
245 * @param a First rectangle
246 * @param b Second rectangle
247 * @return @c true iff rectangles share any pixels
248 */
249bool gfx_rect_is_incident(gfx_rect_t *a, gfx_rect_t *b)
250{
251 gfx_rect_t r;
252
253 gfx_rect_clip(a, b, &r);
254 return !gfx_rect_is_empty(&r);
255}
256
257/** Return true if rectangle @a a is contained in rectangle @a b.
258 *
259 * @param a Inside rectangle
260 * @param b Outside rectangle
261 * @return @c true iff @a a is (non-strictly) inside @a b
262 */
263bool gfx_rect_is_inside(gfx_rect_t *a, gfx_rect_t *b)
264{
265 gfx_rect_t sa;
266 gfx_rect_t sb;
267
268 gfx_rect_points_sort(a, &sa);
269 gfx_rect_points_sort(b, &sb);
270
271 if (sa.p0.x < sb.p0.x || sa.p0.y < sb.p0.y)
272 return false;
273
274 if (sa.p1.x > sb.p1.x || sa.p1.y > sb.p1.y)
275 return false;
276
277 return true;
278}
279
280/** Get rectangle dimensions.
281 *
282 * Get a vector containing the x, y dimensions of a rectangle. These are
283 * always nonnegative.
284 *
285 * @param rect Rectangle
286 * @param dims Place to store dimensions
287 */
288void gfx_rect_dims(gfx_rect_t *rect, gfx_coord2_t *dims)
289{
290 gfx_rect_t srect;
291
292 gfx_rect_points_sort(rect, &srect);
293 gfx_coord2_subtract(&srect.p1, &srect.p0, dims);
294}
295
296/** Return true if pixel at coordinate @a coord lies within rectangle @a rect. */
297bool gfx_pix_inside_rect(gfx_coord2_t *coord, gfx_rect_t *rect)
298{
299 gfx_rect_t sr;
300
301 gfx_rect_points_sort(rect, &sr);
302
303 if (coord->x < sr.p0.x || coord->y < sr.p0.y)
304 return false;
305
306 if (coord->x >= sr.p1.x || coord->y >= sr.p1.y)
307 return false;
308
309 return true;
310}
311
312/** @}
313 */
Note: See TracBrowser for help on using the repository browser.