Hlavní navigace

Prohlížení vektorových výkresů ve formátu HPGL/PLT

15. 3. 2007
Doba čtení: 10 minut

Sdílet

V dnešním pokračování seriálu, ve kterém si popisujeme oblíbené a často používané grafické formáty, si na příkladu ukážeme, jak je možné programově zpracovat soubory typu HPGL/PLT, ve kterých bývají uloženy vektorové výkresy. Vytvoříme jednoduchý prohlížeč tohoto formátu využívající pro zobrazení grafickou knihovnu OpenGL.

Obsah

1. Vektorový grafický formát HPGL prakticky
2. Specifika ovladače plotteru Hewlett-Packard HP 7475
3. Demonstrační výkresy převedené do formátu HPGL
4. Rozpoznání jednotlivých příkazů uložených v souboru HPGL
5. Vykreslení načteného výkresu na základě uložených příkazů
6. Popis demonstračního příkladu
7. Možné další rozšíření demonstračního příkladu
8. Odkazy na další informační zdroje
9. Obsah dalšího pokračování tohoto seriálu

1. Vektorový grafický formát HPGL prakticky

V předchozí části tohoto seriálu jsme si popsali jazyk HPGL (Hewlett-Packard Graphics Language) používaný pro popis vektorových výkresů. Tento jazyk je použitý buď přímo při komunikaci s tiskárnou či plotterem (většinou přímo přes sériový či paralelní port, nověji také přes spooler) nebo při zápisu vektorové podoby výkresu do souborů s koncovkou .PLT, .HGL či .HPG. Také jsme si řekli, že pro každé kreslicí zařízení se generuje poněkud odlišný soubor podle toho, jak je které zařízení „inteligentní“. Některé plottery například nedokáží provádět vyplňování uzavřených obrazců, tisknout řetězce znaků, vykreslovat oblouky apod. Při komunikaci s těmito plottery je tedy zapotřebí všechny složitější grafické entity nechat rozložit na jednotlivé úsečky a teprve ty vykreslovat, popř. ukládat do souboru.

Na první pohled může podpora mnoha plotterů vypadat velmi složitě a nepřehledně, v některých případech si však situaci můžeme naopak podstatným způsobem zjednodušit – pokud například v daném grafickém programu (tím může být CAD/CAM, vektorový grafický editor apod.) nastavíme tisk na „málo inteligentní“ plotter, program sám či ovladač plotteru provede potřebné rozložení složitých grafických entit na entity jednodušší a ty je možné snadněji zpracovat. Tímto způsobem je možné mezi různými programy přenášet i výkresy obsahující složité prvky typu řetězce znaků či křivky, musíme se však smířit s tím, že jsou tyto prvky rozloženy na úsečky a jejich opětovné složení je velmi složité (křivky) či nemožné (texty).

V dalších kapitolách si ukážeme, jakým způsobem je možné načítat a zobrazovat soubory určené pro plotter HP 7475 a celou řadu kompatibilních tiskových zařízení.

2. Specifika ovladače plotteru Hewlett-Packard HP 7475

Typ plotteru Hewlett-Packard HP 7475 je velmi starý a tak se s tímto zařízením pravděpodobně již nesetkáte (i když výrobky HP z té doby jsou proslulé svou výdrží a technickou kvalitou – viz například „nezničitelná“ LaserJet 4). To, že tento plotter již morálně zastaral, však nevadí, celá řada plotterů HP 74.. byla velmi oblíbená a výrazným způsobem přispěla k rozšíření i akceptaci jazyka HPGL. Na tuto řadu navázali i další výrobci, proto je možné vektorové výkresy určené pro tisk na HP 7475 zpracovat i na dalších typech plotterů, včetně jejich moderních variant, které už nepoužívají klasická rýsovací pera nebo inkoustové fixy, ale rastrovou tiskovou technologii (v podstatě nejde o nic jiného, než o velkoformátové inkoustové nebo laserové tiskárny s přidanými pomůckami, například pro ořez papíru).

Plotter HP 7475 akceptuje pouze omezenou skupinu příkazů jazyka HPGL. To může být výhodné, protože při výběru tohoto typu plotteru, například v programech typu CAD, můžeme generovat soubory, které jsou kompatibilní s dalšími modernějšími plottery. Tyto soubory je možné díky své jednoduchosti i snadněji načítat a posléze zobrazovat, což si ukážeme na dnešním demonstračním příkladu. Abych byl konkrétní, uvedu v následující tabulce seznam příkazů, které plotter HP 7475 akceptuje:

