1 /* 2 DSFML - The Simple and Fast Multimedia Library for D 3 4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 6 This software is provided 'as-is', without any express or implied warranty. 7 In no event will the authors be held liable for any damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial applications, 10 and to alter it and redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 14 15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 16 17 3. This notice may not be removed or altered from any source distribution 18 */ 19 20 module dsfml.graphics.rect; 21 22 import std.traits; 23 24 import dsfml.system.vector2; 25 26 /++ 27 + Utility class for manipulating 2D axis aligned rectangles. 28 + 29 + A rectangle is defined by its top-left corner and its size. 30 + 31 + It is a very simple class defined for convenience, so its member variables (left, top, width and height) are public and can be accessed directly, just like the vector classes (Vector2 and Vector3). 32 + 33 + To keep things simple, Rect doesn't define functions to emulate the properties that are not directly members (such as right, bottom, center, etc.), it rather only provides intersection functions. 34 + 35 + Rect uses the usual rules for its boundaries: 36 + - The let and top edges are included in the rectangle's area 37 + - The right (left + width) and bottom (top + height) edges are excluded from the rectangle's area 38 + 39 + This means that IntRect(0, 0, 1, 1) and IntRect(1, 1, 1, 1) don't intersect. 40 + 41 + Rect is a template and may be used with any numeric type, but for simplicity the instanciations used by SFML are typedefed: 42 + - Rect!(int) is IntRect 43 + - Rect!(float) is FloatRect 44 + 45 + So that you don't have to care about the template syntax. 46 + 47 + Authors: Laurent Gomila, Jeremy DeHaan 48 + See_Also: http://www.sfml-dev.org/documentation/2.0/classsf_1_1Rect.php#details 49 +/ 50 struct Rect(T) 51 if(isNumeric!(T)) 52 { 53 /// Left coordinate of the rectangle. 54 T left = 0; 55 /// Top coordinate of the rectangle. 56 T top = 0; 57 /// Width of the rectangle. 58 T width= 0; 59 /// HEight of the rectangle. 60 T height = 0; 61 62 63 this(T rectLeft, T rectTop, T rectWidth, T rectHeight) 64 { 65 left = rectLeft; 66 top = rectTop; 67 width = rectWidth; 68 height = rectHeight; 69 } 70 71 this(Vector2!(T) position, Vector2!(T) size) 72 { 73 left = position.x; 74 top = position.y; 75 width = size.x; 76 height = size.y; 77 } 78 79 /** 80 * Check if a point is inside the rectangle's area. 81 * 82 * Params: 83 * x = X coordinate of the point to test 84 * y = Y coordinate of the point to test 85 * 86 * Returns: True if the point is inside, false otherwise. 87 */ 88 bool contains(E)(E X, E Y) const 89 if(isNumeric!(E)) 90 { 91 if(left <= X && X<= (left + width)) 92 { 93 if(top <= Y && Y <= (top + height)) 94 { 95 return true; 96 } 97 else 98 { 99 return false; 100 } 101 } 102 else 103 { 104 return false; 105 } 106 } 107 108 /** 109 * Check if a point is inside the rectangle's area. 110 * 111 * Params: 112 * point = Point to test 113 * 114 * Returns: True if the point is inside, false otherwise. 115 */ 116 bool contains(E)(Vector2!(E) point) const 117 if(isNumeric!(E)) 118 { 119 if(left <= point.x && point.x<= (left + width)) 120 { 121 if(top <= point.y && point.y <= (top + height)) 122 { 123 return true; 124 } 125 else 126 { 127 return false; 128 } 129 } 130 else 131 { 132 return false; 133 } 134 } 135 136 /** 137 * Check the intersection between two rectangles. 138 * 139 * Params: 140 * rectangle = Rectangle to test 141 * 142 * Returns: True if rectangles overlap, false otherwise. 143 */ 144 bool intersects(E)(Rect!(E) rectangle) const 145 if(isNumeric!(E)) 146 { 147 Rect!(T) rect; 148 149 return intersects(rectangle, rect); 150 } 151 152 /** 153 * Check the intersection between two rectangles. 154 * 155 * This overload returns the overlapped rectangle in the intersection parameter. 156 * 157 * Params: 158 * rectangle = Rectangle to test 159 * intersection = Rectangle to be filled with the intersection 160 * 161 * Returns: True if rectangles overlap, false otherwise. 162 */ 163 bool intersects(E,O)(Rect!(E) rectangle, out Rect!(O) intersection) const 164 if(isNumeric!(E) && isNumeric!(O)) 165 { 166 O interLeft = intersection.max(left, rectangle.left); 167 O interTop = intersection.max(top, rectangle.top); 168 O interRight = intersection.min(left + width, rectangle.left + rectangle.width); 169 O interBottom = intersection.min(top + height, rectangle.top + rectangle.height); 170 171 if ((interLeft < interRight) && (interTop < interBottom)) 172 { 173 intersection = Rect!(O)(interLeft, interTop, interRight - interLeft, interBottom - interTop); 174 return true; 175 } 176 else 177 { 178 intersection = Rect!(O)(0, 0, 0, 0); 179 return false; 180 } 181 } 182 183 bool opEquals(E)(const Rect!(E) otherRect) const 184 if(isNumeric!(E)) 185 { 186 return ((left == otherRect.left) && (top == otherRect.top) && (width == otherRect.width) && (height == otherRect.height) ); 187 } 188 189 string toString() 190 { 191 import std.conv; 192 return "Left: " ~ text(left) ~ " Top: " ~ text(top) ~ " Width: " ~ text(width) ~ " Height: " ~ text(height); 193 } 194 195 private T max(T a, T b) 196 { 197 if(a>b) 198 { 199 return a; 200 } 201 else 202 { 203 return b; 204 } 205 } 206 207 private T min(T a, T b) 208 { 209 if(a<b) 210 { 211 return a; 212 } 213 else 214 { 215 return b; 216 } 217 } 218 219 } 220 221 unittest 222 { 223 version(DSFML_Unittest_Graphics) 224 { 225 import std.stdio; 226 227 writeln("Unit test for Rect"); 228 229 auto rect1 = IntRect(0,0,100,100); 230 auto rect2 = IntRect(10,10,100,100); 231 auto rect3 = IntRect(10,10,10,10); 232 auto point = Vector2f(-20,-20); 233 234 235 236 assert(rect1.intersects(rect2)); 237 238 FloatRect interRect; 239 240 rect1.intersects(rect2, interRect); 241 242 assert(interRect == IntRect(10,10, 90, 90)); 243 244 assert(rect1.contains(10,10)); 245 246 assert(!rect1.contains(point)); 247 248 writeln(); 249 } 250 } 251 252 alias Rect!(int) IntRect; 253 alias Rect!(float) FloatRect;