Számítógépi grafika
Markerek

Feladat

Egy grafikus markert kezelő program elkészítése, amely képes

1.        a markert a képernyőn mozgatni (a kurzormozgató billentyűk segítségével),

2.        a méretét növelni, illetve csökkenteni (a méret a mozgás lépésköze),

3.        alakját megváltoztatni (amely külső jegye lehet az esetleges speciális funkciójának).

Tudnivalók

1.        Mindenekelőtt próbálja ki: mire lehet gondolni (Marker.exe)! („Kezeléséhez”: mozgatás a kurzormozgató billentyűkkel, méretnövelés „+” billentyű, csökkentés „-” billentyű, alak­változtatás az „0”..„4” billentyűkkel, kilépni az „Esc” billentyűvel.)

2.        A marker Pascal típusa:

TMarker=Record
          typ:TMarkerType;
          size,color:Integer;{alaki jellemzők}
          x,y:Integer;{hollét}
        End;
TMarkerType=(MT_Pont,MT_Plusz,MT_Rombusz,MT_X,MT_Nyil);
            {0
Þpont, 1Þ+; 2Þà; 3Þ´; 4Þã (ferde nyíl)}

3.        A markert kezelő műveletek:

Procedure SetMarker(
    Var mk:TMarker;
    Const typ:TMarkerType; siz,col,x,y: Integer);
    {beállítja a marker tulajdonságait}
Procedure SetMarkerType(
    Var mk:TMarker; Const typ:TMarkerType);
    {átállítja a marker típusát}
Procedure SetMarkerSize(
    Var mk:TMarker; Const siz:Integer);
    {átállítja a marker méretét}
Procedure SetMarkerColor(
    Var mk:TMarker; Const col:Integer);
    {átállítja a marker színét}

Procedure Marker(
    Var mk:TMarker; Const x,y:Integer);
    {kirajzolja a markert az (x,y) bázisponttól}

       … és ezek közül a legtöbbnek  GetOperáció  nevű függvénypárja, mint pl. az alábbi.

Function GetMarkerType(Const mk:TMarker):TMarkerType;
    {visszadja a marker típusát}

4.        A XORPut vonalrajzolási mód beállításával elérhető, hogy könnyen visszaállíthassuk a mar­ker „alatti” képeket annak elmozdulásakor. Elegendő ugyanott „újrarajzolni” a markert, és máris előtűnik az a kép, amelyre rákerült a kirajzoláskor. [1] A vonalrajzolási mód beállítása a SetWriteMode(XORPut) utasítással történik. A rajzolásmód figyelembevételével működik a Line, a LineTo, a Rectangle, de nem így a PutPixel és a Circle… L. a Turbo Gra­fika súgóját.

5.        A Free Pascal esetén két ablakban fut az alkalmazás: egyik a „normál” konzolablak, a másik a grafikus ablak. Mivel a beavatkozás műveleteit (ReadKey, KeyPressed) szokásosan a Crt unit tartalmazza, ezért a beavatkozáshoz a konzolablakot kell aktívvá tenni, ekkor vi­szont részben takarva lesz a „főszereplő” ablak. Ezen segíthetünk a WinCrt unittal. Azonban fontos a Crt, WinCrt sorrendje a Uses sorban: előbb legyen a Crt.

 

Először megírandó a markert kezelő unit (MarkerUn.pas néven)! E unitra építve a fent körvo­nalazott egyszerű feladatot az alábbi program megoldja. (Letöltheti a Marker.pas-t.)

Az első PróbaProgram


Program Markerek;

(*

  Markerek témához próbaprogram.

  Egy marker kezelése.

  Egy marker kezelése: mozgatás, nagyítás/kicsinyítés, típusváltás.

  A marker típusa (alakja) és billentyűje:

  * "pont"    -- 0

  * "+"       -- 1

  * "rombusz" -- 2

  * "X"       -- 3

  * "nyíl"    -- 4

*)

  Uses

{$IFNDEF FPC -- TurboPascal}

    Newdelay, {hogy ne szálljon el a Crt-ben}

{$ENDIF}

    Crt,

{$IFDEF FPC -- FreePascal}

    WinCrt, {hogy a GUI-ban billentyűkkel lehessen vezérelni; Crt után!!!}

{$ENDIF}

    Graph, MarkerUn;

 

  Const

    path='c:\LANGS\bp\bgi\' ;

    ESC=#27;

    Le=#80;  Fel=#72;  Bal=#75;  Jobb=#77;

  Var

    bfx,bfy,jax,jay:Integer; {rajzterület}

    mk   :TMarker;

    ch   :Char;

    x,y  :Integer;

    meret:Integer;

 

  Procedure Karkezd;

  Begin

    Window(1,1,80,25);

    TextBackGround(Green);

    ClrScr;

  End;

 

  Procedure Szovegesre;

  Begin

    CloseGraph;

    RestoreCrtMode;

  End;

 

  Procedure Grafikusra;

    Var

      gd,gm:Integer;

  Begin

    gd:=detect; gm:=0;

    InitGraph(gd,gm,path);

    SetBkColor(Green);

    ClearDevice;

    SetLineStyle(SolidLn,0[2],ThickWidth);

    Rectangle(2,2,GetMaxX-2,GetMaxY-2);

    bfx:=5; bfy:=5; jax:=GetMaxX-5; jay:=GetMaxY-5;

    SetWriteMode(XORPut);

  End;

 

