Ключевым моментом решения поставленных задач является построение плоскости и бортиков. Для построения плоскости используется функция DrawPool, а для построения бортиков – DrawBorder.
Для решения задачи перемещения и поворота объектов в методах прорисовки поверхности октаэдра с диффузионной и зеркальной моделями освещения использовались аффинные преобразования (приложение Г). Положения октаэдра задается функцией SetPos, изменение положения октаэдра в зависимости от скорости – Move, а начальные параметры задаются в функции SetV.
Для решения задачи изображения трехмерного процесса на двухмерном дисплее с учетом положения наблюдателя использовались матрицы пересчета из мировых координат в видовые и из видовых – в оконные. Первая формируется функцией CreateViewCoords, а вторая – функцией SpaceToWindow. Определения функций представлены в приложении Е.
Задачи сохранения данных решены при помощи встроенных функций библиотек MFC при помощи дескрипторов устройств. Они используются в методе SaveImg (приложение Ж), вызываемом при успешном завершении диалога сохранения файла.
Построение поля, пересчет координат, поверхности октаэдр по настроенным параметрам можно изобразить следующим образом:
нет |
Конец |
Расчет матриц пересчета из мировой системы координат (МСК) в видовую и из видовой в оконную (ОСК) |
Построение поля в МСК, пересчет координат, вывод на экран в ОСК |
fi<=180 |
q<=180 |
Расчет требуемых шагов по вертикали (dq) и по горизонтали (df), перемещение МСК в центр пирамиды, расчет смещения октаэдра относительно начала мировых координат в ОСК |
Начало |
Выбрана диффузионная модель освещения |
Расчет положения точки поверхности октаэдра в МСК, вычисление ее освещенности в зависимости от косинуса угла между падающим лучом и нормалью к поверхности в данной точке, установка пикселя соответствующего цвета в ОСК, q+=dq; |
fi+=dfi; |
да |
да |
нет |
да |
нет |
Расчет требуемых шагов по вертикали (dq) и по горизонтали (df), перемещение МСК в центр пирамиды, расчет смещения октаэдра относительно начала мировых координат в ОСК |
q<=180 |
fi+=dfi; |
fi<=180 |
Расчет положения точки поверхности октаэдра в МСК, вычисление ее освещенности в зависимости от косинуса угла между отраженным лучом и направлением на наблюдателя в данной точке, установка пикселя соответствующего цвета в ОСК, q+=dq; |
нет |
нет |
да |
да |
Заключение
Разработанное приложение моделирует заданный процесс движения октаэдра по плоскости с задаваемыми начальными параметрами движения. В дальнейшем возможно усовершенствование приложения путем использования аппаратных средств пересчета координат. Возможно сохранение смоделированных изображений в графические файлы. Получены навыки практического использования пакета MFC и математического аппарата аффинных преобразований.
Демонстрация работы приложения:
Рисунок 3 – Демонстрация работы приложения
Приложения
Приложение А. Структура CPyramid.
#include "stdafx.h"
class CPyramid
{
CMatrix Vertices; // Координаты вершин
CMatrix Vertices2; // Координаты вершин
void GetRect(CMatrix& Vert,CRectD& RectView);
public:
CPyramid();
void Draw(CDC& dc,CMatrix& P,CRect& RW);
void Draw1(CDC& dc,CMatrix& P,CRect& RW);
void ColorDraw(CDC& dc,CMatrix& PView,CRect& RW,COLORREF Color, CMatrix& PLight, int LightMode);
void ColorDrawD(CDC& dc, CMatrix& PView, CRect& RW, COLORREF Color, CMatrix& PLight);
void ColorDrawP(CDC& dc, CMatrix& PView, CRect& RW, COLORREF Color, CMatrix& PLight, int LightMode);
};
Приложение Б. Описание класса LibGraph.
#ifndef LIBGRAPH
#define LIBGRAPH 1
const double pi=3.14159;
//typedef double (*pfunc)(double); // Указатель на функцию
typedef double (*pfunc2)(double,double); // Указатель на функцию
struct CSizeD
{
double cx;
double cy;
};
//-----------------------------------------------------------------------------------
struct CRectD
{
double left;
double top;
double right;
double bottom;
CRectD(){left=top=right=bottom=0;};
CRectD(double l,double t,double r,double b);
void SetRectD(double l,double t,double r,double b);
CSizeD SizeD();
};
Приложение В. Описание класса CMatrix.
#include "Math.h"
#ifndef CMATRIXH
# define CMATRIXH 1
class CMatrix
{
double **array;
int n_rows; // Число строк
int n_cols; // Число столбцов
public:
CMatrix(); // Конструктор по умолчанию (1 на 1)
CMatrix(int,int); // Конструктор
CMatrix(int); // Конструктор -вектора (один столбец)
CMatrix(const CMatrix&); // Конструктор копирования
~CMatrix();
double &operator()(int,int); // Выбор элемента матрицы по индексу
double &operator()(int); // Выбор элемента вектора по индексу
CMatrix operator-(); // Оператор "-"
CMatrix operator=(const CMatrix&); // Оператор "Присвоить": M1=M2
CMatrix operator*(CMatrix&); // Оператор "Произведение": М1*М2
CMatrix operator*(double x); // Оператор "Произведение": М1*a
CMatrix operator/(double x); // Оператор "Деление": М1/a
CMatrix operator+(CMatrix&); // Оператор "+": M1+M2
CMatrix operator-(CMatrix&); // Оператор "-": M1-M2
CMatrix operator+(double); // Оператор "+": M+a
CMatrix operator-(double); // Оператор "-": M-a
int rows()const{return n_rows;}; // Возвращает число строк
int cols()const{return n_cols;}; // Возвращает число строк
CMatrix Transp(); // Возвращает матрицу,транспонированную к текущей
CMatrix GetRow(int); // Возвращает строку по номеру
CMatrix GetRow(int,int,int);
CMatrix GetCol(int); // Возвращает столбец по номеру
CMatrix GetCol(int,int,int);
CMatrix RedimMatrix(int,int); // Изменяет размер матрицы с уничтожением данных
CMatrix RedimData(int,int); // Изменяет размер матрицы с сохранением данных,
//которые можно сохранить
CMatrix RedimMatrix(int); // Изменяет размер матрицы с уничтожением данных
CMatrix RedimData(int); // Изменяет размер матрицы с сохранением данных,
//которые можно сохранить
double MaxElement(); // Максимальный элемент матрицы
double MinElement(); // Минимальный элемент матрицы
double Abs(); // Модуль матрицы
};
#endif
Приложение Г. Методы класса LibGraph.
#include "stdafx.h"
CRectD::CRectD(double l,double t,double r,double b)
{
left=l;
top=t;
right=r;
bottom=b;
}
//------------------------------------------------------------------------------
void CRectD::SetRectD(double l,double t,double r,double b)
{
left=l;
top=t;
right=r;
bottom=b;
}
//------------------------------------------------------------------------------
CSizeD CRectD::SizeD()
{
CSizeD cz;
cz.cx=fabs(right-left); // Ширина прямоугольной области
cz.cy=fabs(top-bottom); // Высота прямоугольной области
return cz;
}
//------------------------------------------------------------------------------
CMatrix SpaceToWindow(CRectD& RS,CRect& RW)
// Возвращает матрицу пересчета координат из мировых в оконные
// RS - область в мировых координатах - double
// RW - область в оконных координатах - int
{
CMatrix M(3,3);
CSize sz = RW.Size(); // Размер области в ОКНЕ
int dwx=sz.cx; // Ширина
int dwy=sz.cy; // Высота
CSizeD szd=RS.SizeD(); // Размер области в МИРОВЫХ координатах
double dsx=szd.cx; // Ширина в мировых координатах
double dsy=szd.cy; // Высота в мировых координатах
double kx=(double)dwx/dsx; // Масштаб по x
double ky=(double)dwy/dsy; // Масштаб по y
M(0,0)=kx; M(0,1)=0; M(0,2)=(double)RW.left-kx*RS.left; // Обновлено
M(1,0)=0; M(1,1)=-ky; M(1,2)=(double)RW.bottom+ky*RS.bottom; // Обновлено
M(2,0)=0; M(2,1)=0; M(2,2)=1;
return M;
}
//------------------------------------------------------------------------------
void SetMyMode(CDC& dc,CRect& RS,CRect& RW) //MFC
// Устанавливает режим отображения MM_ANISOTROPIC и его параметры
// dc - ссылка на класс CDC MFC
// RS - область в мировых координатах - int
// RW - Область в оконных координатах - int
{
int dsx=RS.right-RS.left;
int dsy=RS.top-RS.bottom;
int xsL=RS.left;
int ysL=RS.bottom;
int dwx=RW.right-RW.left;
int dwy=RW.bottom-RW.top;
int xwL=RW.left;
int ywH=RW.bottom;
dc.SetMapMode(MM_ANISOTROPIC);
dc.SetWindowExt(dsx,dsy);
dc.SetViewportExt(dwx,-dwy);
dc.SetWindowOrg(xsL,ysL);
dc.SetViewportOrg(xwL,ywH);
}
//------------------------------------------------------------------------------------
CMatrix CreateTranslate2D(double dx, double dy)
// Афинные преобразования
// Формирует матрицу для преобразования координат объекта при его смещении
// на dx по оси X и на dy по оси Y в фиксированной системе координат
// --- ИЛИ ---
// Формирует матрицу для преобразования координат объекта при смещении начала
// системы координат на -dx оси X и на -dy по оси Y при фиксированном положении объекта
{
CMatrix TM(3,3);
TM(0,0)=1; TM(0,2)=dx;
TM(1,1)=1; TM(1,2)=dy;
TM(2,2)=1;
return TM;
}
//-------------------------------------------------------------------------------------
CMatrix CreateTranslate3D(double dx, double dy,double dz)
// Формирует матрицу для преобразования координат объекта при его смещении
// на dx по оси X, на dy по оси Y,на dz по оси Z в фиксированной системе координат
// --- ИЛИ ---
// Формирует матрицу для преобразования координат объекта при смещении начала
// системы координат на -dx оси X,на -dy по оси Y, на -dz по оси Z
// при фиксированном положении объекта
{
CMatrix TM(4,4);
for(int i=0;i<4;i++) TM(i,i)=1;
TM(0,3)=dx;
TM(1,3)=dy;
TM(2,3)=dz;
return TM;
}
//------------------------------------------------------------------------------------
CMatrix CreateRotate2D(double fi)
// Формирует матрицу для преобразования координат объекта при его повороте
// на угол fi (при fi>0 против часовой стрелки)в фиксированной системе координат
// --- ИЛИ ---
// Формирует матрицу для преобразования координат объекта при повороте начала
// системы координат на угол -fi при фиксированном положении объекта
// fi - угол в градусах
{
double fg=fmod(fi,360.0);
double ff=(fg/180.0)*pi; // Перевод в радианы
CMatrix RM(3,3);
RM(0,0)=cos(ff); RM(0,1)=-sin(ff);
RM(1,0)=sin(ff); RM(1,1)=cos(ff);
RM(2,2)=1;
return RM;
}
//--------------------------------------------------------------------------------
CMatrix CreateRotate3DZ(double fi)
// Формирует матрицу для преобразования координат объекта при его повороте вокруг оси Z
// на угол fi (при fi>0 против часовой стрелки)в фиксированной системе координат
// --- ИЛИ ---
// Формирует матрицу для преобразования координат объекта при повороте начала
// системы координат вокруг оси Z на угол -fi при фиксированном положении объекта
// fi - угол в градусах
{
double fg=fmod(fi,360.0);
double ff=(fg/180.0)*pi; // Перевод в радианы
CMatrix RM(4,4);
RM(0,0)=cos(ff); RM(0,1)=-sin(ff);
RM(1,0)=sin(ff); RM(1,1)=cos(ff);
RM(2,2)=1;
RM(3,3)=1;
return RM;
}
//--------------------------------------------------------------------------------
CMatrix CreateRotate3DX(double fi)
// Формирует матрицу для преобразования координат объекта при его повороте вокруг оси X
// на угол fi (при fi>0 против часовой стрелки)в фиксированной системе координат
// --- ИЛИ ---
// Формирует матрицу для преобразования координат объекта при повороте начала
// системы координат вокруг оси X на угол -fi при фиксированном положении объекта
// fi - угол в градусах
{
double fg=fmod(fi,360.0);
double ff=(fg/180.0)*pi; // Перевод в радианы
CMatrix RM(4,4);
RM(0,0)=1;
RM(1,1)=cos(ff); RM(1,2)=-sin(ff);
RM(2,1)=sin(ff); RM(2,2)=cos(ff);
RM(3,3)=1;
return RM;
}
//--------------------------------------------------------------------------------
CMatrix CreateRotate3DY(double fi)
// Формирует матрицу для преобразования координат объекта при его повороте вокруг оси Y
// на угол fi (при fi>0 против часовой стрелки)в фиксированной системе координат
// --- ИЛИ ---
// Формирует матрицу для преобразования координат объекта при повороте начала
// системы координат вокруг оси Y на угол -fi при фиксированном положении объекта
// fi - угол в градусах
{
double fg=fmod(fi,360.0);
double ff=(fg/180.0)*pi; // Перевод в радианы
CMatrix RM(4,4);
RM(0,0)=cos(ff); RM(0,2)=sin(ff);
RM(1,1)=1;
RM(2,0)=-sin(ff); RM(2,2)=cos(ff);
RM(3,3)=1;
return RM;
}
//--------------------------------------------------------------------------------
CMatrix VectorMult(CMatrix& V1,CMatrix& V2)
// Вычисляет векторное произведение векторов V1 и V2
{
int b1=(V1.cols()==1)&&(V1.rows()==3);
int b2=(V2.cols()==1)&&(V2.rows()==3);
int b=b1&&b2;
if(!b)
{
MessageBox(NULL,L"VectorMult: неправильные размерности векторов! ",L"Ошибка",MB_ICONSTOP);
exit(1);
}
CMatrix W(3);
W(0)=V1(1)*V2(2)-V1(2)*V2(1);
//double x=W(0);
W(1)=-(V1(0)*V2(2)-V1(2)*V2(0));
//double y=W(1);
W(2)=V1(0)*V2(1)-V1(1)*V2(0);
//double z=W(2);
return W;
}
//-------------------------------------------------------------------------------
double ScalarMult(CMatrix& V1,CMatrix& V2)
// Вычисляет скалярное произведение векторов V1 и V2
{
int b1=(V1.cols()==1)&&(V1.rows()==3);
int b2=(V2.cols()==1)&&(V2.rows()==3);
int b=b1&&b2;
if(!b)
{
MessageBox(NULL,L"ScalarMult: неправильные размерности векторов! ",L"Ошибка",MB_ICONSTOP);
exit(1);
}
double p=V1(0)*V2(0)+V1(1)*V2(1)+V1(2)*V2(2);
return p;
}
//-------------------------------------------------------------------------
double ModVec(CMatrix& V)
// Вычисляет модуль вектора V
{
int b=(V.cols()==1)&&(V.rows()==3);
if(!b)
{
MessageBox(NULL,L"ModVec: неправильнfz размерность вектора! ",L"Ошибка",MB_ICONSTOP);
exit(1);
}
double q=sqrt(V(0)*V(0)+V(1)*V(1)+V(2)*V(2));
return q;
}
//-------------------------------------------------------------------------
double CosV1V2(CMatrix& V1,CMatrix& V2)
// Вычисляет КОСИНУС угла между векторами V1 и V2
{
double modV1=ModVec(V1);
double modV2=ModVec(V2);
int b=(modV1<1e-7)||(modV2<1e-7);
if(b)
{
MessageBox(NULL,L"CosV1V2: модуль одного или обоих векторов < 1e-7!",L"Ошибка",MB_ICONSTOP);
exit(1);
}
int b1=(V1.cols()==1)&&(V1.rows()==3);
int b2=(V2.cols()==1)&&(V2.rows()==3);
b=b1&&b2;
if(!b)
{
MessageBox(NULL,L"CosV1V2: неправильные размерности векторов! ",L"Ошибка",MB_ICONSTOP);
exit(1);
}
double cos_f=ScalarMult(V1,V2)/(modV1*modV2);
return cos_f;
}
//-------------------------------------------------------------------------
double AngleV1V2(CMatrix& V1,CMatrix& V2)
// Вычисляет угол между векторами V1 и V2 в градусах
{
double modV1=ModVec(V1);
double modV2=ModVec(V2);
int b=(modV1<1e-7)||(modV2<1e-7);
if(!b)
{
MessageBox(NULL,L"AngleV1V2: модуль одного или обоих векторов < 1e-7!",L"Ошибка",MB_ICONSTOP);
exit(1);
}
int b1=(V1.cols()==1)&&(V1.rows()==3);
int b2=(V2.cols()==1)&&(V2.rows()==3);
b=b1&&b2;
if(!b)
{
MessageBox(NULL,L"AngleV1V2: неправильные размерности векторов! ",L"Ошибка",MB_ICONSTOP);
exit(1);
}
double cos_f=ScalarMult(V1,V2)/(modV1*modV2);
if(fabs(cos_f)>1)
{
MessageBox(NULL,L"AngleV1V2: модуль cos(f)>1! ",L"Ошибка",MB_ICONSTOP);
exit(1);
}
double f;
if(cos_f>0)f=acos(cos_f);
else f=pi-acos(cos_f);
double fg=(f/pi)*180;
return fg;
}
//--------------------------------------------------------------------------------
CMatrix CreateViewCoord(double r,double fi,double q)
// Создает матрицу пересчета точки из мировой системы координат в видовую
// (r,fi,q)- координата ТОЧКИ НАБЛЮДЕНИЯ(начало видовой системы координат)
// в мировой сферической системе координат(углы fi и q в градусах)
{
double fg=fmod(fi,360.0);
double ff=(fg/180.0)*pi; // Перевод в радианы
fg=fmod(q,360.0);
double qq=(fg/180.0)*pi; // Перевод в радианы
CMatrix VM(4,4);
VM(0,0)=-sin(ff); VM(0,1)=cos(ff);
VM(1,0)=-cos(qq)*cos(ff); VM(1,1)=-cos(qq)*sin(ff); VM(1,2)=sin(qq);
VM(2,0)=-sin(qq)*cos(ff); VM(2,1)=-sin(qq)*sin(ff); VM(2,2)=-cos(qq); VM(2,3)=r;
VM(3,3)=1;
return VM;
}
//-----------------------------------------------------------------------------------
CMatrix SphereToCart(CMatrix& PView)
// Преобразует сферические координаты PView точки в декартовы
// PView(0) - r
// PView(1) - fi - азимут(отсчет от оси X), град.
// PView(2) - q - угол(отсчетот оси Z), град.
// Результат: R(0)- x, R(1)- y, R(2)- z
{
CMatrix R(3);
double r=PView(0);
double fi=PView(1); // Градусы
double q=PView(2); // Градусы
double fi_rad=(fi/180.0)*pi; // Перевод fi в радианы
double q_rad=(q/180.0)*pi; // Перевод q в радианы
R(0)=r*sin(q_rad)*cos(fi_rad); // x- координата точки наблюдения
R(1)=r*sin(q_rad)*sin(fi_rad); // y- координата точки наблюдения
R(2)=r*cos(q_rad); // z- координата точки наблюдения
return R;
}
//-------------------------- GetProjection -------------------------------------------
void GetProjection(CRectD& RS,CMatrix& Data,CMatrix& PView,CRectD& PR)
// Вычисляет координаты проекции охватывающего фигуру паралелепипеда на
// плоскость XY в ВИДОВОЙ системе координат
// Data - матрица данных
// RS - область на плоскости XY, на которую опирается отображаемая поверхность
// PView - координаты точки наблюдения в мировой сферической системе координат
// PR - проекция
{
double Zmax=Data.MaxElement();
double Zmin=Data.MinElement();
CMatrix PS(4,4); // Точки в мировом пространстве
PS(3,0)=1; PS(3,1)=1; PS(3,2)=1; PS(3,3)=1;
CMatrix MV=CreateViewCoord(PView(0),PView(1),PView(2)); //Матрица(4x4) пересчета
//в видовую систему координат
PS(0,0)=RS.left;
PS(1,0)=RS.top;
PS(2,0)=Zmax;
PS(0,1)=RS.left;
PS(1,1)=RS.bottom;
PS(2,1)=Zmax;
PS(0,2)=RS.right;
PS(1,2)=RS.top;
PS(2,2)=Zmax;
PS(0,3)=RS.right;
PS(1,3)=RS.bottom;
PS(2,3)=Zmax;
CMatrix Q=MV*PS; // Координаты верхней плоскости паралелепипеда в видовой СК
CMatrix V=Q.GetRow(0); // Строка X - координат
double Xmin=V.MinElement();
double Xmax=V.MaxElement();
V=Q.GetRow(1); // Строка Y - координат
double Ymax=V.MaxElement();
PS(2,0)=Zmin;
PS(2,1)=Zmin;
PS(2,2)=Zmin;
PS(2,3)=Zmin;
Q=MV*PS; // Координаты нижней плоскости паралелепипеда в видовой СК
V=Q.GetRow(1); // Строка Y - координат
double Ymin=V.MinElement();
PR.SetRectD(Xmin,Ymax,Xmax,Ymin);
}
Приложение Д. Функции аффинных преобразований.
CMatrix Translate2D(double x,double y){ //смещение в двухмерной системе координат
CMatrix m(3,3);
m(0,0)=1;m(1,1)=1;m(2,2)=1;
m(0,2)=x;
m(1,2)=y;
return m;
}
CMatrix Rotate2D(double fi){ //поворот в двухмерной системе координат
CMatrix m(3,3);
double fi_r=fi*pi/180.0;
m(0,0)=cos(fi_r);
m(1,1)=cos(fi_r);
m(2,2)=1;
m(0,1)=-sin(fi_r);
m(1,0)=sin(fi_r);
return m;
}
//смещение в трехмерной системе координат
CMatrix Translate3D(double x,double y,double z){
CMatrix m(4,4);
m(0,0)=1;m(1,1)=1;m(2,2)=1;m(3,3)=1;
m(0,3)=x;
m(1,3)=y;
m(2,3)=z;
return m;
}
//поворот вокруг оси ОZ
CMatrix Rotate3Dz(double fi){
CMatrix m(4,4);
double fi_r=fi*pi/180.0;
m(0,0)=cos(fi_r);
m(1,1)=cos(fi_r);
m(2,2)=1;m(3,3)=1;
m(0,1)=-sin(fi_r);
m(1,0)=sin(fi_r);
return m;
}
//поворот вокруг оси ОХ
CMatrix Rotate3Dx(double fi){
CMatrix m(4,4);
double fi_r=fi*pi/180.0;
m(1,1)=cos(fi_r);
m(2,2)=cos(fi_r);
m(0,0)=1;m(3,3)=1;
m(1,2)=-sin(fi_r);
m(2,1)=sin(fi_r);
return m;
}
//поворот вокруг оси ОY
CMatrix Rotate3Dy(double fi){
CMatrix m(4,4);
double fi_r=fi*pi/180.0;
m(0,0)=cos(fi_r);
m(2,2)=cos(fi_r);
m(1,1)=1;m(3,3)=1;
m(0,2)=-sin(fi_r);
m(2,0)=sin(fi_r);
return m;
}
Приложение Е. Функции преобразования координат.
//получение видовых координат по положению наблюдателя
CMatrix CreateViewCoord(double R,double fi,double theta){
CMatrix Ve(4,4),Mz(4,4);
Mz(0,0)=-1;Mz(1,1)=1;Mz(2,2)=1;Mz(3,3)=1;
double fi_r=fi*pi/180;
double theta_r=theta*pi/180;
Ve=Mz*Rotate3Dx(180-theta)*Rotate3Dz(90-fi);
return Ve;
}
//получение оконных координат по видовым
CMatrix SpaceToWindow(CRectD& rs, CRect& rw){
CMatrix m(3,3);
double kx=(rw.right-rw.left)/(rs.right-rs.left);
double ky=(rw.bottom-rw.top)/(rs.top-rs.bottom);
m(2,2)=1;
m(0,0)=kx;
m(1,1)=-ky;
m(0,2)=rw.left-kx*rs.left;
m(1,2)=rw.top-ky*rs.bottom;
return m;
}
Приложение Ж. Функция сохранения изображения в файл
//сохранение изображения окна hwnd в файл с путем-именем filename
char* SaveImg(HWND hwnd, char* filename)
{
BITMAPFILEHEADER bmfHdr; //файловый заголовок графического файла
BITMAPINFOHEADER bi; //информационный заголовок графического файла
RECT r;
int BitToPixel=24;
GetClientRect(hwnd,&r); //получение клиентской области окна
HDC hdc=GetDC(hwnd); //получение исходного контекста окна
HDC hdcMem=CreateCompatibleDC(hdc); //создание совместимого контекста
HBITMAP BitMap=CreateCompatibleBitmap(hdc,r.right,r.bottom); //создание совместимой битовой карты
HBITMAP OldBitMap=(HBITMAP)SelectObject(hdcMem,BitMap); //совмещение битовой карты с контекстом
BitBlt(hdcMem,0,0,r.right,r.bottom,hdc,0,0,SRCCOPY); //копирование изображения из исходного контекста в совместимый
BitMap=(HBITMAP)SelectObject(hdcMem,OldBitMap);
ZeroMemory(&bi,sizeof(BITMAPINFOHEADER));
//заполнение информационного заголовка
bi.biSize=sizeof(BITMAPINFOHEADER); //размер заголовка
bi.biWidth=r.right; //ширина изображения
bi.biHeight=r.bottom; //высота изображения
bi.biPlanes=1; //число слоев=1
bi.biBitCount=BitToPixel; //число битов/пиксель=24
bi.biSizeImage=(r.right*BitToPixel+31)/32*4*r.bottom; //размер изображения
DWORD dwWritten;
//получение дескриптора указанного файла
HANDLE fh=CreateFile(filename,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
//заполнение файлового заголовка
bmfHdr.bfType=('M'<<8)|'B'; //префикс графического файла bmp
bmfHdr.bfSize=bi.biSizeImage+sizeof(bmfHdr)+bi.biSize; //размер файла
bmfHdr.bfReserved1=bmfHdr.bfReserved2=0; //резервные биты
//отступ от начала файла до начала битов изображения=сумма длин заголовков
bmfHdr.bfOffBits=sizeof(bmfHdr)+bi.biSize;
//запись в файл файлового заголовка
WriteFile(fh,(LPSTR)&bmfHdr,sizeof(bmfHdr),&dwWritten,NULL);
//запись в файл информационного заголовка
WriteFile(fh,(LPSTR)&bi,sizeof(bi),&dwWritten,NULL);
//выделение памяти для битов изображения
char* lp=(char*)GlobalAlloc(GMEM_FIXED,bi.biSizeImage);
//получение аппаратно-независимого изображения
int err=GetDIBits(hdc,BitMap,0,(UINT)r.bottom,lp,(LPBITMAPINFO)&bi,DIB_RGB_COLORS);
//запись изображения в файл
WriteFile(fh,lp,bi.biSizeImage,&dwWritten,NULL);
//освобождение памяти, дескрипторов, контекстов.
GlobalFree(GlobalHandle(lp));
CloseHandle(fh);
ReleaseDC(hwnd,hdc);
DeleteDC(hdcMem);
return "Готово!";
}
Список литературы
1. Поляков А., Брусенцев В. - Методы и алгоритмы компьютерной графики в примерах на Visual C++ - СПб.: БХВ-Петербург, 2003.
2. Давыдов В. - Visual C++. Разработка Windows-приложений с помощью MFC и API-функций.
3. Форум www.stackoverflow.com