Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   графика, нужна помощь срочно! (http://forum.oszone.net/showthread.php?t=97495)

filmo 07-01-2008 00:34 710680

графика, нужна помощь срочно!
 
Так долго искал в сети справочную информацию по 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 710715

если что - ася в личке!

Admiral 07-01-2008 01:14 710726

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

filmo 07-01-2008 01:59 710762

Admiral, если честно, мне не легче ))
оч нужна помощь...
сижу ипусь...

Admiral 07-01-2008 02:11 710768

Цитата:

Цитата filmo
сделать ... треугольник»

можно так
Код:

Line(80,110,85,130);
Line(85,130,110,170);
Line(110,170,80,110);

Цитата:

Цитата filmo
как нарисовать 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 710886

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

pva 07-01-2008 16:47 711174

Вложений: 1
поворот производится операцией сдвига и умножения на матрицу. немного теории:
в 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;
}



Время: 09:51.

Время: 09:51.
© OSzone.net 2001-