Отображение
графика
График отображается
в такой последовательности. Сначала рисуется ограничивающий прямоугольник (рамка),
затем дважды вызывается функция Scale, которая подготавливает данные для разметки
осей. После этого выводятся экстремальные значения функции. В этот момент в
более сложном случае следует создавать и выводить так называемую легенду графика
— информацию о соответствии маркеров и стилей линий определенным кривым. Так
как мы изображаем только одну кривую, то эта часть работы сведена к минимуму.
Перед тем как отобразить координатную сетку, следует создать и выбрать в контекст
другое перо (gridPen). Сама сетка изображается в двух последовательных циклах
прохода по диапазонам координат, подготовленных в методе Scale.
В каждом цикле
мы сначала нормируем текущую координату, затем преобразовываем ее в оконную,
вызывая одну из функций типа MapToLog*. Одновременно с линией сетки выводится
цифровая метка. В ходе процесса нам несколько раз приходится менять способ выравнивания
текста (см. вызовы SetTextAlign). Подстройка местоположения текста осуществляется
с помощью переменной m_LH (better Height), значение которой зависит от выбранного
размера шрифта. После вывода координатной сетки происходит вывод трех строк
текста: метки осей и заголовок графика. В последнюю очередь происходит вывод
самой кривой графика. В более сложном случае, который не реализован, мы в цикле
проходим по всем объектам класса MyLine и просим каждую линию изобразить себя
в нашем контексте устройства. Каждая линия при этом помнит и использует свой
стиль, толщину, цвет и маркировку:
void
CGraph::Draw(CDC
*pDC) {
//======
С помощью контекста устройства
//======
узнаем адрес окна, его использующего
CWnd
*pWnd =pDC->GetWindow();
CRect
r;
pWnd->GetClientRect(ir);
//======
Уточняем размеры окна
m_Size
= r.Size();
m_Center
= CPoint(m_Size.cx/2, m_Size.cy/2);
//======
Сохраняем атрибуты контекста
int
nDC = pDC->SaveDC();
//======
Создаем черное перо для изображения рамки
CPen
pen(PS_SOLID, О, COLORREF(0));
pDC->SelectObject(Spen);
//======
Преобразуем координаты рамки
int
It = MapToLogX(-0.S),
rt
= MapToLogX(0.S),
tp
= MapToLogY(0.S),
bm
= MapToLogY(-0.S);
pDC->Rectangle
(It, tp, rt, bm);
//======
Задаем цвет и выравнивание текста
pDC->SetTextColor
(0);
pDC->SetTextAlign(TA_LEFT
| TA_BASELINE);
//======
Выбираем шрифт
pDC->SelectObject
(&m_Font);
//======
Вычисляем атрибуты координатных осей
Scale(m_DataX);
Scale(m_DataY);
//======
Выводим экстремумы функции
CString
s;
s.Format("Min
= %.3g",m_DataY.Min);
pDC->TextOut(rt+m_LH,
tp+m_LH, s) ;
s.Format("Max
= %.3g",m_DataY.Max);
pDC->TextOut(rt+m_LH,
tp+m_LH+m_LH, s);
//======
Готовимся изображать координатную сетку
CPen
gridPen(PS_SOLID, 0, RGB(92,200, 178));
pDC->SelectObject(SgridPen);
pDC->SetTextAlign(TA_CENTER
| TA_BASELINE);
//======Рисуем
вертикальные линии сетки
for
(double x = m_DataX.Start;
X
< m_DataX.End - m_DataX.Step/2.;
x
+= m_DataX.Step) {
//======
Нормируем координату х
double
xn = (x - m_DataX.Start) /
(m_DataX.End
- m_DataX.Start) - 0.5;
//======
Вычисляем оконную координату
int
xi = MapToLogX(xn);
//======
Пропускаем крайние линии,
//======
так как они совпатают с рамкой
if
(x > m_DataX.Start && x < m_DataX.End)
{
pDC->MoveTo(xi,
bm);
pDC->LineTo(xi,
tp); )
//======
Наносим цифровую метку
pDC->TextOut
(xi, bm+m_LH, MakeLabel(true, x)); }
//===
Повторяем цикл для горизонтальных линий сетки
pDC->SetTextAlign(ТА
RIGHT | TA_BASELINE);
for
(double у = m_DataY.Start;
у
< m_DataY.End - m_DataY.Step/2.; у += m_DataY.Step)
{
double
yn = (y - m_DataY.Start) /
(m_DataY.End
- m_DataY.Start) - 0.5;
int
yi = MapToLogY(yn);
if
(y > m_DataY. Start &S, у < m_DataY.End)
{
pDC->MoveTo(lt,
yi) ;
pDC->LineTo(rt,
yi) ;
pDC->TextOut(lt-m_LH/2,yi,MakeLabel
(false,
y));
}
}
//======
Вывод меток осей
pDC->TextOut(lt-m_LH/2,
tp - m_LH, m_sY);
pDC->SetTextAlign(TA_LEFT
| TA_BASELINE);
pDC->TextOut(rt-m_LH,
bm + m_LH, m_sX);
//======
Вывод заголовка
if
(ra_sTitle.GetLength() > 40)
m_sTitle.Left(40);
pDC->SelectObject(Sm_TitleFont);
pDC->SetTextAlign(TA_CENTER
| TA_BASELINE);
pDC->TextOut((It+rt)/2,
tp - m_LH, m_sTitle);
//======
Вывод линии графика
DrawLine(pDC);
//======
Восстанавливаем инструменты GDI
pDC->RestoreDC(nDC);
}
Вывод линии
графика начинается с создания и выбора пера. Эти действия можно вынести и поместить
в какой-нибудь диалог по изменению атрибутов пера, но мы не будем этого делать,
так как данное действие целесообразно только в случае, когда график состоит
из нескольких линий. Обе координаты каждой точки сначала нормируются переходом
к относительным значениям в диапазоне (-0.5*0.5), затем приводятся к оконным.
После чего точки графика последовательно соединяются с помощью GDI-функции LineTo:
void
CGraph::DrawLine(CDC
*pDC) {
//======
Уничтожаем старое перо
if
(m_Pen.m_hObject)
m_Pen.DeleteObject()
; //====== Создаем новое
m_Pen.CreatePen(PS_SOLID,
m_Width, m_Clr);
pDC->SelectObject(im_Pen);
double
x0 = m_DataX.dStart,
y0
= m_DataY.dStart,
dx
= m_DataX.dEnd - x0,
dy
= m_DataY.dEnd - y0;
//======
Проход по всем точкам
for
(UINT i=0; i < m_Points.size(); i++) {
//======
Нормируем координаты
double
x = (ra_Points[i].x - xO) / dx - .5,
у
= (m_Points[i].у - y0) / dy - .5;
//======
Переход к оконным координатам
CPoint
pt (MapToLogX(x) ,MapToLogY(y)) ;
//======
Если точка первая, то ставим перо
if
(i==0)
pDC->MoveTo(pt);
else
pDC->LineTo(pt);
}
}
Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий