Файловые операции
Создание тестовой
поверхности, чтение данных из файла и хранение этих данных в контейнере мы будем
делать так же, как и в проекте MFC. Для разнообразия используем другую формулу
для описания поверхности по умолчанию, то есть того графика, который увидит
пользователь элемента ActiveX при его инициализации в рамках окна контейнера.
Вот эта формула:
Yi,j=exp[-(i+20*j)/256]*SIN[3*п*
(i-Nz/2)/Nz]*SIN[3*п*(j-Nx/2)/Nx]
Приведем тело
функции Def aultGraphic, которая генерирует значения этой функции над дискретной
сеткой узлов в плоскости X-Z и записывает их в файл с именем «expidat». В теле
этой функции мы вызываем другую вспомогательную функцию SetGraphPoints, которая
наполняет контейнер точек типа CPointSD. При этом, как вы помните, она генерирует
недостающие две координаты (z, x) и масштабирует ординаты (у) так, чтобы соблюсти
разумные пропорции изображения графика на экране:
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+1];
//======
Показываем на него указателем целого типа
UINT
*p = (UINT*)buff;
//
Размещаем данные целого типа
*р++
= m_xSize;
*р++
= m_zSize;
//=====
Меняем тип указателя, так как дальше
//======
собираемся записывать вещественные числа
float
*pf = (float*)p;
//
Предварительно вычисляем коэффициенты уравнения
double
fi = atan(l.)*12, kx=fi/nx, kz=fi/nz;
//===
В двойном цикле пробега по сетке узлов
//===
вычисляем и помещаем в буфер данные типа float
for
(UINT i=0; i<m_zSize;
for
(UINT j=0; j<m_xSize;
*pf++
=
float (exp(-(i+20.*j)/256.)
*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;
}
Коды функций
SetGraphPoints, ReadData и DoRead возьмите из MFC-ГфИЛО-ження OG, которое мы
разработали ранее. При этом не забудьте изменить заголовки функций. Например,
функция SetGraphPoints теперь является членом класса COpenGL, а не COGView,
как было ранее. Кроме того, метод ReadData теперь стал экспонируемым, а это
означает, что он описывается как STDMETHODIMP COpenGL: : ReadData (void) и должен
возвращать значения во всех ветвях своего алгоритма. В связи с этими изменениями
приведем полностью код функции ReadData.
STDMETHODIMP
COpenGL::ReadData(void)
{
//===
Строка, в которую будет помещен файловый путь
TCHAR
szFile[MAX_PATH] = { 0 };
//===
Строка фильтров демонстрации файлов
TCHAR
*szFilter =
TEXT("Graphics
Data Files (*.dat)\0")
TEXT("*.dat\0")
TEXT("All
FilesX()")
TEXT("*.*\0");
//===
Выявляем текущую директорию
TCHAR
szCurDir[MAX_PATH];
::GetCurrentDirectory(MAX_PATH-l,szCurDir)
;
//
Структура данных, используемая файловым диалогом
OPENFILENAME
ofn;
ZeroMemory(&ofn,sizeof(OPENFILENAME));
//===
Установка параметров будущего диалога
ofn.lStructSize
= sizeof(OPENFILENAME) ;
//===
Окно-владелец диалога
ofn.hwndOwner
= GetSafeHwnd();
ofn.IpstrFilter
= szFilter;
//===
Индекс строки фильтра (начиная с единицы)
ofn.nFilterlndex=
1;
ofn.IpstrFile
= szFile;
ofn.nMaxFile
= sizeof(szFile);
//===
Заголовок окна диалога
ofn.IpstrTitle
= _Т("Найдите файл с данными");
ofn.nMaxFileTitle
= sizeof
(ofn.IpstrTitle);
//===
Особый стиль диалога (только в Win2K)
ofn.Flags
= OFN_EXPLORER;
//===
Создание и вызов диалога
//
В случае неудачи GetOpenFileName возвращает О
if
(GetOpenFileName(&ofn))
{
//
Попытка открыть файл, который должен существовать
HANDLE
hFile = CreateFile(ofn.IpstrFile, GENERIC READ, FILE SHARE READ, 0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0) ;
//=====
В случае неудачи CreateFile возвращает -1
if
(hFile == (HANDLE)-1)
{
MessageBox(_T("He
удалось открыть файл"));
return
S_FALSE;
}
//===
Попытка прочесть данные о графике
if
(IDoRead(hFile))
return
S_FALSE;
//======
Создание нового изображения
DrawScene();
//======
Перерисовка окна OpenGL
Invalidate(FALSE);
}
return
S_OK;
}
Если вы используете
операционную систему Windows 2000, то файловый диалог, который создает функция
GetOpenFileName, должен иметь другой стиль. Он задан флагом OFN_EXPLORER.