1 // SPDX-FileCopyrightText: 2002 Dominique Devriese <devriese@kde.org>
2 
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 #include "rect.h"
6 #include "common.h"
7 
operator =(const Rect & other)8 Rect& Rect::operator=( const Rect& other )
9 {
10   if (this != &other)
11   {
12     setBottomLeft( other.bottomLeft() );
13     setWidth( other.width() );
14     setHeight( other.height() );
15   }
16   normalize();
17   return *this;
18 }
19 
operator ==(const Rect & r,const Rect & s)20 bool operator==( const Rect& r, const Rect& s )
21 {
22   return ( r.bottomLeft() == s.bottomLeft()
23            && r.width() == s.width()
24            && r.height() == s.height() );
25 }
26 
operator <<(QDebug & s,const Rect & t)27 QDebug& operator<<( QDebug& s, const Rect& t )
28 {
29   s << "left: " << t.left()
30     << "bottom: " << t.bottom()
31     << "right: " << t.right()
32     << "top: " << t.top();
33   return s;
34 }
35 
Rect(const Coordinate & bottomLeft,const Coordinate & topRight)36 Rect::Rect( const Coordinate &bottomLeft, const Coordinate &topRight )
37   : mBottomLeft(bottomLeft)
38 {
39   mwidth = topRight.x - bottomLeft.x;
40   mheight = topRight.y - bottomLeft.y;
41   normalize();
42 }
43 
Rect(const Coordinate & p,const double width,const double height)44 Rect::Rect( const Coordinate &p, const double width, const double height )
45   : mBottomLeft(p),
46     mwidth(width),
47     mheight(height)
48 {
49   normalize();
50 }
51 
Rect(double xa,double ya,double width,double height)52 Rect::Rect( double xa, double ya, double width, double height )
53   : mBottomLeft( xa, ya ),
54     mwidth( width ),
55     mheight( height )
56 {
57   normalize();
58 }
59 
Rect(const Rect & r)60 Rect::Rect( const Rect& r )
61   : mBottomLeft (r.mBottomLeft),
62     mwidth(r.mwidth),
63     mheight(r.mheight)
64 {
65   normalize();
66 }
67 
Rect()68 Rect::Rect()
69   : mwidth(0),
70     mheight(0)
71 {
72 }
73 
setBottomLeft(const Coordinate & p)74 void Rect::setBottomLeft( const Coordinate &p )
75 {
76   mBottomLeft = p;
77 }
78 
setBottomRight(const Coordinate & p)79 void Rect::setBottomRight( const Coordinate &p )
80 {
81   mBottomLeft = p - Coordinate(mwidth,0);
82 }
83 
setTopRight(const Coordinate & p)84 void Rect::setTopRight( const Coordinate &p )
85 {
86   mBottomLeft = p - Coordinate(mwidth, mheight);
87 }
88 
setCenter(const Coordinate & p)89 void Rect::setCenter( const Coordinate &p )
90 {
91   mBottomLeft = p - Coordinate(mwidth, mheight)/2;
92 }
93 
setLeft(const double p)94 void Rect::setLeft( const double p )
95 {
96   double r = right();
97   mBottomLeft.x = p;
98   setRight( r );
99 }
100 
setRight(const double p)101 void Rect::setRight( const double p )
102 {
103   mwidth = p - left();
104 }
105 
setBottom(const double p)106 void Rect::setBottom( const double p )
107 {
108   double t = top();
109   mBottomLeft.y = p;
110   setTop( t );
111 }
112 
setTop(const double p)113 void Rect::setTop( const double p )
114 {
115   mheight = p - bottom();
116 }
117 
setWidth(const double w)118 void Rect::setWidth( const double w )
119 {
120   mwidth = w;
121 }
122 
setHeight(const double h)123 void Rect::setHeight( const double h )
124 {
125   mheight = h;
126 }
127 
normalize()128 void Rect::normalize()
129 {
130   if ( mwidth < 0 )
131     {
132       mBottomLeft.x += mwidth;
133       mwidth = -mwidth;
134     };
135   if ( mheight < 0 )
136     {
137       mBottomLeft.y += mheight;
138       mheight = -mheight;
139     };
140 }
141 
moveBy(const Coordinate & p)142 void Rect::moveBy( const Coordinate &p )
143 {
144   mBottomLeft += p;
145 }
146 
scale(const double r)147 void Rect::scale( const double r )
148 {
149   mwidth *= r;
150   mheight *= r;
151 }
152 
153 
toQRect() const154 QRect Rect::toQRect() const
155 {
156   return QRect(mBottomLeft.toQPoint(), topRight().toQPoint());
157 }
158 
bottomLeft() const159 Coordinate Rect::bottomLeft() const
160 {
161   return mBottomLeft;
162 }
163 
bottomRight() const164 Coordinate Rect::bottomRight() const
165 {
166   return mBottomLeft + Coordinate(mwidth, 0);
167 }
168 
topLeft() const169 Coordinate Rect::topLeft() const
170 {
171   return mBottomLeft + Coordinate(0, mheight);
172 }
173 
topRight() const174 Coordinate Rect::topRight() const
175 {
176   return mBottomLeft + Coordinate(mwidth, mheight);
177 }
178 
center() const179 Coordinate Rect::center() const
180 {
181   return mBottomLeft + Coordinate(mwidth, mheight)/2;
182 }
183 
left() const184 double Rect::left() const
185 {
186   return mBottomLeft.x;
187 }
right() const188 double Rect::right() const
189 {
190   return left() + mwidth;
191 }
bottom() const192 double Rect::bottom() const
193 {
194   return mBottomLeft.y;
195 }
196 
top() const197 double Rect::top() const
198 {
199   return bottom() + mheight;
200 }
201 
width() const202 double Rect::width() const
203 {
204   return mwidth;
205 }
206 
height() const207 double Rect::height() const
208 {
209   return mheight;
210 }
211 
contains(const Coordinate & p,double allowed_miss) const212 bool Rect::contains( const Coordinate& p, double allowed_miss ) const
213 {
214   return p.x - left() >= - allowed_miss &&
215     p.y - bottom() >= - allowed_miss &&
216     p.x - left() - width() <= allowed_miss &&
217     p.y - bottom() - height() <= allowed_miss;
218 }
219 
contains(const Coordinate & p) const220 bool Rect::contains( const Coordinate& p ) const
221 {
222   return p.x >= left() &&
223     p.y >= bottom() &&
224     p.x - left() <= width() &&
225     p.y - bottom() <= height();
226 }
227 
intersects(const Rect & p) const228 bool Rect::intersects( const Rect& p ) const
229 {
230   // never thought it was this simple :)
231   if( p.left() < left() && p.right() < left()) return false;
232   if( p.left() > right() && p.right() > right()) return false;
233   if( p.bottom() < bottom() && p.top() < bottom()) return false;
234   if( p.bottom() > top() && p.top() > top()) return false;
235   return true;
236 }
237 
setContains(const Coordinate & p)238 void Rect::setContains( const Coordinate &p )
239 {
240   normalize();
241   if( p.x < left() ) setLeft( p.x );
242   if( p.x > right() ) setRight(p.x);
243   if( p.y < bottom() ) setBottom( p.y );
244   if( p.y > top() ) setTop( p.y );
245 }
246 
normalized() const247 Rect Rect::normalized() const
248 {
249   Rect t = *this;
250   (void) t.normalize();
251   return t;
252 }
253 
fromQRect(const QRect & r)254 Rect Rect::fromQRect( const QRect& r )
255 {
256   return Rect( r.left(), r.top(), r.right(), r.bottom() );
257 }
258 
setTopLeft(const Coordinate & p)259 void Rect::setTopLeft( const Coordinate &p )
260 {
261   Coordinate bl = Coordinate( p.x, p.y - mheight );
262   setBottomLeft( bl );
263 }
264 
operator |(const Rect & lhs,const Rect & rhs)265 Rect operator|( const Rect& lhs, const Rect& rhs )
266 {
267   Rect r( lhs );
268   r |= rhs;
269   return r;
270 }
271 
eat(const Rect & r)272 void Rect::eat( const Rect& r )
273 {
274   setLeft( kigMin( left(), r.left() ) );
275   setRight( kigMax( right(), r.right() ) );
276   setBottom( kigMin( bottom(), r.bottom() ) );
277   setTop( kigMax( top(), r.top() ) );
278 }
279 
matchShape(const Rect & rhs,bool shrink) const280 Rect Rect::matchShape( const Rect& rhs, bool shrink ) const
281 {
282   Rect ret = *this;
283   Coordinate c = center();
284   double v = width()/height(); // current ratio
285   double w = rhs.width()/rhs.height(); // wanted ratio
286 
287   // we don't show less than r, if the dimensions don't match, we
288   // extend r into some dimension...
289   if( ( v > w ) ^ shrink )
290     ret.setHeight( ret.width() / w );
291   else
292     ret.setWidth( ret.height() * w );
293 
294   ret.setCenter(c);
295   return ret.normalized();
296 }
297 
valid()298 bool Rect::valid()
299 {
300   return mBottomLeft.valid() && mwidth != double_inf && mheight != double_inf;
301 }
302 
invalidRect()303 Rect Rect::invalidRect()
304 {
305   return Rect( Coordinate::invalidCoord(), double_inf, double_inf );
306 }
307