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(boost::optional<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 NRRect::NRRect(Geom::OptRect const &rect) {
32 if (rect) {
33 x0 = rect->min()[Geom::X];
34 y0 = rect->min()[Geom::Y];
35 x1 = rect->max()[Geom::X];
36 y1 = rect->max()[Geom::Y];
37 } else {
38 nr_rect_d_set_empty(this);
39 }
40 }
42 boost::optional<NR::Rect> NRRect::upgrade() const {
43 if (nr_rect_d_test_empty_ptr(this)) {
44 return boost::optional<NR::Rect>();
45 } else {
46 return NR::Rect(NR::Point(x0, y0), NR::Point(x1, y1));
47 }
48 }
50 Geom::OptRect NRRect::upgrade_2geom() const {
51 if (nr_rect_d_test_empty_ptr(this)) {
52 return Geom::OptRect();
53 } else {
54 return Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1));
55 }
56 }
58 /**
59 * \param r0 Rectangle.
60 * \param r1 Another rectangle.
61 * \param d Filled in with the intersection of r0 and r1.
62 * \return d.
63 */
65 NRRectL *nr_rect_l_intersect(NRRectL *d, const NRRectL *r0, const NRRectL *r1)
66 {
67 NR::ICoord t;
68 t = std::max(r0->x0, r1->x0);
69 d->x1 = std::min(r0->x1, r1->x1);
70 d->x0 = t;
71 t = std::max(r0->y0, r1->y0);
72 d->y1 = std::min(r0->y1, r1->y1);
73 d->y0 = t;
75 return d;
76 }
78 NRRect *
79 nr_rect_d_intersect (NRRect *d, const NRRect *r0, const NRRect *r1)
80 {
81 NR::Coord t;
82 t = MAX (r0->x0, r1->x0);
83 d->x1 = MIN (r0->x1, r1->x1);
84 d->x0 = t;
85 t = MAX (r0->y0, r1->y0);
86 d->y1 = MIN (r0->y1, r1->y1);
87 d->y0 = t;
89 return d;
90 }
92 // returns minimal rect which covers all of r0 not covered by r1
93 NRRectL *
94 nr_rect_l_subtract(NRRectL *d, NRRectL const *r0, NRRectL const *r1)
95 {
96 bool inside1 = nr_rect_l_test_inside(r1, r0->x0, r0->y0);
97 bool inside2 = nr_rect_l_test_inside(r1, r0->x1, r0->y0);
98 bool inside3 = nr_rect_l_test_inside(r1, r0->x1, r0->y1);
99 bool inside4 = nr_rect_l_test_inside(r1, r0->x0, r0->y1);
101 if (inside1 && inside2 && inside3) {
102 nr_rect_l_set_empty (d);
104 } else if (inside1 && inside2) {
105 d->x0 = r0->x0;
106 d->y0 = r1->y1;
108 d->x1 = r0->x1;
109 d->y1 = r0->y1;
110 } else if (inside2 && inside3) {
111 d->x0 = r0->x0;
112 d->y0 = r0->y0;
114 d->x1 = r1->x0;
115 d->y1 = r0->y1;
116 } else if (inside3 && inside4) {
117 d->x0 = r0->x0;
118 d->y0 = r0->y0;
120 d->x1 = r0->x1;
121 d->y1 = r1->y0;
122 } else if (inside4 && inside1) {
123 d->x0 = r1->x1;
124 d->y0 = r0->y0;
126 d->x1 = r0->x1;
127 d->y1 = r0->y1;
128 } else {
129 d->x0 = r0->x0;
130 d->y0 = r0->y0;
132 d->x1 = r0->x1;
133 d->y1 = r0->y1;
134 }
135 return d;
136 }
138 NR::ICoord nr_rect_l_area(NRRectL *r)
139 {
140 if (!r || NR_RECT_DFLS_TEST_EMPTY (r)) {
141 return 0;
142 }
143 return ((r->x1 - r->x0) * (r->y1 - r->y0));
144 }
146 NRRect *
147 nr_rect_d_union (NRRect *d, const NRRect *r0, const NRRect *r1)
148 {
149 if (NR_RECT_DFLS_TEST_EMPTY (r0)) {
150 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
151 nr_rect_d_set_empty (d);
152 } else {
153 *d = *r1;
154 }
155 } else {
156 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
157 *d = *r0;
158 } else {
159 NR::Coord t;
160 t = MIN (r0->x0, r1->x0);
161 d->x1 = MAX (r0->x1, r1->x1);
162 d->x0 = t;
163 t = MIN (r0->y0, r1->y0);
164 d->y1 = MAX (r0->y1, r1->y1);
165 d->y0 = t;
166 }
167 }
168 return d;
169 }
171 NRRectL *
172 nr_rect_l_union (NRRectL *d, const NRRectL *r0, const NRRectL *r1)
173 {
174 if (NR_RECT_DFLS_TEST_EMPTY (r0)) {
175 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
176 nr_rect_l_set_empty (d);
177 } else {
178 *d = *r1;
179 }
180 } else {
181 if (NR_RECT_DFLS_TEST_EMPTY (r1)) {
182 *d = *r0;
183 } else {
184 NR::ICoord t;
185 t = MIN (r0->x0, r1->x0);
186 d->x1 = MAX (r0->x1, r1->x1);
187 d->x0 = t;
188 t = MIN (r0->y0, r1->y0);
189 d->y1 = MAX (r0->y1, r1->y1);
190 d->y0 = t;
191 }
192 }
193 return d;
194 }
196 NRRect *
197 nr_rect_union_pt(NRRect *dst, NR::Point const &p)
198 {
199 using NR::X;
200 using NR::Y;
202 return nr_rect_d_union_xy(dst, p[X], p[Y]);
203 }
205 NRRect *
206 nr_rect_d_union_xy (NRRect *d, NR::Coord x, NR::Coord y)
207 {
208 if ((d->x0 <= d->x1) && (d->y0 <= d->y1)) {
209 d->x0 = MIN (d->x0, x);
210 d->y0 = MIN (d->y0, y);
211 d->x1 = MAX (d->x1, x);
212 d->y1 = MAX (d->y1, y);
213 } else {
214 d->x0 = d->x1 = x;
215 d->y0 = d->y1 = y;
216 }
217 return d;
218 }
220 NRRect *
221 nr_rect_d_matrix_transform(NRRect *d, NRRect const *const s, NR::Matrix const &m)
222 {
223 using NR::X;
224 using NR::Y;
226 if (nr_rect_d_test_empty_ptr(s)) {
227 nr_rect_d_set_empty(d);
228 } else {
229 NR::Point const c00(NR::Point(s->x0, s->y0) * m);
230 NR::Point const c01(NR::Point(s->x0, s->y1) * m);
231 NR::Point const c10(NR::Point(s->x1, s->y0) * m);
232 NR::Point const c11(NR::Point(s->x1, s->y1) * m);
233 d->x0 = std::min(std::min(c00[X], c01[X]),
234 std::min(c10[X], c11[X]));
235 d->y0 = std::min(std::min(c00[Y], c01[Y]),
236 std::min(c10[Y], c11[Y]));
237 d->x1 = std::max(std::max(c00[X], c01[X]),
238 std::max(c10[X], c11[X]));
239 d->y1 = std::max(std::max(c00[Y], c01[Y]),
240 std::max(c10[Y], c11[Y]));
241 }
242 return d;
243 }
245 NRRect *
246 nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NR::Matrix const *m)
247 {
248 return nr_rect_d_matrix_transform(d, s, *m);
249 }
251 /** Enlarges the rectangle given amount of pixels to all directions */
252 NRRectL *
253 nr_rect_l_enlarge(NRRectL *d, int amount)
254 {
255 d->x0 -= amount;
256 d->y0 -= amount;
257 d->x1 += amount;
258 d->y1 += amount;
259 return d;
260 }
262 namespace NR {
264 Rect::Rect(const Point &p0, const Point &p1)
265 : _min(std::min(p0[X], p1[X]), std::min(p0[Y], p1[Y])),
266 _max(std::max(p0[X], p1[X]), std::max(p0[Y], p1[Y]))
267 {}
269 /** returns the four corners of the rectangle in the correct winding order */
270 Point Rect::corner(unsigned i) const {
271 switch (i % 4) {
272 case 0:
273 return _min;
274 case 1:
275 return Point(_max[X], _min[Y]);
276 case 2:
277 return _max;
278 default: /* i.e. 3 */
279 return Point(_min[X], _max[Y]);
280 }
281 }
283 /** returns the midpoint of this rectangle */
284 Point Rect::midpoint() const {
285 return ( _min + _max ) / 2;
286 }
288 Point Rect::cornerFarthestFrom(Point const &p) const {
289 Point m = midpoint();
290 unsigned i = 0;
291 if (p[X] < m[X]) {
292 i = 1;
293 }
294 if (p[Y] < m[Y]) {
295 i = 3 - i;
296 }
297 return corner(i);
298 }
300 /** returns a vector from topleft to bottom right. */
301 Point Rect::dimensions() const {
302 return _max - _min;
303 }
305 /** Translates the rectangle by p. */
306 void Rect::offset(Point p) {
307 _min += p;
308 _max += p;
309 }
311 /** Makes this rectangle large enough to include the point p. */
312 void Rect::expandTo(Point p) {
313 for ( int i=0 ; i < 2 ; i++ ) {
314 _min[i] = std::min(_min[i], p[i]);
315 _max[i] = std::max(_max[i], p[i]);
316 }
317 }
319 void Rect::growBy(double size) {
320 for ( unsigned d = 0 ; d < 2 ; d++ ) {
321 _min[d] -= size;
322 _max[d] += size;
323 if ( _min[d] > _max[d] ) {
324 _min[d] = _max[d] = ( _min[d] + _max[d] ) / 2;
325 }
326 }
327 }
329 /** Returns the set of points shared by both rectangles. */
330 boost::optional<Rect> intersection(boost::optional<Rect> const & a, boost::optional<Rect> const & b) {
331 if ( !a || !b ) {
332 return boost::optional<Rect>();
333 } else {
334 Rect r;
335 for ( int i=0 ; i < 2 ; i++ ) {
336 r._min[i] = std::max(a->_min[i], b->_min[i]);
337 r._max[i] = std::min(a->_max[i], b->_max[i]);
338 if ( r._min[i] > r._max[i] ) {
339 return boost::optional<Rect>();
340 }
341 }
342 return r;
343 }
344 }
346 /** returns the smallest rectangle containing both rectangles */
347 Rect union_bounds(Rect const &a, Rect const &b) {
348 Rect r;
349 for ( int i=0 ; i < 2 ; i++ ) {
350 r._min[i] = std::min(a._min[i], b._min[i]);
351 r._max[i] = std::max(a._max[i], b._max[i]);
352 }
353 return r;
354 }
356 } // namespace NR
359 /*
360 Local Variables:
361 mode:c++
362 c-file-style:"stroustrup"
363 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
364 indent-tabs-mode:nil
365 fill-column:99
366 End:
367 */
368 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :