/**************************************************************************** ** $Id: rs_vector.cpp 2378 2005-05-16 17:05:15Z andrew $ ** ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved. ** ** This file is part of the qcadlib Library project. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** Licensees holding valid qcadlib Professional Edition licenses may use ** this file in accordance with the qcadlib Commercial License ** Agreement provided with the Software. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.ribbonsoft.com for further details. ** ** Contact info@ribbonsoft.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #include "rs_vector.h" //#include #include "rs_debug.h" #include "rs_math.h" #include "rs_constructionline.h" /** * Constructor for a point with default coordinates. */ RS_Vector::RS_Vector() { //RS_DEBUG->print("RS_Vector::RS_Vector"); set(0.0, 0.0, 0.0); } /** * Constructor for a point with given coordinates. */ RS_Vector::RS_Vector(double vx, double vy, double vz) { //RS_DEBUG->print("RS_Vector::RS_Vector"); set(vx, vy, vz); } /** * Constructor for a point with given coordinates in an array * or three doubles. */ //RS_Vector::RS_Vector(double v[]) { // set(v[0], v[1], v[2]); //} /** * Constructor for a point with given valid flag. * * @param valid true: a valid vector with default coordinates is created. * false: an invalid vector is created */ RS_Vector::RS_Vector(bool valid) { //RS_DEBUG->print("RS_Vector::RS_Vector"); set(0.0, 0.0, 0.0); this->valid = valid; } /** * Destructor. */ RS_Vector::~RS_Vector() { //RS_DEBUG->print("RS_Vector::~RS_Vector"); } /** * Sets a new position for the vector. */ void RS_Vector::set(double vx, double vy, double vz) { x = vx; y = vy; z = vz; valid = true; } /** * Sets a new position for the vector in polar coordinates. */ void RS_Vector::setPolar(double radius, double angle) { x = radius * cos(angle); y = radius * sin(angle); z = 0.0; valid = true; } /** * @return The angle from zero to this vector (in rad). */ double RS_Vector::angle() const { double ret = 0.0; double m = magnitude(); if (m>1.0e-6) { double dp = dotP(*this, RS_Vector(1.0, 0.0)); RS_DEBUG->print("RS_Vector::angle: dp/m: %f/%f", dp, m); if (dp/m>=1.0) { ret = 0.0; } else if (dp/m<-1.0) { ret = M_PI; } else { ret = acos( dp / m); } if (y<0.0) { ret = 2*M_PI - ret; } } return ret; } /** * @return The angle from this and the given coordinate (in rad). */ double RS_Vector::angleTo(const RS_Vector& v) const { if (!valid || !v.valid) { return 0.0; } else { return (v-(*this)).angle(); } } /** * @return Magnitude (length) of the vector. */ double RS_Vector::magnitude() const { double ret = 0.0; // Note that the z coordinate is also needed for 2d // (due to definition of crossP()) if (!valid) { ret = 0.0; } else { ret = sqrt(RS_Math::pow(x,2) + RS_Math::pow(y,2) + RS_Math::pow(z,2)); } return ret; } /** * */ RS_Vector RS_Vector::lerp(const RS_Vector& v, double t) const { return RS_Vector(x+(v.x-x)*t, y+(v.y-y)*t); } /** * @return The distance between this and the given coordinate. */ double RS_Vector::distanceTo(const RS_Vector& v) const { if (!valid || !v.valid) { return RS_MAXDOUBLE; } else { return (*this-v).magnitude(); } } /** * @return true is this vector is within the given range. */ bool RS_Vector::isInWindow(const RS_Vector& firstCorner, const RS_Vector& secondCorner) { double minX = std::min(firstCorner.x, secondCorner.x); double maxX = std::max(firstCorner.x, secondCorner.x); double minY = std::min(firstCorner.y, secondCorner.y); double maxY = std::max(firstCorner.y, secondCorner.y); return (x>=minX && x<=maxX && y>=minY && y<=maxY); } /** * Moves this vector by the given offset. Equal to the operator +=. */ RS_Vector RS_Vector::move(RS_Vector offset) { *this+=offset; return *this; } /** * Rotates this vector around 0/0 by the given angle. */ RS_Vector RS_Vector::rotate(double ang) { RS_DEBUG->print("RS_Vector::rotate: angle: %f", ang); double r = magnitude(); RS_DEBUG->print("RS_Vector::rotate: r: %f", r); double a = angle() + ang; RS_DEBUG->print("RS_Vector::rotate: a: %f", a); x = cos(a) * r; y = sin(a) * r; RS_DEBUG->print("RS_Vector::rotate: x/y: %f/%f", x, y); return *this; } /** * Rotates this vector around the given center by the given angle. */ RS_Vector RS_Vector::rotate(RS_Vector center, double ang) { *this = center + (*this-center).rotate(ang); return *this; } /** * Scales this vector by the given factors with 0/0 as center. */ RS_Vector RS_Vector::scale(RS_Vector factor) { x *= factor.x; y *= factor.y; return *this; } /** * Scales this vector by the given factors with the given center. */ RS_Vector RS_Vector::scale(RS_Vector center, RS_Vector factor) { *this = center + (*this-center).scale(factor); return *this; } /** * Mirrors this vector at the given axis. */ RS_Vector RS_Vector::mirror(RS_Vector axisPoint1, RS_Vector axisPoint2) { /* RS_ConstructionLine axis(NULL, RS_ConstructionLineData(axisPoint1, axisPoint2)); RS_Vector xp = axis.getNearestPointOnEntity(*this); xp = xp - (*this); (*this) += (xp*2); */ double phi1 = axisPoint1.angleTo(*this); double phi2 = axisPoint1.angleTo(axisPoint2) - phi1; double r1 = axisPoint1.distanceTo(*this); double r2 = axisPoint2.distanceTo(*this); if (r1<1.0e-6 || r2<1.0e-6) { // point touches one axis point } else { setPolar(r1, phi1 + 2*phi2); (*this) += axisPoint1; } return *this; } /** * Streams the vector components to stdout. e.g.: "1/4/0" */ std::ostream& operator << (std::ostream& os, const RS_Vector& v) { if(v.valid) { os << v.x << "/" << v.y << "/" << v.z; } else { os << "invalid vector"; } return os; } /** * binary + operator. */ RS_Vector RS_Vector::operator + (const RS_Vector& v) const { return RS_Vector(x + v.x, y + v.y, z + v.z); } /** * binary - operator. */ RS_Vector RS_Vector::operator - (const RS_Vector& v) const { return RS_Vector(x - v.x, y - v.y, z - v.z); } /** * binary * operator. */ RS_Vector RS_Vector::operator * (double s) const { return RS_Vector(x * s, y * s, z * s); } /** * binary / operator. */ RS_Vector RS_Vector::operator / (double s) const { return RS_Vector(x / s, y / s, z / s); } /** * unary - operator. */ RS_Vector RS_Vector::operator - () const { return RS_Vector(-x, -y, -z); } /** * Scalarproduct (dot product). */ double RS_Vector::dotP(const RS_Vector& v1, const RS_Vector& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } /** * += operator. Assert: both vectors must be valid. */ void RS_Vector::operator += (const RS_Vector& v) { x += v.x; y += v.y; z += v.z; } /** * -= operator */ void RS_Vector::operator -= (const RS_Vector& v) { x -= v.x; y -= v.y; z -= v.z; } /** * *= operator */ void RS_Vector::operator *= (double s) { x *= s; y *= s; z *= s; } /** * == operator */ bool RS_Vector::operator == (const RS_Vector& v) const { return (x==v.x && y==v.y && z==v.z && valid==v.valid); } /** * @return A vector with the minimum components from the vectors v1 and v2. * These might be mixed components from both vectors. */ RS_Vector RS_Vector::minimum (const RS_Vector& v1, const RS_Vector& v2) { return RS_Vector (std::min(v1.x, v2.x), std::min(v1.y, v2.y), std::min(v1.z, v2.z)); } /** * @return A vector with the maximum values from the vectors v1 and v2 */ RS_Vector RS_Vector::maximum (const RS_Vector& v1, const RS_Vector& v2) { return RS_Vector (std::max(v1.x, v2.x), std::max(v1.y, v2.y), std::max(v1.z, v2.z)); } /** * @return Cross product of two vectors. */ RS_Vector RS_Vector::crossP(const RS_Vector& v1, const RS_Vector& v2) { return RS_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); } /** * Constructor for no solution. */ RS_VectorSolutions::RS_VectorSolutions() : vector(NULL) { clean(); } /** * Copy constructor */ RS_VectorSolutions::RS_VectorSolutions(const RS_VectorSolutions& s) : vector(NULL) { alloc(s.getNumber()); setTangent(s.isTangent()); for (int i=0; inum = num; vector = new RS_Vector[num]; for (int i=0; i