теория, алгоритмы, примеры на С++ и OpenGL  

Мы vkontakte.ru


Rambler's Top100 Rambler's Top100
Каталог@Mail.ru - каталог ресурсов интернет

Друзья

Словарь синонимов русского языка

Логическая система координат

Мы нарисовали треугольник, задав координаты его вершин. В какой системе координат мы взяли их? Правильный ответ, в оконной системе координат. Опишем основные недостатки такого подхода:

  • при изменении размеров окна размер изображения остается прежним, тем самым нарушается логическая картина;
  • неудобство задания координат. Нам придется все время прикидывать, где будет находиться объект на экране;
  • неестественное расположение осей. В Windows используется система координат, в которой ось y направлена вниз. При естественном порядке рисования, объекты будут нарисованы вверх ногами.

Чтобы устранить все эти недостатки используется логическая система координат. Можно установить эту систему координат, используя WinAPI, но мы сделаем это вручную.

Есть много способов ввести логическую систему координат. Самый лучший вариант, когда можно самостоятельно задавать направление осей, центр координат и прочие параметры. Но для простоты мы возьмем фиксированную систему, как показано на рисунке. Также появляется такая вещь, как отступ (margin), или, если хотите, поля. Это сделано для того, чтобы изображение не ’’упиралось” в край формы и мы можем смело использовать весь диапазон координат от -1 до +1.

Преобразование координат

X_Window = MARGIN + (1.0 / 2) * (X_Log + 1) * (Width - 2 * MARGIN);
Y_Window = MARGIN + (-1.0 / 2) *  (Y_Log - 1) * (Height - 2 * MARGIN);
 

Проследим цепочку преобразований:

  • X_Log соответствует [-1; 1]
  • X_Log + 1 соответствует [0; 2]
  • (1.0 / 2) * (X_Log + 1) соответствует [0; 1]
  • (1.0 / 2) * (X_Log + 1) * (Width – 2 * Margin) соответствует [0; Width – 2 * Margin]
  • X = Margin + (1.0 / 2) * (X_Log + 1) * (Width – 2 * Margin) соответствует [Margin; Width – 2 * Margin] 

Вуаля! Получаем то, что нужно. Следует заметить, что X = T(X_Log) возрастающая функция, а Y = T(Y_Log) убывающая. Это показывает разницу направлений осей в логической и оконной системах координат.

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

Вот треугольник из предыдущего урока. Сохранив свои пропорции, он получил некоторые преимущества. 

Ниже приводится новый код модуля draw.cpp:

#include <windows.h> 

int Width, Height;

const int MARGIN = 10; 

void SetWindowSize(int _Width, int _Height){
      Width = _Width;
      Height = _Height;
}

int Tx(double X_Log){
      int X_Window;
      X_Window = MARGIN + (1.0 / 2) * (X_Log + 1) * (Width - 2 * MARGIN);
      return X_Window;
} 

int Ty(double Y_Log){
      int Y_Window;
      Y_Window = MARGIN + (-1.0 / 2) *  (Y_Log - 1) * (Height - 2 * MARGIN);
      return Y_Window;
} 

void Draw(HDC hdc){
      MoveToEx(hdc, Tx(0.0), Ty(0.5), NULL);
      LineTo(hdc, Tx(0.5), Ty(0.0));
      LineTo(hdc, Tx(-0.5), Ty(-0.5));
      LineTo(hdc, Tx(0.0), Ty(0.5));
} 

В draw.h добавляется объявление новой функции:

void Draw(HDC hdc);
void
SetWindowSize(int _Width, int _Height); 

В модуль main.cpp добавляем обработчик события WM_SIZE и WM_ERASEBKGND:

            case WM_SIZE:
                  GetClientRect(hWnd, &Rect);
                  SetWindowSize(Rect.right - Rect.left, Rect.bottom - Rect.top);
                  break;

case WM_ERASEBKGND:

                  return 1;
                  break; 

Теперь при изменении размеров окна наш треугольник подстраивается под новые размеры.

Прим. В чем суть обработчика WM_ERASEBKGND, причем не содержащего никакой код? По умолчанию при необходимости перерисовки окна это происходит в две стадии:

  • WM_ERASEBKGND: Очистка фона
  • WM_PAINT: Рисование изображения поверх фона

Т.о. можно установить кисть, для закраски фона в структуре WNDCLASS, и стандартный обработчик WM_ERASEBKGND закрасит фон с помощью этой кисти. Другой способ – взять закраску фона на себя. Тогда мы самостоятельно обрабатываем WM_ERASEBKGND, а фон заполняем в сообщении WM_PAINT. Если не обрабатывать WM_ERASEBKGND самостоятельно будет заметно мерцание при перерисовывании.

Скачать исходный текст демонстрационной программы