Міністерство освіти та наукиУкраїни
Національний університет “Львівська політехніка”
Графічно-розрахункова робота № 1
з курсу «Програмування комп’ютерної графіки»
варіант 16 -16 -10
Львів 2014
Завдання
Побудувати графік функції заданої таблично. Масштаб розмітки осей координат графіка повинен відповідати реальним результатам розрахунків.
Параметри для побудови графіка визначені у таблиці 2.
Необхідно передбачити плаваючий центр координат – основну частину екрану мають займати ті чверті в яких знаходиться графік функції.
Завдання для побудови графіку
Таблиця 1
№ варіанту
Функція f(x)
Діапазон зміни аргументу
16
y=arcsin(x)
[-0,95;0,95]
Таблиця 2
№ варіанту
Тип лінії для побудови
Товщина лінії
Колір лінії
16
______________
3
Red
Завдання
Створити на екрані комп’ютера графічне вікно і сформувати в ньому рухоме зображення. Вікно розмістити у верхньому правому куті екрану. Навести межі вікна.
Параметри зображення задані в пікселях. Графік і вікно з рухомим зображенням повинні бути присутні на екрані одночасно.
Завдання для побудови зображення
№ варіанту
Структура зображення
Пояснення
10
/
Плавний рух стрілок годинника з правильним показом часу.
Кольори стрілок різні.
Параметри: R=80
2.1 Розрахунок функціональних залежностей для побудови графіка
Оскільки реальні координати графіка функції, що виводяться на екран можуть бути або значно більшими, або значно меншими за машинні координати монітору, необхідно визначити значення масштабних коефіцієнтів стискання або розтягу для функції що виводяться на екран.
Протабулюємо задану функцію на проміжку зміни аргументу з метою визначення максимального та мінімального значень функції і аргументу: xmax , xmin , ymax , ymin.
Знайдемо значення масштабуючи коефіцієнтів:
kx = (xm2 - 50) / (xrmax - xrmin);
ky = (ym2 - 50) / (yrmax - yrmin);
Використовуючи обчислені коефіцієнти побудуємо графік функції і осі координат, нанесемо розмітку.
2.2 Розрахунок матриці перетворень для рухомого зображення
Для побудови зображень на екрані комп’ютера використовується операція переносу, масштабування, повороту та їх композицій.
У моїй програмі використовуються такі формули розрахунку переносу:
zmyn = r - r*cos(kuth*pi / 180);
zmxn = r*sin(kuth*pi / 180);
3. Список ідентифікаторів програми
Побудова графіка функцій:
rect – структура, в якій записані розміри екрана.
rect.bottom, rect.right – нижня та права сторона вікна, відповідає за розміри клієнтського вікна.
rect.top, rect.left – верхня та ліва сторона вікна, рівна 0.
rectright – зміння яка задає ширину області для побудови графіка функції.
str[192] – массив символів.
kx, ky – коефініент перетворення координат.
x0,y – мінімальне значення графіка в машинних координатах по осях x та y відповідно.
x – змінна, з інтервалом зміни від x1 до x2 з кроком h.
y – значення функції.
lx, ly – довжина осі по x та z відповідно.
sx, sy – ціле значення від розбиття осі на 10 частин по x та z відповідно.
tx, ty – змінна, значення якої відповідає довжині додатної осі по x та від’ємної по z відповідно.
xc, yc – центр графіка в точці x=0 по осях x та z відповідно. Плаваючий центр координат.
xx, yy – змінна, яка відповідає за розбиття графіка на 10 частин по осях x та z відповідно.
xmax , xmin, ymax, ymin – мінімальне та максимальне значення функції по осях x та z відповідно.
txp, txm, typ, tym – змінні, які визначають положення тексту розмітки осей у додатному та від’мному напрямках x та y відповідно.
Побудова анімації:
R – радіус маятника.
kuth, kutm, kuts, – кут, на який повертається нитка маятника.
zmxn, zmyn – матриця руху.
Команди і функції:
GetClientRect(&rect) – команда для запису розмірів екрана в структуру rect.
swprintf_s() – записує значення змінної в масив str.
TextOut() – виводить значення змінної по заданих координатах.
MoveTo(x, y) – переміщує поточну вершину, змінна x, y визначають координати нової поточної вершини.
LineTo(x, y) – будує лінію з поточної вершини у точку з координатами x, y.
Rectangle(int x1, int y1, int x2, int y2) - малює прямокутник, x1, у1 задають координати верхнього лівого куга, a x2, у2 правого нижнього кута прямокутника.
При використанні функцій «перо» , колір контуру еліпса задається «пером».
Створює і задає перо з параметрами:
CPen «ім’я»;
«ім’я».CreatePen(«стиль пера», «товщина пера», «колір RGB»);
dc.SelectObject(&«ім’я»).
4. Блок-схема.
5. Лістинг вихідної програми:
#include "stdafx.h"
#include "PKG_Rozracha.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CChildView::CChildView()
{}
CChildView::~CChildView()
{}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this);
RECT rect;
GetClientRect(&rect);
wchar_t str[192];
double kx, ky, x0, y0, x, y, lx, ly, sx, sy, xc, yc, tx, ty, xx, yy, t;
double xmax = 0, xmin = 0, ymax = 0, ymin = 0, txp = 0, txm = 0, typ = 0, tym = 0;
double x1 = -0.95, x2 = 0.95, hh = 0.0005;
double rectright = rect.right - 270;
// ==================
// Побудова графіка
// ==================
// Табулювання заданої функції на проміжку зміни аргументу з метою визначення максимального та мінімального значень функції
for (x = x1; x <= x2; x = x + hh)
{
y = asin(x);
if (ymin > -y)
{
ymin = -y;
}
else if (ymax<-y)
{
ymax = -y;
}
if (xmin>x)
{
xmin = x;
}
else if (xmax < x)
{
xmax = x;
}
}
//знаходимо значення функції в точці x=0
x = 0;
y = asin(x);
//знаходимо коефіцієнти і центр реальних координат
kx = (rectright - 50) / (xmax - xmin);
ky = (rect.bottom - 50) / (ymax - ymin);
x0 = xmin*kx - 25;
y0 = ymin*ky - 25;
xc = x*kx - x0;
yc = -y*ky - y0;
//Побудова осей
//побудова Z
dc.MoveTo(xc, rect.top + 10);
dc.LineTo(xc, rect.bottom - 10);
//побудова Х
dc.MoveTo(rect.left + 10, yc);
dc.LineTo(rectright - 10, yc);
dc.MoveTo(xc - 5, rect.top + 15); // стрілка осі Z
dc.LineTo(xc, rect.top + 10);
dc.LineTo(xc + 5, rect.top + 15);
dc.MoveTo(rectright - 15, yc - 5); // стрілка осі Х
dc.LineTo(rectright - 10, yc);
dc.LineTo(rectright - 15, yc + 5);
//розмітка осей
const CString Y("Y"), X("X"), O("0");
dc.TextOutW(xc - 20, rect.top + 5, Y);
dc.TextOutW(rectright - 20, yc + 5, X);
dc.TextOutW(xc + 5, yc + 5, O);
lx = (rectright - 10) - (rect.left + 10); //довжини осей
ly = (rect.bottom - 10) - (rect.top + 10);
sx = floor(lx / 15);
sy = floor(ly / 15);
tx = rectright - fabs(x0);
ty = rect.bottom - fabs(y0);
xx = (xmax - xmin) / 15;
yy = (ymax - ymin) / 15;
//розмітка осі Х
for (t = sx; t <= -x0 - 30; t = t + sx) //в відємному напрямі
{
txm = txm - xx;
dc.MoveTo(xc - t, yc - 5);
dc.LineTo(xc - t, yc + 5);
swprintf_s(str, 50, L"%.1f", txm);
dc.TextOut(xc - t - 10, yc + 5, str);
}
for (t = sx; t <= tx - 30; t = t + sx)//в додатньому напрямі
{
txp = txp + xx;
dc.MoveTo(xc + t, yc - 5);
dc.LineTo(xc + t, yc + 5);
swprintf_s(str, 50, L"%.1f", txp);
dc.TextOut(xc + t - 10, yc + 5, str);
}
//розмітка осі Y
for (t = sy; t <= -y0 - 15; t = t + sy)//в додатньому напрямі
{
typ = typ + yy;
dc.MoveTo(xc - 5, yc - t);
dc.LineTo(xc + 5, yc - t);
swprintf_s(str, 50, L"%.1f", typ);
dc.TextOut(xc + 10, yc - t - 10, str);
}
for (t = sy; t <= ty - 15; t = t + sy)//в відємному напрямі
{
tym = tym - yy;
dc.MoveTo(xc - 5, yc + t);
dc.LineTo(xc + 5, yc + t);
swprintf_s(str, 50, L"%.1f", tym);
dc.TextOut(xc + 10, yc + t - 10, str);
}
CPen dRED;
dRED.CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
dc.SelectObject(&dRED);
//побудова графіка
for (x = x1; x <= x2; x = x + hh)
{
y = asin(x);
if (x == x1)
{
dc.MoveTo(x*kx - x0, -y*ky - y0);
}
dc.LineTo(x*kx - x0, -y*ky - y0);
}
// =============
// Анімація
// =============
int xm1 = rect.right, R = 80, r1 = 70, r2 = 50, r3 = 30, p1, p2, p3, p4, V = 360, B = 330, N = 360, M = 287;
double kuts, kutm, kuth, xn, yn, xn1, yn1, xs1, xs2, xs3, xs4, xs5, xs6, ys1, ys2, ys3, ys4, ys5, ys6;
double pi = 3.14, zmxn, zmyn;
// рамка анімації
dc.SelectStockObject(BLACK_PEN);
dc.Rectangle(xm1 - 210, 10, xm1 - 10, 210);
dc.MoveTo(xm1 - 110 + R, 110);
dc.AngleArc(xm1 - 110, 110, R, 0, 361);
CPen white_pen3;
white_pen3.CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
CPen white_pen2;
white_pen2.CreatePen(PS_SOLID, 2, RGB(255, 255, 255));
CPen gren_pen;
gren_pen.CreatePen(PS_SOLID, 3, RGB(102, 255, 0));
CPen red_pen2;
red_pen2.CreatePen(PS_SOLID, 2, RGB(128, 0, 32));
CPen indigo_pen2;
indigo_pen2.CreatePen(PS_SOLID, 1, RGB(49, 0, 98));
// лінії для цифр
CPen black_pen2;
black_pen2.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
dc.SelectObject(&black_pen2);
dc.MoveTo(xm1 - 110, 110 - R + 5);
dc.LineTo(xm1 - 110, 110 - R - 5);
dc.MoveTo(xm1 - 110 - R + 5, 110);
dc.LineTo(xm1 - 110 - R - 5, 110);
dc.MoveTo(xm1 - 110, 110 + R + 5);
dc.LineTo(xm1 - 110, 110 + R - 5);
dc.MoveTo(xm1 - 110 + R + 5, 110);
dc.LineTo(xm1 - 110 + R - 5, 110);
// цифри на годинику
dc.SelectStockObject(BLACK_PEN);
LPCTSTR q = L"12", w = L"9", e = L"6", r = L"3";
dc.TextOutW(xm1 - 110 + 3, 110 - R - 17, q, 2);
dc.TextOutW(xm1 - 110 - R - 10, 113, w, 1);
dc.TextOutW(xm1 - 110 + 3, 110 + R + 3, e, 1);
dc.TextOutW(xm1 - 110 + R + 10, 113, r, 1);
// рух стрілок годинника
for (int j = 1; j <= 12; j++)
{
for (kuth = V; kuth > B; kuth -= 6)
{
xn1 = xs5 = xs6 = xm1 - 110;
yn1 = ys5 = ys6 = 110;
zmyn = r3 - r3*cos(kuth*pi / 180);
zmxn = r3*sin(kuth*pi / 180);
ys5 = ys5 + r3 - 10 - (r3 - 10)*cos((kuth - 3)*pi / 180);
ys6 = ys6 + r3 - 10 - (r3 - 10)*cos((kuth + 3)*pi / 180);
xs5 = xs5 - (r3 - 10)*sin((kuth - 3)*pi / 180);
xs6 = xs6 - (r3 - 10)*sin((kuth + 3)*pi / 180);
yn1 = yn1 + zmyn;
xn1 = xn1 - zmxn;
dc.SelectObject(&gren_pen);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xs5, ys5 - r3 + 10);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xs6, ys6 - r3 + 10);
for (kutm = N; kutm > M; kutm -= 6)
{
x = xs3 = xs4 = xm1 - 110;
y = ys3 = ys4 = 110;
zmyn = r2 - r2*cos(kutm*pi / 180);
zmxn = r2*sin(kutm*pi / 180);
ys3 = ys3 + r2 - 10 - (r2 - 10)*cos((kutm - 3)*pi / 180);
ys4 = ys4 + r2 - 10 - (r2 - 10)*cos((kutm + 3)*pi / 180);
xs3 = xs3 - (r2 - 10)*sin((kutm - 3)*pi / 180);
xs4 = xs4 - (r2 - 10)*sin((kutm + 3)*pi / 180);
y = y + zmyn;
x = x - zmxn;
dc.SelectObject(&red_pen2);
dc.MoveTo(x, y - r2);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(x, y - r2);
dc.LineTo(xs3, ys3 - r2 + 10);
dc.MoveTo(x, y - r2);
dc.LineTo(xs4, ys4 - r2 + 10);
for (kuts = 360; kuts >= 0; kuts -= 6)
{
xn = xs1 = xs2 = xm1 - 110;
yn = ys1 = ys2 = 110;
zmyn = r1 - r1*cos(kuts*pi / 180);
zmxn = r1*sin(kuts*pi / 180);
yn = yn + zmyn;
ys1 = ys1 + r1 - 10 - (r1 - 10)*cos((kuts - 3)*pi / 180);
ys2 = ys2 + r1 - 10 - (r1 - 10)*cos((kuts + 3)*pi / 180);
xn = xn - zmxn;
xs1 = xs1 - (r1 - 10)*sin((kuts - 3)*pi / 180);
xs2 = xs2 - (r1 - 10)*sin((kuts + 3)*pi / 180);
dc.SelectObject(&indigo_pen2);
dc.MoveTo(xn, yn - r1);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(xn, yn - r1);
dc.LineTo(xs1, ys1 - r1 + 10);
dc.MoveTo(xn, yn - r1);
dc.LineTo(xs2, ys2 - r1 + 10);
Sleep(30);
dc.SelectStockObject(WHITE_PEN);
dc.MoveTo(xn, yn - r1);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(xn, yn - r1);
dc.LineTo(xs1, ys1 - r1 + 10);
dc.MoveTo(xn, yn - r1);
dc.LineTo(xs2, ys2 - r1 + 10);
dc.SelectObject(&red_pen2);
dc.MoveTo(x, y - r2);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(x, y - r2);
dc.LineTo(xs3, ys3 - r2 + 10);
dc.MoveTo(x, y - r2);
dc.LineTo(xs4, ys4 - r2 + 10);
dc.SelectObject(&gren_pen);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xs5, ys5 - r3 + 10);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xs6, ys6 - r3 + 10);
}
dc.SelectObject(&white_pen2);
dc.MoveTo(x, y - r2);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(x, y - r2);
dc.LineTo(xs3, ys3 - r2 + 10);
dc.MoveTo(x, y - r2);
dc.LineTo(xs4, ys4 - r2 + 10);
}
dc.SelectObject(&white_pen3);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xm1 - 110, 110);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xs5, ys5 - r3 + 10);
dc.MoveTo(xn1, yn1 - r3);
dc.LineTo(xs6, ys6 - r3 + 10);
N = N - 72;
M = M - 72;
}
V = V - 30;
B = B - 30;
}
}
6. Результат роботи програми:
/
7. Висновок:
Виконавши завдання даної роботи я набув практичних навиків в складанні програми для побудови зображень на екрані комп’ютера в середовищі Microsoft Visual Studio C++ 2013. Ключовим моментом у програмуванні анімації є точне визначення матриць руху чи обертання реперних точок фігури та максимально точне обчислення координат подальшого положення фігури з метою уникнення похибок, які можуть суттєво погіршити результат. Суть анімації – зміна положення предмета з “затиранням” попереднього положення.