Hlavní navigace

Metapost: datové typy

16. 8. 2007
Doba čtení: 10 minut

Sdílet

V následujícím článku o Metapostu se seznámíme s datovými typy color a transform a se snadnějšími prostředky datového typu string, umožňujícími zobrazovat písmena, číslice a běžné znaky anglické abecedy. To se nám hodí zejména na popisky výkresů z deskriptivní geometrie a podobné informace.

Datový typ color

Barvy metapostu jsou definovány v systému RGB. To znamená, že barva představuje třísložkový vektor obsahující definici barev červené, zelené a modré. Jedná se tedy o aditivní míšení barev (tedy vlastně míšení barevných světel). Pro tuto trojici hodnot je definován datový typ color. Ten si můžeme pojmenovat a poté mu přidělit buď systémovou nebo vlastní barvu, namíchanou z různé intenzity základních barev. Dílčí barvy mohou nabývat hodnotu od 0 do 1; barva (0,0,0) je barvou černou, barva (1,1,1) bílou.

color mojebarva; % Do proměnné mojecolor bude nadefinována barva
mojebarva:=(.15,.25,.85); % mojecolor byla přidělena konkrétní barva
draw cesta withcolor mojebarva;
% path cesta byla nakreslena implicitním (nebo dříve zadaným) perem
% nadefinovanou barvou mojebarva (tato konkrétní je šedomodrá)

V systému jsou předdefinovány základní barvy: blue (modrá) (0,0,1), green (zelená) (0,1,0) a red (červená). Dále jsou nadefinovány barvy black (černá), která je implicitně nastavena jako barva čar a výplní, a barva white (bílá), která je implicitně nadefinována jako barva pozadí.

Uvedené (i námi nadefinované) barvy lze násobit, čímž dostaneme při násobení číslem menším než 1 tmavší tóny. Nejčastěji je tento postup užíván k definování šedých tónů. Např. 0.95white je velmi slabě šedá, na řadě rozlišovacích zařízení neodlišitelná od bílé, 0.05white je zase téměř neodlišitelná od černé. 0.5white je šedá, dobře rozpoznatelná od černé i bílé barvy. Zkratka Nwhite tedy znamená barvu (N,N,N). Podobně ale můžeme ovlivnit i obecnou barvu (r,g,b), kdy výsledkem je barva (Nr,Ng,N*b). Zde ovšem musíme dávat pozor, aby se některá ze složek vektoru nezvětšila nad hodnotu 1, protože poté by došlo při pokusu o užití takové barvy k chybovému hlášení. Na druhé straně vytvoření takového vektoru není bráno jako chyba.

Následující obrázek ukazuje několik čtverců, vykreslených jak předdefinovanými, tak nově nadefinovanými barvami:

Paleta

Zdrojový text, generující obrázek, je zde:

PaletaZ

Ze zdrojového textu můžeme jasně vidět, že lze použít barvy předdefinované systémem, jejich modifikace, barvy předem pojmenované i barvy definované „na místě“, tedy až v okamžiku vykreslení.

Separace složek barvy

Podobně jako složky dvoučlenného vektoru pair můžeme separovat i složky vektoru color příkazy redpart, greenpart a bluepart.

Ukázka programu separujícího dílčí barvy z proměnné typu color

color a; numeric b,c,d;
a=(.25,.5,.18); b=redpart a; c=greenpart a; d=bluepart a;
show a; show b; show c; show d;
end;

Ukázka z chodu předcházejícího programu

This is MetaPost, Version 0.641 (Web2C 7.4.5) (mem=mpost 2004.2.16)  20 OCT 2005 09:09
**Barvy.mp

(Barvy.mp
>> (0.25,0.5,0.18)
>> 0.25
>> 0.5
>>> 0.18 )

Palety

Z hlediska praxe, zejména pokud předpokládáme pro naše barevné obrázky uplatnění na různých výstupních zařízeních, je vhodné mít barvy nadefinovány ve zvláštním souboru. Výhodné je to proto, že „dobře vypadající“ barvy budou pro každé takové zařízení trochu jiné. Načtením barevné palety jednou např. ze souboru monitor.mp a podruhé ze souboru inkoustovatis­karna.mp nám umožňuje zachovat prakticky celý soubor vykreslující barevné obrazce stejný, vyjma řádku, kde je definován soubor s barevnou paletou. Pokud bychom definovali barvy přímo v něm, museli bychom vždy po změně výstupního zařízení celý soubor prohledávat a přepisovat definice barev.

