473,320 Members | 1,865 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Angle class - how is my code ?

Hi there,

I've attempted to implement an Angle class. An Angle is a subset of an
integer, where the range is [0,360). All other operations should be
permitted.

The code works, I think... except (for example) a = b + 10;
needs to be a = b + (Angle) 10;

Could some kind soul comment on my code and show me how it could be
done better?

class Angle {
friend std::ostream& operator<<(std::ostream&, const Angle&) {
os << s.theta;
return os;
}

public:
Angle() : theta(0) { };
Angle(int t) : theta(t) { };
Angle(const Angle& a) : theta(a) { };

Angle& operator=(const Angle& rhs) {
theta = rhs % 360;
return *this;
}

Angle& operator+=(const Angle& a) {
theta = (theta + a) % 360;
if (theta < 0)
theta = 360 - abs(theta);
return *this;
}

Angle& operator-=(const Angle& a) {
Angle t = a % 360;
theta = theta - t;
if (theta < 0)
theta = 360 - abs(theta);
return *this;
}

operator int() const {
return theta;
}

private:
int theta;
};

Angle operator-(const Angle& l, const Angle& r) {
Angle a = l;
a -= r;
return a;
}

Angle operator+(const Angle& l, const Angle& r) {
Angle a = l;
a += r;
return a;
}

Many thanks,
Darren
Jul 22 '05 #1
5 3095
Darren Grant writes:
I've attempted to implement an Angle class. An Angle is a subset of an
integer, where the range is [0,360). All other operations should be
permitted.

The code works, I think... except (for example) a = b + 10;
needs to be a = b + (Angle) 10;

[snip]

The standard work around for that is to make the + operator a friend rather
than a member function. Friends are treated better than relatives. Go
figure.


Jul 22 '05 #2
Darren Grant wrote:
Hi there,

I've attempted to implement an Angle class. An Angle is a subset of an
integer, where the range is [0,360). All other operations should be
permitted.

The code works, I think... except (for example) a = b + 10;
needs to be a = b + (Angle) 10; This is because you have a conversion to int operator. Do you need this
conversion operator? I find that these kind of conversions to basic
types just get in the way. Normally providing a conversion constructor
and the appropriate operator overloads works fine.

Could some kind soul comment on my code and show me how it could be
done better?
#include <iostream>

class Angle {
friend std::ostream& operator<<(std::ostream&, const Angle&) {
os << s.theta;
return os;
} It does help to post the actual code :).
friend std::ostream& operator<<(std::ostream& os, const Angle&s) {

I prefer to avoid friends and you could by doing:
std::ostream& operator<<(std::ostream& os, const Angle&s) {
os << (int)s;
return os;
}
although a method to access to angle could be useful, e.g get_angle().

public:
Angle() : theta(0) { };
This allows theta to be out of range: Angle(int t) : theta(t) { }; If you had a function:
int clamp_angle ( int angle ) {
if ( angle >= 0 )
return angle % 360;
else
return 360 - (angle % 360);
}
then you could put:
Angle(int t) : theta(clamp_angle(t)) { };
Angle(const Angle& a) : theta(a) { };

Angle& operator=(const Angle& rhs) {
theta = rhs % 360; If angles are always in the range [0,360) why take the modulo here?
return *this;
}

Angle& operator+=(const Angle& a) {
theta = (theta + a) % 360;
if (theta < 0)
theta = 360 - abs(theta);
return *this;
} Once again if angles are always positive how can the result be less that 0?
Angle& operator+=(const Angle& a) {
theta = (theta + a) % 360;
return *this;
}
Angle& operator-=(const Angle& a) {
Angle t = a % 360;
theta = theta - t;
if (theta < 0)
theta = 360 - abs(theta);
return *this;
} You could do it more efficiently like this:
Angle& operator-=(const Angle& a) {
theta -= a;
if (theta < 0)
theta += 360;
return *this;
}

operator int() const {
return theta;
} I am not a big fan of these operators.

private:
int theta;
};

Angle operator-(const Angle& l, const Angle& r) {
Angle a = l;
a -= r;
return a;
}

Angle operator+(const Angle& l, const Angle& r) {
Angle a = l;
a += r;
return a;
}

Many thanks,
Darren

Jul 22 '05 #3
On Mon, 15 Dec 2003 16:57:04 +0000, Michael Mellor <news-at-@michaelmellor-
dot-.com> wrote:
Darren Grant wrote:
Hi there,

I've attempted to implement an Angle class. An Angle is a subset of an
integer, where the range is [0,360). All other operations should be
permitted.
Hi there,

Thanks for your time. I've looked over your suggestions, and implemented
some of them, which has made my code a lot better, but there is still one
small
problem. First may I present my updated code;

#include <iostream>

