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

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

Need to be able to paint in the negative quadrants

  • Property mode set to 100644
File size: 8.6 KB
RevLine 
[7b882c1f]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>
[8b1ce56]37#include <macros.h>
38#include <stdbool.h>
[6301a24f]39#include <stddef.h>
[7b882c1f]40
[32066f2]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
[7b882c1f]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
[1388f7f0]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 */
[e1f2079]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
[1388f7f0]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
[8b1ce56]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
[7b882c1f]155/** Move (translate) rectangle.
156 *
[fdc8e40]157 * @param trans Translation offset
[7b882c1f]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{
[fdc8e40]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);
[7b882c1f]177}
178
[8b1ce56]179/** Compute envelope of two rectangles.
180 *
181 * Envelope is the minimal rectangle covering all pixels of both rectangles.
[fdc8e40]182 *
183 * @param a First rectangle
184 * @param b Second rectangle
185 * @param dest Place to store enveloping rectangle
[8b1ce56]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
[fdc8e40]212/** Compute intersection of two rectangles.
213 *
214 * If the two rectangles do not intersect, the result will be an empty
[c2250702]215 * rectangle (check with gfx_rect_is_empty()). The resulting rectangle
[6301a24f]216 * is always sorted. If @a clip is NULL, no clipping is performed.
[fdc8e40]217 *
218 * @param rect Source rectangle
[6301a24f]219 * @param clip Clipping rectangle or @c NULL
[fdc8e40]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
[6301a24f]226 if (clip == NULL) {
227 *dest = *rect;
228 return;
229 }
230
[fdc8e40]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
[8b1ce56]240/** Sort points of a rectangle.
241 *
242 * Shuffle around coordinates of a rectangle so that p0.x < p1.x and
243 * p0.y < p0.y.
244 *
245 * @param src Source rectangle
246 * @param dest Destination (sorted) rectangle
247 */
248void gfx_rect_points_sort(gfx_rect_t *src, gfx_rect_t *dest)
249{
250 gfx_span_points_sort(src->p0.x, src->p1.x, &dest->p0.x, &dest->p1.x);
251 gfx_span_points_sort(src->p0.y, src->p1.y, &dest->p0.y, &dest->p1.y);
252}
253
254/** Determine if rectangle contains no pixels
255 *
256 * @param rect Rectangle
257 * @return @c true iff rectangle contains no pixels
258 */
259bool gfx_rect_is_empty(gfx_rect_t *rect)
260{
261 return rect->p0.x == rect->p1.x || rect->p0.y == rect->p1.y;
262}
263
[6301a24f]264/** Determine if two rectangles share any pixels
265 *
266 * @param a First rectangle
267 * @param b Second rectangle
268 * @return @c true iff rectangles share any pixels
269 */
270bool gfx_rect_is_incident(gfx_rect_t *a, gfx_rect_t *b)
271{
272 gfx_rect_t r;
273
274 gfx_rect_clip(a, b, &r);
275 return !gfx_rect_is_empty(&r);
276}
277
[afcf704]278/** Return true if rectangle @a a is contained in rectangle @a b.
279 *
280 * @param a Inside rectangle
281 * @param b Outside rectangle
282 * @return @c true iff @a a is (non-strictly) inside @a b
283 */
284bool gfx_rect_is_inside(gfx_rect_t *a, gfx_rect_t *b)
285{
286 gfx_rect_t sa;
287 gfx_rect_t sb;
288
289 gfx_rect_points_sort(a, &sa);
290 gfx_rect_points_sort(b, &sb);
291
292 if (sa.p0.x < sb.p0.x || sa.p0.y < sb.p0.y)
293 return false;
294
295 if (sa.p1.x > sb.p1.x || sa.p1.y > sb.p1.y)
296 return false;
297
298 return true;
299}
300
[0e6e77f]301/** Get rectangle dimensions.
302 *
303 * Get a vector containing the x, y dimensions of a rectangle. These are
304 * always nonnegative.
305 *
306 * @param rect Rectangle
307 * @param dims Place to store dimensions
308 */
309void gfx_rect_dims(gfx_rect_t *rect, gfx_coord2_t *dims)
310{
311 gfx_rect_t srect;
312
313 gfx_rect_points_sort(rect, &srect);
314 gfx_coord2_subtract(&srect.p1, &srect.p0, dims);
315}
316
[fb420e48]317/** Return true if pixel at coordinate @a coord lies within rectangle @a rect. */
318bool gfx_pix_inside_rect(gfx_coord2_t *coord, gfx_rect_t *rect)
319{
320 gfx_rect_t sr;
321
322 gfx_rect_points_sort(rect, &sr);
323
324 if (coord->x < sr.p0.x || coord->y < sr.p0.y)
325 return false;
326
327 if (coord->x >= sr.p1.x || coord->y >= sr.p1.y)
328 return false;
329
330 return true;
331}
332
[7b882c1f]333/** @}
334 */
Note: See TracBrowser for help on using the repository browser.