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