class Angle {
public:
Angle() : theta(0) { };
Angle(int t) : theta(clamp_angle(t)) { };

Angle(const Angle& a) : theta(a) { };

Angle& operator=(const Angle& rhs) {
theta = rhs % 360;
return *this;
}

Angle& operator+=(const Angle& a) {
theta = (theta + a) % 360;
return *this;
}

Angle& operator-=(const Angle& a) {
theta = (theta - a) % 360;
if (theta < 0)
theta += 360;
return *this;
}

operator int() const {
return theta;
}

private:
int theta;

int clamp_angle(int angle) {
if (angle >= 0)
return angle % 360;
else
return 360 + (angle % 360);
}
};

Angle operator-(const Angle&, const Angle&);
Angle operator+(const Angle&, const Angle&);

std::ostream& operator<<(std::ostream& os, const Angle& s) {
os << (int) s;
return os;
}

Angle operator-(const Angle& l, const Angle& r) {
Angle a = l;
a -= r;
return a;
}

Angle operator+(const Angle& l, const Angle& r) {
Angle a = l;
a += r;
return a;
}

I've removed some of the quoted text, and responded to the parts which
are still relevent:
The code works, I think... except (for example) a = b + 10;
needs to be a = b + (Angle) 10; This is because you have a conversion to int operator. Do you need this
conversion operator? I find that these kind of conversions to basic types
just get in the way. Normally providing a conversion constructor and the
appropriate operator overloads works fine.


I don't know how else to do it. If I comment out the conversion, I get
the error 'initializing' : cannot convert from 'const class Angle' to
'int'
for Angle(const Angle& a) : theta(a) { };
(and more errors).

I understand why - I just don't know how else to do it.
class Angle {
friend std::ostream& operator<<(std::ostream&, const Angle&) {
os << s.theta;
return os;
}

It does help to post the actual code :).
friend std::ostream& operator<<(std::ostream& os, const Angle&s) {


Sorry :) More care taken this time.
I prefer to avoid friends and you could by doing:
std::ostream& operator<<(std::ostream& os, const Angle&s) {
os << (int)s;
return os;
}
This works, which is cool. I'm learning C++ from Accelerated C++, which
used a friend in their example.
although a method to access to angle could be useful, e.g get_angle().
I havn't put this in, yet... I was hoping to get away with the int
conversion function.
public:
Angle() : theta(0) { };


This allows theta to be out of range:
Angle(int t) : theta(t) { };

If you had a function:
int clamp_angle ( int angle ) {
if ( angle >= 0 )
return angle % 360;
else
return 360 - (angle % 360);
}
then you could put:
Angle(int t) : theta(clamp_angle(t)) { };


Implemented, although I think you may have made a small mistake with
the sign in the last line of the function; corrected in my code above.
Angle(const Angle& a) : theta(a) { };

Angle& operator=(const Angle& rhs) {
theta = rhs % 360;

If angles are always in the range [0,360) why take the modulo here?


Ah, I meant the description, above, of the angles being in the
range [0,360) as a constraint, not a pre-condition.
Angle& operator-=(const Angle& a) {
Angle t = a % 360;
theta = theta - t;
if (theta < 0)
theta = 360 - abs(theta);
return *this;
}

You could do it more efficiently like this:
Angle& operator-=(const Angle& a) {
theta -= a;
if (theta < 0)
theta += 360;
return *this;
}


I don't think this worked right away, but I did implement a nicer bit of
code based on it.
operator int() const {
return theta;
}

I am not a big fan of these operators.


So, the class works (I have included the code I used to test it with below)
,
and it's a lot nicer than my first attempt, thanks to your email, and an
early
morning start :) But I still have the small problem, where
b + 10; needs to be
b + (Angle) 10;
else I get the error '+' : 2 overloads have similar conversions.

Can you provide any more help to sort this out?

Also,
On Mon, 15 Dec 2003 10:44:00 -0800, osmium <r1********@comcast.net> wrote: The standard work around for that is to make the + operator a friend
rather
than a member function. Friends are treated better than relatives. Go
figure.


I tried this, just by putting
friend Angle operator+(const Angle&, const Angle&);
in the class definition, instead of outside without 'friend', but I get
the error '+' : 2 overloads have similar conversions
for theta = (theta + a) % 360; (in Angle& operator+=()).

So can you show me the correct path? :)

Many thanks for your help,
Darren
Here is the code I have used to test my class with;

using namespace std;