U datového typu picture se naučíme ještě efektivnější způsob záměny výplní různých ploch na obrázku, kde můžeme barvy kombinovat i s různými typy šrafování.

Transformace

Transformace slouží k posunům, změnám velikosti, zkosení, případně rotaci a překlápění.

Datový typ transform je umožňuje nejprve nadefinovat a pojmenovat a poté je použít. Velmi často se pro transformace používá pole proměnných t[].

transform t[]; definuje pole transformací

Do jednotlivých transformací můžeme nadefinovat změny objektu. Syntaxe je: objekt2:=objekt1 transformed t;, kdy oba objekty musejí být stejného datového druhu, buď path nebo picture.

Pochopitelně, takto vzniklý objekt můžeme využít pro další transformace:

objekt2:=objekt1 transformed t1;
objekt3:=objekt2 transformed t2;
...
objekt[x+1]:=objekt[x] transformed t[x];

Posuny

Posunutí o vektor (a,b) se děje příkazem:

t= identity shifted (a,b); Místo vektoru můžeme zadat též proměnnou typu pair (tedy v podstatě souřadnice bodu a vektor je poté spojnice bodu (0,0) se zadaným bodem).

Trans1

Rotace kolem bodu (0,0)

Rotace kolem centra souřadnic je zajištěna příkazem:

t= identity rotated uhel; uhel je úhel rotace uváděný ve stupních, rotace je proti směru hodinových ručiček.

Trans2

Zkosení koeficientem}

Zkosení, kdy souřadnice jednotlivých bodů jsou přepočteny podle rovnice:

(x,y) ⇒ (x+ay,y), přičemž a je koeficient zkosení, je zajištěno příkazem:

t= identity slanted a;

Trans3

Stejnolehlost s koeficientem

Stejnolehlost (tedy vynásobení x i y souřadnic všech bodů koeficientem a) je zajištěna příkazem:

t= identity scaled a;

Trans4

Změna měřítka ve směru jedné z os

Tato změna, tj. vynásobení souřadnic x koeficientem a resp. souřadnic y tímto koeficientem, je zajištěna příkazy:

t1= identity xscaled a;
t2= identity yscaled a;
Trans5
Trans6

Pokud jeden a tentýž objekt transformujeme xscaled a yscaled se stejnou hodnotou koeficientu, bude výsledek stejný, jako kdybychom použili jen jedenkrát scaled.

Rotace a stejnolehlost

Souřadnice x a y jsou přepočteny koeficinty a a b podle rovnice:

(x,y) ⇒ (ax – by,bx + ay)

Zajišťuje to příkaz:

t= identity zclaled(a,b);

Trans7

Objekt osově souměrný

Osově souměrný objekt podle přímky zadané dvěma body vznikne příkazem:

t= identity reflectedabou­t(a,b);

a a b jsou buď proměnné typu pair, nebo příkaz zapíšeme ve formě:

t= identity reflectedabout;, kdy zadáváme přímo souřadnice příslušných bodů, buď jako konkrétní čísla nebo proměnné typu numeric.

Trans8

Otočení o zadaný úhel kolem zadaného bodu}

Otočení o úhel zadaný ve stupních kolem zadaného středu otáčení zajistí příkaz:

t= rotatedaround((x1,y1),u­hel);, případně ve varientě:

t= rotatedaround(z1,u­hel);, kdy z1 je proměnná typu pair.

Trans9

Kombinace transformací

Jak bylo výše uvedeno, transformace lze různě kombinovat, takže lze např. ze základní cesty různými způsoby transformované vytvořit objekt a ten celý dále transformovat.

Při změnách měřítka je vhodné si uvědomit, že pokud změníme měřítko cesty a tu následně vykreslíme čarou určité tloušťky, bude tloušťka čáry odpovídat zadané. Pokud cestu vykreslíme čarou určité tloušťky do obrázku (datový typ picture – příště) a ten budeme transformovat, bude se transformace týkat i tloušťky čáry.

V některých případech je sled transformací zaměnitelný (např. výše zmíněné kombinace xscaled a yscaled). V řadě případů vznikne záměnou pořadí transformací jiný výsledný objekt.

Syntaxe

Pokud definujeme transformaci (datový typ transform), potřebujeme slovo „identity“, jak bylo uvedeno výše. Pokud je transformace součástí konstrukce, toto slovo nepoužíváme. Už jsme užívali např. jednotkový čtverec nebo kruh zvětšený na potřebnou velikost (ct:= unitsquare scaled a shifted (b,c);). Zkuste si promyslet, zda v tomto případě přehození transformací ovlivní výsledný obrázek.

Řetězce

Problematika řetězců se rozpadá v metapostu na dva okruhy problémů:

  1. samotné řetězce, tedy sledy znaků (mohou být i nealfanumerické, takže sice horko-težko, ale v principu můžeme takto pracovat i s binárními daty)
  2. jejich grafická presentace (vykreslení – zde pokus „normálně“ vykreslit binární data – včetně písmen s diakritikou – končí chybovým hlášením; takže můžeme vykreslovat velká a malá písmena, číslice a několik málo dalších znaků), kde omezení vykreslování samotných řetězců mohou být řešena jejich převodem na datový typ picture. V něm můžeme mít „obrázky textu“, obsahující prakticky vše, co umí TeX.

Datový typ string

String je reprezentován sledem znaků, umístěným do uvozovek. Případně obsahem proměnné, jíž byl tento sled znaků přidělen jako obsah.

Možnosti práce s tímto datovým typem jsou velmi omezené.
Je možno:

  • Vytvořit z části řetězce samostatný řetězec.
    Metapost toto provádí zvláštním způsobem. Jsou očíslovány mezery mezi znaky v řetězci, přičemž číslo 0 je před první pozicí, číslo odpovídající délce řetězce (=počtu znaků v něm) je za poslední pozicí.
    Podřetězec je definován příkazem:
    podretezec = substring(a,b) of retezec;
    substring(0,3) z řetězce „abeceda“ je „abe“, substring(2,6) je „eced“.
    Pokud zadáme čísla za koncem řetězce, vrátí funkce prázdný řetězec.
  • spojení dvou řetězců operátorem &
  • Vestavěná funkce ASCII vrátí ASCII kód prvního znaku řetězce.
  • Vestavěná funkce oct vrátí hodnotu řetězce, jako by to bylo číslo v osmičkové soustavě. Pokud řetězec obsahuje něco jiného než čísla 0–7, ohlásí chybu.
  • Vestavěná funkce hex vrátí hodnotu řetězce jako čísla v šestnáctkové soustavě. Opět ohlásí chybu, pokud řetězec obsahuje jiné znaky než číslice 0 – 9, písmena A – F nebo a – f.

Ukázka práce s řetězci

Program

prologues:=1;
string a[];                       % deklarujeme proměnnou typu string
a0="priserne zlutoucky kun upel dabelske ody"; % přidělíme jí hodnotu
a1=substring(0,3) of a0;          % jako substringy z ní definujeme
a2=substring(10,15) of a0;        % další dvě proměnné
a3=a2&a1;                         % a spojíme do čtvrté
show a0; show a1; show a2; show a3; % výsledek vypíšeme
end;

Výpis z činnosti programu

This is MetaPost, Version 0.641 (Web2C 7.4.5) (mem=mpost 2004.2.16)   27 SEP 2005 23:47
**Retezce.mp
(Retezce.mp
>> "priserne zlutoucky kun upel dabelske ody"
>> "pri"
>> "lutou"
>> "lutoupri" )

Metapost bohužel nemá prostředky k převedení řetězce na číslo v desítkové soustavě a nemá ani prostředky ke zjištění délky řetězce. Je možné pomocí krájení řetězce na jednopísmenkové substringy pomocí cyklu a následným vyhodnocením znaků jako ACSII nebo hex čísel je převést na desítkovou soustavu, musí však být ohlídáno vrácení prázdného řetězce "", až se program dostane za konec analyzovaného řetězce.

Zobrazení řetězců bez diakritiky

Příkaz label(umístění text, souradnice); umístí text tak, že střed obdélníka opsaného kolem písmen je na bodu zadaném souřadnicemi.

Přehled umístění textu v uvedeném obdélníku ukazuje tabulka.

Tabulka

Nevýhodou uvedeného příkazu je skutečnost, že zpracovává pouze jeden font (tvar, řez i velikost) a není možné zadat písmena s diakritikou. Pokud chceme font změnit, je nutné přenastavit implicitní font, 

