add Rect::shrink(Distance) even though it arguably should be handled by Rect::expand()
[ardour.git] / libs / canvas / types.cc
1 /*
2     Copyright (C) 2011-2013 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <algorithm>
21 #include <cfloat>
22 #include <cassert>
23
24 #include <cairomm/context.h>
25
26 #include "canvas/types.h"
27
28 using namespace std;
29 using namespace ArdourCanvas;
30
31 Coord const ArdourCanvas::COORD_MAX = 1.7e307;
32
33 static inline Coord
34 safe_add (Coord a, Coord b)
35 {
36         if (((COORD_MAX - a) <= b) || ((COORD_MAX - b) <= a)) {
37                 return COORD_MAX;
38         }
39
40         return a + b;
41 }
42
43 Duple
44 Duple::translate (Duple t) const
45 {
46         Duple d;
47
48         d.x = safe_add (x, t.x);
49         d.y = safe_add (y, t.y);
50         
51         return d;
52 }
53
54 boost::optional<Rect>
55 Rect::intersection (Rect const & o) const
56 {
57         Rect i;
58         
59         i.x0 = max (x0, o.x0);
60         i.y0 = max (y0, o.y0);
61         i.x1 = min (x1, o.x1);
62         i.y1 = min (y1, o.y1);
63
64         if (i.x0 > i.x1 || i.y0 > i.y1) {
65                 return boost::optional<Rect> ();
66         }
67         
68         return boost::optional<Rect> (i);
69 }
70
71 Rect
72 Rect::translate (Duple t) const
73 {
74         Rect r;
75
76         r.x0 = safe_add (x0, t.x);
77         r.y0 = safe_add (y0, t.y);
78         r.x1 = safe_add (x1, t.x);
79         r.y1 = safe_add (y1, t.y);
80         return r;
81 }
82
83 Rect
84 Rect::extend (Rect const & o) const
85 {
86         Rect r;
87         r.x0 = min (x0, o.x0);
88         r.y0 = min (y0, o.y0);
89         r.x1 = max (x1, o.x1);
90         r.y1 = max (y1, o.y1);
91         return r;
92 }
93
94 Rect
95 Rect::expand (Distance amount) const
96 {
97         Rect r;
98         r.x0 = x0 - amount;
99         r.y0 = y0 - amount;
100         r.x1 = safe_add (x1, amount);
101         r.y1 = safe_add (y1, amount);
102         return r;
103 }
104
105 Rect
106 Rect::shrink (Distance amount) const
107 {
108         /* This isn't the equivalent of expand (-distance) because
109            of the peculiarities of safe_add() with negative values.
110            Maybe.
111         */
112
113         Rect r;
114
115         r.x0 = safe_add (x0, amount);
116         r.y0 = safe_add (y0, amount);
117         r.x1 = x1 - amount;
118         r.y1 = y1 - amount;
119
120         return r;
121 }
122
123 bool
124 Rect::contains (Duple point) const
125 {
126         return point.x >= x0 && point.x <= x1 && point.y >= y0 && point.y <= y1;
127 }
128
129 Rect
130 Rect::fix () const
131 {
132         Rect r;
133         
134         r.x0 = min (x0, x1);
135         r.y0 = min (y0, y1);
136         r.x1 = max (x0, x1);
137         r.y1 = max (y0, y1);
138
139         return r;
140 }
141
142 bool
143 ArdourCanvas::operator!= (Rect const& a, Rect const& b)
144 {
145         return a.x0 != b.x0 ||
146                 a.x1 != b.x1 ||
147                 a.y0 != b.y0 ||
148                 a.y1 != b.y1;
149 }
150
151
152 Duple
153 ArdourCanvas::operator- (Duple const & o)
154 {
155         return Duple (-o.x, -o.y);
156 }
157
158 Duple
159 ArdourCanvas::operator+ (Duple const & a, Duple const & b)
160 {
161         return Duple (safe_add (a.x, b.x), safe_add (a.y, b.y));
162 }
163
164 bool
165 ArdourCanvas::operator== (Duple const & a, Duple const & b)
166 {
167         return a.x == b.x && a.y == b.y;
168 }
169
170 bool
171 ArdourCanvas::operator!= (Duple const & a, Duple const & b)
172 {
173         return a.x != b.x || a.y != b.y;
174 }
175
176 Duple
177 ArdourCanvas::operator- (Duple const & a, Duple const & b)
178 {
179         return Duple (a.x - b.x, a.y - b.y);
180 }
181
182 Duple
183 ArdourCanvas::operator/ (Duple const & a, double b)
184 {
185         return Duple (a.x / b, a.y / b);
186 }
187
188 ostream &
189 ArdourCanvas::operator<< (ostream & s, Duple const & r)
190 {
191         s << "(" << r.x << ", " << r.y << ")";
192         return s;
193 }
194
195 ostream &
196 ArdourCanvas::operator<< (ostream & s, Rect const & r)
197 {
198         s << "[(" << r.x0 << ", " << r.y0 << "), (" << r.x1 << ", " << r.y1 << ") " << r.width() << " x " << r.height() << "]";
199         return s;
200 }
201