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
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 05/21/2010 Added this text. :-)
17 #include "rs.h" // For RS_MIN/MAXDOUBLE (!)
22 * Constructor for a point with default coordinates.
26 //RS_DEBUG->print("Vector::Vector");
31 * Constructor for a point with given coordinates.
33 Vector::Vector(double vx, double vy, double vz)
35 //RS_DEBUG->print("Vector::Vector");
40 * Constructor for a point with given coordinates in an array
43 //Vector::Vector(double v[]) {
44 // set(v[0], v[1], v[2]);
48 * Constructor for a point with given valid flag.
50 * @param valid true: a valid vector with default coordinates is created.
51 * false: an invalid vector is created
53 Vector::Vector(bool valid)
55 //RS_DEBUG->print("Vector::Vector");
65 //RS_DEBUG->print("Vector::~Vector");
69 * Sets a new position for the vector.
71 void Vector::set(double vx, double vy, double vz)
80 * Sets a new position for the vector in polar coordinates.
82 void Vector::setPolar(double radius, double angle)
84 x = radius * cos(angle);
85 y = radius * sin(angle);
91 * @return The angle from zero to this vector (in rad).
93 double Vector::angle() const
96 double m = magnitude();
100 double dp = dotP(*this, Vector(1.0, 0.0));
101 RS_DEBUG->print("Vector::angle: dp/m: %f/%f", dp, m);
105 else if (dp / m < -1.0)
111 ret = 2 * M_PI - ret;
118 * @return The angle from this and the given coordinate (in rad).
120 double Vector::angleTo(const Vector & v) const
122 if (!valid || !v.valid)
125 return (v - (*this)).angle();
129 * @return Magnitude (length) of the vector.
131 double Vector::magnitude() const
134 // Note that the z coordinate is also needed for 2d
135 // (due to definition of crossP())
142 ret = sqrt(RS_Math::pow(x, 2) + RS_Math::pow(y, 2) + RS_Math::pow(z, 2));
151 Vector Vector::lerp(const Vector& v, double t) const
153 return Vector(x + (v.x - x) * t, y + (v.y - y) * t);
157 * @return The distance between this and the given coordinate.
159 double Vector::distanceTo(const Vector & v) const
161 if (!valid || !v.valid)
167 return (*this - v).magnitude();
172 * @return true is this vector is within the given range.
174 bool Vector::isInWindow(const Vector & firstCorner, const Vector & secondCorner)
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);
181 return (x >= minX && x <= maxX && y >= minY && y <= maxY);
185 * Moves this vector by the given offset. Equal to the operator +=.
187 Vector Vector::move(Vector offset)
194 * Rotates this vector around 0/0 by the given angle.
196 Vector Vector::rotate(double ang)
198 RS_DEBUG->print("Vector::rotate: angle: %f", ang);
200 double r = magnitude();
202 RS_DEBUG->print("Vector::rotate: r: %f", r);
204 double a = angle() + ang;
206 RS_DEBUG->print("Vector::rotate: a: %f", a);
211 RS_DEBUG->print("Vector::rotate: x/y: %f/%f", x, y);
217 * Rotates this vector around the given center by the given angle.
219 Vector Vector::rotate(Vector center, double ang)
221 *this = center + (*this - center).rotate(ang);
226 * Scales this vector by the given factors with 0/0 as center.
228 Vector Vector::scale(Vector factor)
236 * Scales this vector by the given factors with the given center.
238 Vector Vector::scale(Vector center, Vector factor)
240 *this = center + (*this - center).scale(factor);
245 * Mirrors this vector at the given axis.
247 Vector Vector::mirror(Vector axisPoint1, Vector axisPoint2)
250 RS_ConstructionLine axis(NULL,
251 RS_ConstructionLineData(axisPoint1, axisPoint2));
253 Vector xp = axis.getNearestPointOnEntity(*this);
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);
263 if (r1 < 1.0e-6 || r2 < 1.0e-6)
265 // point touches one axis point
269 setPolar(r1, phi1 + 2 * phi2);
270 (*this) += axisPoint1;
277 * Streams the vector components to stdout. e.g.: "1/4/0"
279 std::ostream & operator<<(std::ostream & os, const Vector & v)
282 os << v.x << "/" << v.y << "/" << v.z;
284 os << "invalid vector";
292 Vector Vector::operator+(const Vector & v) const
294 return Vector(x + v.x, y + v.y, z + v.z);
300 Vector Vector::operator-(const Vector & v) const
302 return Vector(x - v.x, y - v.y, z - v.z);
308 Vector Vector::operator*(double s) const
310 return Vector(x * s, y * s, z * s);
316 Vector Vector::operator/(double s) const
318 return Vector(x / s, y / s, z / s);
324 Vector Vector::operator-() const
326 return Vector(-x, -y, -z);
330 * Scalarproduct (dot product).
332 double Vector::dotP(const Vector & v1, const Vector & v2)
334 return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
338 * += operator. Assert: both vectors must be valid.
340 void Vector::operator+=(const Vector & v)
350 void Vector::operator-=(const Vector & v)
360 void Vector::operator*=(double s)
370 bool Vector::operator==(const Vector & v) const
372 return (x == v.x && y == v.y && z == v.z && valid == v.valid);
375 bool Vector::operator!=(const Vector & v) const
377 return !operator==(v);
381 * @return A vector with the minimum components from the vectors v1 and v2.
382 * These might be mixed components from both vectors.
384 Vector Vector::minimum (const Vector& v1, const Vector& v2)
386 return Vector (std::min(v1.x, v2.x), std::min(v1.y, v2.y), std::min(v1.z, v2.z));
390 * @return A vector with the maximum values from the vectors v1 and v2
392 Vector Vector::maximum (const Vector& v1, const Vector& v2)
394 return Vector (std::max(v1.x, v2.x), std::max(v1.y, v2.y), std::max(v1.z, v2.z));
398 * @return Cross product of two vectors.
400 Vector Vector::crossP(const Vector & v1, const Vector & v2)
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);