Иллюстрированный самоучитель по Visual Studio .NET

График по умолчанию

Пришла пора создать тестовую поверхность у = f (x, z), которую мы будем демонстрировать по умолчанию, то есть до того, как пользователь обратился к файловому диалогу и выбрал файл с данными, которые он хочет отобразить в окне OpenGL Функция DefaultGraphic, коды которой вы должны вставить в файл ChildView.cpp, задает поверхность, описываемую уравнением:

Yi,j=[3*n*(i-Nz/2)/2*Nz]*SIN [3*n*(j-Nx/2)/2*Nx]

Здесь n обозначает количество ячеек сетки вдоль оси Z, а nх количество ячеек вдоль оси X. Индексы i (0 < i < nz) и j (0 < j < nx)выполняют роль дискретных значений координат (Z, X) и обозначают местоположение текущей ячейки при пробеге по всем ячейкам сетки в порядке, описанном выше. Остальные константы подобраны экспериментально так, чтобы видеть полтора периода изменения гармонической функции.

Мы собираемся работать с двоичным файлом и хранить в нем информацию в своем формате. Формат опишем словесно: сначала следуют два целых числа m_xsize и m_zSize (размеры сетки), затем последовательность значений функции у = f (х, z) в том же порядке, в котором они были созданы. Перед тем как записать данные в файл, мы поместим их в буфер, то есть временный массив buff, каждый элемент которого имеет тип BYTE, то есть unsigned char.

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

void COGView::DefaultGraphic()
{
//====== Размеры сетки узлов
m xSize = m zSize = 33;
//====Число ячеек на единицу меньше числа узлов
UINTnz = m_zSize – 1, nx = m_xSize – 1;
// Размер файла в байтах для хранения значений функции
DWORD nSize = m_xSize * m_zSize * sizeof (float) + 2*sizeof (UINT);
//====== Временный буфер для хранения данных
BYTE *buff = new BYTE[nSize+l];
//====== Показываем на него указателем целого типа
UINT *p = (UINT*)buff;
//====== Размещаем данные целого типа
*р++ = m_xSize;
*р++ = m_zSize;
//====== Меняем тип указателя, так как дальше
//====== собираемся записывать вещественные числа
float *pf = (float*)?;
//=== Предварительно вычисляем коэффициенты уравнения
double fi = atan(l.)*6,
kx = fi/nx,
kz = fi/nz;
//====== В двойном цикле пробега по сетке узлов
//=== вычисляем и помещаем в буфер данные типа float
for (UINT i=0; i<ra_zSize;
for (UINT j=0; j<m_xSize;
{
*pf++ = float (sin(kz* (i-nz/2.)) * sin (kx* (j-nx/2.))
}
}
//=== Переменная для того, чтобы узнать сколько
//=== байт было реально записано в файл DWORD nBytes;
//=== Создание и открытие файла данных sin.dat
HANDLE hFile = CreateFile (_T ("sin.dat"), GENERIC_WRITE,
0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
//====== Запись в файл всего буфера
WriteFile (hFile, (LPCVOID) buff, nSize, SnBytes, 0);
//====== Закрываем файл
CloseHandle (hFile);
//====== Создание динамического массива m_cPoints
SetGraphPoints (buff, nSize);
//====== Освобождаем временный буфер
delete [ ] buff;
}

В процессе создания, открытия и записи в файл мы пользуемся API-функциями CreateFile, WriteFile и CloseHandle, которые предоставляют значительно больше возможностей управлять файловых хозяйством, чем, например, методы класса CFile или функции из библиотек stdio.h или iostream.h. Обратитесь к документации, для того чтобы получить представление о них.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.