Пример использования виджета QwtPolarPlot из библиотеки QwtPolar
В статье рассматриваются приемы построения графиков в полярных
координатах с использование библитеки QwtPolar на конкретном примере.
Следует отметить, что данную тематику в интернете как-то обделили,
и разработчику, решившему взять на вооружение библиотеку, остается
опираться только на примеры, поставляемые вместе с ней. QwtPolar
не является независимой и требует наличия установленной библиотеки
Qwt. Проект будем разрабатывать с помощью Qt Creator, постараемся
обеспечить возможность его сборки как на разных платформах (Ubuntu
или Windows), так и с разными версиями библиотек. Для Вашего удобства
готовый проект доступен по ссылке.
Для определения подключаемых к проекту библиотек используем следующие файлы
файл "qwt.pri"
#-------------------------------------------------
#
# QwtLibrary configuration file
#
#-------------------------------------------------
# QWT_VER = 5.2.3
QWT_VER = 6.0.2
contains(QWT_VER,^5\\..*\\..*) {
VER_SFX = 5
UNIX_SFX = -qt4
} else {
VER_SFX =
UNIX_SFX =
}
unix {
QWT_PATH = /usr
QWT_INC_PATH = $${QWT_PATH}/include/qwt$${UNIX_SFX}
QWT_LIB = qwt$${UNIX_SFX}
}
win32 {
win32-x-g++ {
QWT_PATH = /usr/qwt$${VER_SFX}-win
} else {
QWT_PATH = C:/Qt/qwt-$${QWT_VER}
}
QWT_INC_PATH = $${QWT_PATH}/include
CONFIG(debug,debug|release) {
DEBUG_SFX = d
} else {
DEBUG_SFX =
}
QWT_LIB = qwt$${DEBUG_SFX}$${VER_SFX}
}
INCLUDEPATH += $${QWT_INC_PATH}
LIBS += -L$${QWT_PATH}/lib -l$${QWT_LIB}
файл "qwtpolar.pri"
#-------------------------------------------------
#
# QwtPolarLibrary configuration file
#
#-------------------------------------------------
POLAR_VER = 1.0.1
contains(QWT_VER,^5\\..*\\..*) {
POLAR_VER = 0.1.0
VER_SFX = 0
UNIX_SFX = -qt4
} else {
VER_SFX =
UNIX_SFX =
}
unix {
POLAR_PATH = /usr
POLAR_INC_PATH = $${POLAR_PATH}/include/qwtpolar$${UNIX_SFX}
POLAR_LIB = qwtpolar$${UNIX_SFX}
}
win32 {
win32-x-g++ {
POLAR_PATH = /usr/qwtpolar$${VER_SFX}-win
} else {
POLAR_PATH = C:/Qt/qwtpolar-$${POLAR_VER}
}
POLAR_INC_PATH = $${POLAR_PATH}/include
CONFIG(debug,debug|release) {
DEBUG_SFX = d
} else {
DEBUG_SFX =
}
POLAR_LIB = qwtpolar$${DEBUG_SFX}$${VER_SFX}
}
INCLUDEPATH += $${POLAR_INC_PATH}
LIBS += -L$${POLAR_PATH}/lib -l$${POLAR_LIB}
Данные файлы обеспечивают включение в проект следующих вариантов
директив
# Платформа Ubuntu
[Переключить]
# Версия библиотеки Qwt 5.2.2
[Переключить]
INCLUDEPATH += /usr/ include/qwt-qt4
LIBS += -L/usr/lib -lqwt-qt4
INCLUDEPATH += /usr/ include/qwtpolar-qt4
LIBS += -L/usr/lib -lqwtpolar-qt4
# Версия библиотеки Qwt 6.0.0
[Переключить]
INCLUDEPATH += /usr/ include/qwt
LIBS += -L/usr/lib -lqwt
INCLUDEPATH += /usr/ include/qwtpolar
LIBS += -L/usr/lib -lqwtpolar
# Платформа Windows
[Переключить]
# Версия библиотеки Qwt 5.2.3
[Переключить]
INCLUDEPATH += C:/Qt/qwt-5.2.3/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -LC:/Qt/qwt-5.2.3/lib -lqwt5
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -LC:/Qt/qwt-5.2.3/lib -lqwtd5
INCLUDEPATH += C:/Qt/qwtpolar-0.1.0/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -LC:/Qt/qwtpolar-0.1.0/lib -lqwtpolar0
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -LC:/Qt/qwtpolar-0.1.0/lib -lqwtpolard0
# Версия библиотеки Qwt 6.0.2
[Переключить]
INCLUDEPATH += C:/Qt/qwt-6.0.2/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -LC:/Qt/qwt-6.0.2/lib -lqwt
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -LC:/Qt/qwt-6.0.2/lib -lqwtd
INCLUDEPATH += C:/Qt/qwtpolar-1.0.1/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -LC:/Qt/qwtpolar-1.0.1/lib -lqwtpolar
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -LC:/Qt/qwtpolar-1.0.1/lib -lqwtpolard
Замечания. Версии библиотек актуальны на момент написания статьи.
Пути к заголовочным и библиотечным файлам соответствуют рекомендациям
по установке библиотек, описанным в посвященных этому вопросу статьях
(здесь и здесь).
С Qwt 5.x.x совместима только QwtPolar 0.1.0, а с Qwt 6.x.x
QwtPolar 1.0.1 и предположительно последующие версии.
Для того чтобы выполнить сборку проекта с другими версиями библиотек,
достаточно изменить значения переменных QWT_VER
и POLAR_VER. Файлы "qwt.pri"
и "qwtpolar.pri" предусматривают
и такой редкий случай, как сборка проекта в Ubuntu для Windows
(см. статью), а конкретнее, в этом
случае в файл проекта будут включены варианты директив
# Версия библиотеки Qwt 5.x.x
[Переключить]
INCLUDEPATH += /usr/qwt5-win/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -L/usr/qwt5-win/lib -lqwt5
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -L/usr/qwt5-win/lib -lqwtd5
INCLUDEPATH += /usr/qwtpolar0-win/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -L/usr/qwtpolar0-win/lib -lqwtpolar0
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -L/usr/qwtpolar0-win/lib -lqwtpolard0
# Версия библиотеки Qwt 6.x.x
[Переключить]
INCLUDEPATH += /usr/qwt-win/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -L/usr/qwt-win/lib -lqwt
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -L/usr/qwt-win/lib -lqwtd
INCLUDEPATH += /usr/qwtpolar-win/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -L/usr/qwtpolar-win/lib -lqwtpolar
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -L/usr/qwtpolar-win/lib -lqwtpolard
Создадим в Qt Creator проект с именем demo_qwtpolar.
В дизайнере откроем форму "mainwindow.ui",
удалим из нее главное меню menuBar, панель
инструментов mainToolBar и панель состояния
statusBar, так как они не будут использоваться
в данном приложении. Установим размеры формы 480 x 480.
Поместим на нее виджет QwtPolarPlot и присвом
ему имя myPlot. Активируем для центрального
виджета компоновщик Скомпоновать по сетке,
который заставит график занять все свободное пространство формы.
Установим равными "3" свойства компоновщика layoutLeftMargin,
layoutTopMargin, layoutRightMargin
и layoutBottomMargin. В результате получим
форму, изображенную на рисунке. Элемент управления компоновщиком
и индикатор его активного состояния в инспекторе объектов отмечены
на рисунке символом "К".
Откроем файл проекта, его содержимое сгенерировано автоматически.
файл "demo_qwtpolar.pro"
#-------------------------------------------------
#
# Project created by QtCreator 2012-07-15T23:40:54
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = demo_qwtpolar
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
# Директивы, определяющие библиотеки
[Скрыть]
include(qwt.pri)
include(qwtpolar.pri)
# Включение класса QData (QData5)
[Скрыть]
contains(QWT_VER,^5\\..*\\..*) {
SOURCES += qdata5.cpp
HEADERS += qdata5.h
} else {
SOURCES += qdata.cpp
HEADERS += qdata.h
}
Поскольку форма нашего проекта содержит виджет QwtPolarPlot,
то для успешной сборки в файле проекта следует прописать директивы,
определяющие библиотеки Qwt и QwtPolar
include(qwt.pri)
include(qwtpolar.pri)
Кроме того, в папку с проектом необходимо поместить
файлы "qwt.pri" и "qwtpolar.pri",
содержимое которых приведено выше. Теперь проект уже можно собрать,
но при запуске приложения пока что будет отбражаться пустой график,
поскольку его наполнением мы еще не занимались.
Определимся с тем, что мы хотим увидеть на графике. В полярных координатах
можно строить, например, диаграммы направленности антенн, розу ветров,
эллиптические траектории небесных тел и т.п. Остановимся на первом
варианте и зададимся целью получить график, представленный на рисунке.
Это диаграммы направленности двух антенн. Одна из них широкая
и направлена вдоль азимута 0°. Вторая узкая и отклонена на
30°. Диаграммы направленности идеальные и аппроксимированы зависимостью
типа sin(kx)/kx, где параметр k
определеят ширину.
Данные для построения кривых, изображенных на графике, подготовить
не сложно, важно правильно передать их кривым. Для этого требуется
дополнительный класс, созданный по определенным правилам. Он предназначен
для хранения серии точек кривой и обеспечения доступа к точкам по
их индексу.
Если Вы используетет библиотеку Qwt 6.x.x, то дополнительный
класс должен наследовать свойства класса QwtSeriesData<QwtPointPolar>.
Помимо конструктора, обеспечивающего прием данных, в нем должны
быть реализованы несколько обязательных функций:
size_t size() возвращает количество
точек в серии;
QwtPointPolar sample(size_t) по заданному
индексу возвращает пару значений азимут и радиус;
QRectF boundingRect() возвращает
рабочую (ограничивающую) область для кривой.
В случае с библиотекой Qwt 5.x.x дополнительный класс должен
наследовать свойства класса QwtData. В нем
должны быть реализованы следующие функциии:
size_t size() возвращает количество
точек в серии;
double x(size_t) по заданному индексу
возвращает азимут;
double у(size_t) по заданному индексу
возвращает радиус;
QwtData *copy() создает новый экземпляр
класса и возвращает указатель на него.
Чтобы не путать, дадим наименование QData
классу, который будет использоваться с Qwt 6.x.x, и QData5
классу, предназначенному для Qwt 5.x.x. Файлы того или
другого класса должны быть добавлены в перечни файлов реализации
и заголовочных файлов проекта. Сделать это можно так:
contains(QWT_VER,^5\\..*\\..*) {
SOURCES += qdata5.cpp
HEADERS += qdata5.h
} else {
SOURCES += qdata.cpp
HEADERS += qdata.h
}
Эти инструкции следует поместить в файле проекта
сразу после директив #include, определяющих
библиотеки. Ниже приведено содержимое файлов классов QData
и QData5.
файл "qdata.h"
#ifndef QDATA_H
#define QDATA_H
#include <qwt_series_data.h>
class QData : public
QwtSeriesData<QwtPointPolar>
{
public:
QData(double
*,double *,size_t);
~QData();
virtual size_t size() const;
virtual QwtPointPolar sample(size_t) const;
virtual QRectF boundingRect() const;
protected:
double *azimuth;
double *radial;
size_t d_size;
};
#endif // QDATA_H
файл "qdata.cpp"
#include "qdata.h"
QData::QData(double
*az,double *rad,size_t
sz)
{
azimuth = (double
*)malloc(2*sz*sizeof(double));
radial = azimuth
+ sz;
for (int
k=0; k < (int)sz;
k++)
{
azimuth[k] = az[k];
radial[k] = rad[k];
}
d_size = sz;
}
QData::~QData() {
free((void *)azimuth);
}
size_t QData::size()
const {
return d_size;
}
QwtPointPolar QData::sample(size_t
i) const {
return QwtPointPolar(azimuth[i],radial[i]);
}
QRectF QData::boundingRect()
const
{
if (d_boundingRect.width()
< 0)
d_boundingRect
= qwtBoundingRect(*this);
return d_boundingRect;
}
файл "qdata5.h"
#ifndef QDATA5_H
#define QDATA5_H
#include <qwt_data.h>
class QData5 : public
QwtData
{
public:
QData5(double
*,double *,size_t);
~QData5();
virtual size_t
size() const;
virtual double
x(size_t) const;
virtual double
y(size_t) const;
virtual QwtData
*copy() const;
protected:
double *azimuth;
double *radial;
size_t d_size;
};
#endif // QDATA5_H
файл "qdata5.cpp"
#include "qdata5.h"
QData5::QData5(double
*az,double *rad,size_t
sz)
{
azimuth = (double
*)malloc(2*sz*sizeof(double));
radial = azimuth
+ sz;
for (int
k=0; k < (int)sz;
k++)
{
azimuth[k] = az[k];
radial[k] = rad[k];
}
d_size = sz;
}
QData5::~QData5() {
free((void *)azimuth);
}
size_t QData5::size()
const {
return d_size;
}
double QData5::x(size_t
i) const {
return azimuth[i];
}
double QData5::y(size_t
i) const {
return radial[i];
}
QwtData *QData5::copy()
const {
return new
QData5(azimuth,radial,d_size);
}
Оба класса и QData, и QData5
в конструкторе получают указатели на два массива с данными и количество
элементов в массивах. Для хранения данных выделяется блок памяти
нужного размера, в который данные и копируются. В деструкторе выделенный
блок памяти освобождается. Файлы этих классов нужно создать и поместить
их в папку с проектом.
Теперь можно заняться непосредственно оформлением графика. Порядок действий
очень напоминает аналогичный при создании графика QwtPlot
из библиотеки Qwt (см. соответствующую статью).
Заглянем в файлы главного окна приложения.
файл "mainwindow.h"
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// Дополнительные директивы
#include [Скрыть]
#include <qwt_legend.h>
#include <qwt_polar_grid.h>
#include <qwt_polar_curve.h>
#include <qwt_polar_panner.h>
#include <qwt_polar_magnifier.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
// Указатели на элементы графика
[Скрыть]
QwtLegend *leg;
QwtPolarGrid *grid;
QwtPolarCurve *curv1,*curv2;
QwtPolarPanner *pan;
QwtPolarMagnifier *zoom;
};
#endif // MAINWINDOW_H
файл "mainwindow.cpp"
#include "mainwindow.h"
#include "ui_mainwindow.h"
// Дополнительные директивы
#include [Скрыть]
#include <QPen>
#if QWT_VERSION < 0x060000
#include "qdata5.h"
#else
#include "qdata.h"
#endif
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Инструкции оформления графика
[Скрыть]
// Заголовок графика
ui->myPlot->setTitle("QwtPolarPlot Demo");
// Легенда
leg = new QwtLegend();
leg->setItemMode(QwtLegend::ReadOnlyItem);
ui->myPlot->insertLegend(leg,QwtPolarPlot::BottomLegend);
// Сетка
grid = new QwtPolarGrid;
for (int sc=0; sc < QwtPolar::ScaleCount; sc++)
{
grid->showMinorGrid(sc);
grid->setMajorGridPen(sc,QPen(Qt::lightGray));
grid->setMinorGridPen(sc,QPen(Qt::lightGray,0,Qt::DotLine));
}
grid->showAxis(QwtPolar::AxisRight,false);
grid->showAxis(QwtPolar::AxisTop,true);
grid->attach(ui->myPlot);
// Границы и шаг для каждой шкалы
ui->myPlot->setScale(QwtPolar::Radius,0,1,0.2);
ui->myPlot->setScale(QwtPolar::Azimuth,0,360,30);
// Первая кривая
curv1 = new QwtPolarCurve(QString("DNA 1"));
curv1->setPen(QPen(Qt::darkGreen,2));
// Вторая кривая
curv2 = new QwtPolarCurve(QString("DNA 2"));
curv2->setPen(QPen(Qt::red));
// Выделение памяти под массивы данных
const int N1 = 361;
const int N2 = 1441;
double *X1 = (double *)malloc((2*N1+2*N2)*sizeof(double));
double *Y1 = X1 + N1;
double *X2 = Y1 + N1;
double *Y2 = X2 + N2;
// Данные для первой кривой
double d
= 40; //
ширина ДНА
double kd = 2.7831 / d;
double h = 360./(N1-1);
for (int k = 0; k < N1; k++)
{
double fi = k*h;
X1[k] = fi;
double x = fi;
while (x >= 180) x -= 360;
double y = 1;
if (x != 0) y = qAbs(sin(kd*x)/(kd*x));
Y1[k] = y;
}
// Данные для второй кривой
const double fi0
= 30; // смещение
d = 6;
//
ширина ДНА
kd = 2.7831 / d;
h = 360./(N2-1);
for (int k = 0; k < N2; k++)
{
double fi = k*h;
X2[k] = fi;
double x = fi - fi0;
while (x >= 180) x -= 360;
double y = 1;
if (x != 0) y = qAbs(sin(kd*x)/(kd*x));
Y2[k] = y;
}
// Передача данных кривым
#if QWT_VERSION < 0x060000
curv1->setData(QData5(X1,Y1,N1));
curv2->setData(QData5(X2,Y2,N2));
#else
curv1->setData(new QData(X1,Y1,N1));
curv2->setData(new QData(X2,Y2,N2));
#endif
// Освобождение памяти
free((void *)X1);
// Помещение кривых на график
curv1->attach(ui->myPlot);
curv2->attach(ui->myPlot);
// Менеджер перемещения
pan = new QwtPolarPanner(ui->myPlot->canvas());
// Менеджер масштабирования
zoom = new QwtPolarMagnifier(ui->myPlot->canvas());
}
MainWindow:: ~MainWindow()
{
// Инструкции удаления элементов графика
[Показать]
// Инструкции удаления элементов графика
[Скрыть]
delete pan;
delete zoom;
delete curv1;
delete curv2;
delete grid;
delete leg;
delete ui;
}
Поместим в заголовочный файл "mainwindow.h" директивы #include,
которые нам потребуются
#include <qwt_legend.h>
#include <qwt_polar_grid.h>
#include <qwt_polar_curve.h>
#include <qwt_polar_panner.h>
#include <qwt_polar_magnifier.h>
В секции private класса MainWindow
объявляем указатели на используемые элементы графика
QwtLegend *leg;
QwtPlotGrid *grid;
QwtPlotCurve *curv1,*curv2;
QwtPolarPanner *pan;
QwtPolarMagnifier *zoom;
В файле реализации главного окна приложения "mainwindow.cpp"
добавляем еще директивы #include
#include <QPen>
#if QWT_VERSION < 0x060000
#include "qdata5.h"
#else
#include "qdata.h"
#endif
Основные операции производятся в конструкторе. Большинство элементов
графика создается командой new. По завершении
работы приложения они должны быть удалены командой delete.
Поэтому мы и сделали указатели на эти элементы членами класса MainWindow,
чтобы иметь доступ кним в деструкторе.
Итак, устанавливаем заголовок графика
ui->myPlot->setTitle(QString("QwtPolarPlot
Demo"));
Создаем легенду расшифровку отображаемых кривых по цветам,
запрещаем ее редактировать, добавляем легенду в нижнюю часть графика
leg = new QwtLegend();
leg->setItemMode(QwtLegend::ReadOnlyItem);
ui->myPlot->insertLegend(leg,QwtPolarPlot::BottomLegend);
Создаем координатную сетку. Для всех шкал разрешаем отображение
линий сетки, соответствующих вспомогательным делениям нижней шкалы.
Назначаем цвет для линий сетки светло-серый. Вспомогательные
линии сетки будут изображаться пунктирной линией.
grid = new QwtPolarGrid;
for (int sc=0; sc < QwtPolar::ScaleCount; sc++)
{
grid->showMinorGrid(sc);
grid->setMajorGridPen(sc,QPen(Qt::lightGray));
grid->setMinorGridPen(sc,QPen(Qt::lightGray,0,Qt::DotLine));
}
Запрещаем отображение радиальной шкалы справа и разрешаем
сверху
ui->myPlot->showAxis(QwtPolar::AxisRight,false);
ui->myPlot->showAxis(QwtPolar::AxisTop,true);
Связываем созданную сетку с графиком
grid->attach(ui->myPlot);
Устанавливаем наименование нижней шкалы, минимальную и максимальную
границы для нее. Аналогичные установки делаем для левой шкалы.
ui->myPlot->setScale(QwtPlot::Radius,0,1,0.2);
ui->myPlot->setScale(QwtPlot::Azimuth,0,360,30);
Создаем первую кривую с наименованием "DNA
1", назначаем ей толщину 2 и цвет прорисовки
темно-зеленый
curv1 = new QwtPlotCurve(QString("DNA 1"));
curv1->setPen(QPen(Qt::darkGreen),2);
Создаем вторую кривую с наименованием "DNA
2", назначаем ей цвет прорисовки красный
curv2 = new QwtPlotCurve(QString("DNA 2"));
curv2->setPen(QPen(Qt::red));
Теперь займемся подготовкой данных для кривых, изображаемых на
графике. Первая кривая будет содержать 361 точку, вторая
1441. Поскольку ширина диаграммы направленности во втором случае
меньше, то точек на кривой должно быть больше.
const int N1 = 361;
const int N2 = 1441;
Объявляем массивы данных: X1 и Y1 для первой кривой, X2 и Y2 для
второй. Выделяем блок памяти под размещение данных (общий для всех
данных), массивы в нем располагаются последовательно так, как показано
на рисунке.
double *X1 = (double *)malloc((2*N1+2*N2)*sizeof(double));
double *Y1 = X1 + N1;
double *X2 = Y1 + N1;
double *Y2 = X2 + N2;
Вычисляем массивы данных для кривых 1 и 2. X принимает значения
от 0 до 360, шаг приращения по углу зависит от количества точек
на кривой.
double d = 40;
// ширина ДНА
double kd = 2.7831
/ d;
double h = 360./(N1-1);
for (int k = 0;
k < N1; k++)
{
double fi = k*h;
X1[k] = fi;
double x = fi;
while (x >= 180)
x -= 360;
double y = 1;
if (x != 0)
y = qAbs(sin(kd*x)/(kd*x));
Y1[k] = y;
}
const double fi0 = 30; //
смещение
d = 6; //
ширина ДНА
kd = 2.7831 / d;
h = 8./(N2-1);
for (int k = 0;
k < N2; k++)
{
double fi = k*h;
X2[k] = fi;
double x = fi - fi0;
while (x >= 180)
x -= 360;
double y = 1;
if (x != 0)
y = qAbs(sin(kd*x)/(kd*x));
Y2[k] = y;
}
Далее, передаем кривым подготовленные данные
#if QWT_VERSION < 0x060000
curv1->setData(QData5(X1,Y1,N1));
curv2->setData(QData5(X2,Y2,N2));
#else
curv1->setData(new
QData(X1,Y1,N1));
curv2->setData(new
QData(X2,Y2,N2));
#endif
Освобождаем выделенную память
free((void *)X1);
Помещаем кривые на график
curv1->attach(ui->myPlot);
curv2->attach(ui->myPlot);
В заключение конструктора создаем менеджеры перемещения и масштабирования
графика. Первый из них действует при нажатой левой кнопке мыши,
а второй при нажатой правой.
pan = new
QwtPolarPanner(ui->myPlot->canvas());
zoom = new QwtPolarMagnifier(ui->myPlot->canvas());
Осталось вставить в деструктор команды удаления объектов, созданных
в конструкторе команодой new
delete pan;
delete zoom;
delete curv1;
delete curv2;
delete grid;
delete leg;
Наконец, можем выполнить сборку проекта и запустить приложение.
Реализация класса QData (равно как и QData5),
предложенная в данной статье, обеспечивает средства для приема и
хранения данных каждой из кривой, изображаемой на графике QwtPolarPlot.
При этом совершенно неважно как именно эти данные были получены.
В рассматриваемом примере диаграмма направленности была вычислена
с помощью аппроксимирующего выражения, она могла быть снята экспериментально
или получена в результате моделирования антенны в специализированном
программном пакете. Во всех случаях передача данных кривой осуществляется
единообразно, и для всех кривых используется один и тот же класс.
На мой взгляд, такой подход является универсальным и достаточно
целесообразным.
Существует другой подход, реализованный в примере polardemo,
поставляемом вместе с библиотекой QwtPolar. В нем на графике изображаются
две кривые, для генерации данных которых предназначены два класса
SpiralData и RoseData,
созданные по тем же правилам, что и класс QData
(или QData5) из нашего примера. Обратите
внимание, что для каждой кривой предназначен свой класс. Данные
в эти классы не передаются, они вычисляются непосредственно при
вызове функции sample() или соответственно
функций x() и y().
Такой подход имеет право на существование, но не является универсальным
зависимость, изображаемая на графике, не всегда может быть
выражена аналитически, или требует большого объема вычислений (например,
при моделировании). Вам предлагается самомтоятельно посмотреть,
как можно построить диаграммы направленности из нашего примера с
применением такого подхода, альтернативный проект доступен по
ссылке.
|