2D Vector/Point

source: vec2.zip

This class captures the non-graphical behavior (i.e. the mathematics) of two-dimensional points or vectors.

Consider a coordinate point as being specified by a vector whose tail is located or fixed at the origin.

Contents

vec2.h
vec2.cpp
main.cpp
stdafx.h
test results

vec2.h


/*\file vec2.h
*/
/*!    Vec2 is a two dimensional point
*/

#pragma once
#include <iostream>
#include <assert.h>
#include <math.h>


//! defines two-dimensional point
class Vec2 {
public:	
	Vec2() { Vec2(0.0,0.0); } //!< default no-argument constructor
	~Vec2() {} //!< destructor
	//! constructs Vec2 from (x,y) coordinates
	Vec2(double x, double y) { body[0] = x; body[1] = y; }
	//! constucts unit vector at angle theta (in degrees) from x-axis
	Vec2(double theta);
	//! returns length of associated array
	int length() const { return 2; }
	//! return pointer to first element
	double * vptr() { return body; }
	//! set Vec2 to new value
	Vec2 &set(double x, double y) { body[0]=x; body[1]=y; return *this; }
	//! scale Vec2 by constant factor
	Vec2 &scale(double scl) { body[0]*=scl; body[1] *=scl; return *this; }
	Vec2 &rotate(double theta);
	//! translate Vec2 by (x,y)
	Vec2 &translate(double x, double y) { body[0] += x; body[1] += y; return *this; }
	//! translate Vec2 by another Vec2
	Vec2 &translate(Vec2 &v) { body[0] += v[0]; body[1] += v[1]; return *this; }
	//! result = a + b
	friend void sum(Vec2 &result,const Vec2 &a,const Vec2 &b);
	//! result = a - b
	friend void diff(Vec2 &result, const Vec2 &a, const Vec2 &b);
	//! returns magnitude (norm 2) of vector
	double getSize() const;
	//! sets magnitude of vector
	Vec2 &setSize(double sz);
	// subscript operatator
	//! subscript operator (non-const object)
	double &operator[](int k)  { return body[k]; }
	//! subscript operator (const object)
	const double &operator[](int k) const { return body[k]; }
	//operator overloads
	Vec2 &operator+=(const Vec2&b);
	friend Vec2 operator+(const Vec2&a, const Vec2&b);
	friend Vec2 operator-(const Vec2&a, const Vec2&b);
	friend Vec2 operator-(const Vec2&a);
	friend Vec2 operator+(const Vec2&a, double b);
	friend Vec2 operator-(const Vec2&a, double b);
	friend Vec2 operator*(const Vec2&a, double b);
	friend Vec2 operator/(const Vec2&a, double b);
	
	//! iostream output
	friend std::ostream& operator << (std::ostream& s, const Vec2& v);
	//! iostream input
	friend std::istream& operator >> (std::istream& s, Vec2& v);
private:
	double body[2]; //!< contains the elements of a 2D point or vector
};

//! returns a += b;
inline Vec2 & Vec2::operator+=(const Vec2 &b)
{
	body[0] += b[0];
	body[1] += b[1];
	return *this;
}


//! returns (a+b)
inline Vec2 operator+(const Vec2 &a, const Vec2 &b)
{
	return Vec2(a[0]+b[0],a[1]+b[1]);
}

inline void sum(Vec2 &result, const Vec2 &a, const Vec2 &b)
{
	result[0] = a[0]+b[0];
	result[1] = a[1]+b[1];
}

//! returns (a-b)
inline Vec2 operator-(const Vec2 &a, const Vec2 &b)
{
	return Vec2(a[0]-b[0],a[1]-b[1]);
}

inline void diff(Vec2 &result, const Vec2 &a, const Vec2 &b)
{
	result[0] = a[0]-b[0];
	result[1] = a[1]-b[1];
}

//! returns -a
inline Vec2 operator-(const Vec2 &a) { return Vec2(-a[0],-a[1]); }

//! returns a + scalar
inline Vec2 operator+(const Vec2&a, double b) {return Vec2(a[0]+b,a[1]+b); }
//! returns a - scalar
inline Vec2 operator-(const Vec2&a, double b) {return Vec2(a[0]-b,a[1]-b); }
//! returns a * scalar
inline Vec2 operator*(const Vec2&a, double b) {return Vec2(a[0]*b,a[1]*b); }
//! returns a / scalar
inline Vec2 operator/(const Vec2&a, double b) {return Vec2(a[0]/b,a[1]/b); }

//! return dot product 
inline double dot(const Vec2 &a, const Vec2 &b)
{
	return a[0]*b[0]+a[1]*b[1];
}

//! return 2D point perpendicular to argument
inline Vec2 perp(const Vec2 &v) { return Vec2(-v[1],v[0]); }

//! return 2-norm (vector length, distance from origin)
inline double magn(const Vec2 &a)
{
	return a.getSize();
}

//! return 2-norm (vector magnitude or length, distance from origin)
inline double Vec2::getSize() const
{
	const Vec2 &p = *this;
	return _hypot(p[0],p[1]);
}

//! set vector to specified len,gth or magnitude
inline Vec2 &Vec2::setSize(double sz)
{
	Vec2 &p = *this;
	double vn = getSize();
	assert(vn>0.0);
	sz /= vn;
	p[0] *= sz;
	p[1] *= sz;
	return *this;
}
	

