1 /** 2 2D Axis-aligned bounding box. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.core.rect2; 14 15 import godot.core.defs; 16 import godot.core.vector2, godot.core.transform2d; 17 18 import std.algorithm.comparison; 19 import std.algorithm.mutation : swap; 20 21 /** 22 Rect2 consists of a position, a size, and several utility functions. It is typically used for fast overlap tests. 23 */ 24 struct Rect2 25 { 26 @nogc nothrow: 27 28 Vector2 pos; 29 Vector2 size; 30 31 this( real_t p_x, real_t p_y, real_t p_width, real_t p_height) 32 { 33 pos=Vector2(p_x,p_y); 34 size=Vector2(p_width, p_height); 35 } 36 37 real_t getArea() const { return size.width*size.height; } 38 39 bool intersects(in Rect2 p_rect) const 40 { 41 if ( pos.x >= (p_rect.pos.x + p_rect.size.width) ) 42 return false; 43 if ( (pos.x+size.width) <= p_rect.pos.x ) 44 return false; 45 if ( pos.y >= (p_rect.pos.y + p_rect.size.height) ) 46 return false; 47 if ( (pos.y+size.height) <= p_rect.pos.y ) 48 return false; 49 50 return true; 51 } 52 53 bool encloses(in Rect2 p_rect) const 54 { 55 return (p_rect.pos.x>=pos.x) && (p_rect.pos.y>=pos.y) && 56 ((p_rect.pos.x+p_rect.size.x)<(pos.x+size.x)) && 57 ((p_rect.pos.y+p_rect.size.y)<(pos.y+size.y)); 58 } 59 bool hasNoArea() const 60 { 61 return (size.x<=0 || size.y<=0); 62 } 63 64 bool hasPoint(in Vector2 p_point) const 65 { 66 if (p_point.x < pos.x) 67 return false; 68 if (p_point.y < pos.y) 69 return false; 70 71 if (p_point.x >= (pos.x+size.x) ) 72 return false; 73 if (p_point.y >= (pos.y+size.y) ) 74 return false; 75 76 return true; 77 } 78 79 Rect2 grow(real_t p_by) const 80 { 81 Rect2 g=this; 82 g.pos.x-=p_by; 83 g.pos.y-=p_by; 84 g.size.width+=p_by*2; 85 g.size.height+=p_by*2; 86 return g; 87 } 88 89 Rect2 expand(in Vector2 p_vector) const 90 { 91 Rect2 r = this; 92 r.expandTo(p_vector); 93 return r; 94 } 95 96 void expandTo(in Vector2 p_vector) 97 { 98 Vector2 begin=pos; 99 Vector2 end=pos+size; 100 101 if (p_vector.x<begin.x) 102 begin.x=p_vector.x; 103 if (p_vector.y<begin.y) 104 begin.y=p_vector.y; 105 106 if (p_vector.x>end.x) 107 end.x=p_vector.x; 108 if (p_vector.y>end.y) 109 end.y=p_vector.y; 110 111 pos=begin; 112 size=end-begin; 113 } 114 115 116 real_t distanceTo(in Vector2 p_point) const 117 { 118 real_t dist = 1e20; 119 120 if (p_point.x < pos.x) 121 { 122 dist=min(dist,pos.x-p_point.x); 123 } 124 if (p_point.y < pos.y) 125 { 126 dist=min(dist,pos.y-p_point.y); 127 } 128 if (p_point.x >= (pos.x+size.x) ) 129 { 130 dist=min(p_point.x-(pos.x+size.x),dist); 131 } 132 if (p_point.y >= (pos.y+size.y) ) 133 { 134 dist=min(p_point.y-(pos.y+size.y),dist); 135 } 136 137 if (dist==1e20) 138 return 0; 139 else 140 return dist; 141 } 142 143 Rect2 clip(in Rect2 p_rect) const 144 { 145 146 Rect2 new_rect=p_rect; 147 148 if (!intersects( new_rect )) 149 return Rect2(); 150 151 new_rect.pos.x = max( p_rect.pos.x , pos.x ); 152 new_rect.pos.y = max( p_rect.pos.y , pos.y ); 153 154 Vector2 p_rect_end=p_rect.pos+p_rect.size; 155 Vector2 end=pos+size; 156 157 new_rect.size.x=min(p_rect_end.x,end.x) - new_rect.pos.x; 158 new_rect.size.y=min(p_rect_end.y,end.y) - new_rect.pos.y; 159 160 return new_rect; 161 } 162 163 Rect2 merge(in Rect2 p_rect) const 164 { 165 Rect2 new_rect; 166 167 new_rect.pos.x=min( p_rect.pos.x , pos.x ); 168 new_rect.pos.y=min( p_rect.pos.y , pos.y ); 169 170 171 new_rect.size.x = max( p_rect.pos.x+p_rect.size.x , pos.x+size.x ); 172 new_rect.size.y = max( p_rect.pos.y+p_rect.size.y , pos.y+size.y ); 173 174 new_rect.size = new_rect.size - new_rect.pos; //make relative again 175 176 return new_rect; 177 } 178 179 180 181 bool intersectsSegment(in Vector2 p_from, in Vector2 p_to, Vector2* r_pos,Vector2* r_normal) const 182 { 183 real_t min=0,max=1; 184 int axis=0; 185 real_t sign=0; 186 187 for(int i=0;i<2;i++) 188 { 189 real_t seg_from=p_from[i]; 190 real_t seg_to=p_to[i]; 191 real_t box_begin=pos[i]; 192 real_t box_end=box_begin+size[i]; 193 real_t cmin,cmax; 194 real_t csign; 195 196 if (seg_from < seg_to) 197 { 198 if (seg_from > box_end || seg_to < box_begin) 199 return false; 200 real_t length=seg_to-seg_from; 201 cmin = (seg_from < box_begin)?((box_begin - seg_from)/length):0; 202 cmax = (seg_to > box_end)?((box_end - seg_from)/length):1; 203 csign=-1.0; 204 205 } 206 else 207 { 208 if (seg_to > box_end || seg_from < box_begin) 209 return false; 210 real_t length=seg_to-seg_from; 211 cmin = (seg_from > box_end)?(box_end - seg_from)/length:0; 212 cmax = (seg_to < box_begin)?(box_begin - seg_from)/length:1; 213 csign=1.0; 214 } 215 216 if (cmin > min) 217 { 218 min = cmin; 219 axis=i; 220 sign=csign; 221 } 222 if (cmax < max) 223 max = cmax; 224 if (max < min) 225 return false; 226 } 227 228 229 Vector2 rel=p_to-p_from; 230 231 if (r_normal) 232 { 233 Vector2 normal; 234 normal[axis]=sign; 235 *r_normal=normal; 236 } 237 238 if (r_pos) 239 *r_pos=p_from+rel*min; 240 241 return true; 242 } 243 244 245 bool intersectsTransformed(in Transform2D p_xform, in Rect2 p_rect) const 246 { 247 //SAT intersection between local and transformed rect2 248 249 Vector2[4] xf_points=[ 250 p_xform.xform(p_rect.pos), 251 p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y)), 252 p_xform.xform(Vector2(p_rect.pos.x,p_rect.pos.y+p_rect.size.y)), 253 p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y+p_rect.size.y)), 254 ]; 255 256 real_t low_limit; 257 258 //base rect2 first (faster) 259 260 if (xf_points[0].y>pos.y) 261 goto next1; 262 if (xf_points[1].y>pos.y) 263 goto next1; 264 if (xf_points[2].y>pos.y) 265 goto next1; 266 if (xf_points[3].y>pos.y) 267 goto next1; 268 269 return false; 270 271 next1: 272 273 low_limit=pos.y+size.y; 274 275 if (xf_points[0].y<low_limit) 276 goto next2; 277 if (xf_points[1].y<low_limit) 278 goto next2; 279 if (xf_points[2].y<low_limit) 280 goto next2; 281 if (xf_points[3].y<low_limit) 282 goto next2; 283 284 return false; 285 286 next2: 287 288 if (xf_points[0].x>pos.x) 289 goto next3; 290 if (xf_points[1].x>pos.x) 291 goto next3; 292 if (xf_points[2].x>pos.x) 293 goto next3; 294 if (xf_points[3].x>pos.x) 295 goto next3; 296 297 return false; 298 299 next3: 300 301 low_limit=pos.x+size.x; 302 303 if (xf_points[0].x<low_limit) 304 goto next4; 305 if (xf_points[1].x<low_limit) 306 goto next4; 307 if (xf_points[2].x<low_limit) 308 goto next4; 309 if (xf_points[3].x<low_limit) 310 goto next4; 311 312 return false; 313 314 next4: 315 316 Vector2[4] xf_points2=[ 317 pos, 318 Vector2(pos.x+size.x,pos.y), 319 Vector2(pos.x,pos.y+size.y), 320 Vector2(pos.x+size.x,pos.y+size.y), 321 ]; 322 323 real_t maxa=p_xform.elements[0].dot(xf_points2[0]); 324 real_t mina=maxa; 325 326 real_t dp = p_xform.elements[0].dot(xf_points2[1]); 327 maxa=max(dp,maxa); 328 mina=min(dp,mina); 329 330 dp = p_xform.elements[0].dot(xf_points2[2]); 331 maxa=max(dp,maxa); 332 mina=min(dp,mina); 333 334 dp = p_xform.elements[0].dot(xf_points2[3]); 335 maxa=max(dp,maxa); 336 mina=min(dp,mina); 337 338 real_t maxb=p_xform.elements[0].dot(xf_points[0]); 339 real_t minb=maxb; 340 341 dp = p_xform.elements[0].dot(xf_points[1]); 342 maxb=max(dp,maxb); 343 minb=min(dp,minb); 344 345 dp = p_xform.elements[0].dot(xf_points[2]); 346 maxb=max(dp,maxb); 347 minb=min(dp,minb); 348 349 dp = p_xform.elements[0].dot(xf_points[3]); 350 maxb=max(dp,maxb); 351 minb=min(dp,minb); 352 353 354 if ( mina > maxb ) 355 return false; 356 if ( minb > maxa ) 357 return false; 358 359 maxa=p_xform.elements[1].dot(xf_points2[0]); 360 mina=maxa; 361 362 dp = p_xform.elements[1].dot(xf_points2[1]); 363 maxa=max(dp,maxa); 364 mina=min(dp,mina); 365 366 dp = p_xform.elements[1].dot(xf_points2[2]); 367 maxa=max(dp,maxa); 368 mina=min(dp,mina); 369 370 dp = p_xform.elements[1].dot(xf_points2[3]); 371 maxa=max(dp,maxa); 372 mina=min(dp,mina); 373 374 maxb=p_xform.elements[1].dot(xf_points[0]); 375 minb=maxb; 376 377 dp = p_xform.elements[1].dot(xf_points[1]); 378 maxb=max(dp,maxb); 379 minb=min(dp,minb); 380 381 dp = p_xform.elements[1].dot(xf_points[2]); 382 maxb=max(dp,maxb); 383 minb=min(dp,minb); 384 385 dp = p_xform.elements[1].dot(xf_points[3]); 386 maxb=max(dp,maxb); 387 minb=min(dp,minb); 388 389 390 if ( mina > maxb ) 391 return false; 392 if ( minb > maxa ) 393 return false; 394 395 396 return true; 397 398 } 399 } 400