Příkaz Význam Parametry Popis
IN Initialize inicializace plotteru
SC Scaling x, y, x, y nastavení měřítka pomocí obdélníku nebo inicializace měřítka
SP Select Pen n výběr kreslicího pera číslo n
LT Line Type číslo, délka nastavení typu vykreslované úsečky
VS Velocity Select v nastavení rychlosti kreslení
PA Plot Absolute x, y, … nastavení absolutních souřadnic (může kreslit)
PU Pen Up x, y, … zdvižení pera na souřadnice x, y; bývá bez souřadnic
PD Pen Down x, y, … spuštění pera na souřadnice x, y; bývá bez souřadnic

3. Demonstrační výkresy převedené do formátu HPGL

Pro ukázku zpracování výkresů uložených v souborech typu HPGL/PLT jsem vybral trojici výkresů vytvořenou v programu AutoCAD:

  1. Na prvním výkresu se nachází několik kružnic o různém poloměru. Touto kresbou je předvedeno, jakým způsobem AutoCAD provedl rozklad kružnic na řetězec na sebe navazujících úseček. Celý výkres může být vykreslen jedním kreslicím perem, tj. jednobarevně. První výkres si můžete stáhnout zde.
  2. Na druhém výkresu je vytvořen raketoplán vykreslený v několika barvách. Opět se jedná o obrázek, ve kterém musely být původně zaoblené tvary převedeny na řetězec úseček. Současně je možné otestovat funkce změny kreslicího pera a tím pádem i barvy či tloušťky kreslených čar. Konkrétní typ pera (barva, tloušťka) původně závisel na uživateli, protože pera bylo možné v zásobníku prohazovat. Soubor s druhým výkreslem si můžete stáhnout zde.
  3. Na třetím výkresu je vyobrazen pohled na původně trojrozměrný model. V souborech typu HPGL/PLT se však samozřejmě nachází pouze dvourozměrná varianta, tj. průmět 3D scény do promítací roviny. Původní výkres neobsahoval žádné oblouky ani křivky, proto zde nemuselo docházet k rozkladu těchto tvarů na úsečky. Soubor se třetím výkresem se nachází pod tímto odkazem.

plt1
Obrázek 1: Několik kružnic

plt2
Obrázek 2: Raketoplán

plt3
Obrázek 3: Pohled na trojrozměrný model

4. Rozpoznání jednotlivých příkazů uložených v souboru HPGL

Vzhledem k tomu, že soubory generované pro plotter HP 7475 obsahují pouze několik příkazů, může být parsovací funkce poměrně jednoduchá. Jedinou výraznější komplikací je fakt, že některé ovladače (konkrétně například ovladač v AutoCADu 2006) spojují příkazy PU a PA, popř. PD a PA do jednoho slova PUPA popř. PDPA. To samozřejmě neodporuje pravidlům stanoveným pro jazyk HPGL, ale přebytečně načtený znak je nutné vrátit zpět do bufferu načítaného souboru (nebo použít složitější programovou logiku, například KA). Po načtení příkazů, které provádí nastavení barvy pera nebo přímo vykreslují, se parametry těchto příkazů uloží do lineárního seznamu, který posléze slouží pro vykreslení celého výkresu na obrazovku. V lineárním seznamu je uložena identifikace příkazu, nové souřadnice pera (pro kreslení úseček) a popř. i nově nastavená barva pera:

// typ prikazu
typedef enum {
    PEN_UP,                     // zvednuti kresliciho pera
    PEN_DOWN,                   // spusteni kresliciho pera
    MOVE_TO,                    // presun kresliciho pera
    SELECT_PEN                  // vyber kresliciho pera ~ vyber barvy
} Command;

// jeden zaznam ziskany ze souboru HPGL
typedef struct Item {
    Command cmd;                // prikaz - (PEN_UP, PEN_DOWN, MOVE_TO, SELECT_PEN)
    double  x;                  // souradnice
    double  y;
    int     pen;                // barva pera
    struct Item *next;          // vazba v linearnim seznamu
} Item; 

Funkce pro načtení všech relevantních příkazů ze souboru typu HPGL/PLT může vypadat následovně (všimněte si, že nevýznamné příkazy jako IN apod. jsou přeskakovány, stejně jako několik úvodních bytů na začátku souboru, které slouží k inicializaci plotteru):

//-----------------------------------------------------------------------------
// Precteni HPGL souboru urceneho pro HP7475
//-----------------------------------------------------------------------------
int readItems(char *fileName)
{
    FILE *fin=fopen(fileName, "rt");
    int c;
    char s[100];
    if (!fin) return 0;
    // smycka, ve ktere se zanalyzuje cely soubor HPGL
    do {
        int i;
        // nacteni jednoho prikazu (oddelovacem je vetsinou strednik)
        for (i=0; (c=fgetc(fin))!=';' && c!=EOF; i++) {
            // tato podminka je nutna pro ovladace,
            // ktere generuji kod ve stylu 'PUPA10,10'
            // misto 'PU;PA10,10
            if (i==2 && isalpha(c)) {
                ungetc(c, fin);
                break;
            }
            // prevod znaku na velka pismena (pro jistotu)
            s[i]=(c>='a' && c<='z') ? c-'a'+'A':c;
        }
        s[i]=0;                             // ukonceni retezce
        if (!strcmp(s, "PU")) {
            addItem(PEN_UP, 0, 0, 0);
        }
        if (!strcmp(s, "PD")) {
            addItem(PEN_DOWN, 0, 0, 0);
        }
        if (!strncmp(s, "SP", 2)) {         // prikaz SP
            int pen=strtol(s+2, NULL, 10);  // = nacteme barvu pera
            addItem(SELECT_PEN, 0, 0, pen);
        }
        if (!strncmp(s, "PA", 2)) {         // prikaz PA
            double x, y;                    // = musime nacist obe souradnice
            for (i=0; s[i]!='-' && s[i]!='+' && !isdigit(s[i]); i++)
                ;
            x=strtod(s+i, NULL);
            i++;
            for (; s[i]!='-' && s[i]!='+' && s[i]!=','; i++)
                ;
            i++;
            y=strtod(s+i, NULL);
            addItem(MOVE_TO, x, y, 0);
        }
    } while (c!=EOF);                       // cteni az do konce souboru
    fclose(fin);
    return 1;
}

//----------------------------------------------------------------------------- 

5. Vykreslení načteného výkresu na základě uložených příkazů

Vykreslení všech částí načteného výkresu je poměrně jednoduché, protože plotter HP 7475 vlastně vykresluje pouze jednotlivé úsečky nebo lomené čáry, které se opět skládají z úseček. Použitá grafická knihovna OpenGL vykreslování úseček samozřejmě podporuje, proto je převod „pohybu kreslicího pera“ na úsečky poměrně přímočarý (vzhledem k tomu, že příkazy PU a PD nejsou párovány, je další zjednodušování prakticky nemožné a musíme používat pomocné proměnné x1, y1, x2, y2). V demonstračním příkladu je možné výkresem posouvat a měnit jeho velikost (zvětšení, zmenšení), proto se před vlastním vykreslováním musí vhodně nastavit transformační matice ModelView. Výběr barvy pera je řešen přes barvovou paletu; změnou hodnot v této paletě je možné výkres jednoduše přebarvit (přesné mapování čísla pera na barvu není stanoveno).

//-----------------------------------------------------------------------------
// Prekresleni vektorove kresby
//-----------------------------------------------------------------------------
void redrawDrawing(double scale,                    // meritko obrazce
                   double xpos,                     // posun obrazce
                   double ypos)
{
    Item *item=p_first;
    double x1=0, y1=0, x2=0, y2=0;                  // souradnice pro vypocet usecek
    float  r=1.0, g=1.0, b=1.0;                     // barva kresliciho pera
    float  scale2=mouse.ztran0/100.0+1.0;           // zmena meritka zadana mysi
    Command pen=PEN_DOWN;

    // posun a zmena meritka kresby
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(xpos, ypos, 0);                    // posun zadany klavesnici
    glTranslatef(mouse.xtran0, -mouse.ytran0, 0);   // posun zadany mysi
    // posunuti pocatku (pro zmenu meritka vuci stredu okna
    // je nutna mala programova uprava)
    glTranslatef(window.width/2, window.height/2, 0);
    glScalef(scale, scale, scale);                  // zmena meritka zadana klavesnici
    glScalef(scale2, scale2, scale2);               // zmena meritka zadana mysi
    glScalef(0.1, 0.1, 0.1);
    glTranslatef(-window.width/2, -window.height/2, 0);

    // projit celym seznamem a aplikovat v nem ulozene prikazy
    while (item!=NULL) {
        Command cmd=item->cmd;                      // nacist prikaz
        double x=item->x;                           // nacist souradnice
        double y=item->y;
        int    pencolor=item->pen;                  // nacist barvu pera
        item=item->next;                            // prechod na dalsi polozku
        switch (cmd) {
            case PEN_UP:                            // zvednuti kresliciho pera
                pen=PEN_UP;
                break;
            case PEN_DOWN:                          // polozeni kresliciho pera
                pen=PEN_DOWN;
                break;
            case MOVE_TO:                           // zmena pozice kresliciho pera
                if (pen==PEN_UP) {                  // PEN_UP - presun bez kresleni
                    x1=x;
                    y1=y;
                }
                else {                              // PEN_DOWN - kreslime
                    x2=x;
                    y2=y;
                    glColor3f(r, g, b);             // nastavit barvu
                    glBegin(GL_LINES);              // a vykreslit usecku
                        glVertex2d(x1, y1);
                        glVertex2d(x2, y2);
                    glEnd();
                    x1=x;                           // zapamatovat si pozici
                    y1=y;                           // pro dalsi MOVE_TO
                }
                break;
            case SELECT_PEN:                        // zmena barvy pera
                {
                    static float palette[][3]={     // static=alokace 1x za behu
                        {0.0, 0.0, 1.0},
                        {0.0, 1.0, 0.0},
                        {0.0, 1.0, 1.0},
                        {1.0, 0.0, 0.0},
                        {1.0, 0.0, 1.0},
                        {1.0, 1.0, 0.0},
                        {1.0, 1.0, 1.0},
                        {0.5, 0.5, 0.5},
                    };
                    if (pencolor>=0 && pencolor<=7) { // HP7475 ma osm per
                        r=palette[pencolor][0];
                        g=palette[pencolor][1];
                        b=palette[pencolor][2];
                    }
                    else {                          // kazdy jiny index=bila barva
                        r=1.0;
                        g=1.0;
                        b=1.0;
                    }
                }
                break;
            default:                                // ostatni prikazy ignorujeme
                break;
        }
    }
}

