Hey everyone, I'm back in C++ this semester; Last semester I went through Structured C++ (and passed with a 4.0; many thanks to all of you!) and this semester I'm in OOP.

I don't have sample code yet because I haven't started. But I was talking to a classmate, and one of our programming exercises wants us to write a function that will modify a point (i.e., (3, 2)) so that it will rotate it 90 degrees, clockwise. Is there an easier way to do this rather than 5 or 6 "If" statements?


Example scenario:

I input point x as 3 and point y as 2. I select the option to rotate the point by 90 degrees and should get x as 2 and y as -3.

How do you rotate a point? A point is a point, there's no kind of transformation you can do until you have more than one. :D

How do you rotate a point? A point is a point, there's no kind of transformation you can do until you have more than one. :D

I haven't taken a math class in many, many years, but from what I can recall, you rotate a point by drawing a vector starting at the origin and passing through the point, and then rotate that vector 90 degrees, in this case.

I haven't taken a math class in many, many years, but from what I can recall, you rotate a point by drawing a vector starting at the origin and passing through the point, and then rotate that vector 90 degrees, in this case.

Yes that's right, but it assumes you're rotating about the origin :) Either way, the origin is a point, so, as hamrick said, you need two points in order to rotate something. :)

Thanks Dave; any tips as to which ones? ;)

Hamrick: sorry I didn't clarify. There is an assumed point (i'm guessing) that is constant at (0,0).

x' = x * cosine(90) + y * sine(90)
y' = x * sine(90) - y * cosine(90)

that look right?

edit] i think these are the right ones:

rx = x * cos(90) + y * sin(90) ;
ry = y * cos(90) - x * sin(90) ;

point(double x_ = 0, double y_ = 0)
   : x(x_), y(y_), 
   radius(std::sqrt(x * x + y * y)), 
   angle(std::atan(y / x))
   {
   }
   void rotate(double radians)
   {
      angle = std::fmod(angle + radians, 2 * pi);
      x = radius * cos(angle);
      y = radius * sin(angle);
   }

Ok, here's how I am doing it; is this wrong?

#include <cmath>
#include <iostream>
using namespace std ;

int main () 
{
    int x ;
    int y ;
    double angle ;
    int rx ;
    int ry ;

    angle = 90 ;
    x = 3 ;
    y = 2 ;
    rx = x * cos(angle) + y * sin(angle) ;
    ry = y * cos(angle) - x * sin(angle) ;

    cout << rx << " " << ry << endl ;

    return 0 ;
}

something is wrong, because for x i get 0 output, but when i do it in my calculator i get the right answer (2) !

Edited 3 Years Ago by pyTony: fixed formatting

Ok i've tried my equation with multiple expamples and i think it works, but why am i getting the wrong output?

for output i get x = 0 y = -3; x should be 2, y is right.

ha! Isn't it horrible when you have to spend more time on the math fundimentals than on the programming?

I'm getting ready for bed, but if someone could give me a hand in the next couple minutes I would really appreciate it!!

Here's my current delima:

//header

#pragma once

#include <cmath>
#include <iostream>
using namespace std ;

class Point
{
public:
    void menu ( ) ;
    void set ( int , int ) ;
private:
    void movePoints ( int , int ) ;
    void rotate ( int , int ) ;
    void getX ( ) const ;
    void getY ( ) const ;

    int x ;
    int y ;
    int rx ;
    int ry ;

    double angle ;
};

//other relevant code
//header file
#include "prob3.h"

//driver function
int main () 
{
    Point PointOpp ;

    int xCoord ;
    int yCoord ;

    cout << "Please enter your 'x' coordinant:  " << flush ;
    cin >> xCoord ;
    cout << "Please enter your 'y' coordinant:  " << flush ;
    cin >> yCoord ;

    PointOpp.set ( xCoord , yCoord ) ;
    PointOpp.menu ( ) ;

    return 0 ;
}

//last of relevant code
void Point::menu ( ) 
{
    int a ;
    int opp ;
    int xAm ;
    int yAm ;

    do
    {
    cout << "1.  Move the point" << endl ;
    cout << "2.  Rotate the point by 90 degrees" << endl ;
    cout << "3.  Print 'x' value" << endl ;
    cout << "4.  Print 'y' value" << endl ;

    cout << "Please specify an opperation:  " << flush ;
    cin >> opp ;

    switch ( opp )
    {
    case 1:
        cout << "Specify the ammount in which to move the 'x' axis point:  " << flush ;
        cin >> xAm ;
        cout << "Specify the ammount in which to move the 'y' axis point:  " << flush ;
        cin >> yAm ;
        movePoints ( xAm , yAm ) ;
        break ;
    case 2:
        rotate( x , y ) ;
        break ;
    case 3:
        getX ( ) ;
        break ;
    case 4:
        getY ( ) ;
        break ;
    case 5:
        a = 5 ;
        break ;
    default:
        cout << "Invalid opption specified :: Limit input to '1', '2', '3', or '4'" << endl ;
        exit(1) ;
    }
} while ( a != 5 ) ;
}

//rotate function
void Point::rotate ( int rx , int ry )
{
    x = rx * cos(angle) + ry * sin(angle) ;
    y = ry * cos(angle) - rx * sin(angle) ;
    cout << x << " " << y << endl ;
}

All the other functions work, so I haven't posted them in here. My rotate function just outputs the orriginal x and y coordinates, with no changes.

I am almost positive the equation works, but you may want to double-check me. Maybe I'm using the cos/sin functions wrong? I'm not very familiar with cmath; only used it a couple times.

thanks for any help; i r really tired so i'll be getting in bed in a few and will finish up tomorrow morning if noone has posted in the next 10 minutes or so.

nite all

Edited 3 Years Ago by __avd: fixed formatting,

Just happened to think someone may want to put my code in their compiler; here's all of my code (see attached).

Attachments
#include "prob3.h"

void Point::menu ( ) 
{
	int a ;
	int opp ;
	int xAm ;
	int yAm ;

	do
	{
	cout << "1.  Move the point" << endl ;
	cout << "2.  Rotate the point by 90 degrees" << endl ;
	cout << "3.  Print 'x' value" << endl ;
	cout << "4.  Print 'y' value" << endl ;

	cout << "Please specify an opperation:  " << flush ;
	cin >> opp ;

	switch ( opp )
	{
	case 1:
		cout << "Specify the ammount in which to move the 'x' axis point:  " << flush ;
		cin >> xAm ;
		cout << "Specify the ammount in which to move the 'y' axis point:  " << flush ;
		cin >> yAm ;
		movePoints ( xAm , yAm ) ;
		break ;
	case 2:
		rotate( x , y ) ;
		break ;
	case 3:
		getX ( ) ;
		break ;
	case 4:
		getY ( ) ;
		break ;
	case 5:
		a = 5 ;
		break ;
	default:
		cout << "Invalid opption specified :: Limit input to '1', '2', '3', or '4'" << endl ;
		exit(1) ;
	}
} while ( a != 5 ) ;
}


void Point::set ( int xPoint, int yPoint )
{
	x = xPoint ;
	y = yPoint ;
}


void Point::movePoints ( int xPoint , int yPoint )
{
	x += xPoint ;
	y += yPoint ;
}


void Point::rotate ( int rx , int ry )
{
	x = rx * cos(angle) + ry * sin(angle) ;
	y = ry * cos(angle) - rx * sin(angle) ;
	cout << x << " " << y << endl ;
}


void Point::getX ( ) const
{
	cout << x << endl ;
}


void Point::getY ( ) const
{
	cout << y << endl ;
}
#pragma once

#include <cmath>
#include <iostream>
using namespace std ;

class Point
{
public:
	void menu ( ) ;
	void set ( int , int ) ;
private:
	void movePoints ( int , int ) ;
	void rotate ( int , int ) ;
	void getX ( ) const ;
	void getY ( ) const ;
	
	int x ;
	int y ;
	int rx ;
	int ry ;

	double angle ;
};
// File:  prob3.main.cpp
// Location:  C:\Documents and Settings\ctote.REG\Desktop\My Docs\c++\OOP - ch6.assign3\OOP - ch6.assign3
// Author:  Caleb Tote
// Date:  Aug. 28, 2007
// Class:  C++ - OOP


//header file
#include "prob3.h"

//driver function
int main () 
{
	Point PointOpp ;

	int xCoord ;
	int yCoord ;

	cout << "Please enter your 'x' coordinant:  " << flush ;
	cin >> xCoord ;
	cout << "Please enter your 'y' coordinant:  " << flush ;
	cin >> yCoord ;

	PointOpp.set ( xCoord , yCoord ) ;
	PointOpp.menu ( ) ;
	
	return 0 ;
}

> something is wrong, because for x i get 0 output,
If you had bothered to read the manual, you would have discovered that the trig functions work in radians, not degrees.

Comments
w00p, thanks!