int main(void) {
Angle a(10);
cout << "Angle a(10); a = " << a << endl;

Angle b(a);
cout << "Angle b(a); b = " << b << endl;

a = 50;
cout << "a = 50; a = " << a << endl;

a = b;
cout << "a = b; a = " << a << endl;

Angle c = -15;
cout << "Angle c = -15; c = " << c << endl << endl;

a = 10 + 5;
cout << "small addition; a = 10 + 5;\t\ta = " << a << endl;

a = 355 + 10;
cout << "large addition; a = 355 + 10;\t\ta = " << a << endl;

a = 355 + 710;
cout << "very large addition; a = 355 + 710;\ta = " << a << endl;

a = 10 + -15;
cout << "addition of a negative; a = 10 + -15;\ta = " << a << endl
<< endl;

a = 10 - 5;
cout << "a = 10 - 5; a = " << a << endl;

a = 5 - 10;
cout << "a = 5 - 10; a = " << a << endl;

a = -5 - 10;
cout << "a = -5 - 10; a = " << a << endl;

a = -5 - 370;
cout << "a = -5 - 370; a = " << a << endl << endl;

a = 10;
a += 365;
cout << "a = 10; a += 365;\ta = " << a << endl;

a = 10;
a -= 15;
cout << "a = 10; a -= 15;\ta = " << a << endl;

a = 10;
a -= 355;
cout << "a = 10; a -= 355;\ta = " << a << endl;

a = 10;
a -= 365;
cout << "a = 10; a -= 365;\ta = " << a << endl;

a = 10;
a -= 730;
cout << "a = 10; a -= 730;\ta = " << a << endl << endl;

cout << "b + 10 = " << (b + (Angle) 10) << endl;
cout << "b - 30 = " << (b - (Angle) 30) << endl;

return 0;
}
Jul 22 '05 #4
Darren Grant wrote:
On Mon, 15 Dec 2003 16:57:04 +0000, Michael Mellor
<news-at-@michaelmellor- dot-.com> wrote:
Darren Grant wrote:
Hi there,

I've attempted to implement an Angle class. An Angle is a subset of an
integer, where the range is [0,360). All other operations should be
permitted. [...]

This allows theta to be out of range:
Angle(int t) : theta(t) { };
If you had a function:
int clamp_angle ( int angle ) {
if ( angle >= 0 )
return angle % 360;
else
return 360 - (angle % 360);
}
then you could put:
Angle(int t) : theta(clamp_angle(t)) { };

Implemented, although I think you may have made a small mistake with
the sign in the last line of the function; corrected in my code above.


I am guilty of never testing the code.
Angle(const Angle& a) : theta(a) { };

Angle& operator=(const Angle& rhs) {
theta = rhs % 360;


If angles are always in the range [0,360) why take the modulo here?

Ah, I meant the description, above, of the angles being in the
range [0,360) as a constraint, not a pre-condition.


I am confused by the difference between constraint and pre-condition. As
I currently see it is your constraint is that theta will be in the range
[0,360) which implies the pre-condition for all methods of theta being
in that range.

[...]
I tried this, just by putting
friend Angle operator+(const Angle&, const Angle&);
in the class definition, instead of outside without 'friend', but I get
the error '+' : 2 overloads have similar conversions
for theta = (theta + a) % 360; (in Angle& operator+=()).

So can you show me the correct path? :)

You would have to remove the conversion operator and implement the class
something like this:
class Angle {
public:
Angle() : theta(0) { };
Angle(int t) : theta(clamp_angle(t)) { };

Angle(const Angle& a) : theta(a.get_angle()) { };

Angle& operator=(const Angle& rhs) {
// This modulo really isn't needed, if you allow an angle to
// be out of range why not allow the one your assigning it
// to be out of range?
theta = rhs.get_angle() % 360;
return *this;
}

Angle& operator+=(const Angle& a) {
theta = (theta + a.get_angle()) % 360;
return *this;
}

Angle& operator-=(const Angle& a) {
// This modulo can also go if you keep theta in range
// which the class does do
theta = (theta - a.get_angle()) % 360;
if (theta < 0)
theta += 360;
return *this;
}

int get_angle () const {
return theta;
}
private:
int theta;

int clamp_angle(int angle) {
if (angle >= 0)
return angle % 360;
else
return 360 + (angle % 360);
}
};

then this would work
Angle a(10);
Angle b(a);
cout << "b + 10 = " << (b + 10) << '\n';
cout << "b - 30 = " << (b - 30) << '\n';

BTW endl terminates the line and flushes the buffer, '\n' or "\n" just
terminate the line.

Mike
Jul 22 '05 #5
On Tue, 16 Dec 2003 14:24:05 +0000, Michael Mellor <news-at-@michaelmellor-
dot-.com> wrote:

[...]
Angle(const Angle& a) : theta(a) { };

Angle& operator=(const Angle& rhs) {
theta = rhs % 360;

If angles are always in the range [0,360) why take the modulo here?
Ah, I meant the description, above, of the angles being in the
range [0,360) as a constraint, not a pre-condition.

I am confused by the difference between constraint and pre-condition. As
I currently see it is your constraint is that theta will be in the range
[0,360) which implies the pre-condition for all methods of theta being in
that range.


Ok, I'll drop the jargon I don't fully understand. I simply meant that,
although any value (eg -400) can be assigned to an Angle, they will always
be clamped to [0,360). So,
a = -10; // a == 350
a = 370; // a == 10
[...]
I tried this, just by putting
friend Angle operator+(const Angle&, const Angle&);
in the class definition, instead of outside without 'friend', but I get
the error '+' : 2 overloads have similar conversions
for theta = (theta + a) % 360; (in Angle& operator+=()).

So can you show me the correct path? :)
You would have to remove the conversion operator and implement the class
something like this:
class Angle {
public:
Angle() : theta(0) { };
Angle(int t) : theta(clamp_angle(t)) { };

Angle(const Angle& a) : theta(a.get_angle()) { };


Cool, this works.
Angle& operator=(const Angle& rhs) {
// This modulo really isn't needed, if you allow an angle to
// be out of range why not allow the one your assigning it
// to be out of range?
theta = rhs.get_angle() % 360;
return *this;
}
I don't allow an angle to be out of range (or rather, if an angle is
assigned an out of range value, it is clamped), but I found that I
could remove this operator anyway - and the Angle(int t) constructor
is of course used instead.

I also rewrote the += operator;
Angle& operator+=(const Angle& a) {
*this = theta + a.get_angle();
return *this;
}
I hope this is good technique?
BTW endl terminates the line and flushes the buffer, '\n' or "\n" just
terminate the line.


Oh, ta.

Many thanks for your help - I really understand this a lot better now.

My code now looks like this - smaller and simpler than before:

class Angle {

friend Angle operator-(const Angle& l, const Angle& r);
friend Angle operator+(const Angle& l, const Angle& r);

public:
Angle() : theta(0) { };
Angle(int t) : theta(clamp_angle(t)) { };

Angle(const Angle& a) : theta(a.get_angle()) { };

Angle& operator+=(const Angle& a) {
*this = theta + a.get_angle();
return *this;
}

Angle& operator-=(const Angle& a) {
*this = theta - a.get_angle();
return *this;
}

int get_angle() const {
return theta;
}

private:
int theta;

int clamp_angle(int angle) {
if (angle >= 0)
return angle % 360;
else
return 360 + (angle % 360);
}
};

std::ostream& operator<<(std::ostream& os, const Angle& s) {
os << s.get_angle();
return os;
}

Angle operator-(const Angle& l, const Angle& r) {
Angle a = l;
a -= r;
return a;
}

Angle operator+(const Angle& l, const Angle& r) {
Angle a = l;
a += r;
return a;
}
Thanks again,
Darren
Jul 22 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Ricardo Furtado | last post by:
I'm programming in vb .Net and i need to know how to determine angles. For example i have a figure like the following: | | | ------------------ | | |
29
by: Vol | last post by:
I think 'atan' can get the angle but it is not the four quadrant angle. Is there any function that i can get the angle from -pi to pi? or I have to use some if ... else? I know in Matlab, we use...
15
by: cwsullivan | last post by:
Hi gang, I have a grid full of particles in my program, and I want to find an angle between two particles. I'm having trouble because it seems like the answer depends on whether or not the target...
0
by: SurajPrabhu | last post by:
Hi All, I am tying to build a ASP.net 2.0 based web page which displays a Analog Guage ( 0 to 180 degrees) with an Arrow in the middle. The application accepts the Percentage as input from a...
4
by: Jem | last post by:
Hi all I have the following code which draws a vertical line on a form... Dim VertCrossHairX1 As Integer = 75 Dim VertCrossHairX2 As Integer = 75 Dim VertCrossHairY1 As Integer = 70 Dim...
3
by: Doraj | last post by:
Hello ! Here is my problem : I had some php scripts which worked well with php 4.0.5 (GD 1.6.2 according to phpinfo() ) and i put them on a new server with php 4.4.2 (and GD 2.0.28). Now,...
4
by: Nunzio | last post by:
I am trying to build an email address in PHP code using v5.1.2. All works well until I try to surround the email address with angle brackets. Every method I try causes the email address to...
6
by: royrana | last post by:
Hello, I am working on a problem in which a particle hits a wall and gets reflected. I need to calculate the tangential velocity and the impact angle with the wall. I wrote this: /*for...
2
by: laredotornado | last post by:
Hi, I'm using php 4.4.4. Maybe I'm misreading the docs, but in the imagettfbbox manual (http://us2.php.net/imagettfbbox), it says that text coordinates are the same regardless of what the angle...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.