//! return distance between two points
//  This is the same as magn(a-b)
inline double distance(const Vec2 &a, const Vec2 &b)
{
	return _hypot(a[0]-b[0],a[1]-b[1]);
}


double perpdot(const Vec2 &a, const Vec2 &b);
double angle(const Vec2 &a,const Vec2 &b);
Vec2 rotate(const Vec2 &a, double theta);


vec2.cpp


/* \file vec2.cpp
 *
 */
#include "stdafx.h"
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <iostream>
#include "vec2.h"

//! overloaded insertion operator <<
std::ostream& operator << (std::ostream& s, const Vec2& v)
{
	s << "[" << v[0] << " "  << v[1] << "]";
	return s ;
}

//! overloaded extraction operator >>
std::istream& operator >> (std::istream& s, Vec2& v) {
	char	c = ' ';

	while (isspace(c))
		s >> c;
    // The vectors can be formatted either as x y or [ x y ]
	if (c == '[') {
		s >> v[0] >> v[1];
		while (s >> c && isspace(c)) ;
		if (c != ']') s.putback(c); // let someone else deal with it
	}
	else {
		s.putback(c);
		s >> v[0] >> v[1];
	}
	return s;
}

//! return magnitude of cross product
/*!
 *  for 2D this is dot(perp(a),b)\n
 *  for 3D this is the magnitude of cross(a,b)
 */
double perpdot(const Vec2 &a, const Vec2 &b)
{
	return a[0]*b[1]-a[1]*b[0];
}

//! returns angle (in degrees) between two vectors
double angle(const Vec2 &a, const Vec2 &b)
{
	double c, s;
	const double dgr = 45.0/atan(1.0);
	c = dot(a,b);
	s = perpdot(a,b);
	return dgr*atan2(s,c);
}

const double radg = atan(1.0)/45.0;


Vec2::Vec2(double theta)
{
	theta *= radg;
	set(cos(theta),sin(theta));
}

//! rotate Vec2 about the origin by angle theta in degrees
Vec2 &Vec2::rotate(double theta)
{
	double c, s;
	Vec2 &a = *this;
	if (theta==0.0) return a;
	theta *= radg;
	c = cos(theta);
	s = sin(theta);
	double tmp = s*a[0]+c*a[1];
	a[0] = c*a[0]-s*a[1];
	a[1] = tmp;
	return a;
}

//! returns vec rotated by angle theta in degrees
Vec2 rotate(const Vec2 &a, double theta)
{
	double c, s;
	theta *= radg;
	c = cos(theta);
	s = sin(theta);
	return Vec2(c*a[0]-s*a[1],s*a[0]+c*a[1]);
}


stdafx.h


// stdafx.h
// stub for console applications


main.cpp


/* main
 */
#include <stdio.h>
#include <math.h>
#include <iostream>
using namespace std;
#include "vec2.h"

void test1();
void test2();
void test3();

int main()
{
	test1();
	cout << "main program done"<<endl;
	return 0;
}

void test3()
{
	Vec2 a(5,8);
	Vec2 b(4,-3);
	cout << "angle (a,b) = " << angle(a,b) << endl;
	cout << "perpdot(a,b) = " << perpdot(a,b) << endl;
	cout << "dot(perp(a),b)- perpdot(a,b) = " << dot(perp(a),b)-perpdot(a,b) << endl;
	cout << "done test3" << endl;
}

void test2()
{
	Vec2 a(10,20);
	Vec2 b(-5,12);
	Vec2 d(11,9);
	double p = dot(a-b,d);
	cout << "dot(a-b,d) = " << p << endl;
	cout << "b-d-a = " << b-d-a << endl;
	cout << "test2 done" << endl;
}	

void test1()
{
	Vec2 a(4,20);
	Vec2 b(4,-3);
	Vec2 d(-8,4);

	//printf("Vec2 a "); a.print();
	cout << "Vec2 a " << a << endl;
	cout << "Vec2 b " << b << endl;
	cout << "a + b " << a+b << endl;
	cout << "perp(a) " << perp(a) << endl;
	double s = perpdot(a,b)/magn(a)/magn(b);
	printf("sine = %g\n",s);
	double c = dot(a,b)/magn(a)/magn(b);
	printf("cosine = %g\n",c);
	printf("check that c^2 + s^2 - 1 = 0 :\n");
	cout << "magn(Vec2(c,s))-1 = " << magn(Vec2(c,s))-1 << endl;
	cout << "c*c+s*s - 1.0 = " << c*c+s*s-1.0 << endl;
	cout << "angle from a to b: " << angle(a,b) <<endl;
	cout << "sum of angles for three points : " << angle(a,d)+angle(d,b)+angle(b,a)<<endl;
	cout << "test1 done" << endl;
}
	


Results

Vec2 a [4 20]
Vec2 b [4 -3]
a + b [8 17]
perp(a) [-20 4]
sine = -0.902134
cosine = -0.431455
check that c^2 + s^2 - 1 = 0 :
magn(Vec2(c,s))-1 = -2.22045e-016
c*c+s*s - 1.0 = -3.33067e-016
angle from a to b: -115.56
sum of angles for three points : 360
test1 done
main program done


Maintained by John Loomis, updated Thu Jan 24 19:16:14 2008