1 /** 2 Copyright: Copyright (c) 2016-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.geometry.rect; 7 8 import voxelman.math; 9 10 struct frect 11 { 12 this (float x, float y, float width, float height) { 13 this.position = vec2(x, y); 14 this.size = vec2(width, height); 15 } 16 17 this (T1, T2)(T1 position, T2 size) { 18 this.position = position; 19 this.size = size; 20 } 21 22 this (irect rect) { 23 this.position = rect.position; 24 this.size = rect.size; 25 } 26 27 vec2 position = vec2(0, 0); 28 vec2 size = vec2(0, 0); 29 30 float area() @property const @nogc 31 { 32 return size.x * size.y; 33 } 34 35 vec2 endPosition() @property const 36 { 37 return position + size; 38 } 39 40 bool empty() const @property 41 { 42 return size.x == 0 && size.y == 0; 43 } 44 45 bool contains(vec2 point) const 46 { 47 if (point.x < position.x || point.x >= position.x + size.x) return false; 48 if (point.y < position.y || point.y >= position.y + size.y) return false; 49 return true; 50 } 51 } 52 53 RectT rectIntersection(RectT)(const RectT a, const RectT b) 54 { 55 typeof(RectT.size.x)[2] xIntersection = intersection(a.position.x, a.position.x + a.size.x, b.position.x, b.position.x + b.size.x); 56 typeof(RectT.size.x)[2] yIntersection = intersection(a.position.y, a.position.y + a.size.y, b.position.y, b.position.y + b.size.y); 57 if (xIntersection[0] > xIntersection[1]) return RectT(); 58 if (yIntersection[0] > yIntersection[1]) return RectT(); 59 60 return RectT(xIntersection[0], yIntersection[0], xIntersection[1] - xIntersection[0], yIntersection[1] - yIntersection[0]); 61 } 62 63 T[2] intersection(T)(const T aStart, const T aEnd, const T bStart, const T bEnd) 64 if (is(T == int) || is(T == float)) 65 { 66 T[2] res; 67 68 if (aStart < bStart) 69 { 70 res[0] = bStart; 71 } 72 else if (aStart > bStart) 73 { 74 res[0] = aStart; 75 } 76 else 77 { 78 res[0] = aStart; 79 } 80 81 if (aEnd < bEnd) 82 { 83 res[1] = aEnd; 84 } 85 else if (aEnd > bEnd) 86 { 87 res[1] = bEnd; 88 } 89 else 90 { 91 res[1] = bEnd; 92 } 93 94 return res; 95 } 96 97 struct irect 98 { 99 this (ivec2 position, ivec2 size) { 100 this.position = position; 101 this.size = size; 102 } 103 104 this (int x, int y, int width, int height) { 105 this.x = x; 106 this.y = y; 107 this.width = width; 108 this.height = height; 109 } 110 111 union { 112 ivec2 position; 113 struct { int x, y; } 114 } 115 union { 116 ivec2 size; 117 struct { int width, height; } 118 } 119 120 int area() @property const @nogc 121 { 122 return width * height; 123 } 124 125 int endX() @property const { return x + width - 1; } 126 int endY() @property const { return y + height - 1; } 127 128 ivec2 endPosition() @property const 129 { 130 return position + size - ivec2(1,1); 131 } 132 133 bool empty() const @property 134 { 135 return width == 0 && height == 0; 136 } 137 138 bool contains(ivec2 point) const 139 { 140 if (point.x < x || point.x >= x + width) return false; 141 if (point.y < y || point.y >= y + height) return false; 142 return true; 143 } 144 145 /// Adds a point to a rectangle. 146 /// This results in the smallest rectangle that contains both the rectangle and the point. 147 void add(ivec2 point) 148 { 149 if (point.x < x) 150 { 151 immutable int diff_x = x - point.x; 152 width += diff_x; 153 x -= diff_x; 154 } 155 else if(point.x > x + width - 1) 156 { 157 immutable int diff_x = point.x - (x + width - 1); 158 width += diff_x; 159 } 160 161 if (point.y < y) 162 { 163 immutable int diff_y = y - point.y; 164 height += diff_y; 165 y -= diff_y; 166 } 167 else if(point.y > y + height - 1) 168 { 169 immutable int diff_y = point.y - (y + height - 1); 170 height += diff_y; 171 } 172 } 173 174 void toString()(scope void delegate(const(char)[]) sink) const 175 { 176 import std.format : formattedWrite; 177 sink.formattedWrite("irect(x %s y %s w %s h %s)", x, y, width, height); 178 } 179 }