]> Shamusworld >> Repos - architektonas/blob - src/base/vector.cpp
c8e4dd1c01a73172652eb6a0ac0c9282e1440660
[architektonas] / src / base / vector.cpp
1 // vector.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/21/2010  Added this text. :-)
13 //
14
15 #include "vector.h"
16
17 #include "rs.h"                                                                 // For RS_MIN/MAXDOUBLE (!)
18 #include "rs_debug.h"
19 #include "rs_math.h"
20
21 /**
22  * Constructor for a point with default coordinates.
23  */
24 Vector::Vector()
25 {
26     //RS_DEBUG->print("Vector::Vector");
27     set(0.0, 0.0, 0.0);
28 }
29
30 /**
31  * Constructor for a point with given coordinates.
32  */
33 Vector::Vector(double vx, double vy, double vz)
34 {
35     //RS_DEBUG->print("Vector::Vector");
36     set(vx, vy, vz);
37 }
38
39 /**
40  * Constructor for a point with given coordinates in an array
41  * or three doubles.
42  */
43 //Vector::Vector(double v[]) {
44 //    set(v[0], v[1], v[2]);
45 //}
46
47 /**
48  * Constructor for a point with given valid flag.
49  *
50  * @param valid true: a valid vector with default coordinates is created.
51  *              false: an invalid vector is created
52  */
53 Vector::Vector(bool valid)
54 {
55         //RS_DEBUG->print("Vector::Vector");
56         set(0.0, 0.0, 0.0);
57         this->valid = valid;
58 }
59
60 /**
61  * Destructor.
62  */
63 Vector::~Vector()
64 {
65         //RS_DEBUG->print("Vector::~Vector");
66 }
67
68 /**
69  * Sets a new position for the vector.
70  */
71 void Vector::set(double vx, double vy, double vz)
72 {
73         x = vx;
74         y = vy;
75         z = vz;
76         valid = true;
77 }
78
79 /**
80  * Sets a new position for the vector in polar coordinates.
81  */
82 void Vector::setPolar(double radius, double angle)
83 {
84         x = radius * cos(angle);
85         y = radius * sin(angle);
86         z = 0.0;
87         valid = true;
88 }
89
90 /**
91  * @return The angle from zero to this vector (in rad).
92  */
93 double Vector::angle() const
94 {
95         double ret = 0.0;
96         double m = magnitude();
97
98         if (m > 1.0e-6)
99         {
100                 double dp = dotP(*this, Vector(1.0, 0.0));
101                 RS_DEBUG->print("Vector::angle: dp/m: %f/%f", dp, m);
102
103                 if (dp / m >= 1.0)
104                         ret = 0.0;
105                 else if (dp / m < -1.0)
106                         ret = M_PI;
107                 else
108                 ret = acos(dp / m);
109
110                 if (y < 0.0)
111             ret = 2 * M_PI - ret;
112     }
113
114         return ret;
115 }
116
117 /**
118  * @return The angle from this and the given coordinate (in rad).
119  */
120 double Vector::angleTo(const Vector & v) const
121 {
122         if (!valid || !v.valid)
123                 return 0.0;
124
125         return (v - (*this)).angle();
126 }
127
128 /**
129  * @return Magnitude (length) of the vector.
130  */
131 double Vector::magnitude() const
132 {
133         double ret = 0.0;
134     // Note that the z coordinate is also needed for 2d
135     //   (due to definition of crossP())
136         if (!valid)
137         {
138                 ret = 0.0;
139         }
140         else
141         {
142                 ret = sqrt(RS_Math::pow(x, 2) + RS_Math::pow(y, 2) + RS_Math::pow(z, 2));
143         }
144
145         return ret;
146 }
147
148 /**
149  *
150  */
151 Vector Vector::lerp(const Vector& v, double t) const
152 {
153     return Vector(x + (v.x - x) * t, y + (v.y - y) * t);
154 }
155
156 /**
157  * @return The distance between this and the given coordinate.
158  */
159 double Vector::distanceTo(const Vector & v) const
160 {
161         if (!valid || !v.valid)
162         {
163                 return RS_MAXDOUBLE;
164         }
165         else
166         {
167         return (*this - v).magnitude();
168         }
169 }
170
171 /**
172  * @return true is this vector is within the given range.
173  */
174 bool Vector::isInWindow(const Vector & firstCorner, const Vector & secondCorner)
175 {
176         double minX = std::min(firstCorner.x, secondCorner.x);
177         double maxX = std::max(firstCorner.x, secondCorner.x);
178         double minY = std::min(firstCorner.y, secondCorner.y);
179         double maxY = std::max(firstCorner.y, secondCorner.y);
180
181         return (x >= minX && x <= maxX && y >= minY && y <= maxY);
182 }
183
184 /**
185  * Moves this vector by the given offset. Equal to the operator +=.
186  */
187 Vector Vector::move(Vector offset)
188 {
189         *this += offset;
190         return *this;
191 }
192
193 /**
194  * Rotates this vector around 0/0 by the given angle.
195  */
196 Vector Vector::rotate(double ang)
197 {
198         RS_DEBUG->print("Vector::rotate: angle: %f", ang);
199
200         double r = magnitude();
201
202         RS_DEBUG->print("Vector::rotate: r: %f", r);
203
204         double a = angle() + ang;
205
206         RS_DEBUG->print("Vector::rotate: a: %f", a);
207
208         x = cos(a) * r;
209         y = sin(a) * r;
210
211         RS_DEBUG->print("Vector::rotate: x/y: %f/%f", x, y);
212
213         return *this;
214 }
215
216 /**
217  * Rotates this vector around the given center by the given angle.
218  */
219 Vector Vector::rotate(Vector center, double ang)
220 {
221         *this = center + (*this - center).rotate(ang);
222         return *this;
223 }
224
225 /**
226  * Scales this vector by the given factors with 0/0 as center.
227  */
228 Vector Vector::scale(Vector factor)
229 {
230         x *= factor.x;
231         y *= factor.y;
232         return *this;
233 }
234
235 /**
236  * Scales this vector by the given factors with the given center.
237  */
238 Vector Vector::scale(Vector center, Vector factor)
239 {
240         *this = center + (*this - center).scale(factor);
241         return *this;
242 }
243
244 /**
245  * Mirrors this vector at the given axis.
246  */
247 Vector Vector::mirror(Vector axisPoint1, Vector axisPoint2)
248 {
249         /*
250         RS_ConstructionLine axis(NULL,
251                 RS_ConstructionLineData(axisPoint1, axisPoint2));
252
253         Vector xp = axis.getNearestPointOnEntity(*this);
254         xp = xp - (*this);
255         (*this) += (xp*2);
256         */
257
258         double phi1 = axisPoint1.angleTo(*this);
259         double phi2 = axisPoint1.angleTo(axisPoint2) - phi1;
260         double r1 = axisPoint1.distanceTo(*this);
261         double r2 = axisPoint2.distanceTo(*this);
262
263         if (r1 < 1.0e-6 || r2 < 1.0e-6)
264         {
265                 // point touches one axis point
266         }
267         else
268         {
269                 setPolar(r1, phi1 + 2 * phi2);
270                 (*this) += axisPoint1;
271         }
272
273         return *this;
274 }
275
276 /**
277  * Streams the vector components to stdout. e.g.: "1/4/0"
278  */
279 std::ostream & operator<<(std::ostream & os, const Vector & v)
280 {
281     if (v.valid)
282         os << v.x << "/" << v.y << "/" << v.z;
283     else
284         os << "invalid vector";
285
286         return os;
287 }
288
289 /**
290  * binary + operator.
291  */
292 Vector Vector::operator+(const Vector & v) const
293 {
294         return Vector(x + v.x, y + v.y, z + v.z);
295 }
296
297 /**
298  * binary - operator.
299  */
300 Vector Vector::operator-(const Vector & v) const
301 {
302         return Vector(x - v.x, y - v.y, z - v.z);
303 }
304
305 /**
306  * binary * operator.
307  */
308 Vector Vector::operator*(double s) const
309 {
310         return Vector(x * s, y * s, z * s);
311 }
312
313 /**
314  * binary / operator.
315  */
316 Vector Vector::operator/(double s) const
317 {
318         return Vector(x / s, y / s, z / s);
319 }
320
321 /**
322  * unary - operator.
323  */
324 Vector Vector::operator-() const
325 {
326         return Vector(-x, -y, -z);
327 }
328
329 /**
330  * Scalarproduct (dot product).
331  */
332 double Vector::dotP(const Vector & v1, const Vector & v2)
333 {
334         return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
335 }
336
337 /**
338  * += operator. Assert: both vectors must be valid.
339  */
340 void Vector::operator+=(const Vector & v)
341 {
342         x += v.x;
343         y += v.y;
344         z += v.z;
345 }
346
347 /**
348  * -= operator
349  */
350 void Vector::operator-=(const Vector & v)
351 {
352         x -= v.x;
353         y -= v.y;
354         z -= v.z;
355 }
356
357 /**
358  * *= operator
359  */
360 void Vector::operator*=(double s)
361 {
362         x *= s;
363         y *= s;
364         z *= s;
365 }
366
367 /**
368  * == operator
369  */
370 bool Vector::operator==(const Vector & v) const
371 {
372         return (x == v.x && y == v.y && z == v.z && valid == v.valid);
373 }
374
375 bool Vector::operator!=(const Vector & v) const
376 {
377         return !operator==(v);
378 }
379
380 /**
381  * @return A vector with the minimum components from the vectors v1 and v2.
382  * These might be mixed components from both vectors.
383  */
384 Vector Vector::minimum (const Vector& v1, const Vector& v2)
385 {
386         return Vector (std::min(v1.x, v2.x), std::min(v1.y, v2.y), std::min(v1.z, v2.z));
387 }
388
389 /**
390  * @return A vector with the maximum values from the vectors v1 and v2
391  */
392 Vector Vector::maximum (const Vector& v1, const Vector& v2)
393 {
394         return Vector (std::max(v1.x, v2.x), std::max(v1.y, v2.y), std::max(v1.z, v2.z));
395 }
396
397 /**
398  * @return Cross product of two vectors.
399  */
400 Vector Vector::crossP(const Vector & v1, const Vector & v2)
401 {
402         return Vector(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
403 }
404