1 // Copyright (C) 2002-2012 Nikolaus Gebhardt 2 // This file is part of the "Irrlicht Engine". 3 // For conditions of distribution and use, see copyright notice in irrlicht.h 4 5 #ifndef __IRR_RECT_H_INCLUDED__ 6 #define __IRR_RECT_H_INCLUDED__ 7 8 #include "irrTypes.h" 9 #include "dimension2d.h" 10 #include "position2d.h" 11 12 namespace irr 13 { 14 namespace core 15 { 16 17 //! Rectangle template. 18 /** Mostly used by 2D GUI elements and for 2D drawing methods. 19 It has 2 positions instead of position and dimension and a fast 20 method for collision detection with other rectangles and points. 21 22 Coordinates are (0,0) for top-left corner, and increasing to the right 23 and to the bottom. 24 */ 25 template <class T> 26 class rect 27 { 28 public: 29 30 //! Default constructor creating empty rectangle at (0,0) rect()31 rect() : UpperLeftCorner(0,0), LowerRightCorner(0,0) {} 32 33 //! Constructor with two corners rect(T x,T y,T x2,T y2)34 rect(T x, T y, T x2, T y2) 35 : UpperLeftCorner(x,y), LowerRightCorner(x2,y2) {} 36 37 //! Constructor with two corners rect(const position2d<T> & upperLeft,const position2d<T> & lowerRight)38 rect(const position2d<T>& upperLeft, const position2d<T>& lowerRight) 39 : UpperLeftCorner(upperLeft), LowerRightCorner(lowerRight) {} 40 41 //! Constructor with upper left corner and dimension 42 template <class U> rect(const position2d<T> & pos,const dimension2d<U> & size)43 rect(const position2d<T>& pos, const dimension2d<U>& size) 44 : UpperLeftCorner(pos), LowerRightCorner(pos.X + size.Width, pos.Y + size.Height) {} 45 46 //! move right by given numbers 47 rect<T> operator+(const position2d<T>& pos) const 48 { 49 rect<T> ret(*this); 50 return ret+=pos; 51 } 52 53 //! move right by given numbers 54 rect<T>& operator+=(const position2d<T>& pos) 55 { 56 UpperLeftCorner += pos; 57 LowerRightCorner += pos; 58 return *this; 59 } 60 61 //! move left by given numbers 62 rect<T> operator-(const position2d<T>& pos) const 63 { 64 rect<T> ret(*this); 65 return ret-=pos; 66 } 67 68 //! move left by given numbers 69 rect<T>& operator-=(const position2d<T>& pos) 70 { 71 UpperLeftCorner -= pos; 72 LowerRightCorner -= pos; 73 return *this; 74 } 75 76 //! equality operator 77 bool operator==(const rect<T>& other) const 78 { 79 return (UpperLeftCorner == other.UpperLeftCorner && 80 LowerRightCorner == other.LowerRightCorner); 81 } 82 83 //! inequality operator 84 bool operator!=(const rect<T>& other) const 85 { 86 return (UpperLeftCorner != other.UpperLeftCorner || 87 LowerRightCorner != other.LowerRightCorner); 88 } 89 90 //! compares size of rectangles 91 bool operator<(const rect<T>& other) const 92 { 93 return getArea() < other.getArea(); 94 } 95 96 //! Returns size of rectangle getArea()97 T getArea() const 98 { 99 return getWidth() * getHeight(); 100 } 101 102 //! Returns if a 2d point is within this rectangle. 103 /** \param pos Position to test if it lies within this rectangle. 104 \return True if the position is within the rectangle, false if not. */ isPointInside(const position2d<T> & pos)105 bool isPointInside(const position2d<T>& pos) const 106 { 107 return (UpperLeftCorner.X <= pos.X && 108 UpperLeftCorner.Y <= pos.Y && 109 LowerRightCorner.X >= pos.X && 110 LowerRightCorner.Y >= pos.Y); 111 } 112 113 //! Check if the rectangle collides with another rectangle. 114 /** \param other Rectangle to test collision with 115 \return True if the rectangles collide. */ isRectCollided(const rect<T> & other)116 bool isRectCollided(const rect<T>& other) const 117 { 118 return (LowerRightCorner.Y > other.UpperLeftCorner.Y && 119 UpperLeftCorner.Y < other.LowerRightCorner.Y && 120 LowerRightCorner.X > other.UpperLeftCorner.X && 121 UpperLeftCorner.X < other.LowerRightCorner.X); 122 } 123 124 //! Clips this rectangle with another one. 125 /** \param other Rectangle to clip with */ clipAgainst(const rect<T> & other)126 void clipAgainst(const rect<T>& other) 127 { 128 if (other.LowerRightCorner.X < LowerRightCorner.X) 129 LowerRightCorner.X = other.LowerRightCorner.X; 130 if (other.LowerRightCorner.Y < LowerRightCorner.Y) 131 LowerRightCorner.Y = other.LowerRightCorner.Y; 132 133 if (other.UpperLeftCorner.X > UpperLeftCorner.X) 134 UpperLeftCorner.X = other.UpperLeftCorner.X; 135 if (other.UpperLeftCorner.Y > UpperLeftCorner.Y) 136 UpperLeftCorner.Y = other.UpperLeftCorner.Y; 137 138 // correct possible invalid rect resulting from clipping 139 if (UpperLeftCorner.Y > LowerRightCorner.Y) 140 UpperLeftCorner.Y = LowerRightCorner.Y; 141 if (UpperLeftCorner.X > LowerRightCorner.X) 142 UpperLeftCorner.X = LowerRightCorner.X; 143 } 144 145 //! Moves this rectangle to fit inside another one. 146 /** \return True on success, false if not possible */ constrainTo(const rect<T> & other)147 bool constrainTo(const rect<T>& other) 148 { 149 if (other.getWidth() < getWidth() || other.getHeight() < getHeight()) 150 return false; 151 152 T diff = other.LowerRightCorner.X - LowerRightCorner.X; 153 if (diff < 0) 154 { 155 LowerRightCorner.X += diff; 156 UpperLeftCorner.X += diff; 157 } 158 159 diff = other.LowerRightCorner.Y - LowerRightCorner.Y; 160 if (diff < 0) 161 { 162 LowerRightCorner.Y += diff; 163 UpperLeftCorner.Y += diff; 164 } 165 166 diff = UpperLeftCorner.X - other.UpperLeftCorner.X; 167 if (diff < 0) 168 { 169 UpperLeftCorner.X -= diff; 170 LowerRightCorner.X -= diff; 171 } 172 173 diff = UpperLeftCorner.Y - other.UpperLeftCorner.Y; 174 if (diff < 0) 175 { 176 UpperLeftCorner.Y -= diff; 177 LowerRightCorner.Y -= diff; 178 } 179 180 return true; 181 } 182 183 //! Get width of rectangle. getWidth()184 T getWidth() const 185 { 186 return LowerRightCorner.X - UpperLeftCorner.X; 187 } 188 189 //! Get height of rectangle. getHeight()190 T getHeight() const 191 { 192 return LowerRightCorner.Y - UpperLeftCorner.Y; 193 } 194 195 //! If the lower right corner of the rect is smaller then the upper left, the points are swapped. repair()196 void repair() 197 { 198 if (LowerRightCorner.X < UpperLeftCorner.X) 199 { 200 T t = LowerRightCorner.X; 201 LowerRightCorner.X = UpperLeftCorner.X; 202 UpperLeftCorner.X = t; 203 } 204 205 if (LowerRightCorner.Y < UpperLeftCorner.Y) 206 { 207 T t = LowerRightCorner.Y; 208 LowerRightCorner.Y = UpperLeftCorner.Y; 209 UpperLeftCorner.Y = t; 210 } 211 } 212 213 //! Returns if the rect is valid to draw. 214 /** It would be invalid if the UpperLeftCorner is lower or more 215 right than the LowerRightCorner. */ isValid()216 bool isValid() const 217 { 218 return ((LowerRightCorner.X >= UpperLeftCorner.X) && 219 (LowerRightCorner.Y >= UpperLeftCorner.Y)); 220 } 221 222 //! Get the center of the rectangle getCenter()223 position2d<T> getCenter() const 224 { 225 return position2d<T>( 226 (UpperLeftCorner.X + LowerRightCorner.X) / 2, 227 (UpperLeftCorner.Y + LowerRightCorner.Y) / 2); 228 } 229 230 //! Get the dimensions of the rectangle getSize()231 dimension2d<T> getSize() const 232 { 233 return dimension2d<T>(getWidth(), getHeight()); 234 } 235 236 237 //! Adds a point to the rectangle 238 /** Causes the rectangle to grow bigger if point is outside of 239 the box 240 \param p Point to add to the box. */ addInternalPoint(const position2d<T> & p)241 void addInternalPoint(const position2d<T>& p) 242 { 243 addInternalPoint(p.X, p.Y); 244 } 245 246 //! Adds a point to the bounding rectangle 247 /** Causes the rectangle to grow bigger if point is outside of 248 the box 249 \param x X-Coordinate of the point to add to this box. 250 \param y Y-Coordinate of the point to add to this box. */ addInternalPoint(T x,T y)251 void addInternalPoint(T x, T y) 252 { 253 if (x>LowerRightCorner.X) 254 LowerRightCorner.X = x; 255 if (y>LowerRightCorner.Y) 256 LowerRightCorner.Y = y; 257 258 if (x<UpperLeftCorner.X) 259 UpperLeftCorner.X = x; 260 if (y<UpperLeftCorner.Y) 261 UpperLeftCorner.Y = y; 262 } 263 264 //! Upper left corner 265 position2d<T> UpperLeftCorner; 266 //! Lower right corner 267 position2d<T> LowerRightCorner; 268 }; 269 270 //! Rectangle with float values 271 typedef rect<f32> rectf; 272 //! Rectangle with int values 273 typedef rect<s32> recti; 274 275 } // end namespace core 276 } // end namespace irr 277 278 #endif 279 280