//----------------------------------------------------------------------------- 

6. Popis demonstračního příkladu

Céčkovské funkce redrawDrawing() a readItems() jsou použity i v dnešním demonstračním příkladu, jehož zdrojový soubor je možné získat pod tímto odkazem, k dispozici je i HTML varianta zdrojového textu se zvýrazněnou syntaxí. Při spouštění demonstračního příkladu je nutné jako první argument zadat jméno souboru uloženého ve formátu HPGL/PLT. Program se posléze pokusí z tohoto souboru načíst všechny příkazy PU, PD, PA a SP spolu s jejich parametry a uloží je do lineárního seznamu. Potom je obsah tohoto seznamu interpretován a převeden na příkazy OpenGL.

Zobrazeným výkresem je možné posouvat pomocí kurzorových kláves nebo pohybem myši se stlačeným levým tlačítkem. Také je možné výkres zvětšit či zmenšit klávesami [PageUp] a [PageDown], popřípadě i pohybem myši se stlačeným pravým tlačítkem. Při posunu a změně měřítka je použit double-buffering, takže nedochází k žádnému viditelnému poblikávání. Klávesou [Q] a [Esc] se běh programu ukončí.

7. Možné další rozšíření demonstračního příkladu

Výše uvedený demonstrační příklad je samozřejmě možné dále rozšiřovat, například se pokusit načítat i složitější příkazy než uvedenou čtveřici PU, PD, PA a SP. Pro některé modernější plottery se generují příkazy pro kresbu kružnic (CI, WG, EW), kruhových oblouků (AA, AR), textů (LB, CS, SS, CN, SI, SR…), vyplňovaných polygonů (RA, RR) apod. Kromě textů, pro jejichž korektní vykreslení je zapotřebí mít k dispozici stejné vektorové fonty (soubory typu SHX převedené do vektorů apod.), je tvar ostatních grafických entit známý i bez dalších informací a je možné provádět jejich vykreslování.

root_podpora

8. Odkazy na další informační zdroje

  1. Heslo HPGL na Wikipedii:
    http://en.wiki­pedia.org/wiki/HPGL
  2. Hewlett Packard Graphics Language Commands:
    http://www.sxlis­t.com/techref­/language/hpgl/com­mands.htm
  3. HP-GL Graphics Language:
    http://cstep.lu­berth.com/HPGL­.pdf
  4. EscapeE:
    http://www.pclvi­ewer.com/
    (komerční software pro prohlížení a konverzi vektorových formátů, existuje trial verze pro Win32)
  5. HPGL Viewer (AutoVue):
    http://www.cim­metry.com/hpgl_vi­ewer.html
    poměrně známý prohlížeč vektorových formátů, dostupná je i evaluation ver­ze
  6. What is HPGL?
    http://www.swif­tview.com/pclcor­ner/pclcorner1­.htm#HPGL
  7. A Comparison of File Formats:
    http://www.swif­tview.com/pclcor­ner/comparefor­mat.htm
    porovnání PDF vs. HPGL vs. další formáty z hlediska několika požadavků (HPGL kupodivu vychází ze srovnání poměrně dobře)

9. Obsah dalšího pokračování tohoto seriálu

V následujícím pokračování tohoto seriálu si popíšeme další poměrně jednoduchý a přitom velmi rozšířený a často používaný vektorový formát. Bude se jednat o formát DXF (Drawing Interchange File), který navrhla firma AutoDesk pro svůj známý CAD systém AutoCAD. Tento formát se posléze tak rozšířil (zejména na počítačích PC), že se stal prakticky standardem při přenášení výkresů mezi jednotlivými CAD systémy, ať už dvourozměrnými či trojrozměrnými.

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.