Logo Search packages:      
Sourcecode: qcad version File versions  Download package

rs_vector.cpp

/****************************************************************************
** $Id: rs_vector.cpp,v 1.23 2004/08/25 17:34:46 andrew Exp $
**
** 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 <values.h>

#include "rs_debug.h"
#include "rs_math.h"
#include "rs_constructionline.h"

/**
 * Constructor for a point with default coordinates.
 */
00039 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.
 */
00049 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
 */
00070 RS_Vector::RS_Vector(bool valid) {
    //RS_DEBUG->print("RS_Vector::RS_Vector");
    set(0.0, 0.0, 0.0);
    this->valid = valid;
}


/**
 * Destructor.
 */
00080 RS_Vector::~RS_Vector() {
    //RS_DEBUG->print("RS_Vector::~RS_Vector");
}


/**
 * Sets a new position for the vector.
 */
00088 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.
 */
00099 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).
 */
00111 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 {
            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).
 */
00136 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.
 */
00150 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;
}



/**
 * @return The distance between this and the given coordinate.
 */
00169 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.
 */
00183 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 +=.
 */
00199 RS_Vector RS_Vector::move(RS_Vector offset) {
    *this+=offset;
    return *this;
}



/**
 * Rotates this vector around 0/0 by the given angle.
 */
00209 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.
 */
00232 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.
 */
00241 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.
 */
00252 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.
 */
00262 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"
 */
00293 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.
 */
00307 RS_Vector RS_Vector::operator + (const RS_Vector& v) const {
    //assert(valid && v.valid);
    return RS_Vector(x + v.x, y + v.y, z + v.z);
}



/**
 * binary - operator.
 */
00317 RS_Vector RS_Vector::operator - (const RS_Vector& v) const {
    //assert(valid && v.valid);
    return RS_Vector(x - v.x, y - v.y, z - v.z);
}


/**
 * binary * operator.
 */
00326 RS_Vector RS_Vector::operator * (double s) const {
    //assert(valid && v.valid);
    return RS_Vector(x * s, y * s, z * s);
}



/**
 * binary / operator.
 */
00336 RS_Vector RS_Vector::operator / (double s) const {
    //assert(valid && v.valid);
    return RS_Vector(x / s, y / s, z / s);
}



/**
 * unary - operator.
 */
00346 RS_Vector RS_Vector::operator - () const {
    return RS_Vector(-x, -y, -z);
}



/**
 * Scalarproduct (dot product).
 */
00355 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.
 */
00364 void RS_Vector::operator += (const RS_Vector& v) {
    //assert(valid && v.valid);
    x += v.x;
    y += v.y;
    z += v.z;
}


/**
 * -= operator
 */
00375 void RS_Vector::operator -= (const RS_Vector& v) {
    //assert(valid && v.valid);
    x -= v.x;
    y -= v.y;
    z -= v.z;
}



/**
 * *= operator
 */
00387 void RS_Vector::operator *= (double s) {
    //assert(valid);
    x *= s;
    y *= s;
    z *= s;
}



/**
 * == operator
 */
00399 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.
 */
00409 RS_Vector RS_Vector::minimum (const RS_Vector& v1, const RS_Vector& v2) {
    //assert(v1.valid && v2.valid);
    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
 */
00421 RS_Vector RS_Vector::maximum (const RS_Vector& v1, const RS_Vector& v2) {
    //assert(v1.valid && v2.valid);
    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.
 */
00433 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);
}



/**
 * Testing
 */
#ifdef RS_TEST
00445 bool RS_Vector::test() {

    double a, r, x, y;

    std::cout << "Testing RS_Vector\n";

    std::cout << "  Constructors..";
    RS_Vector v1;
    assert(v1.x==0.0);
    assert(v1.y==0.0);
    assert(v1.z==0.0);
    assert(v1.valid);

    RS_Vector v2(1.0,2.0,3.0);
    assert(v2.x==1.0);
    assert(v2.y==2.0);
    assert(v2.z==3.0);
    assert(v2.valid);

    /*
    double v[] = {4.0, 5.0, 6.0};
    RS_Vector v3(v);
    assert(v3.x==4.0);
    assert(v3.y==5.0);
    assert(v3.z==6.0);
    assert(v3.valid);
    */

    RS_Vector v4(false);
    assert(!v4.valid);
    std::cout << "OK\n";


    std::cout << "  Set\n";

    std::cout << "    set..";
    RS_Vector v5;
    v5.set(7.0, 8.0, 9.0);
    assert(v5.x==7.0);
    assert(v5.y==8.0);
    assert(v5.z==9.0);
    assert(v5.valid);
    std::cout << "OK\n";

    std::cout << "    setPolar..";
    RS_Vector v6;
    for (r=0.0; r<=32000.0; r+=10.0) {
        for (a=-2*M_PI; a<=2*M_PI; a+=0.05) {
            //std::cout << "r: " << r << " a: " << a << "\n";
            v6.setPolar(r, a);
            assert(fabs(v6.x - (cos(a)*r))<RS_TOLERANCE);
            assert(fabs(v6.y - (sin(a)*r))<RS_TOLERANCE);
            assert(v6.z==0.0);
            assert(v6.valid);
        }
    }
    std::cout << "OK\n";


    std::cout << "  Calculations\n";

    std::cout << "    distanceTo / angleTo..";
    RS_Vector v7, v8;
    // move around in every quadrant:
    for (x=-50.0; x<50.0; x+=10.0) {
        for (y=-50; y<50.0; y+=10.0) {
            v7.set(x,y);
            //std::cout << " x: " << x << " y: " << y << "\n";
            // create different distances:
            for (r=0.0; r<=32000.0; r+=1.0*(r+10.0)) {
                // with different angles:
                for (a=0.0; a<=2*M_PI; a+=0.1) {
                    //std::cout << " r: " << r << " a: " << a << "\n";
                    v8.setPolar(r,a);
                    v8+=v7;
                    assert(fabs(v7.distanceTo(v8) - r) < RS_TOLERANCE);
                    if (r>0.0) {
                        assert(fabs(v7.angleTo(v8) - a) < RS_TOLERANCE);
                    } else {
                        assert(fabs(v7.angleTo(v8)) < RS_TOLERANCE);
                    }
                }
            }
        }
    }
    std::cout << "OK\n";

    std::cout << "    angle..";
    RS_Vector v9;
    for (r=0.0; r<=32000.0; r+=1.0*(r+10.0)) {
        for (a=0.0; a<=2*M_PI; a+=0.05) {
            //std::cout << " a: " << a << "\n";
            v9.setPolar(r,a);
            if (r>0.0) {
                assert(fabs(v9.angle() - a) < RS_TOLERANCE);
            } else {
                assert(fabs(v9.angle()) < RS_TOLERANCE);
            }
        }
    }
    std::cout << "OK\n";


    std::cout << "  Modifications\n";

    std::cout << "    move..";
    RS_Vector v10(-50.0,-50.0);
    for (x=-50.0; x<50.0; x+=10.0) {
        for (y=-50; y<50.0; y+=10.0) {
            //std::cout << " x: " << x << " y: " << y << "\n";
            //std::cout << " v10.x: " << v10.x << " v10.y: " << v10.y << "\n";
            assert(v10.x==x);
            assert(v10.y==y);
            v10.move(RS_Vector(0.0,10.0));
        }
        v10.move(RS_Vector(10.0,-100.0));
    }
    std::cout << "OK\n";

    std::cout << "    rotate..";
    RS_Vector v11(50.0,0.0);
    for (a=0.0; a<2*M_PI; a+=0.05) {
        //std::cout << "a: " << a << " v11.angle: " << v11.angle() << "\n";
        assert(fabs(v11.angle()-a) < RS_TOLERANCE);
        v11.rotate(0.05);
    }
    std::cout << "OK\n";

    std::cout << "    rotate with center..";
    RS_Vector v12, v13;
    // move center around in every quadrant:
    for (x=-50.0; x<50.0; x+=10.0) {
        for (y=-50; y<50.0; y+=10.0) {
            v12.set(x,y);  // center of rotation
            //std::cout << " x: " << x << " y: " << y << "\n";
            // create different radiuses:
            for (r=0.001; r<=32000.0; r+=1.0*(r+10.0)) {
                v13.set(x+r,y);
                // with different angles:
                for (a=0.0; a<=2*M_PI; a+=0.1) {
                    //std::cout << " a: " << a << "\n";
                    //std::cout << " angleTo: " << v12.angleTo(v13) << "\n";
                    //std::cout << " diff: " << fabs(v12.angleTo(v13) - a) << "\n";
                    assert(fabs(v12.angleTo(v13) - a) < RS_TOLERANCE);
                    v13.rotate(v12, 0.1);
                }
            }
        }
    }
    std::cout << "OK\n";

      std::cout << "RS_VectorSolutions\n";
      std::cout << "RS_VectorSolutions: 001\n";
      RS_VectorSolutions s1(5);
      std::cout << "RS_VectorSolutions: 002\n";
      RS_VectorSolutions s2 = s1;
      std::cout << "RS_VectorSolutions: 003\n";
      RS_VectorSolutions s3(s1);
      std::cout << "RS_VectorSolutions: 004\n";

    return true;
}
#endif



/**
 * Constructor for no solution.
 */
00614 RS_VectorSolutions::RS_VectorSolutions() : vector(NULL) {
    clean();
}



/**
 * Copy constructor
 */
00623 RS_VectorSolutions::RS_VectorSolutions(const RS_VectorSolutions& s) 
      : vector(NULL) {
      alloc(s.getNumber());
      setTangent(s.isTangent());
      for (int i=0; i<s.getNumber(); ++i) {
            set(i, s.get(i));
      }
}



/**
 * Constructor for num solutions.
 */
00637 RS_VectorSolutions::RS_VectorSolutions(int num) : vector(NULL) {
      //this->num = num;
    //vector = new RS_Vector[num];
      //for (int i=0; i<num; ++i)  {
    //      vector[i] = RS_Vector(false);
      //}
    //tangent = false;
      alloc(num);
}



/**
 * Constructor for one solution.
 */
00652 RS_VectorSolutions::RS_VectorSolutions(const RS_Vector& v1) {
    num = 1;
    vector = new RS_Vector[num];
    vector[0] = v1;
    tangent = false;
}



/**
 * Constructor for two solutions.
 */
00664 RS_VectorSolutions::RS_VectorSolutions(const RS_Vector& v1,
                                       const RS_Vector& v2) {
    num = 2;
    vector = new RS_Vector[num];
    vector[0] = v1;
    vector[1] = v2;
    tangent = false;
}



/**
 * Constructor for three solutions.
 */
00678 RS_VectorSolutions::RS_VectorSolutions(const RS_Vector& v1,
                                       const RS_Vector& v2,
                                                         const RS_Vector& v3) {
    num = 3;
    vector = new RS_Vector[num];
    vector[0] = v1;
    vector[1] = v2;
    vector[2] = v3;
    tangent = false;
}


/**
 * Constructor for four solutions.
 */
00693 RS_VectorSolutions::RS_VectorSolutions(const RS_Vector& v1,
                                       const RS_Vector& v2,
                                       const RS_Vector& v3,
                                       const RS_Vector& v4) {
    num = 4;
    vector = new RS_Vector[num];
    vector[0] = v1;
    vector[1] = v2;
    vector[2] = v3;
    vector[3] = v4;
    tangent = false;
}


/**
 * Constructor for four solutions.
 */
00710 RS_VectorSolutions::RS_VectorSolutions(const RS_Vector& v1,
                                       const RS_Vector& v2,
                                       const RS_Vector& v3,
                                       const RS_Vector& v4,
                                                         const RS_Vector& v5) {
    num = 5;
    vector = new RS_Vector[num];
    vector[0] = v1;
    vector[1] = v2;
    vector[2] = v3;
    vector[3] = v4;
    vector[4] = v5;
    tangent = false;
}



