Возращаемое значение:
TRUE – в случае благополучного завершения,
FALSE – в случае неудачи.
Для повышения мобильности пакета ГРАФОР было сделано следующее. Поскольку средства непосредственного вывода изображения в различных операционных системах и/или средах различны, вывод изображения на экран осуществляется так: сначала программа, использующая пакет, записывает файл в подмножество языка HP-GL и файл закрывается, а затем вызывается подпрограмма, читающая этой файл, интерпретирующая команды HP-GL и выводящая соответствующую графику на экран. Заметим, что при этом вся "вычислительная часть" пакета (т.е. получение изображения, а ещё точнее – координат отрезков) остается неизменной, а подпрограмма, реализующая непосредственный вывод на дисплей, может использовать различные средства для этого вывода, а также может быть написана и на другом языке программирования.
Остановимся более подробно на языке описания данных HP-GL, созданным более четверти века назад (1976 г.) и поддерживаемом (наряду с более поздним стандартом HP-GL/2) многими производителями (как оборудования, в основном плоттеров и принтеров, так и программных средств, в первую очередь CAD-систем).
Язык использует только коды ASCII. Оператор языка обязательно включает мнемонический код операции (mnemonics), который состоит из двух прописных либо строчных букв, и несколько параметров, разделенных запятыми и/или пробелами. В качестве разделителя между мнемоническим кодом и первым параметром используется пробел, который может отсутствовать. Параметры могут быть необязательными. Если опущен какой либо из них, то должны отсутствовать и все параметры, следующие за ним.
Для разделения операторов используется точка с запятой, в случае отсутствия разделителя концом оператора считается начало следующего. Управляющие символы CR и LF при интерпретации игнорируются.
Задаваемые к качестве параметров в операторе числовые значения записываются в виде цепочек ASCII-символов. Допускается до пяти знаков дробной части. Если дробная часть отсутствует, десятичная точка может опускаться. В качестве параметров других типов допускаются также только цепочки символов. Целые значения типа clamped integer должны удовлетворять неравенству
а вещественные(–32767) £ ClampedIntegerType £ 32767,
(–32767.9999) £ ClampedRealType £ 32767.9999.
Таким образом, структура оператора (назовем его ХХ) выглядит следующим образом:
ХХ <параметр>… <разделитель>< параметр>.
Пример вариантов записи конкретного оператора:
"PDPU10,20" или "PD;PU10,20;" или "PD PU 10 20;".
Ядро языка HP-GL/2 содержит 55 операторов, которые должны поддерживаться всеми устройствами вывода изображения. Заметим, что даже при этом возможны случаи "разночтения" разными устройствами. Например, команда LT(LineType – тип линии) в плоттере HP7475A воспринимает первый параметр, принимающий значения 0, 1, 2, 3, 4, 5 и 6. А для плоттера HP7550A он может быть и отрицательным (0, ±1, ±2, ±3, ±4, ±5, ±6). К тому же в перьевых плоттерах карусели имеют различное количество гнезд (≡цветов).
Таким образом, лучше выбрать и использовать только необходимый минимум команд, позволяющих реализовывать все графические операции. Приведем их краткое описание.
IN | Инициализация. Восстанавливает стандартные значения всех параметров устройства. |
IP ЛНx ЛНy ПВx ПВy | Определение значений масштабных точек (левого нижнего и правого верхнего углов чертежа). |
SC Xmin, Xmax, Ymin, Ymax | Задание системы координат пользователя. |
SP N | Установить цвет, определяемый номером. |
PU X, Y | Переместиться в указанную точку. |
PD X, Y | Провести линию в указанную точку. |
Для наглядности приведем фрагмент файла, записываемого в результате работы пакета:
IN; IP 0, 4019, 6028, 0; SC 0, 300, 0, 200; SP 1 ;PU 139 139 ;PD 139 20 ;SP 2 ;PU 139 25 ;PD 278 25 . . . . . . . . ;SP 3 ;PU 265 101 ;PD 267 106 ;SP0;
Создана подпрограмма пакета, осуществляющая запись результатов работы в файл, формат которого является подмножеством (используется минимум команд, достаточный для реализации всех графических элементов) языка HP-GL (Hewlett-Packard Graphic Language). Поскольку формат таких файлов чисто текстовый (plain ASCII), обеспечивается их передача на другие платформы и операционные системы.
Для повышения мобильности программ отображения (обычно эта часть программное обеспечения наиболее трудно переносится на другие платформы) их реализация в системах семейства Windows (95/98/ME/NT/2000) теперь осуществляется средствами OpenGL. В новой версии экранного драйвера она вызывается вместо подпрограммы, в которой отображение на экран осуществляется с помощью встроенных средств MS Fortran Power Station/Compaq Visual Fortran.
Относительно старой версии также добавились возможности: более простой передачи изображения в буфер обмена, масштабирования и подстраивания под размер окна.
Также реализована отдельная динамическая библиотека HglView.dll, которая содержит функции, позволяющие просматривать HP-GL-файлы формата, описанного выше. Универсальность модуля позволяет вызывать его функции как из приложений, написанных на Фортране, так и на Си. HglView.dll создает собственное меню, через которое можно управлять окнами просмотра HP-GL файлами. Меню содержит следующие команды:
File | → | Close | – Закрыть активное окно просмотра HP-GL файла |
Edit | → | Copy .hgl file to the Clipboard | – Скопировать содержимое активного окна в буфер обмена |
View | → | Size To Fit | – Изменить масштаб и размеры изображения в соответствии с реальными размерами HP-GL файла |
→ | Zoom In | – Увеличить размер изображения | |
→ | Zoom Out | – Уменьшить размер изображения | |
Window | → | Cascade | – Расположить окна с перекрытием |
→ | Tile | – Расположить окна без перекрытия | |
→ | Close All | – Закрыть все окна просмотра HP-GL файлов |
READHGLFILE | – выбрать HP-GL файл через стандартный OPEN диалог и показать его. |
VIEWHGLFILE | – показать заданный HP-GL файл. |
SIZETOFIT | – изменить размеры окна HP-GL изображения в соответствии с его реальным размером. |
ZOOM | – осуществить масштабирование HP-GL изображения в сторону увеличения/уменьшения; масштабирование осуществляется по следующей шкале: ... 12,5% 25% 50% 100% 150% 200% 250% ... |
ISHGLVIEW | – определить, содержит ли заданное окно HP-GL изображение. |
1) HglView.dll – следует разместить либо в системной директории, либо в ту, где будет находиться приложение, обращающееся к данному модулю.
2) HglView.lib – библиотека, необходимая для linker'а.
3) HglViewExt.h – файл, содержащий объявление функций; необходим для нормальной работы модулей на СИ.
4) Cview файлы – Пример работы с библиотекой на СИ.
Для работы в ФОРТРАНЕ требуется наличие Compaq Visual Fortran 6 или аналогичного продукта. Необходимо выполнить следующие шаги:
1) Создать проект QuickWin (multiple windows).
2) Добавить в созданный проект библиотеку HglView.lib .
3) Добавить в файл на ФОРТРАНЕ вызов нужной фукции.
Для работы в СИ требуется наличие MS Visual C++ 6.0. Необходимо выполнить следующие шаги:
1) Создать проект Win32 Application.
2) Добавить в созданный проект файл HglViewExt.h и библиотеку HglView.lib.
3) Создать обычное MDI приложение.
Пример Cview позволяет увидеть, что нужно добавить для работы с данной библиотекой. Чтобы иметь возможность работать с меню, создаваемым для HP-GL окна надо в процедуру обработки сообщения (message) WM_COMMAND добавить следующие строки:LONG lResult = 0; HWND hChild; hChild =(HWND)SendMessage(hwndMDIClient,WM_MDIGETACTIVE,0,(LPARAM)NULL); if (ISHGLVIEW (hChild)) //если handle принадлежит HP-GL окну, то передать { // команду меню на обработку процедуре HP-GL окна lResult = SendMessage (hChild, WM_COMMAND, wParam, lParam); if (!lResult) return 0; }
__declspec(dllimport) extern BOOL __stdcall READHGLFILE(void);
С помощью этой функции пользователь может выбрать HP-GL файл для просмотра через стандартное диалоговое окно OPEN
Аргументы: - нет.
Возращаемое значение:
TRUE – в случае благополучного завершения,
FALSE – в случае неудачи.
__declspec(dllimport) extern BOOL __stdcall VIEWHGLFILE(LPINT pnFile);
Данная функция открывает для просмотра предварительно заданный HP-GL файл
Аргументы:
- pnFile
- указатель на номер HP-GL файла. По умолчанию имя HP-GL файла - HPxx.HGL, где xx ::= 1|2|...|99.
Возращаемое значение:
TRUE – в случае благополучного завершения,
FALSE – в случае неудачи.
__declspec(dllimport) extern void __stdcall SIZETOFIT (void);
Функция восстанавливает реальные размеры и масштаб HP-GL изображения.
__declspec (dllimport) extern void __stdcall ZOOM (int nDirection);
Функция осуществляет масштабирование HP-GL изображения; масштабирование осуществляется по следующей шкале: ... 12,5% 25% 50% 100% 150% 200% 250% ...
– в сторону увеличения
– в сторону уменьшения
__declspec (dllimport) extern BOOL __stdcall ISHGLVIEW (HWND hWnd);
Функция проверяет является ли данное окно окном HP-GL изображения.
Возращаемое значение:
Программа просмотра ( Viewer ).
Создана отдельная программа просмотра, которой можно просматривать файлы и после окончания работы с пакетом, поскольку по умолчанию они не уничтожаются и остаются на жестком диске в директории проекта. Пример работы приведен на рисунке.
Здесь, помимо возможностей передачи изображения в буфер обмена, масштабирования, подстраивания под размер, имеются возможности посмотреть, какая директория является текущей, задать просмотр одного конкретного файла или всех файлов из текущей директории, а также узнать полное имя текущего файла.
Меню содержит команды работы с окнами просмотра HP - GL файлов.
File | –> | Open | – Выбрать HP - GL файл для просмотра через стандартное диалоговое окно Open |
|
–> | Open All | – Открыть для просмотра все HP - GL файлы из текущей директории |
|
–> | Export PostScript | – Сохранить текущее изображение в файле PS -формата |
|
–> |
Close |
– Закрыть активное окно просмотра HP-GL файла |
|
–> | Exit | – Закрыть все окна и завершить работу |
Edit |
–> | Copy .hgl file to the Clipboard |
solid windowtext .75pt;solid windowtext .75pt;padding:
0cm 5.4pt 0cm 5.4pt">
– Скопировать содержимое активного окна в буфер обмена |
View |
margin-left:36.0pt;text-indent:-1mso-list: l0 level1 lfo9;tab-stops:36.0pt"> –font:7.0pt 'Times New Roman'"> полное имя, margin-left:36.0pt;text-indent:-1mso-list: l0 level1 lfo9;tab-stops:36.0pt"> –font:7.0pt 'Times New Roman'"> размер файла, margin-left:36.0pt;text-indent:-1mso-list: l0 level1 lfo9;tab-stops:36.0pt"> –font:7.0pt 'Times New Roman'"> дату создания и размер изображения в точках X на Y . | ||
–> | Current Directory | – Показать текущую директорию | |
Window –> |
Cascade |
– Расположить окна с перекрытием |
|
|
–> |
Tile |
– Расположить окна без перекрытия |
|
–> |
Close All |
– Закрыть все окна просмотра HP-GL файлов |
Help |
–> | About… | solid windowtext .75pt;solid windowtext .75pt;padding: 0cm 5.4pt 0cm 5.4pt"> – Показать диалоговое окно с информацией о программе |
Работа пакета ГРАФОР в Linux
Пакет ГРАФОР перенесен на платформу Linux . При написании программы визуализации для пакета ГРАФОР использовалась графическая библиотека QT версии 2.3.1.
Исполнимый файл собирается из 3-х модулей :
1) Модуль, написанный на Fortran - callwin.f, реализует функции, необходимые пользователю .
2) Модуль, написанный на C – sig .c, нужен для связи с модулем main . cpp .
3) Модуль, написанный на C++ – main . cpp , реализует визуализацию результатов, полученных в callwin.f.
Взаимодействие модулей осуществляется так :1. Запускается функция main () модуля main . cpp . Она назначает процедуру signal 1() обработчиком сигнала SIG _ USR 1, подготавливает среду для создания окон приложения и вызывает главную процедуру модуля callwin . f .
2. В модуле callwin . f после создания файла-результата для его отображения вызывается процедура dowin1() модуля sig . c ,
3. Процедура dowin 1() модуля sig . c изменяет глобальную переменную num _ win ( в данном случае в 1) и посылает приложению ( то есть себе) сигнал SIG_USR1.
4. Процедура signal 1() модуля main . cpp создает динамический объект класса MWidget , вызывая его конструктор и передавая num _ win в качестве параметра . Конструктор читает файл-результат, создает цепочку, каждый элемент которой – отрезок ( цвет+координаты) в окне и инициализирует окно . Функция прорисовки окна берет информацию из цепочки.
Об ' ект класса Mwidget c оздает окно, меню которого содержит пункты :36.0pt"> ' Close ' - закрывает окно,
36.0pt"> '1 x 1' - устанавливает масштаб 1х1,
36.0pt"> ' In ' - увеличивает изображение в 2 раза,
36.0pt"> ' Out ' - уменьшает изображение в 2 раза.
36.0pt">
Если изображение не помещается в окне, то повляется соответствующая (Х и/или У) полоса прокрутки. При закрытии последнего окна приложение заканчивает работу. Имена процедур в С/С++ не совпадают ( добавлен символ подчеркивания в конце ) c именами в Fortran’ е . Пример окна :Исходные тексты :
/********** 'Times New Roman';begin 'Times New Roman';callwin'Times New Roman'">.'Times New Roman'; f'Times New Roman'"> ***************/ yes; TIMES NEW ROMAN CYR" lang=" subroutine fortran integer argc character(*) argv call dowin1 call dowin2 end /********** 'Times New Roman'; end 'Times New Roman'; callwin.f ***************/ /************* begin sig.c *************/ #include <signal.h> char num_win; void dowin1_() { num_win=1; kill( getpid(), SIGUSR1); } void dowin2_() { num_win=2; kill( getpid(), SIGUSR1); } /************* end sig.c **************/ // begin main.cpp #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <iostream.h> #include <qapp.h> #include <qmenubar.h> #include <qpainter.h> #include <qscrollbar.h> #include <qstring.h> #include <qfile.h> #include <qtstream.h> struct TChain { unsigned short int x; unsigned short int y; unsigned short int x2; unsigned short int y2; 2"> unsigned int cl:8; struct TChain *next; }; class MWidget : public QWidget { Q_OBJECT public: MWidget( QWidget *parent=0, const char *name=0, uint number=0, uint w=0, uint h=0 ); ~MWidget(); private slots: void fzoomin(){ scale.x*=2; scale.y*=2; setMaxH();setMaxV(); repaint(FALSE); }; void fzoomout(){ scale.x/=2; scale.y/=2; setMaxH();setMaxV(); repaint(FALSE); }; void fzoom1x1(){ scale.x=scale.y=1.0; setMaxH();setMaxV(); repaint(FALSE); }; void setH( int val ){ shft.x=val; repaint(FALSE); } void setV( int val ){ shft.y=val; repaint(FALSE); } void setMaxH(){ 2"> if(size.x*scale.x>hsb->width()){ 2"> hsb->setMaxValue( size.x*scale.x-hsb->width() ); hsb->show(); 2"> }else{ hsb->hide(); shft.x=0; hsb->setValue(0);} 2"> } void setMaxV(){ 2"> if(size.y*scale.y>vsb->height()){ 2"> vsb->setMaxValue( size.y*scale.y-vsb->height() ); vsb->show(); 2"> }else{ vsb->hide(); shft.y=0; vsb->setValue(0); } 2"> } private: void paintEvent( QPaintEvent * ); void resizeEvent( QResizeEvent * ); QMenuBar *menubar; QScrollBar *hsb, *vsb; uint h,w, i,j, n; struct TChain *tree, *lnk; struct Tscale { float x; float y; } scale; struct { uint x; uint y; } size, shft; }; MWidget::MWidget( QWidget *parent, const char *name, uint number,uint w, uint h ) : QWidget( parent, name) { char s[]='Window N '; char fname[]='HP00.HGL'; bool ok; int *pint, a,b,c,d; struct TChain e; scale.x=scale.y=1.0; shft.x=shft.y=0; setWFlags(WDestructiveClose); menubar = new QMenuBar( this, 'menu' ); CHECK_PTR( menubar ); menubar->insertItem( '&Close', this, SLOT(close()) ); menubar->insertItem( '1x1', this, SLOT(fzoom1x1()) ); menubar->insertItem( 'In', this, SLOT(fzoomin()) ); menubar->insertItem( 'Out', this, SLOT(fzoomout()) ); hsb = new QScrollBar( 0,255,10,40,0,Horizontal, this, 0 ); connect( hsb, SIGNAL(valueChanged(int)), SLOT(setH(int)) ); vsb = new QScrollBar( 0,255,1,10,0,Vertical, this, 0 ); connect( vsb, SIGNAL(valueChanged(int)), SLOT(setV(int)) ); n=number; tree=NULL; fname[2]='0'+number/10; fname[3]='0'+number%10; QFile f(fname); if(f.open( IO_ReadOnly )){ QTextStream t( &f ); QString s; s=t.readLine(); s=t.readLine(); s=t.readLine(); if(s[0]=='S' && s[1]=='C'){ if((sscanf((const char*)s,'SC %d, %d, %d, %d;',&a,&b,&c,&d))==4){ size.x=b; size.y=d; }else return; }else return; e.x=e.y=e.x2=e.y2=e.cl=0; e.next=NULL; while(!t.eof()){ s=t.readLine(); //SP if(!strncmp(s,' ;SP',4)){ s=t.readLine(); e.cl=s.toUInt(&ok); if(!ok) break; //PU s=t.readLine(); if(s.contains(';PU',FALSE)){ s=t.readLine(); e.x=s.toUInt(&ok); if(!ok) break; s=t.readLine(); e.y=s.toUInt(&ok); if(!ok) break; //PD s=t.readLine(); 1"> }else{ 1"> e.x=e.x2; e.y=e.y2; 1"> } if(!s.contains(';PD',FALSE)) break; s=t.readLine(); e.x2=s.toUInt(&ok); if(!ok) break; s=t.readLine(); e.y2=s.toUInt(&ok); if(!ok) break; //LNK lnk=new TChain[1]; lnk->next=tree; tree=lnk; lnk->x=e.x;lnk->y=e.y; lnk->x2=e.x2;lnk->y2=e.y2; lnk->cl=e.cl; }//else printf('s= %s\n',s2); } if(!t.eof()){// printf('Error: s=%s\n',(const char*)s); 1"> cout << 'Error: s=' << s << '\n'; 1"> f.close(); close(); return; } f.close(); }else{ printf('Error: number= %d\n',number); close(); return; } setMinimumSize(150,100); resize( w, h ); s[11]=number/10+'0'; s[12]=number%10+'0'; setCaption(s); show(); } MWidget::~MWidget() {// int n=0; lnk=tree; while(lnk){ tree=lnk->next; free(lnk);// n++; lnk=tree; }// printf('freed %d\n',n); } void MWidget::resizeEvent( QResizeEvent * ) { int mh=menubar->heightForWidth(width()); hsb->setGeometry( 0, height()-15, width()-15, 15 ); setMaxH(); vsb->setGeometry( width()-15, mh, 15,height()-15-mh ); setMaxV(); repaint(FALSE); } void MWidget::paintEvent( QPaintEvent * ) { QColor colors[]={ QColor(0,0,0), QColor(255,0,0), QColor(0,255,0), QColor(0,0,255), QColor(136,0,136), QColor(128,128,128) }; QPainter paint; paint.begin( this ); paint.setBrush( 0xffffff ); paint.drawRect(0,menubar->height(),width()-15,height()-menubar->height()-15); lnk=tree; while(lnk){ paint.setPen( colors[lnk->cl]); paint.drawLine((int)(scale.x*lnk->x)-shft.x, (int)(scale.y*lnk->y)+menubar->height()-shft.y, (int)(scale.x*lnk->x2)-shft.x, (int)(scale.y*lnk->y2)+menubar->height()-shft.y); lnk=lnk->next; } paint.setPen( 0xc0c0c0 ); paint.setBrush( 0xc0c0c0 ); paint.drawRect( width()-15,height()-15,15,15 ); if(!hsb->isVisible()) paint.drawRect( 0,height()-15,width()-15,15 ); if(!vsb->isVisible()) paint.drawRect( width()-15,menubar->height(),15,height()-menubar->height()-15 ); paint.end(); } #include 'main.moc' extern char num_win; extern 'C' void fortran_(int argc, char **argv); void signal1(int sig) { MWidget *m=new MWidget(0,0, num_win, 300, 200 ); } int main( int argc, char **argv ) { signal( SIGUSR1, signal1 ); QApplication a( argc, argv ); QObject::connect( qApp, SIGNAL( lastWindowClosed() ), qApp, SLOT( quit() ) ); fortran_( argc, argv); return a.exec(); } // end main.cpp
Формат Post Script
Наряду с файлами на языке HP - GL удобно получать файлы на языке PostScript , который является межплатформенным и также имеет текстовый формат. Кратко опишем особенности этого языка.
Файл EPS состоит из двух частей – Prolog и Script , каждая из которых может включать в себя управляющие опреаторы EPS . Содержащиеся в теле файла управляющие операторы EPS начинаются, как и операторы языка PostScript , с символа процента – “%”. Таким образом, EPS -файлы могут обрабатываться как обычным транслятором с языка PostScript , который такие опреаторы будет игнорировать, так и более сложными программами обработки, которыми операторы EPS будут интерпретироваться. Признаком опратора EPS , позволяющего отличить его от комментария, служит второй символ оператора, следующий за “%”. Управляющие операторы начинаются символами “%!” или ”%%”, за которыми следует ASCII -строка. Первый оператор выглядит так ( W , X , Y , Z – конкретные номера версий и подверсий ) :