Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Компьютерная графика.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
4.56 Mб
Скачать

Лабораторная работа №3

«Построение кубических сплайнов и кривых Безье с помощью библиотеки GDI+»

Цель работы Разработка приложения формализующего отображение кубических сплайнов и кривых Безье.

Цель работы: Получить теоретические знания и практические навыки в использовании Microsoft Visual C++ 2010 для формализации приложения формализующего отображение фрактала Мандельброта.

Используемые приемы и технологии: Visual C++ 2010 Professional, Microsoft Visual Studio 6, библиотеки графических интерфейсов Windows Forms (WF) и Microsoft Foundation Classes (MFC).

Ключевые термины: фрактал, среда программирования MS Visual Studio 2010, MS Visual Studio 6, общеязыковая среда исполнения (Common Language Runtime (CLR)), Visual C++.NET, Windows Forms, Microsoft Foundation Classes Library.

Теоретическое введение: Кубический сплайн

Фундаментальные сплайны в GDI+

Основной или фундаментальный сплайн — это последовательность отдельных кривых, объединенных в одну большую кривую. Сплайн задается массивом точек и параметром упругости. Фундаментальный сплайн гладко (не образуя изломов и разрывов) проходит через каждую точку массива. На рис.37 изображен набор точек и проходящий через каждую точку( фундаментальный сплайн).

Рис. 37 Фундаментальный сплайн.

Физические и математические сплайны

Физический сплайн — это пластинка из дерева или другого гибкого материала. Физические сплайны использовались чертежниками для рисования кривых до появления удобных средств рисования математических сплайнов. Чертежники должны были размещать сплайн на листе бумаги и совмещать его с каждой точкой из заданного набора. Затем, проведя карандашом вдоль прижатой к бумаге кромки сплайна, можно было нарисовать нужную кривую. Один набор точек может порождать множество различных кривых в зависимости от свойств физического сплайна. Например, кривая, нарисованная с помощью жесткого сплайна будет отличаться от кривой, нарисованной с помощью очень гибкого сплайна.

Формулы, используемые для построения математических сплайнов, основаны на свойствах гибких стержней, за счет этого кривые, образованные математическими сплайнами, похожи на кривые, нарисованные с помощью физических сплайнов. Точно так же, как физические сплайны разной упругости будут порождать различные кривые для одного набора точек, математические сплайны с различным параметром упругости также будут порождать различные кривые, проходящие через один набор точек. На приведенном ниже рисунке изображены четыре фундаментальных сплайна, проходящих через один набор точек. Для каждого сплайна обозначена его упругость. Упругость, равная 0, соответствует бесконечной физической упругости, из-за которой соответствующая кривая соединяет каждые две соседние точки по кратчайшему пути (по прямой). Упругость, равная 1, соответствует отсутствию физической упругости, за счет которого сплайн занимает положение с наименьшим суммарным изгибом. Если значение упругости превышает 1, кривая начинает действовать как сдавленный берегами ручей, стремящийся увеличить изгиб своих излучин и течь по более длинному пути.

Рис.38 Сплайны с одинаковой касательной в начальной точке

Все четыре сплайна на рис. 38 обладают одинаковой касательной в начальной точке. Касательной к кривой в некоторой точке в простейшем случае называется линия, проходящая через эту точку и через ближайшую к ней точку на кривой. Аналогично, общей касательной к конечной точке называется линия, проведенная через конечную точку и предшествующую ей точку кривой.

Для рисования фундаментальнoго сплайна нужны объекты Graphics, Pen и массив объектов Point. Объект Graphics содержит метод DrawCurve, который выполняет непосредственное рисование сплайна, а объект Pen содержит атрибуты сплайна, такие как цвет и толщина линии. Массив объектов Point содержит все точки, через которые должна пройти кривая. В приведенном ниже примере кода демонстрируется рисование фундаментального сплайна, проходящего через точки, заданные в массиве myPointArray. Третьим параметром является упругость.

Сплайны Безье в GDI+

Сплайн Безье — это кривая, задаваемая четырьмя точками: двумя конечными точками (p1 и p2) и двумя контрольными точками (c1 и c2). Кривая начинается в точке p1 и заканчивается в точке p2. Кривая не проходит через контрольные точки. Эти точки действуют на кривую как магниты, растягивая кривую в нужных направлениях и влияя на ее изгиб. Нарис.39 изображена кривая Безье и все ее конечные и контрольные точки.

Рис. 39 Кривая Безье

Обратите внимание, что кривая начинается в точке p1 и дальше идет в направлении контрольной точки c1. Касательная к кривой в точке p1 проходит через точку c1. А касательная линия в конечной точке p2 проходит через точку c2.

Рисование сплайнов Безье

Чтобы нарисовать сплайн Безье, требуются объекты Graphics и Pen. У экземпляра класса Graphics имеется метод DrawBezier, а в объекте Pen хранятся такие атрибуты, как толщина и цвет линии, с помощью которой выполняется рисование кривой. Объект Pen передается методу DrawBezier в качестве одного из аргументов. Остальные аргументы, передаваемые методу DrawBezier, задают конечные и контрольные точки сплайна. В приведенном ниже примере демонстрируется рисование сплайна Безье из начальной точки с координатами (0, 0) в конечную точку с координатами (100, 10), если контрольные точки имеют координаты (40, 20) и (80, 150).

myGraphics.DrawBezier(myPen, 0, 0, 40, 20, 80, 150, 100, 10);

Рис.40 Кривая с двумя контрольными точками и касательными

На рис.40 изображена описанная выше кривая, контрольные точки и две касательные.

Код программы

//Класс программы

class CCurveDlg

{

private:

//static LONG CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

HICON m_hIcon;

public:

BOOL OnBezier();

void DrawBezier(Gdiplus::Graphics &g);

void DrawSpline(Gdiplus::Graphics &g);

BOOL OnMouseMove(POINT pt, DWORD dwFlags);

int DoModal(int nIdResource);

BOOL OnPaint(PAINTSTRUCT &ps);

BOOL OnInitDialog();

BOOL OnOk();

BOOL OnCancel();

BOOL OnDestroy();

};

BOOL CCurveDlg::OnInitDialog()

{

HICON hicon = (HICON)LoadImage(GetModuleHandle(0),

MAKEINTRESOURCE(IDI_MAIN), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

SendMessage(m_hWnd, WM_SETICON, WPARAM(ICON_SMALL), LPARAM(hicon));

points[0] = Gdiplus::Point(50, 50);

points[1] = Gdiplus::Point(100, 100);

points[2] = Gdiplus::Point(150, 250);

points[3] = Gdiplus::Point(500, 400);

selIndex=0;

bBezier = false;

OnBezier();

return TRUE;

}

BOOL CCurveDlg::OnPaint(PAINTSTRUCT &ps)

{

using namespace Gdiplus;

Graphics g(ps.hdc);

RECT rc;

GetClientRect(m_hWnd, &rc);

Bitmap bm(rc.right, rc.bottom, PixelFormat32bppPARGB);

Graphics temp(&bm);

temp.Clear(Color::White);

for(int i=0;i<sizeof(points)/sizeof(points[0]);i++)

if(i!=selIndex) temp.DrawRectangle(&Pen(Color::Black, 1),

Rect(points[i].X-2, points[i].Y-2, 4, 4));

temp.DrawRectangle(&Pen(Color::Black, 2),

Rect(points[selIndex].X-3, points[selIndex].Y-3, 6, 6));

if(bBezier)

DrawBezier(temp);

else

DrawSpline(temp);

g.DrawImage(&bm, 0, 0, rc.right, rc.bottom);

return TRUE;

}

BOOL CCurveDlg::OnMouseMove(POINT pt, DWORD dwFlags)

{

for(int i=0;i<sizeof(points)/sizeof(points[0]);++i)

{

if(abs(points[i].X-pt.x)<4 && abs(points[i].Y-pt.y)<4)

{

selIndex=i;

break;

}

}

if (dwFlags&MK_LBUTTON)

{

points[selIndex].X = pt.x;

points[selIndex].Y = pt.y;

}

InvalidateRect(m_hWnd, 0, FALSE);

return TRUE;

}

void CCurveDlg::DrawBezier(Gdiplus::Graphics &g)

{

using namespace Gdiplus;

g.SetSmoothingMode(SmoothingModeHighQuality);

g.DrawLine(&Pen(Color::Gray, 1), points[0], points[1]);

g.DrawLine(&Pen(Color::Gray, 1), points[2], points[3]);

g.DrawBezier(&Pen(Color::Blue, 3), points[0], points[1],

points[2], points[3]);

}

void CCurveDlg::DrawSpline(Gdiplus::Graphics &g)

{

using namespace Gdiplus;

g.SetSmoothingMode(SmoothingModeHighQuality);

g.DrawCurve(&Pen(Color::Blue, 3), points, sizeof points/sizeof points[0]);

}

BOOL CCurveDlg::OnBezier()

{

bBezier = !bBezier;

HMENU hMenu = GetMenu(m_hWnd);

CheckMenuRadioItem(hMenu, ID_BEZIER, ID_SPLINE, bBezier?ID_BEZIER:ID_SPLINE, MF_BYCOMMAND);

SetWindowText(m_hWnd, bBezier?L"Кривые Безье":L"Кубический сплайн");

InvalidateRect(m_hWnd, 0, FALSE);

return TRUE;

}

Запуск программы: Кривая Безье

Рис. 41 Кривая Безье

Кубический сплайн приведён на рис. 42.

Рис. 42 Кубический сплайн