d4ba14e1aabb309affe52c70ff2ed705fb6eef56
1 #define __NR_RECT_C__
3 /*
4 * Pixel buffer rendering library
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * This code is in public domain
10 */
12 #include "nr-rect-l.h"
13 #include <algorithm>
15 NRRect::NRRect(NR::Rect const &rect)
16 : x0(rect.min()[NR::X]), y0(rect.min()[NR::Y]),
17 x1(rect.max()[NR::X]), y1(rect.max()[NR::Y])
18 {}
20 NRRect::NRRect(NR::Maybe<NR::Rect> const &rect) {
21 if (rect) {
22 x0 = rect->min()[NR::X];
23 y0 = rect->min()[NR::Y];
24 x1 = rect->max()[NR::X];
25 y1 = rect->max()[NR::Y];
26 } else {
27 nr_rect_d_set_empty(this);
28 }
29 }
31 NR::Maybe<NR::Rect> NRRect::upgrade() const {
32 if (nr_rect_d_test_empty(this)) {
33 return NR::Nothing();
34 } else {
35 return NR::Rect(NR::Point(x0, y0), NR::Point(x1, y1));
36 }
37 }
39 /**
40 * \param r0 Rectangle.
41 * \param r1 Another rectangle.
42 * \param d Filled in with the intersection of r0 and r1.
43 * \return d.
44 */
46 NRRectL *nr_rect_l_intersect(NRRectL *d, const NRRectL *r0, const NRRectL *r1)
47 {
48 NR::ICoord t;
49 t = std::max(r0->x0, r1->x0);
50 d->x1 = std::min(r0->x1, r1->x1);
51 d->x0 = t;
52 t = std::max(r0->y0, r1->y0);
53 d->y1 = std::min(r0->y1, r1->y1);
54 d->y0 = t;
56 return d;
57 }
59 NRRect *
60 nr_rect_d_intersect (NRRect *d, const NRRect *r0, const NRRect *r1)
61 {
62 NR::Coord t;
63 t = MAX (r0->x0, r1->x0);
64 d->x1 = MIN (r0->x1, r1->x1);
65 d->x0 = t;
66 t = MAX (r0->y0, r1->y0);
67 d->y1 = MIN (r0->y1, r1->y1);
68 d->y0 = t;
70 return d;
71 }
73 // returns minimal rect which covers all of r0 not covered by r1
74 NRRectL *
75 nr_rect_l_subtract(NRRectL *d, NRRectL const *r0, NRRectL const *r1)
76 {
77 bool inside1 = nr_rect_l_test_inside(r1, r0->x0, r0->y0);
78 bool inside2 = nr_rect_l_test_inside(r1, r0->x1, r0->y0);
79 bool inside3 = nr_rect_l_test_inside(r1, r0->x1, r0->y1);
80 bool inside4 = nr_rect_l_test_inside(r1, r0->x0, r0->y1);
82 if (inside1 && inside2 && inside3) {
83 nr_rect_l_set_empty (d);
85 } else if (inside1 && inside2) {
86 d->x0 = r0->x0;
87 d->y0 = r1->y1;
89 d->x1 = r0->x1;
90 d->y1 = r0->y1;
91 } else if (inside2 && inside3) {
92 d->x0 = r0->x0;
93 d->y0 = r0->y0;
95 d->x1 = r1->x0;
96 d->y1 = r0->y1;
97 } else if (inside3 && inside4) {
98 d->x0 = r0->x0;
99 d->y0 = r0->y0;
101 d->x1 = r0->x1;
102 d->y1 = r1->y0;
103 } else if (inside4 && inside1) {
104 d->x0 = r1->x1;
105 d->y0 = r0->y0;
107 d->x1 = r0->x1;
108 d->y1 = r0->y1;
109 } else {
110 d->x0 = r0->x0;
111 d->y0 = r0->y0;
113 d->x1 = r0->x1;
114 d->y1 = r0->y1;
115 }
116 return d;
117 }
119 NR::ICoord nr_rect_l_area(NRRectL *r)
120 {
121 if (!r || NR_RECT_DFLS_TEST_EMPTY (r)) {
122 return 0;
123 }
124 return ((r->x1 - r->x0) * (r->y1 - r->y0));
125 }
127 NRRect *
128 nr_rect_d_union (NRRect *d, const NRRect *r0, const NRRect *r1)
129 {
130 if (NR_RECT_DFLS_TEST_EMPTY (r0)) {
131 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
132 nr_rect_d_set_empty (d);
133 } else {
134 *d = *r1;
135 }
136 } else {
137 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
138 *d = *r0;
139 } else {
140 NR::Coord t;
141 t = MIN (r0->x0, r1->x0);
142 d->x1 = MAX (r0->x1, r1->x1);
143 d->x0 = t;
144 t = MIN (r0->y0, r1->y0);
145 d->y1 = MAX (r0->y1, r1->y1);
146 d->y0 = t;
147 }
148 }
149 return d;
150 }
152 NRRectL *
153 nr_rect_l_union (NRRectL *d, const NRRectL *r0, const NRRectL *r1)
154 {
155 if (NR_RECT_DFLS_TEST_EMPTY (r0)) {
156 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
157 nr_rect_l_set_empty (d);
158 } else {
159 *d = *r1;
160 }
161 } else {
162 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
163 *d = *r0;
164 } else {
165 NR::ICoord t;
166 t = MIN (r0->x0, r1->x0);
167 d->x1 = MAX (r0->x1, r1->x1);
168 d->x0 = t;
169 t = MIN (r0->y0, r1->y0);
170 d->y1 = MAX (r0->y1, r1->y1);
171 d->y0 = t;
172 }
173 }
174 return d;
175 }
177 NRRect *
178 nr_rect_union_pt(NRRect *dst, NR::Point const &p)
179 {
180 using NR::X;
181 using NR::Y;
183 return nr_rect_d_union_xy(dst, p[X], p[Y]);
184 }
186 NRRect *
187 nr_rect_d_union_xy (NRRect *d, NR::Coord x, NR::Coord y)
188 {
189 if ((d->x0 <= d->x1) && (d->y0 <= d->y1)) {
190 d->x0 = MIN (d->x0, x);
191 d->y0 = MIN (d->y0, y);
192 d->x1 = MAX (d->x1, x);
193 d->y1 = MAX (d->y1, y);
194 } else {
195 d->x0 = d->x1 = x;
196 d->y0 = d->y1 = y;
197 }
198 return d;
199 }
201 NRRect *
202 nr_rect_d_matrix_transform(NRRect *d, NRRect const *const s, NR::Matrix const &m)
203 {
204 using NR::X;
205 using NR::Y;
207 if (nr_rect_d_test_empty(s)) {
208 nr_rect_d_set_empty(d);
209 } else {
210 NR::Point const c00(NR::Point(s->x0, s->y0) * m);
211 NR::Point const c01(NR::Point(s->x0, s->y1) * m);
212 NR::Point const c10(NR::Point(s->x1, s->y0) * m);
213 NR::Point const c11(NR::Point(s->x1, s->y1) * m);
214 d->x0 = std::min(std::min(c00[X], c01[X]),
215 std::min(c10[X], c11[X]));
216 d->y0 = std::min(std::min(c00[Y], c01[Y]),
217 std::min(c10[Y], c11[Y]));
218 d->x1 = std::max(std::max(c00[X], c01[X]),
219 std::max(c10[X], c11[X]));
220 d->y1 = std::max(std::max(c00[Y], c01[Y]),
221 std::max(c10[Y], c11[Y]));
222 }
223 return d;
224 }
226 NRRect *
227 nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NRMatrix const *m)
228 {
229 return nr_rect_d_matrix_transform(d, s, *m);
230 }
232 /** Enlarges the rectangle given amount of pixels to all directions */
233 NRRectL *
234 nr_rect_l_enlarge(NRRectL *d, int amount)
235 {
236 d->x0 -= amount;
237 d->y0 -= amount;
238 d->x1 += amount;
239 d->y1 += amount;
240 return d;
241 }
243 namespace NR {
245 Rect::Rect(const Point &p0, const Point &p1)
246 : _min(std::min(p0[X], p1[X]), std::min(p0[Y], p1[Y])),
247 _max(std::max(p0[X], p1[X]), std::max(p0[Y], p1[Y]))
248 {
249 if (0) {
250 if ( _min[X] == _max[X] || _min[Y] == _max[Y] ) {
251 throw EmptyRectangle();
252 }
253 }
254 }
256 /** returns the four corners of the rectangle in the correct winding order */
257 Point Rect::corner(unsigned i) const {
258 switch (i % 4) {
259 case 0:
260 return _min;
261 case 1:
262 return Point(_max[X], _min[Y]);
263 case 2:
264 return _max;
265 default: /* i.e. 3 */
266 return Point(_min[X], _max[Y]);
267 }
268 }
270 /** returns the midpoint of this rectangle */
271 Point Rect::midpoint() const {
272 return ( _min + _max ) / 2;
273 }
275 /** returns a vector from topleft to bottom right. */
276 Point Rect::dimensions() const {
277 return _max - _min;
278 }
280 /** Translates the rectangle by p. */
281 void Rect::offset(Point p) {
282 _min += p;
283 _max += p;
284 }
286 /** Makes this rectangle large enough to include the point p. */
287 void Rect::expandTo(Point p) {
288 for ( int i=0 ; i < 2 ; i++ ) {
289 _min[i] = std::min(_min[i], p[i]);
290 _max[i] = std::max(_max[i], p[i]);
291 }
292 }
294 /** Returns the set of points shared by both rectangles. */
295 Maybe<Rect> intersection(Maybe<Rect> const & a, Maybe<Rect> const & b) {
296 if ( !a || !b ) {
297 return Nothing();
298 } else {
299 Rect r;
300 for ( int i=0 ; i < 2 ; i++ ) {
301 r._min[i] = std::max(a->_min[i], b->_min[i]);
302 r._max[i] = std::min(a->_max[i], b->_max[i]);
303 if ( r._min[i] >= r._max[i] ) {
304 return Nothing();
305 }
306 }
307 return r;
308 }
309 }
311 /** returns the smallest rectangle containing both rectangles */
312 Rect union_bounds(Rect const &a, Rect const &b) {
313 Rect r;
314 for ( int i=0 ; i < 2 ; i++ ) {
315 r._min[i] = std::min(a._min[i], b._min[i]);
316 r._max[i] = std::max(a._max[i], b._max[i]);
317 }
318 return r;
319 }
321 } // namespace NR
324 /*
325 Local Variables:
326 mode:c++
327 c-file-style:"stroustrup"
328 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
329 indent-tabs-mode:nil
330 fill-column:99
331 End:
332 */
333 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :