~marmuta/onboardosk/trunk

« back to all changes in this revision

Viewing changes to src/libonboardosk/tools/rect.h

  • Committer: marmuta
  • Date: 2017-08-23 22:00:55 UTC
  • mfrom: (0.1.25 onboardosk)
  • Revision ID: marmvta@gmail.com-20170823220055-4y6meaas01uct8wm
Attempt at reducing include dependencies. Marginally effective.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#ifndef RECT_H
2
2
#define RECT_H
3
3
 
 
4
// rectdecls.h: only brief forward declarations, no include dependencies
 
5
// rectdefs.h:  medium level function definitions with some include dependencies
 
6
// rect.h:      full functionality with more include dependencies
 
7
 
4
8
#include <assert.h>
5
9
#include <cmath>
6
10
#include <ostream>
7
11
#include <vector>
8
12
 
9
 
#include "point.h"
10
 
 
11
 
template<class T=double>
12
 
class TBorder
13
 
{
14
 
    public:
15
 
        TBorder<T>& operator=(const TBorder<T>& other) = default;
16
 
        bool operator==(const TBorder<T>& other) {
17
 
            return left == other.left && top == other.top &&
18
 
                   right == other.right && bottom == other.bottom;
19
 
        }
20
 
 
21
 
        bool operator!=(const TBorder<T>& other) {
22
 
            return !operator==(other);
23
 
        }
24
 
 
25
 
     public:
26
 
        T left{};
27
 
        T top{};
28
 
        T right{};
29
 
        T bottom{};
30
 
};
31
 
typedef TBorder<double> Border;
32
 
 
33
 
template<class T>
34
 
std::ostream& operator<<(std::ostream& s, const TBorder<T>& b){
35
 
    s << "Border(" << b.left << ", " << b.top << ", " << b.right << ", " << b.bottom << ")";
36
 
    return s;
37
 
}
38
 
 
39
 
// Rectangle template class.
40
 
// Left and top are included, right and bottom excluded.
41
 
template<class T=double>
42
 
class TRect {
43
 
    public:
44
 
        TRect() = default;
45
 
        TRect(const TRect<T>& other) = default;
46
 
        TRect(T x_, T y_, T w_, T h_) :
47
 
            x(x_), y(y_), w(w_), h(h_)
48
 
        { }
49
 
        TRect(const TPoint<T>& pt, const TSize<T>& sz) :
50
 
            x(pt.x), y(pt.y), w(sz.w), h(sz.h)
51
 
        { }
52
 
 
53
 
        TRect<T>& operator=(const TRect<T>& other) = default;
54
 
        bool operator==(const TRect<T>& other) {
55
 
            return x == other.x && y == other.y &&
56
 
                   w == other.w && h == other.h;
57
 
        }
58
 
 
59
 
        bool operator!=(const TRect<T>& other) {
60
 
            return !operator==(other);
61
 
        }
62
 
 
63
 
        T& operator[](size_t index) {
64
 
            switch (index)
65
 
            {
66
 
                case 0: return x;
67
 
                case 1: return y;
68
 
                case 2: return w;
69
 
                case 3: return h;
70
 
                default: assert(false);  // invalid index
71
 
            }
72
 
        }
73
 
 
74
 
        // New Rect from two points.
75
 
        // x0 and y0 are considered inside, x1 and y1 are just outside the Rect.
76
 
        static TRect<T> from_extents(T x0, T y0, T x1, T y1)
77
 
        {
78
 
            return TRect<T>(x0, y0, x1 - x0, y1 - y0);
79
 
        }
80
 
 
81
 
        // New Rect from two tuples.
82
 
        static TRect<T> from_position_size(const TPoint<T>& position, const TSize<T>& size)
83
 
        {
84
 
            return TRect<T>(position.x, position.y, size.w, size.h);
85
 
        }
86
 
 
87
 
        // New Rect from two points, left-top and right-botton.
88
 
        // The former lies inside, while the latter is considered to be
89
 
        // just outside the rect.
90
 
        static TRect<T> from_points(const TPoint<T>& p0, const TPoint<T>& p1)
91
 
        {
92
 
            return TRect<T>(p0.x, p0.y, p1.x - p0.x, p1.y - p0.y);
93
 
        }
94
 
        /*
95
 
        def to_extents(self):
96
 
            return x, y , x + w, y + h
97
 
 
98
 
        def to_position_size(self):
99
 
            return (x, y), (w, h)
100
 
        */
101
 
 
102
 
        bool empty() const
103
 
        { return w <= 0 or h <= 0; }
104
 
 
105
 
        TPoint<T> left_top() const
106
 
        { return {x, y}; }
107
 
 
108
 
        TPoint<T> right_bottom() const
109
 
        { return {right(), bottom()}; }
110
 
 
111
 
        TPoint<T> get_position() const
112
 
        { return {x, y}; }
113
 
 
114
 
        TSize<T> get_size() const
115
 
        { return {w, h}; }
116
 
 
117
 
        TPoint<T> get_center() const
118
 
        { return {x + w / 2.0, y + h / 2.0}; }
119
 
 
120
 
        T get_center_x() const
121
 
        { return x + w / 2; }
122
 
 
123
 
        T get_center_y() const
124
 
        { return y + h / 2; }
125
 
 
126
 
        T left() const
127
 
        { return x; }
128
 
 
129
 
        T top() const
130
 
        { return y; }
131
 
 
132
 
        T right() const
133
 
        { return x + w; }
134
 
 
135
 
        T bottom() const
136
 
        { return y + h; }
137
 
 
138
 
        bool contains(const TPoint<T>& pt) const {
139
 
            return contains(pt.x, pt.y);
140
 
        }
141
 
 
142
 
        bool contains(T x_, T y_) const {
143
 
            return this->x <= x_ && this->x + this->w > x_ &&
144
 
                   this->y <= y_ && this->y + this->h > y_;
145
 
        }
146
 
 
147
 
        TRect<T> round() const {
148
 
            return {std::round(x), std::round(y), std::round(w), std::round(h)};
149
 
        }
150
 
 
151
 
        TRect<T> floor() const {
152
 
            return {std::floor(x), std::floor(y), std::floor(w), std::floor(h)};
153
 
        }
154
 
 
155
 
        TRect<int> to_int() const {
156
 
            return {int(x), int(y), int(w), int(h)};
157
 
        }
158
 
 
159
 
        TRect<T> scale(T k) const {
160
 
            return scale(k, k);
161
 
        }
162
 
 
163
 
        TRect<T> scale(T kx, T ky) const {
164
 
            return {x * kx, y * ky, w * kx, h * ky};
165
 
        }
166
 
 
167
 
        // Returns a new Rect displaced by dx and dy.
168
 
        TRect<T> offset(const TVec2<T>& v) const {
169
 
            return offset(v.x, v.y);
170
 
        }
171
 
 
172
 
        // Returns a new Rect displaced by dx and dy.
173
 
        TRect<T> offset(T dx, T dy) const {
174
 
            return {x + dx, y + dy, w, h};
175
 
        }
176
 
 
177
 
        TRect<T> inflate(T k) const {
178
 
            return inflate(k, k);
179
 
        }
180
 
 
181
 
        TRect<T> inflate(const TVec2<T>& v) const {
182
 
            return inflate(v.y, v.x);
183
 
        }
184
 
 
185
 
        TRect<T> inflate(T kx, T ky) const {
186
 
            TRect<T> r = {x - kx, y - ky, w + 2 * kx, h + 2 * ky};
187
 
            return r;
188
 
        }
189
 
 
190
 
        // add border to rect on all four sides
191
 
        TRect<T> inflate(const TBorder<T>& b) const {
192
 
            return {x - b.left, y - b.top,
193
 
                    w + b.left + b.right,
194
 
                    h + b.top + b.bottom};
195
 
        }
196
 
 
197
 
        TRect<T> deflate(T k) const {
198
 
            return deflate(k, k);
199
 
        }
200
 
 
201
 
        TRect<T> deflate(TVec2<T> v) const {
202
 
            return deflate(v.x, v.y);
203
 
        }
204
 
 
205
 
        TRect<T> deflate(T kx, T ky) const {
206
 
            TRect<T> r = {x + kx, y + ky, w - 2*kx, h - 2*ky};
207
 
            return r;
208
 
        }
209
 
 
210
 
        // remove border from rect on all four sides
211
 
        TRect<T> deflate(const TBorder<T>& b) const {
212
 
            return {x + b.left, y + b.top,
213
 
                    w - b.left - b.right,
214
 
                    h - b.top - b.bottom};
215
 
        }
216
 
 
217
 
        // Returns a new Rect with its size multiplied by k.
218
 
        TRect<T> grow(T k) const
219
 
        {
220
 
            return grow(k, k);
221
 
        }
222
 
        TRect<T> grow(T kx, T ky) const
223
 
        {
224
 
            TRect<T> r = *this;
225
 
            grow(r, kx, ky);
226
 
            return r;
227
 
        }
228
 
 
229
 
        // multiply w, h by kx, ky, inplace
230
 
        void grow(TRect<T>& r, T kx) const
231
 
        {
232
 
            grow(r, kx, kx);
233
 
        }
234
 
        void grow(TRect<T>& r, T kx, T ky) const
235
 
        {
236
 
            T w_ = r.w * kx;
237
 
            T h_ = r.h * ky;
238
 
            r.x = r.x + (r.w - w_) / 2.0;
239
 
            r.y = r.y + (r.h - h_) / 2.0;
240
 
            r.w = w_;
241
 
            r.h = h_;
242
 
        }
243
 
 
244
 
        bool intersects(TRect<T> rect) const
245
 
        {
246
 
            return !(x >= rect.x + rect.w ||
247
 
                     x + w <= rect.x ||
248
 
                     y >= rect.y + rect.h ||
249
 
                     y + h <= rect.y);
250
 
        }
251
 
 
252
 
        TRect<T> intersection(const TRect<T>&rect) const
253
 
        {
254
 
            T x0 = std::max(x, rect.x);
255
 
            T y0 = std::max(y, rect.y);
256
 
            T x1 = std::min(x + w, rect.x + rect.w);
257
 
            T y1 = std::min(y + h, rect.y + rect.h);
258
 
            if (x0 > x1 || y0 > y1)
259
 
                return {};
260
 
            else
261
 
                return {x0, y0, x1 - x0, y1 - y0};
262
 
        }
263
 
 
264
 
        TRect<T> union_(const TRect<T>& rect) const
265
 
        {
266
 
            T x0 = std::min(x, rect.x);
267
 
            T y0 = std::min(y, rect.y);
268
 
            T x1 = std::max(x + w, rect.x + rect.w);
269
 
            T y1 = std::max(y + h, rect.y + rect.h);
270
 
            return {x0, y0, x1 - x0, y1 - y0};
271
 
        }
272
 
 
273
 
        // Returns a new Rect with the aspect ratio of self
274
 
        // that fits inside the given rectangle.
275
 
        TRect<T> inscribe_with_aspect(const TRect<T>& rect,
276
 
                                      double x_align=0.5,
277
 
                                      double y_align=0.5) const
278
 
        {
279
 
            if (empty() || rect.empty())
280
 
                return {};
281
 
 
282
 
            double src_aspect = w / static_cast<double>(h);
283
 
            double dst_aspect = rect.w / static_cast<double>(rect.h);
284
 
 
285
 
            TRect<T> result = rect;
286
 
            if (dst_aspect > src_aspect)
287
 
            {
288
 
                result.w = static_cast<T>(rect.h * src_aspect);
289
 
                result.x += static_cast<T>(x_align * (rect.w - result.w));
290
 
            }
291
 
            else
292
 
            {
293
 
                result.h = static_cast<T>(rect.w / src_aspect);
294
 
                result.y += static_cast<T>(y_align * (rect.h - result.h));
295
 
            }
296
 
            return result;
297
 
        }
298
 
 
299
 
        // Resize self to the aspect ratio of aspect_rect.
300
 
        TRect<T> resize_to_aspect(const TRect<T>& aspect_rect) const
301
 
        {
302
 
            if (empty() or aspect_rect.empty())
303
 
                return {};
304
 
 
305
 
            double src_aspect = aspect_rect.w / static_cast<double>(aspect_rect.h);
306
 
            double dst_aspect = w / static_cast<double>(h);
307
 
 
308
 
            TRect<T> result = *this;
309
 
            if (dst_aspect > src_aspect)
310
 
                result.w = static_cast<T>(h * src_aspect);
311
 
            else
312
 
                result.h = static_cast<T>(w / src_aspect);
313
 
            return result;
314
 
        }
315
 
 
316
 
        // Resize self to get the aspect ratio of aspect_rect, but limited
317
 
        // by the given aspect range.
318
 
        TRect<T> resize_to_aspect_range(const TRect<T>& aspect_rect,
319
 
                                        T min_aspect, T max_aspect) const
320
 
        {
321
 
            (void)min_aspect;  // not implemented
322
 
 
323
 
            if (empty() || aspect_rect.empty())
324
 
                return {};
325
 
 
326
 
            TRect<T> r = aspect_rect;
327
 
            if (r.h)
328
 
            {
329
 
                double a0 = r.w / static_cast<double>(r.h);
330
 
                double a0_max = a0 * max_aspect;
331
 
                double a1 = w / static_cast<double>(h);
332
 
                double a = std::min(a1, a0_max);
333
 
 
334
 
                r = {0, 0, a, 1.0};
335
 
            }
336
 
            return resize_to_aspect(r);
337
 
        }
338
 
 
339
 
        // Aligns the given rect inside of self.
340
 
        // x/y_align = 0.5 centers rect.
341
 
        TRect<T> align_rect(const TRect<T>& rect,
342
 
                            double x_align = 0.5,
343
 
                            double y_align = 0.5) const
344
 
        {
345
 
            return {static_cast<T>(this->x + (this->w - rect.w) * x_align),
346
 
                    static_cast<T>(this->y + (this->h - rect.h) * y_align),
347
 
                    rect.w, rect.h};
348
 
        }
349
 
 
350
 
        // Aligns the given rect to a point.
351
 
        // x/y_align = 0.5 centers rect.
352
 
        TRect<T> align_at_point(T x_, T y_,
353
 
                                double x_align = 0.5,
354
 
                                double y_align = 0.5) const
355
 
        {
356
 
            return {static_cast<T>(x_ - this->w * x_align),
357
 
                    static_cast<T>(y_ - this->h * y_align),
358
 
                    this->w, this->h};
359
 
        }
360
 
 
361
 
        // Divide self into columns x rows sub-rectangles
362
 
        std::vector<TRect<T>> subdivide(size_t columns, size_t rows, T spacing={}) const
363
 
        {
364
 
            return subdivide(columns, rows, spacing, spacing);
365
 
        }
366
 
        std::vector<TRect<T>> subdivide(size_t columns, size_t rows, TVec2<T> spacing) const
367
 
        {
368
 
            return subdivide(columns, rows, spacing.x, spacing.y);
369
 
        }
370
 
 
371
 
        std::vector<TRect<T>> subdivide(size_t columns, size_t rows,
372
 
                                        T x_spacing, T y_spacing) const
373
 
        {
374
 
            T ws = static_cast<T>(
375
 
                   (this->w - (columns - 1) * x_spacing) / static_cast<double>(columns));
376
 
            T hs = static_cast<T>(
377
 
                   (this->h - (rows - 1)    * y_spacing) / static_cast<double>(rows));
378
 
 
379
 
            std::vector<TRect<T>> rects;
380
 
            T _y = this->y;
381
 
            for (size_t row=0; row < rows; row++)
382
 
            {
383
 
                T _x = this->x;
384
 
                for (size_t column=0; column < columns; column++)
385
 
                {
386
 
                    rects.emplace_back(_x, _y, ws, hs);
387
 
                    _x += ws + x_spacing;
388
 
                }
389
 
                _y += hs + y_spacing;
390
 
            }
391
 
 
392
 
            return rects;
393
 
        }
394
 
 
395
 
        // Layout num_items sub-rectangles of size item_rect in grow_horizontal or
396
 
        // columns-first order.
397
 
        void flow_layout(std::vector<TRect<T>>& rects_out,
398
 
                         TRect<T>& bounds_out,
399
 
                         const TRect<T>& item_rect, size_t num_items,
400
 
                         T x_spacing, T y_spacing,
401
 
                         bool flow_horizontally=true,
402
 
                         bool grow_horizontally=true) const
403
 