Ok, now I'm getting output, but it's 1 off (for x). The y values are still right.

Here's my updated function:

void Point::rotate ( int rx , int ry )
{
    angle = 1.57079633 ;
    x = rx * cos(angle) + ry * sin(angle) ;
    y = ry * cos(angle) - rx * sin(angle) ;
    cout << x << " " << y << endl ;
}

Edited 3 Years Ago by __avd: fixed formatting

If you're rotating 270 degrees (or any multiple of 2pi/4 radians), there's no reason to be using trig functions. Just replace (x,y) -> (y,-x). That's what your code simplifies to, once you replace cos(angle) with 0 and sin(angle) with 1. You don't really need to know trig for this, just congruent triangles :-)

Also, make a habit of thinking in radians (which is just a way of describing angles as a fraction of a full circle). It's useful. Always look upon degrees as inferior, except when navigating. It helps if you remember that 2pi is a fundamental constant, while pi is merely 2pi/2, and a quarter circle is 2pi/4, etc. The people who decided that 3.141... was worthy of a name while 6.283... was not were noobs.

Also, in your implementation above, you really shouldn't hard-code the constant 2pi/4. Write it as SOME_NAME_FOR_PI/2. The only reason for this is that your constant doesn't have all the digits you need -- and you don't want to go around copying some random mathematical constants all over the place, to 16 decimal places or whatever is needed to completely fill the floating point mantissa you're using. It's much easier to remember the name. You'll suffer inaccuracy from using a constant that only goes to a paltry 8 decimal places. And you're using floating point numbers which gives you inherent accuracy. For rotating integers 90 degrees, using floating point math is just immoral :-) You're getting errors not from the inaccuracy of your constant though, but of the inherent inaccuracy of floating point arithmetic. (For example, what does your computer think sin(4*atan2(1,1)) is?) When truncating that to an integer (as you are recklessly doing) you get numbers that are off by 1.

P.S. What the hello? What do rx and ry mean as members of the Point class? ... WTF?

Comments
thanks! good explanation

If you're rotating 270 degrees (or any multiple of 2pi/4 radians), there's no reason to be using trig functions. Just replace (x,y) -> (y,-x). That's what your code simplifies to, once you replace cos(angle) with 0 and sin(angle) with 1. You don't really need to know trig for this, just congruent triangles :-)

Also, make a habit of thinking in radians (which is just a way of describing angles as a fraction of a full circle). It's useful. Always look upon degrees as inferior, except when navigating. It helps if you remember that 2pi is a fundamental constant, while pi is merely 2pi/2, and a quarter circle is 2pi/4, etc. The people who decided that 3.141... was worthy of a name while 6.283... was not were noobs.

Also, in your implementation above, you really shouldn't hard-code the constant 2pi/4. Write it as SOME_NAME_FOR_PI/2. The only reason for this is that your constant doesn't have all the digits you need -- and you don't want to go around copying some random mathematical constants all over the place, to 16 decimal places or whatever is needed to completely fill the floating point mantissa you're using. It's much easier to remember the name. You'll suffer inaccuracy from using a constant that only goes to a paltry 8 decimal places. And you're using floating point numbers which gives you inherent accuracy. For rotating integers 90 degrees, using floating point math is just immoral :-) You're getting errors not from the inaccuracy of your constant though, but of the inherent inaccuracy of floating point arithmetic. (For example, what does your computer think sin(4*atan2(1,1)) is?) When truncating that to an integer (as you are recklessly doing) you get numbers that are off by 1.

P.S. What the hello? What do rx and ry mean as members of the Point class? ... WTF?

Ah cool, thanks. I just got my c++ teacher to look at it and he had no clue why I was getting the wrong output either. so we simplified the function to:

void Point::rotate ( double rx , double ry )
{
    //angle = 1.57079633 ;
    //x = rx * cos(angle) + ry * sin(angle) ;
    //y = ry * cos(angle) - rx * sin(angle) ;
    x = ry;
    y = -rx;
}

much easier. I was wanting to allow the user to input an angel so that they wouldn't be restricted to just 90 degrees, but oh'well. thanks for the help guys.

oh, and rx and ry weren't supposed to be there, thanks for point that out rash!

ps) if someone could figure out why my equations weren't outputting the right stuff, my teacher asked me to tell him what the problem was.

ps) if someone could figure out why my equations weren't outputting the right stuff, my teacher asked me to tell him what the problem was.

