C++. Сборник рецептов.

11.18. Работа с полярными координатами.

Проблема.

Требуется обеспечить представление полярных координат и манипулирование ими.

Решение.

Шаблон complex из заголовочного файла <complex> содержит функции преобразования в полярные координаты и обратно. Пример 11.34 показывает, как можно использовать класс шаблона complex для представления и манипулирования полярными координатами.

Пример 11.34. Применение шаблонного класса complex для представления полярных координат.

#include <complex>

#include <iostream>

Using namespace std;

Int main() {

 double rho = 3.0; // длина.

 double theta = 3.141592 / 2; // угол.

 complex<double> coord = polar(rho, theta);

 cout << "rho = " << abs(coord) << ", theta = " << arg(coord) << endl;

 coord += polar(4.0, 0.0);

 cout << "rho = " << abs(coord) << ", theta = " << arg(coord) << endl;

}

Программа примера 11.34 выдает следующий результат.

Rho = 3, theta = 1.5708.

Rho = 5, theta = 0.643501.

Обсуждение.

Существует естественная связь между полярными координатами и комплексными числами. Хотя эти понятия в какой-то мере взаимозаменяемы, использование одного и того же типа для представления разных концепций в целом нельзя считать хорошей идеей. Поскольку применение шаблона complex для представления полярных координат не является элегантным решением, я предусмотрел приведенный в примере 11.25 класс полярных координат, допускающий более естественное применение.

Пример 11.35. Класс полярных координат.

#include <complex>

#include <iostream>

Using namespace std;

Template<class T>

Struct BasicPolar {

 public typedef BasicPolar self;

 // конструкторы.

 BasicPolar() : m() {} BasicPolar(const self& x) : m(x.m) {}.

 BasicPolar(const T& rho, const T& theta) : m(polar(rho, theta)) {}.

 // операторы присваивания.

 self operator-() { return Polar(-m); }.

 self& operator+=(const self& x) { m += x.m; return *this; }.

 self& operator-=(const self& x) { m -= x.m; return *this; }.

 self& operator*=(const self& x) { m *= x.m; return *this; }.

 self& operator/=(const self& x) { m /= x.m; return *this; }.

 operator complex<T>() const { return m; }.

 // открытые функции-члены.

 T rho() const { return abs(m); }.

 T theta() const { return arg(m); }.

 // бинарные операции.

 friend self operator+(self x, const self& y) { return x += y; }.

 friend self operator-(self x, const self& y) { return x -= y; }.

 friend self operator*(self x, const self& y) { return x *= y; }.

 friend self operator/(self x, const self& y) { return x /= y; }.

 // операторы сравнения.

 friend bool operator==(const self& x, const self& y) { return x.m == y.m; }.

 friend bool operator!=(const self& x, const self& y) { return x.m ! = y.m; }.

Private:

 complex<T> m;

};

Typedef BasicPolar<double> Polar;

Int main() {

 double rho = 3.0; // длина.

 double theta = 3.141592 / 2; // угол.

 Polar coord(rho, theta);

 cout << "rho = " << coord.rho() << ", theta = " << coord.theta() << endl;

 coord += Polar(4.0, 0.0);

 cout << "rho = " << coord.rho() << ", theta = " << coord.theta() << endl;

 system("pause");

}

В примере 11.35 с помощью typedef я определил тип Polar как специализацию шаблона BasicPolar. Так удобно определять используемый по умолчанию тип, однако вы можете при необходимости специализировать шаблон BasicPolar другим числовым типом. Такой подход используется в стандартной библиотеке в отношении классе string, который является специализацией шаблона basic_string.