        {
404
 
            int nrows;
405
 
            int ncols;
406
 
            rects_out.clear();
407
 
            bounds_out = *this;
408
 
 
409
 
            if (grow_horizontally)
410
 
            {
411
 
                // "This" determines height and minimum width.
412
 
                // Items may overflow the minimum width.
413
 
                nrows = int((h + y_spacing) / (item_rect.h + y_spacing));
414
 
                ncols = int(std::ceil(num_items / static_cast<T>(nrows)));
415
 
                bounds_out.w = 0;
416
 
            }
417
 
            else
418
 
            {
419
 
                // "This" determines width and minimum height.
420
 
                // Items may overflow the minimum height.
421
 
                ncols = int((w + x_spacing) / (item_rect.w + x_spacing));
422
 
                nrows = int(ceil(num_items / static_cast<T>(ncols)));
423
 
                bounds_out.h = 0;
424
 
            }
425
 
 
426
 
            if (flow_horizontally)
427
 
            {
428
 
                for (int row=0; row < nrows; row++)
429
 
                {
430
 
                    for (int col=0; col < ncols; col++)
431
 
                    {
432
 
                        T _x = x + item_rect.w * col +
433
 
                               x_spacing * std::max((col - 1), 0);
434
 
                        T _y = y + item_rect.h * row +
435
 
                               y_spacing * std::max((row - 1), 0);
436
 
                        TRect<T> r(_x, _y, item_rect.w, item_rect.h);
437
 
                        bounds_out = bounds_out.union_(r);
438
 
                        rects_out.push_back(r);
439
 
 
440
 
                        if (rects_out.size() >= num_items)
441
 
                            break;
442
 
                    }
443
 
 
444
 
                    if (rects_out.size() >= num_items)
445
 
                        break;
446
 
                }
447
 
            }
448
 
            else
449
 
            {
450
 
                for (int col=0; col < ncols; col++)
451
 
                {
452
 
                    for (int row=0; row < nrows; row++)
453
 
                    {
454
 
                        T _x = x + item_rect.w * col +
455
 
                               x_spacing * std::max((col - 1), 0);
456
 
                        T _y = y + item_rect.h * row +
457
 
                               y_spacing * std::max((row - 1), 0);
458
 
                        TRect<T> r(_x, _y, item_rect.w, item_rect.h);
459
 
                        bounds_out = bounds_out.union_(r);
460
 
                        rects_out.push_back(r);
461
 
 
462
 
                        if (rects_out.size() >= num_items)
463
 
                            break;
464
 
                    }
465
 
 
466
 
                    if (rects_out.size() >= num_items)
467
 
                        break;
468
 
                }
469
 
            }
470
 
        }
471
 
 
472
 
    public:
473
 
        T x{};
474
 
        T y{};
475
 
        T w{};
476
 
        T h{};
477
 
};
478
 
 
479
 
typedef TRect<double> Rect;
480
 
typedef TRect<int>    RectInt;
 
13
#include "border.h"
 
14
#include "rect_decl.h"
 
15
 
 
16
template<class T>
 
17
T& TRect<T>::operator[](size_t index) {
 
18
    switch (index)
 
19
    {
 
20
        case 0: return x;
 
21
        case 1: return y;
 
22
        case 2: return w;
 
23
        case 3: return h;
 
24
        default: assert(false);  // invalid index
 
25
    }
 
26
}
 
27
 
 
28
template<class T>
 
29
TRect<T> TRect<T>::inflate(const TBorder<T>& b) const {
 
30
    return {x - b.left, y - b.top,
 
31
                w + b.left + b.right,
 
32
                h + b.top + b.bottom};
 
33
}
 
34
 
 
35
template<class T>
 
36
TRect<T> TRect<T>::round() const {
 
37
    return {std::round(x), std::round(y), std::round(w), std::round(h)};
 
38
}
 
39
 
 
40
template<class T>
 
41
TRect<T> TRect<T>::floor() const {
 
42
    return {std::floor(x), std::floor(y), std::floor(w), std::floor(h)};
 
43
}
 
44
 
 
45
template<class T>
 
46
TRect<T> TRect<T>::intersection(const TRect<T>& rect) const
 
47
{
 
48
    T x0 = std::max(x, rect.x);
 
49
    T y0 = std::max(y, rect.y);
 
50
    T x1 = std::min(x + w, rect.x + rect.w);
 
51
    T y1 = std::min(y + h, rect.y + rect.h);
 
52
    if (x0 > x1 || y0 > y1)
 
53
        return {};
 
54
    else
 
55
        return {x0, y0, x1 - x0, y1 - y0};
 
56
}
 
57
 
 
58
template<class T>
 
59
TRect<T> TRect<T>::union_(const TRect<T>& rect) const
 
60
{
 
61
    T x0 = std::min(x, rect.x);
 
62
    T y0 = std::min(y, rect.y);
 
63
    T x1 = std::max(x + w, rect.x + rect.w);
 
64
    T y1 = std::max(y + h, rect.y + rect.h);
 
65
    return {x0, y0, x1 - x0, y1 - y0};
 
66
}
 
67
 
 
68
template<class T>
 
69
TRect<T> TRect<T>::resize_to_aspect_range(const TRect<T>& aspect_rect, T min_aspect, T max_aspect) const
 