/**
 * Destructor.
 */
00730 RS_VectorSolutions::~RS_VectorSolutions() {
    clean();
}


/**
 * Allocates 'num' vectors.
 */
00738 void RS_VectorSolutions::alloc(int num) {
      clean();
      this->num = num;
    vector = new RS_Vector[num];
      for (int i=0; i<num; ++i)  {
      vector[i] = RS_Vector(false);
      }
    tangent = false;
}

/**
 * Deletes vector array and resets everything.
 */
00751 void RS_VectorSolutions::clean() {
    if (vector!=NULL) {
        delete[] vector;
    }
    vector = NULL;
    num = 0;
    tangent = false;
}



/**
 * @return vector solution number i or an invalid vector if there
 * are less solutions.
 */
00766 RS_Vector RS_VectorSolutions::get(int i) const {
    if (i<num) {
        return vector[i];
    } else {
        return RS_Vector(false);
    }
}



/**
 * @return Number of solutions available.
 */
00779 int RS_VectorSolutions::getNumber() const {
    return num;
}



/**
 * @retval true There's at least one valid solution.
 * @retval false There's no valid solution.
 */
00789 bool RS_VectorSolutions::hasValid() const {
      for (int i=0; i<num; i++) {
        if (vector[i].valid) {
                  return true;
            }
      }

      return false;
}



/**
 * Sets the solution i to the given vector.
 * If i is greater than the current number of solutions available,
 * nothing happens.
 */
00806 void RS_VectorSolutions::set(int i, const RS_Vector& v) {
    if (i<num) {
        vector[i] = v;
    }
}



/**
 * Sets the tangent flag.
 */
00817 void RS_VectorSolutions::setTangent(bool t) {
    tangent = t;
}



/**
 * @return true if at least one of the solutions is a double solution
 * (tangent).
 */
00827 bool RS_VectorSolutions::isTangent() const {
    return tangent;
}



/**
 * Rotates all vectors around the given center by the given angle.
 */
00836 void RS_VectorSolutions::rotate(RS_Vector center, double ang) {
    for (int i=0; i<num; i++) {
        if (vector[i].valid) {
                  vector[i].rotate(center, ang);
            }
      }
}


/**
 * Scales all vectors by the given factors with the given center.
 */
00848 void RS_VectorSolutions::scale(RS_Vector center, RS_Vector factor) {
    for (int i=0; i<num; i++) {
        if (vector[i].valid) {
                  vector[i].scale(center, factor);
            }
      }
}


/**
 * @return vector solution which is the closest to the given coordinate.
 * dist will contain the distance if it doesn't point to NULL (default).
 */
00861 RS_Vector RS_VectorSolutions::getClosest(const RS_Vector& coord,
        double* dist, int* index) const {
            
    double curDist;
    double minDist = RS_MAXDOUBLE;
    RS_Vector closestPoint(false);

      //std::cout << "RS_VectorSolutions::getClosest: " << *this << "\n";

    for (int i=0; i<num; i++) {
        if (vector[i].valid) {
            curDist = coord.distanceTo(vector[i]);

            if (curDist<minDist) {
                closestPoint = vector[i];
                minDist = curDist;
                if (dist!=NULL) {
                    *dist = curDist;
                }
                if (index!=NULL) {
                    *index = i;
                }
            }
        }
    }

      //std::cout << "closest: " << closestPoint << "\n";

    return closestPoint;
}


RS_VectorSolutions RS_VectorSolutions::operator = (const RS_VectorSolutions& s) {
      alloc(s.getNumber());
      setTangent(s.isTangent());
      for (int i=0; i<s.getNumber(); ++i) {
            set(i, s.get(i));
      }

      return *this;
}


std::ostream& operator << (std::ostream& os,
                                  const RS_VectorSolutions& s) {
    for (int i=0; i<s.num; ++i) {
        os << "(" << s.get(i) << ")\n";
    }
    os << " tangent: " << (int)s.isTangent() << "\n";
    return os;
}


// EOF


Generated by  Doxygen 1.6.0   Back to index