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 }