70
{
 
71
    (void)min_aspect;  // not implemented
 
72
 
 
73
    if (empty() || aspect_rect.empty())
 
74
        return {};
 
75
 
 
76
    TRect<T> r = aspect_rect;
 
77
    if (r.h)
 
78
    {
 
79
        double a0 = r.w / static_cast<double>(r.h);
 
80
        double a0_max = a0 * max_aspect;
 
81
        double a1 = w / static_cast<double>(h);
 
82
        double a = std::min(a1, a0_max);
 
83
 
 
84
        r = {0, 0, a, 1.0};
 
85
    }
 
86
    return resize_to_aspect(r);
 
87
}
 
88
 
 
89
template<class T>
 
90
std::vector<TRect<T>> TRect<T>::subdivide(size_t columns, size_t rows, T x_spacing, T y_spacing) const
 
91
{
 
92
    T ws = static_cast<T>(
 
93
               (this->w - (columns - 1) * x_spacing) / static_cast<double>(columns));
 
94
    T hs = static_cast<T>(
 
95
               (this->h - (rows - 1)    * y_spacing) / static_cast<double>(rows));
 
96
 
 
97
    std::vector<TRect<T>> rects;
 
98
    T _y = this->y;
 
99
    for (size_t row=0; row < rows; row++)
 
100
    {
 
101
        T _x = this->x;
 
102
        for (size_t column=0; column < columns; column++)
 
103
        {
 
104
            rects.emplace_back(_x, _y, ws, hs);
 
105
            _x += ws + x_spacing;
 
106
        }
 
107
        _y += hs + y_spacing;
 
108
    }
 
109
 
 
110
    return rects;
 
111
}
 
112
 
 
113
template<class T>
 
114
void TRect<T>::flow_layout(std::vector<TRect<T> >& rects_out, TRect<T>& bounds_out, const TRect<T>& item_rect, size_t num_items, T x_spacing, T y_spacing, bool flow_horizontally, bool grow_horizontally) const
 
115
{
 
116
    int nrows;
 
117
    int ncols;
 
118
    rects_out.clear();
 
119
    bounds_out = *this;
 
120
 
 
121
    if (grow_horizontally)
 
122
    {
 
123
        // "This" determines height and minimum width.
 
124
        // Items may overflow the minimum width.
 
125
        nrows = int((h + y_spacing) / (item_rect.h + y_spacing));
 
126
        ncols = int(std::ceil(num_items / static_cast<T>(nrows)));
 
127
        bounds_out.w = 0;
 
128
    }
 
129
    else
 
130
    {
 
131
        // "This" determines width and minimum height.
 
132
        // Items may overflow the minimum height.
 
133
        ncols = int((w + x_spacing) / (item_rect.w + x_spacing));
 
134
        nrows = int(ceil(num_items / static_cast<T>(ncols)));
 
135
        bounds_out.h = 0;
 
136
    }
 
137
 
 
138
    if (flow_horizontally)
 
139
    {
 
140
        for (int row=0; row < nrows; row++)
 
141
        {
 
142
            for (int col=0; col < ncols; col++)
 
143
            {
 
144
                T _x = x + item_rect.w * col +
 
145
                       x_spacing * std::max((col - 1), 0);
 
146
                T _y = y + item_rect.h * row +
 
147
                       y_spacing * std::max((row - 1), 0);
 
148
                TRect<T> r(_x, _y, item_rect.w, item_rect.h);
 
149
                bounds_out = bounds_out.union_(r);
 
150
                rects_out.push_back(r);
 
151
 
 
152
                if (rects_out.size() >= num_items)
 
153
                    break;
 
154
            }
 
155
 
 
156
            if (rects_out.size() >= num_items)
 
157
                break;
 
158
        }
 
159
    }
 
160
    else
 
161
    {
 
162
        for (int col=0; col < ncols; col++)
 
163
        {
 
164
            for (int row=0; row < nrows; row++)
 
165
            {
 
166
                T _x = x + item_rect.w * col +
 
167
                       x_spacing * std::max((col - 1), 0);
 
168
                T _y = y + item_rect.h * row +
 
169
                       y_spacing * std::max((row - 1), 0);
 
170
                TRect<T> r(_x, _y, item_rect.w, item_rect.h);
 
171
                bounds_out = bounds_out.union_(r);
 
172
                rects_out.push_back(r);
 
173
 
 
174
                if (rects_out.size() >= num_items)
 
175
                    break;
 
176
            }
 
177
 
 
178
            if (rects_out.size() >= num_items)
 
179
                break;
 
180
        }
 
181
    }
 
182
}
481
183
 
482
184
template<class T>
483
185
std::ostream& operator<<(std::ostream& s, const TRect<T>& r){