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