příkazem defaultfont:= název_fontu;)

což je systémově závislá operace a je závislá i na konkrétní instalaci TeXu a metapostu v počítači.

Z těchto důvodů se v našich podmínkách hodí tento způsob zobrazování řetězců především pro jednopísmenové popisy os, bodů, vynášení souřadnic apod.; spíše tedy popisky technického a matematického charakteru.

Proměnnou typu string nadefinujeme a hodnotu jí přidělíme obdobně jako proměnné jiných datových typů:

string mujtext;
mujtext = "Prilis zlutoucky kun upel dabelske ody";

a vykreslíme řetězec do středu souřadnic příkazem:

label(mujtext,(0,0));

Příkaz thelabel se stejnou syntaxí umístí text do proměnné typu picture. Uvedený datový typ má ovšem mnoho dalších možností a zaměříme se na něj v příštím díle.

root_podpora

Zdrojový text obrázků demonstrujících transformace

prologues:=1;
u=1mm;
transform t[];      % Definice použitých proměnných
path cesta[],osa;
string popis[];

pen silne;
color barva[];
silne:=pencircle scaled u;% Nadefinujeme i silnější pero k odlišení
                          % původního a transformovaného objektu
osa:=(25u,0)--(25u,25u);  % potřebujeme pro transformaci č. 8
barva0:=(1,0,1);% magenta
barva1:=(1,1,0);% žlutá
barva2:=(0,1,0);% cyan
% Definujeme základní obrazec:
cesta0:=(0,0)--(25u,0)--(25u,15u)--(15u,25u)--(0,25u)--cycle;
% Definujeme transformace a jejich popisy (oboje jako členy polí):
t1:=identity shifted (20u,10u);popis1:="shifted";
t2:=identity rotated 45;       popis2:="rotated";
t3:=identity slanted 2;        popis3:="slanted";
t4:=identity scaled 1.5;       popis4:="scaled";
t5:=identity xscaled 2.5;      popis5:="xscaled";

t6:=identity yscaled .5;       popis6:="yscaled";
t7:=identity zscaled(1.5,2);   popis7:="zscaled";
t8:=identity reflectedabout((25u,0),(25u,25u)); popis8:="reflectedabout";
t9:=identity rotatedaround((10u,15u),45);       popis9:="rotatedaround";
% Prvních sedm transformací vytvoříme cyklem s narůstající
% řídící proměnnou s přednastaveným krokem 1:
for i=1 upto 7:
    beginfig(i);
    cesta[i]:=cesta0 transformed t[i];
    draw cesta0;
    pickup silne;
    draw cesta[i] withcolor barva0;

    label(popis[i],(-10u,-3u)) withcolor barva2;
    pickup defaultpen;
    endfig;
endfor;
% Poslední dva musíme nakreslit "ručně", protože mimo základní
% a transformovaný objekt je tam ještě další objekt
% (šlo by to udělat podmínkou if - elseif - else - if,
% ale na úkor srozumitelnosti kódu - viz další díly
beginfig(8);
cesta8:=cesta0 transformed t8;
draw cesta0; pickup silne;
label(popis[8],(-10u,-3u)) withcolor barva2;
draw cesta8 withcolor barva0;
draw osa dashed evenly withcolor barva1;

endfig;
beginfig(9);
cesta9:=cesta0 transformed t9;
draw cesta0;
pickup silne;
label(popis[9],(-10u,-3u)) withcolor barva2;
drawdot(10u,15u) withcolor red;
draw cesta9 withcolor barva0;
endfig;
end;

String jako obrázek

Pokud místo label použijeme thelabel, dostaneme z textu jeho zobrazení datovým typem picture (pokud nedefinujeme v okamžiku zobrazení, musíme je vložit do předdefinované proměnné typu picture). Podobně zacházíme se stringy i v případě, kdy potřebujeme písmenka mimo rozsah anglické abecedy (tedy nejen s českou diakritikou). V takovém případě místo stringu nadefinujeme TeXový objekt, který je rovněž typu picture.

Uvedená kouzla, která jsou navíc poněkud závislá na tom, zda obrázek generovaný metapostem zobrazujeme rovnou, nebo jako součást (La)TeXového dokumentu, si necháme na příště spolu s datovým typem picture.

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