0
|
1 module interaction.geometry;
|
|
2
|
|
3 private import std.math;
|
|
4
|
|
5 private const double EPSILON = 1e-20;
|
|
6
|
|
7 final class Point {
|
|
8 this() {
|
|
9 this(0.0, 0.0);
|
|
10 }
|
|
11
|
|
12 this(double x, double y) {
|
|
13 _x = x;
|
|
14 _y = y;
|
|
15 }
|
|
16
|
|
17 char[] toString() {
|
|
18 return "(" ~ std.string.toString(_x) ~ ", " ~ std.string.toString(_y) ~ ")";
|
|
19 }
|
|
20
|
|
21 Point opAdd(in Vector v) {
|
|
22 return new Point(_x + v._x, _y + v._y);
|
|
23 }
|
|
24
|
|
25 Vector opSub(in Point p) {
|
|
26 return new Vector(_x - p._x, _y - p._y);
|
|
27 }
|
|
28
|
|
29 double x() { return _x; }
|
|
30 double y() { return _y; }
|
|
31
|
|
32 private {
|
|
33 double _x;
|
|
34 double _y;
|
|
35 }
|
|
36 }
|
|
37
|
|
38 //
|
|
39
|
|
40 final class Vector {
|
|
41 this() {
|
|
42 this(0.0, 0.0);
|
|
43 }
|
|
44
|
|
45 this(double x, double y) {
|
|
46 _x = x;
|
|
47 _y = y;
|
|
48 }
|
|
49
|
|
50 char[] toString() {
|
|
51 return "[" ~ std.string.toString(_x) ~ ", " ~ std.string.toString(_y) ~ "]";
|
|
52 }
|
|
53
|
|
54 Vector opAdd(in Vector v) {
|
|
55 return new Vector(_x + v._x, _y + v._y);
|
|
56 }
|
|
57
|
|
58 Vector opSub(in Vector v) {
|
|
59 return new Vector(_x - v._x, _y - v._y);
|
|
60 }
|
|
61
|
|
62 Vector opNeg() {
|
|
63 return new Vector(-_x, -_y);
|
|
64 }
|
|
65
|
|
66 Vector opMul_r(double d) {
|
|
67 return new Vector(d * _x, d * _y);
|
|
68 }
|
|
69
|
|
70 double length() {
|
|
71 return sqrt(_x * _x + _y * _y);
|
|
72 }
|
|
73
|
|
74 bool has_length() {
|
|
75 return _x * _x + _y * _y > EPSILON * EPSILON;
|
|
76 }
|
|
77
|
|
78 double x() { return _x; }
|
|
79 double y() { return _y; }
|
|
80
|
|
81 private {
|
|
82 double _x;
|
|
83 double _y;
|
|
84 }
|
|
85 }
|
|
86
|
|
87 //
|
|
88
|
|
89 final class Segment {
|
|
90 this() {
|
|
91 }
|
|
92
|
|
93 this(Point start, Point end) {
|
|
94 _start = start;
|
|
95 _end = end;
|
|
96 }
|
|
97
|
|
98 Point start() { return _start; }
|
|
99 Point end() { return _end; }
|
|
100
|
|
101 private {
|
|
102 Point _start;
|
|
103 Point _end;
|
|
104 }
|
|
105 }
|
|
106
|
|
107 //
|
|
108
|
|
109 final class Line {
|
|
110 this() {
|
|
111 }
|
|
112
|
|
113 this(Point point, Vector vector) {
|
|
114 assert(vector.has_length);
|
|
115 _point = point;
|
|
116 _vector = vector;
|
|
117 }
|
|
118
|
|
119 this(Point point1, Point point2) {
|
|
120 _point = point1;
|
|
121 _vector = point2 - point1;
|
|
122 assert(_vector.has_length);
|
|
123 }
|
|
124
|
|
125 private {
|
|
126 Point _point;
|
|
127 Vector _vector;
|
|
128 }
|
|
129 }
|
|
130
|
|
131 //
|
|
132
|
|
133 final class Rectangle {
|
|
134 this() {
|
|
135 this(0.0, 0.0, 0.0, 0.0);
|
|
136 }
|
|
137
|
|
138 this(double x, double y, double w, double h) {
|
|
139 assert(w >= 0.0);
|
|
140 assert(h >= 0.0);
|
|
141 _x = x;
|
|
142 _y = y;
|
|
143 _w = w;
|
|
144 _h = h;
|
|
145 }
|
|
146
|
|
147 double x() { return _x; }
|
|
148 double y() { return _y; }
|
|
149 double w() { return _w; }
|
|
150 double h() { return _h; }
|
|
151 double xw() { return _x + _w; }
|
|
152 double yh() { return _y + _h; }
|
|
153
|
|
154 /*
|
|
155 Point corner00() { return new Point(_x, _y ); }
|
|
156 Point corner10() { return new Point(_x + _w, _y ); }
|
|
157 Point corner11() { return new Point(_x + _w, _y + _h); }
|
|
158 Point corner01() { return new Point(_x, _y + _h); }
|
|
159
|
|
160 Point centre() { return new Point(_x + _w / 2.0, _y + _h / 2.0); }
|
|
161 */
|
|
162
|
|
163 double area() {
|
|
164 return _w * _h;
|
|
165 }
|
|
166
|
|
167 bool has_area() {
|
|
168 return area > 0.0;
|
|
169 }
|
|
170
|
|
171 bool contains(Point point) {
|
|
172 return point.x > x && point.x < xw & point.y > y && point.y < xy;
|
|
173 }
|
|
174
|
|
175 bool contains(Segment segment) {
|
|
176 return contains(segment.start, segment.end);
|
|
177 }
|
|
178
|
|
179 private double _x, _y, _w, _h;
|
|
180 }
|
|
181
|
|
182 unittest {
|
|
183 const double absdiff = 1e-20, reldiff= 1e-20;
|
|
184
|
|
185 bool cmpdouble(in double lhs, in double rhs) {
|
|
186 double adiff = fabs(rhs - lhs);
|
|
187
|
|
188 if (adiff < absdiff && adiff > -absdiff) {
|
|
189 return true;
|
|
190 }
|
|
191
|
|
192 if (fabs(lhs) > absdiff && fabs(rhs) > absdiff) {
|
|
193 double rdiff = rhs / lhs;
|
|
194
|
|
195 if (rdiff < (1.0 + reldiff) && rdiff > 1.0 / (1.0 + reldiff)) {
|
|
196 return true;
|
|
197 }
|
|
198 }
|
|
199
|
|
200 // They must differ significantly
|
|
201
|
|
202 return false;
|
|
203 }
|
|
204
|
|
205 bool cmpvector(in Vector lhs, in Vector rhs) {
|
|
206 return cmpdouble(lhs._x, rhs._x) && cmpdouble(lhs._y, rhs._y);
|
|
207 }
|
|
208
|
|
209 bool cmppoint(in Point lhs, in Point rhs) {
|
|
210 return cmpdouble(lhs._x, rhs._x) && cmpdouble(lhs._y, rhs._y);
|
|
211 }
|
|
212
|
|
213 assert(cmpvector(new Vector(0.0, 0.0), new Vector));
|
|
214 assert(!cmpvector(new Vector(0.0, 1e-10), new Vector));
|
|
215 assert(cmpvector(new Vector(1.0, 2.0) + new Vector(3.0, 4.0), new Vector(4.0, 6.0)));
|
|
216 assert(cmpvector(new Vector(1.0, 2.0) - new Vector(3.0, 4.0), new Vector(-2.0, -2.0)));
|
|
217 assert(cmpvector(-(new Vector(1.0, 2.0)), new Vector(-1.0, -2.0)));
|
|
218 assert(cmpdouble((new Vector(3.0, 4.0)).length(), 5.0));
|
|
219 assert(cmpvector(3.0 * (new Vector(3.0, 4.0)), new Vector(9.0, 12.0)));
|
|
220 }
|