You're talking about the off-by-one errors? You were converting a floating point number to an integer, which is done by truncation. When you try to compute the sine of pi/2 with the inaccurate approximation you had there, you get something like 0.99999394829..., instead of 1. Then, multiplying that by an integer (for example, 5) produces a number slightly less than 5, like 4.99996... Then converting this to an integer truncates, giving 4. If you're going to allow free rotation of points (as you've mentioned the possibility), it doesn't really make sense unless you use doubles to represent the coordinates.

Since you've done your due diligence Duki, and I messed around with this assignment myself, here is what I had come up with (and one quick last-minute change credited to Rashakil Fol).

#include <iostream>
#include <cmath>

static const double pi = 4.0 * std::atan(1.0);

class point
{
   double x, y, radius, angle;
public:
   point(double x_ = 0, double y_ = 0)
   : x(x_), y(y_), radius(std::sqrt(x * x + y * y)), angle(std::atan2(y, x))
   {
   }
   void rotate(double radians)
   {
      angle += radians;
      x = radius * std::cos(angle);
      y = radius * std::sin(angle);
   }
   friend std::ostream &operator<< (std::ostream &o, const point &p)
   {
      return o << p.x << ',' << p.y;
   }
};

int main()
{
   point A(3,2); // A(-3,2);
   std::cout << A << '\n';
   for ( int i = 0; i < 12; ++i )
   {
      A.rotate(-pi / 6);
      std::cout << A << '\n';
   }
   return 0;
}

/* my output
3,2
3.59808,0.232051
3.23205,-1.59808
2,-3
0.232051,-3.59808
-1.59808,-3.23205
-3,-2
-3.59808,-0.232051
-3.23205,1.59808
-2,3
-0.232051,3.59808
1.59808,3.23205
3,2
*/

/* my output
-3,2
-1.59808,3.23205
0.232051,3.59808
2,3
3.23205,1.59808
3.59808,-0.232051
3,-2
1.59808,-3.23205
-0.232051,-3.59808
-2,-3
-3.23205,-1.59808
-3.59808,0.232051
-3,2
*/

FWIW to compare and contrast and criticise.

You're talking about the off-by-one errors? You were converting a floating point number to an integer, which is done by truncation. When you try to compute the sine of pi/2 with the inaccurate approximation you had there, you get something like 0.99999394829..., instead of 1. Then, multiplying that by an integer (for example, 5) produces a number slightly less than 5, like 4.99996... Then converting this to an integer truncates, giving 4. If you're going to allow free rotation of points (as you've mentioned the possibility), it doesn't really make sense unless you use doubles to represent the coordinates.

oh ok; that makes perfect sense, thanks!

Since you've done your due diligence Duki, and I messed around with this assignment myself, here is what I had come up with (and one quick last-minute change credited to Rashakil Fol).

#include <iostream>
#include <cmath>

static const double pi = 4.0 * std::atan(1.0);

class point
{
   double x, y, radius, angle;
public:
   point(double x_ = 0, double y_ = 0)
   : x(x_), y(y_), radius(std::sqrt(x * x + y * y)), angle(std::atan2(y, x))
   {
   }
   void rotate(double radians)
   {
      angle += radians;
      x = radius * std::cos(angle);
      y = radius * std::sin(angle);
   }
   friend std::ostream &operator<< (std::ostream &o, const point &p)
   {
      return o << p.x << ',' << p.y;
   }
};

int main()
{
   point A(3,2); // A(-3,2);
   std::cout << A << '\n';
   for ( int i = 0; i < 12; ++i )
   {
      A.rotate(-pi / 6);
      std::cout << A << '\n';
   }
   return 0;
}

/* my output
3,2
3.59808,0.232051
3.23205,-1.59808
2,-3
0.232051,-3.59808
-1.59808,-3.23205
-3,-2
-3.59808,-0.232051
-3.23205,1.59808
-2,3
-0.232051,3.59808
1.59808,3.23205
3,2
*/

/* my output
-3,2
-1.59808,3.23205
0.232051,3.59808
2,3
3.23205,1.59808
3.59808,-0.232051
3,-2
1.59808,-3.23205
-0.232051,-3.59808
-2,-3
-3.23205,-1.59808
-3.59808,0.232051
-3,2
*/

FWIW to compare and contrast and criticise.

Dang, that looks more effecient than mine. Two steps forward, one step back I guess ;)


Thanks everyone for the help; I'll edit my program tomorrow Rash, so that I can allow multiple angles rather than just 90 degrees. Great explanations too!

I'm going to send this link to my professor in a minute. Thanks again guys.

This article has been dead for over six months. Start a new discussion instead.