Code

f3036eff10be3004c73c7a6d93a9e44b1318ef94
[inkscape.git] / src / libnr / nr-rect.cpp
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;
55         
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;
69         
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;
119 NR::ICoord nr_rect_l_area(NRRectL *r)
121   if (!r || NR_RECT_DFLS_TEST_EMPTY (r)) {
122       return 0;
123   }
124   return ((r->x1 - r->x0) * (r->y1 - r->y0));
127 NRRect *
128 nr_rect_d_union (NRRect *d, const NRRect *r0, const NRRect *r1)
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;
152 NRRectL *
153 nr_rect_l_union (NRRectL *d, const NRRectL *r0, const NRRectL *r1)
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;
177 NRRect *
178 nr_rect_union_pt(NRRect *dst, NR::Point const &p)
180         using NR::X;
181         using NR::Y;
183         return nr_rect_d_union_xy(dst, p[X], p[Y]);
186 NRRect *
187 nr_rect_d_union_xy (NRRect *d, NR::Coord x, NR::Coord y)
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;
201 NRRect *
202 nr_rect_d_matrix_transform(NRRect *d, NRRect const *const s, NR::Matrix const &m)
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;
226 NRRect *
227 nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NRMatrix const *m)
229     return nr_rect_d_matrix_transform(d, s, *m);
232 /** Enlarges the rectangle given amount of pixels to all directions */
233 NRRectL *
234 nr_rect_l_enlarge(NRRectL *d, int amount)
236     d->x0 -= amount;
237     d->y0 -= amount;
238     d->x1 += amount;
239     d->y1 += amount;
240     return d;
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 {}
250 /** returns the four corners of the rectangle in the correct winding order */
251 Point Rect::corner(unsigned i) const {
252         switch (i % 4) {
253         case 0:
254                 return _min;
255         case 1:
256                 return Point(_max[X], _min[Y]);
257         case 2:
258                 return _max;
259         default: /* i.e. 3 */
260                 return Point(_min[X], _max[Y]);
261         }
264 /** returns the midpoint of this rectangle */
265 Point Rect::midpoint() const {
266         return ( _min + _max ) / 2;
269 Point Rect::cornerFarthestFrom(Point const &p) const {
270     Point m = midpoint();
271     unsigned i = 0;
272     if (p[X] < m[X]) {
273         i = 1;
274     }
275     if (p[Y] < m[Y]) {
276         i = 3 - i;
277     }
278     return corner(i);
281 /** returns a vector from topleft to bottom right. */
282 Point Rect::dimensions() const {
283         return _max - _min;
286 /** Translates the rectangle by p. */
287 void Rect::offset(Point p) {
288         _min += p;
289         _max += p;
292 /** Makes this rectangle large enough to include the point p. */
293 void Rect::expandTo(Point p) {
294         for ( int i=0 ; i < 2 ; i++ ) {
295                 _min[i] = std::min(_min[i], p[i]);
296                 _max[i] = std::max(_max[i], p[i]);
297         }
300 void Rect::growBy(double size) {
301   for ( unsigned d = 0 ; d < 2 ; d++ ) {
302     _min[d] -= size;
303     _max[d] += size;
304     if ( _min[d] > _max[d] ) {
305       _min[d] = _max[d] = ( _min[d] + _max[d] ) / 2;
306     }
307   }
308
310 /** Returns the set of points shared by both rectangles. */
311 Maybe<Rect> intersection(Maybe<Rect> const & a, Maybe<Rect> const & b) {
312     if ( !a || !b ) {
313         return Nothing();
314     } else {
315         Rect r;
316         for ( int i=0 ; i < 2 ; i++ ) {
317             r._min[i] = std::max(a->_min[i], b->_min[i]);
318             r._max[i] = std::min(a->_max[i], b->_max[i]);
319             if ( r._min[i] > r._max[i] ) {
320                 return Nothing();
321             }
322         }
323         return r;
324     }
327 /** returns the smallest rectangle containing both rectangles */
328 Rect union_bounds(Rect const &a, Rect const &b) {
329     Rect r;
330     for ( int i=0 ; i < 2 ; i++ ) {
331         r._min[i] = std::min(a._min[i], b._min[i]);
332         r._max[i] = std::max(a._max[i], b._max[i]);
333     }
334     return r;
337 }  // namespace NR
340 /*
341   Local Variables:
342   mode:c++
343   c-file-style:"stroustrup"
344   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
345   indent-tabs-mode:nil
346   fill-column:99
347   End:
348 */
349 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :