Войти

Показать полную графическую версию : графика, нужна помощь срочно!


filmo
07-01-2008, 00:34
Так долго искал в сети справочную информацию по WIN Api, нашел относительно много, но все совсем не по теме.. Навыки программирования у меня небольшие и оч сложно разбираться на чужих примерах без камментов..

к сути:
есть лабораторная работа по винайпи, надо сделать на 8 число.Согласен, времени осталось до ужаса мало, но уже ничо не изменишь.

задание: с помощью функций винапи сделать равнобедренный треугольник и 5 угольник, реализовать функции выбора активной фигуры, перемещения, удаления, поворота по часовой стрелке и смена цвета. все это с помощью клавы чтоб работало.

Если кто возьмется - буду рад и счастлив!

а еще, если всем в лом делать всю работу, то у меня есть аналог такой лабы, пытаюсь ща ее переделать, но получается с трудом. Если есть возможность - подскажите,

*как нарисовать 5 угольник
(вот для примера 4х угольник:
case F.tip of //выбираем тип фигуры
1: begin MoveToEx(dc,F.x-1,F.y+1,NIL); //квадрат

LineTo(dc,F.x-1,F.y-1);
LineTo(dc,F.x+1,F.y-1);
LineTo(dc,F.x+1,F.y+1);
LineTo(dc,F.x-1,F.y+1); )

*в общих чертах подскажите, как реализовать поворот такой фигуры по часовой стреле? даже не представляю..
Заранее спасибо!! ))

filmo
07-01-2008, 00:59
если что - ася в личке!

Admiral
07-01-2008, 01:14
filmo, WinApi - это не язык програмирования, а интерфейс. Те части кода что я вижу очень напоминают Паскаль/Делфи.

filmo
07-01-2008, 01:59
Admiral, если честно, мне не легче ))
оч нужна помощь...
сижу ипусь...

Admiral
07-01-2008, 02:11
сделать ... треугольник»
можно так
Line(80,110,85,130);
Line(85,130,110,170);
Line(110,170,80,110);

как нарисовать 5 угольник »
Line(80,110,85,130);
Line(85,130,110,170);
Line(110,170,150,190);
Line(150,190,170,195);
Line(170,195,80,110);

filmo
07-01-2008, 10:31
ок, спасибо, намекни хотя бы как реализовать его поворот по часовой?
можно конечно, задавать ему другие параметры просто (заранее заготовленные), как и эти, но, кажется таакой подход замутный и есть гораздо проще выход.. тока я его не знаю (

pva
07-01-2008, 16:47
поворот производится операцией сдвига и умножения на матрицу. немного теории:
в 2-мерном векторном (евклидовом) пространстве все элементы можно представить как векторы от точки {0,0} до точки {a,b}. Ещё над векторами есть операции: сложение/вычитание и скалярное умножение (свёртка). Ещё есть так называемое тензорное (внешнее) умножение. Оно превращает 2 вектора в матрицу, 3 и больше векторов в более сложные объекты. Есть группа простейших преобразований: масштабирование, сдвиг и поворот. Они все описываются скалярным умножением вектора на матрицу. И ещё последовательные операции можно комбинировать в одну матрицу.
Короче:
{{Cos[a], Sin[a]}, {-Sin[a], Cos[a]}} . {x,y} - поворот вектора на угол a вокруг точки {0,0}

{c,d} + {{Cos[a], Sin[a]}, {-Sin[a], Cos[a]}} . {x,y} - поворот вектора на угол a и сдвиг точки на {c,d}

есть волшебная функция, которая задаёт это преобразование SetWorldTransform и которая накладывает 2 преобразования ModifyWorldTransform. Они использут структурку:

x' = x * eM11 + y * eM21 + eDx,
y' = x * eM12 + y * eM22 + eDy,

typedef struct _XFORM { // xfrm
FLOAT eM11;
FLOAT eM12;
FLOAT eM21;
FLOAT eM22;
FLOAT eDx;
FLOAT eDy;
} XFORM;

теперь делаем следующим образом: пусть есть исходные координаты, описанные структурой POINT (из winapi)
используем подход с откатами при исключениях (при исключении не портим DC). Что получилось - смотрим скриншот.

#include <vector>
//#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <stdexcept>
//#include <windows.h>
using namespace std;
//----------------------------------------------

void _error(const char* message);
//----------------------------------------------

// не то, чтобы класс, просто кучка функций для того, чтобы было на чём рисовать
// и чтобы результаты трудов потом не затирались

class Window
{
public:
static void execute();
static char* ginit();
static void paint(HDC dc);

private:
static long __stdcall WndProc(HWND, unsigned, unsigned, long);
};
//----------------------------------------------

// класс для рисования объектов
// 1. сохраняет восстанавливает параметры DC
// 2. вычисляет преобразование координат
// 3. рисует полигоны

class draw_t
{
HDC rest_dc;
int rest_mode;
XFORM rest_form;
unsigned steps;

XFORM adv_form;

public:
draw_t(HDC dc) :
steps (10),
rest_dc (dc),
// включаем продвинутый режим драйвера рисования для устройства
// нужно для 2k, не всегда нужно для NT и XP:
rest_mode (SetGraphicsMode(rest_dc, GM_ADVANCED)),
// по умолчанию уменьшение и небольшое смещение
adv_form (draw_t::rotate_scale(0.0174533*10.0, 0.95, -3, -.5))
{
if (0==rest_mode ||
!GetWorldTransform(rest_dc, &rest_form)) // запомнили настройки отображения.
{
_error("draw_t::draw_t");
}
}

~draw_t()
{
// не проверяем на ошибки ибо пофиг уже
SetWorldTransform(rest_dc, &rest_form);
SetGraphicsMode(rest_dc, rest_mode);
}

// вычисляем поворот и масштабирование
static XFORM rotate_scale(const double& angle, const double& scale, const double& x, const double& y)
{
double cos1 = scale*cos(angle);
double sin1 = scale*sin(angle);
XFORM form1 = {cos1, sin1, -sin1, cos1, x, y};
return form1;
}

// вычисляем поворот и масштабирование
static XFORM rotate_scale2(const double& angle, const double& scaleX, const double& scaleY, const double& x, const double& y)
{
double cos1 = cos(angle);
double sin1 = sin(angle);
XFORM form1 = {scaleX*cos1, scaleX*sin1, -scaleY*sin1, scaleY*cos1, x, y};
return form1;
}

// настройка параметров
void setSteps(unsigned n)
{
steps = n;
}

void setTransform(const XFORM& form1)
{
if (!SetWorldTransform(rest_dc, &form1)) _error("draw_t::setTransform");
}

void setAdvance(const XFORM& form1)
{
adv_form = form1;
}

// рисование
void operator()(POINT* points, unsigned count)
{
// собственно говоря, самая полезная функция,
// ради которой все затевалось. Отрисовка на низком уровне.
// остальной код - только для поддержания порядка.

for(unsigned n=0; n<steps; ++n)
{
if (!Polygon(rest_dc, points, count))
_error("draw_t() at polygon");

if (!ModifyWorldTransform(rest_dc, &adv_form, MWT_LEFTMULTIPLY))
_error("draw_t() at modify transform");
}
}
};
//----------------------------------------------

void Window::paint(HDC dc)
{
// здесь происходит отрисовка на высоком уровне
draw_t draw(dc);

// параметры
draw.setSteps(150);
draw.setTransform(draw_t::rotate_scale(0.0174533*0.0, 5.0, 200, 400));
draw.setAdvance(draw_t::rotate_scale2(0.0174533*9.0, 0.90, 1.05, 5., -7.5));

// рисуешь в кореле фигуру и переписываешь сюда координаты её точек ;-)
static POINT tryangle_points[3] = {{-20,-10}, {20, -10}, {0, 20}};
draw(tryangle_points, 3);
}
//----------------------------------------------

char* Window::ginit()
{
// это требуется для создания окна. Можно было через диалоги сделать,
// но там код короче, но запутанней
static char* class_name = 0;

if (!class_name)
{
WNDCLASSEX wcla;
wcla.cbSize = sizeof(WNDCLASSEX);
wcla.style = 0;
wcla.lpfnWndProc = WndProc;
wcla.cbClsExtra = 0;
wcla.cbWndExtra = 4;
wcla.hInstance = GetModuleHandle(0);
wcla.hIcon = LoadIcon(0, IDI_APPLICATION);
wcla.hCursor = LoadCursor(0, IDC_ARROW);
wcla.hbrBackground = HBRUSH(1 + COLOR_BTNFACE);
wcla.lpszMenuName = 0;
wcla.lpszClassName = "Window";
wcla.hIconSm = LoadIcon(0, IDI_APPLICATION);

class_name = reinterpret_cast<char*>(RegisterClassEx(&wcla));
}

return class_name;
}

// структура для обработки события WM_PAINT (вынесена отдельно)
// и чистки мусора после неё, exception-safe
struct safe_dc
{
HWND hwnd;
PAINTSTRUCT ps;

safe_dc(HWND hwnd1) : hwnd(hwnd1)
{
if (!BeginPaint(hwnd1, &ps)) _error("safe_dc::safe_dc");
}

~safe_dc()
{
EndPaint(hwnd, &ps);
}
};

long __stdcall Window::WndProc(HWND hwnd, unsigned code, unsigned wparam, long lparam)
{
// оконная процедура
try
{
if (code==WM_PAINT) // рисуем
{
safe_dc safe_dc1(hwnd);
Window::paint(safe_dc1.ps.hdc);
return 0;
}
else if (code==WM_CLOSE) // закрываемся (выходим)
{
PostQuitMessage(0);
}
}
catch(exception& e)
{
MessageBox(0, e.what(), 0, MB_OK|MB_ICONERROR);
}

return DefWindowProc(hwnd, code, wparam, lparam);
}

void Window::execute()
{
// простейшая обработка ввода/вывода приложения.
MSG cmsg;

while (GetMessage(&cmsg, 0, 0, 0))
{
// TranslateMessage(&cmsg);
DispatchMessage(&cmsg);
}
}
//----------------------------------------------

void _error(const char* message)
{
// генерируем исключение с кодом ошибки ОС
long last_error = GetLastError();
ostringstream ss;
ss << message << " error=";
ss.width(8);
ss.fill('0');
ss.flags(ios::hex|ios::right);
ss << last_error;

throw runtime_error(ss.str());
}

int main()
{
// создали окно, поигрались, уничтожили
HWND hwnd = CreateWindowEx(0, Window::ginit(), "Draw Test", WS_OVERLAPPEDWINDOW|WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
GetDesktopWindow(), 0, GetModuleHandle(0), 0);

if (hwnd)
{
Window::execute();
DestroyWindow(hwnd);
}

return 0;
}




© OSzone.net 2001-2012