geometry.cpp

#include "geometry.h"
#include "stdafx.h"
#include "testing.h"

using namespace std;

/**
 *   Computes the area of a circle
 */
double Circle::area() {
	return PI*radius*radius;
}

/**
 *  Computes the circumference of a circle
 */
double Circle::circumference() {
	return 2*PI*radius;
}

/**
 *  Computes the distance between two cartesian points
 */
double CartesianPoint::distanceTo( const CartesianPoint& other ) const {
    double dx = other.x - x;
    double dy = other.y - y;
    return sqrt( dx*dx + dy*dy );
}

/**
 *  Computes the distance between this and a polar point
 */
double CartesianPoint::distanceTo( const PolarPoint& other ) const {
    return distanceTo( polarToCartesian( other ));
}



/**
 *  Converts polar coordinates to cartesian. Note, this changes x and y.
 */
CartesianPoint polarToCartesian( const PolarPoint& p ) {
    CartesianPoint c;
	c.x = p.r*cos( p.theta );
	c.y = p.r*sin( p.theta );
    return c;
}

/**
 *   Converts Cartesian coordinates to polar coordinates. Note this
 *   changes r and theta.
 */
PolarPoint cartesianToPolar( const CartesianPoint& c) {
    PolarPoint p;
	// Not as easy as it looks to do this
	p.r = sqrt( c.x*c.x + c.y*c.y);
	if (c.y==0.0) {
		if (c.x>=0.0) {
			p.theta = 0.0;
		} else if (c.x<0.0) {
			p.theta = -PI;
		}
	} else {
		p.theta = acos( c.x/p.r);
		if (c.y<0) {
			p.theta = -p.theta;
		}
	}
    return p;
}


/////////////////////////////////////////////////
//
//  Geometry tests
//
/////////////////////////////////////////////////

static void testUsage() {
    CartesianPoint cartesianPoint;
    cartesianPoint.x = 100;
    cartesianPoint.y = 150;
    cout << "Coordinates (";
    cout << cartesianPoint.x ;
    cout << ", ";
    cout << cartesianPoint.y ;
    cout << ")\n";

    cartesianPoint.x *= 2;
    cartesianPoint.y *= 2;
    cout << "Rescaled cordinates (";
    cout << cartesianPoint.x ;
    cout << ", ";
    cout << cartesianPoint.y ;
    cout << ")\n";
}

static void testAreaOfCircle() {
    Circle c;
    c.radius = 4;
	ASSERT_APPROX_EQUAL( c.area(), 16*PI, 0.01 );
}

static void testCircumferenceOfCircle() {
    Circle c;
    c.radius = 2;
	ASSERT_APPROX_EQUAL( c.circumference(), 4*PI, 0.01 );
}

static void testPolarToCartesian() {
    PolarPoint p;
    p.r = 2.0;
    p.theta = PI/2;
	CartesianPoint c = polarToCartesian( p );
	ASSERT_APPROX_EQUAL( c.x,0.0,0.001 );
	ASSERT_APPROX_EQUAL( c.y,2.0,0.001 );
}

static void testCartesianToPolar() {
	// the logic of cartesian to polar is quite complex so we have more tests
	vector<double> angles;
	angles.push_back( 0.0 );
	angles.push_back( PI/4 );
	angles.push_back( PI/2 );
	angles.push_back( 7*PI/8 );
	angles.push_back( PI);
	angles.push_back( -PI/4 );
	angles.push_back( -PI/2 );
	angles.push_back( -7*PI/8 );

	int nAngles = angles.size();
	for (int i=0; i<nAngles; i++) {
        PolarPoint p;
		p.r = 2.0;
		p.theta =angles[i];
		CartesianPoint c =polarToCartesian( p);
		PolarPoint p2;
		p2 = cartesianToPolar( c );
		ASSERT_APPROX_EQUAL( p.r,p2.r,0.001 );
		ASSERT_APPROX_EQUAL( p.theta,p2.theta,0.001 );
	}
}

static void testDistanceTo() {
    CartesianPoint p1;
    p1.x = 1;
    p1.y = 1;
    CartesianPoint p2;
    p2.x = 4;
    p2.y = 5;
    double d = p1.distanceTo( p2 );
    ASSERT_APPROX_EQUAL( d, 5.0, 0.0001);    
}

static void testDistanceToPolar() {
    CartesianPoint p1;
    p1.x = 1;
    p1.y = 1;
    CartesianPoint p2;
    p2.x = 4;
    p2.y = 5;
    double d = p1.distanceTo( cartesianToPolar(p2) );
    ASSERT_APPROX_EQUAL( d, 5.0, 0.0001);    
}




void testGeometry() {
    TEST (testUsage );
	TEST( testAreaOfCircle );
	TEST( testCircumferenceOfCircle );
	TEST( testPolarToCartesian );
	TEST( testCartesianToPolar );
    TEST( testDistanceTo );
    TEST( testDistanceToPolar );
}