Begin {főprogram}

  Karkezd;

  Grafikusra;

  x:=GetMaxX Div 2; y:=GetMaxY Div 2; meret:=8;

  SetMarker(mk,MT_Plusz,meret,Red,x,y);

  Marker(mk,x,y); {marker kirajzolása}

  Repeat

    ch:=ReadKey;

    Marker(mk,x,y); {a régi marker levétele}

    Case ch of

      '0'..'4': SetMarkerType(mk,TMarkerType(ord(ch)-ord('0')));

      '+': Begin

             meret:=meret+1; {alighanem célszerű lenne korlátozni!!!}

             SetMarkerSize(mk,meret);

           End;

      '-': if meret>1 then Begin

             meret:=meret-1;

             SetMarkerSize(mk,meret);

           End;

      #0: Begin {funkció billentyűk esetén}

            ch:=ReadKey;

            case ch of

              Le:   Begin

                      If (y+meret<=jay) then y:=y+meret;

                    End;

              Fel:  Begin

                      If (y-meret>=bfy) then y:=y-meret;

                    End;

              Bal:  Begin

                      If (x-meret>=bfx) then x:=x-meret;

                    End;

              Jobb: Begin

                      If (x+meret<=jax) then x:=x+meret;

                    End;

            End;

          End;

    End;{Case}

    Marker(mk,x,y); {a marker újbóli kirajzolása -- az új állapotában}

  Until ch=Esc;

  Szovegesre;

End.


Fejlesztések

A marker unitját felhasználva készítse el a következő változatokat!

1.        Egyidejűleg két marker legyen látható és vezérelhető (az egyik „aktív”, másik „inaktív”). A markerek közötti váltásra a TAB-billentyű legyen használható. A két marker „funkcionális” (aktív/inaktív) megkülönböztetése történjen színnel. [3] (Kipróbálhatja: Marker2.exe.)

1. ábra. Kezdőállapot.


 

2.        Folytassuk a következővel: a két markert egy „gumiszalag-szerű” vonal állandóan kösse össze, amelyet ENTER-rel rögzíteni is lehet. Így egyenes szakaszokból ábrát is lehet rajzolni. A „gumiszalag” és a rögzített vonal színe (esetleg mintázata is) legyen eltérő. (Kipróbálhatja: Marker3.exe.)

2. ábra. „Vonalazás” közben.


3.        Bővítsük azzal, hogy további fajta alakzatokat is lehessen rajzolni. Pl. „K”-val kört, „D”-vel „dobozt”, és természetesen „V”-vel egyenes vonalat. Az aktuális alakzatot ENTER-rel lehet „rögzíteni”. A körív-rajzolás csak a Line-ra visszavezetve megy, ui. a CIRCLE-re a XORPut nem hat! Ezért az egyik korábbi gyakorlaton készített körív-rajzoló eljárást itt be kell építeni a programba. (Kipróbálhatja: Marker4.exe.)

3. ábra. Rajzolás közben.


4.        További bővítés lehetne a tartományszínezés. A lényeg, hogy a megrajzolt alakzatok vonal­színnel határolt tartományait kitöltő színnel lehessen színezni. Ehhez fel lehet használni a Turbo Grafika FloodFill(x,y,vonalSzin) eljárását.[4] Természetesen nincs akadálya annak sem, hogy a korábbi gyakorlat tartományfestő eljárásainak valamelyikét itt felhasz­nálhassuk.

Problémák a tartományszínezéskor:

·    a markerek ne látsszanak, mert a színezést megzavarják, pl.:

o   eltűnik a tartományba eső részük (és az újrarajzolásnál csonkulnak),

o   miattuk nem lesz zárt a tartomány (és „kifolyik” a szín a tartományból)

·    egyetlen aktív marker, ezért nincs „gumi alakzat”

·    a végleges ábrát a tényleges vonalszínnel rögzíteni kell,

o   azaz ne XORPut módon, hanem NormalPut módon kerüljön kirajzolásra, de

·    a markerek e közben se látsszanak, mert a marker-újrarajzolás nem kívánt nyomot hagy.

A háttérszínt célszerű a legsemlegesebb színre (feketére) változtatni.

Kipróbálhatja: Marker5.exe.

4. ábra. Rajzolás közben.

 



[1]  Kitalálható, hogy e rajzolási mód hátterében a pixelek színbitjeinek XOR („kizáró-vagy”) művelete húzódik, amely –mint köztudomású– saját maga inverz művelete.

[2]     Ez a paraméter a „vonalmintázat”, amelynek szerepe csak az első paraméter „UserBitLn” esetében van.

[3]  Megoldásnál a próbaprogramot úgy kell módosítani, hogy mindig az éppen „aktív” marker paraméterei legyenek kéznél (azaz az „alapmegoldáshoz” képest sok Get-es műveletre lesz szükség.)

[4]  L. még a következő Turbo Grafika fogalmakat:

Type FillPatternType;

Procedure GetFillPattern(pattern), SetFillPattern(pattern,rajzSzin).