Křivky v Metapostu

28. 5. 2007
Doba čtení: 8 minut

Sdílet

V této části se budeme zabývat především cestami, které představují křivky prokládající body. Ukážeme si, jak je konstruovat a jak ovlivnit jejich průběh. Existuje velká škála prostředků, kterými můžeme průběhy křivek ovlivnit. Metapost už se postará o to, aby výsledek vypadal hezky.

Křivky

Pokud při konstrukci cesty body propojíme nikoli dvěma pomlčkami, ale dvěma tečkami, metapost uvedené body proloží křivkou. Jedná se o Beziérovy křivky. Jejich konstrukcí ve smyslu matematického výpočtu se nebudu zabývat, patří do oblasti vysokoškolské matematiky (odborná matematika, snad informatika, některé technické obory), ležící zcela mimo mé možnosti. Z praktického hlediska je důležité, že metapost se „snaží“ vytvořit křivky „pěkně vypadající“. V některých případech nemusíme být s výsledkem jeho práce zcela spokojeni, potom nám nabízí škálu prostředků, jak tvar křivek upravit (mimo zvýšení hustoty záchytných bodů, kterými křivku prokládáme).

Příkaz dir

Příkazem dir nastavujeme směr, kterým křivka do daného bodu vstupuje, nebo z něj naopak vystupuje. Příkaz se píše do svorkových závorek mezi tečky a název bodu spolu s číslem (v rozmezí 0 – 360) reprezentujícím směr. Směr představuje směr pohybu pomyslného bodu po cestě od prvního bodu k bodu poslednímu. Směrovou růžici ukazuje následující obrázek:

Směry

Zdrojový kód obrázku nebudu nyní uvádět, protože obsahuje řetězce, makra a cykly, tedy prvky metapostu, s nimiž jsme se dosud nesetkali.

Nejprve něco opravdu velice jednoduchého:

Máme tři body, ležící na jedné přímce, pro jednoduchost rovnoběžné s osou x a prostřední bod půlí úsečku tvořenou prvním a třetím. Proložíme jimi tři cesty pomocí „..“. První nebude obsahovat žádné určení směru (tenká čára). Druhá bude vstupovat do středového bodu ve směru ke 270 stupňům (rovněž tenká čára), třetí bude ve stejném směru z tohoto bodu vycházet. Co uvidíme?

Dir

Jsou vykresleny následující cesty: (bod1 je nejvíce vlevo, bod 2 nejvíce vpravo)

  • cesta0:=bod1.­.bod2..bod3; (tenká čára)
  • cesta1:=bod1.­.{dir270}bod2­..bod3; (tenká čára)
  • cesta2:=bod1.­.bod2{dir270}­..bod3; (tečkovaná čára)

První cesta je úsečka, tedy část přímky. Metapost nemá důvod, leží-li body na přímce a my mu dále nic nevnucujeme, aby v takovém případě konstruoval nějakou křivku. Druhá a třetí křivka mají odlišný směr: Příkaz {dir270} přiměl obě procházet prostředním bodem ve svislém směru. Jejich splynutí (tenká čára s „korálky“ tlustších teček) navíc značí, že je v takovémto případě jedno, jestli je směr udán na vstupu nebo výstupu z bodu.

Ve druhém příkladě:

Dir2

jsme stejnými body proložili další cesty:

  • cesta3:=bod1.­.{dir270}bod2­..bod3; (tenká čára, totožná s cestou1 z předchozího příkladu)
  • cesta4:=bod1{di­r45}..{dir270}bod­2..bod3; (čárkovaná čára)
  • cesta5:=bod1.­.{dir270}bod2{dir90}­..bod3; (tečkovaná čára)

Cesta3 slouží jen pro kontinuitu s předchozím příkladem. Cesta4 ukazuje, jak se metapost vyrovná s nasměrováním v předchozím bodě. Ukazuje (splynutí druhé poloviny této a předchozí křivky), že pokud je v daném bodě „natvrdo“ zadán směr, pak předchozí průběh křivky situaci za bodem neovlivní. Cesta5 ukazuje, že můžeme zadat různé směry na vstupu do bodu a výstupu z bodu. Tím si vynutíme zlomení křivky v daném bodě.

Ve třetím příkladu je ukázáno uzavření cesty 4 příkazem cycle:

cesta6:=bod1.­.{dir270}bod2­..bod3..cycle;

Bylo pouze změněno měřítko obrázku, aby zůstal v rozumné velikosti:

Dir3

Můžeme pozorovat přizpůsobení cesty6 (vzniklé pouze uzavřením cesty3) prakticky po celé její délce s výjimkou těsného sousedství bodu bod2, kde je její průběh zadán příkazem dir270. Povšiměte si také relativně dlouhého průběhu navazující části, vybíhající daleko za hranice předchozích obrázků.

Program, generující uvedené tři obrázky vypadá následovně:

Dir z

Příkaz tension

Dvě tečky prokládají křivku mezi dvěma body určitým standardním způsobem. Ten je charakterizován mj. parametrem, označovaným jako napětí, tension. Skutečně se chová tak, jako by křivka, ohýbající se mezi dvěma body, byla napjatá a zvýšením hodnoty tohoto parametru se prohnutí snižovalo (asi jako když zvýšíme tah na šňůru se zavěšeným prádlem) a snížením parametru se prohnutí zvýšilo.

Tension se vkládá mezi dva body se syntaxí ..tension n1 and n2.., kdy n1 a n2 jsou proměnné typu numeric nebo přímo odpovídající čísla. Povolená hodnota je od 0.75 po infinity. Implicitní hodnota je 1. Jsou-li mezi body dvě tečky, je to totéž, jako by tam bylo ..tension 1 and 1...

Následující příklad ukazuje cesty, které spojují pod různým napětím konce dvou rovnoběžných úseček. Konce úseček jsou vyznačeny většími kroužky.

  • Nepřerušovaná čára (slabší čáry) znamená cestu, která je vedena celá s implicitním napětím: cesta0:=bod0.­.bod1..bod2..bod3;,
  • cesta vyčárkovaná střídavě kratší a delší čárkou má mezi body 1 a 2 nejslabší napětí cesta1:=bod0.­.bod1..tension .75 and .75..bod2..bod3;
  • a cesta čárkovaná krátkými čárami má v tomtéž úseku definované napětí nekonečné cesta2:=bod0.­.bod1..tension infinity and infinity..bod2­..bod3;.
  • Silnější čáry se stejným vzorem vyznačují cesty lišící se pouze tím, že v bodech 1 a 2 je příkazem dir nadiktován vstup do bodu ve směru vzhůru, resp. dolů.

Můžeme pozorovat, že i cesta s „natvrdo“ daným směrem průchodu skrze bod se napětím o hodnotě infinity zalomí.

Napeti 1

Na dalších příkladech si ukážeme vliv různých hodnot napětí na začátku a konci úseku u cesty. Následující obrázek ukazuje

  • cesta0 z předchozího obrázku
  • a dvě další cesty, čarkované různými délkami čárek cesta7:=bod0.­.bod1..tension 10 and .75..bod2..bod3;kom­binující na počáteční straně (vlevo) tension 10 a vpravo tension .75; čárkovaně tlustěji je cesta8:=bod0.­.bod1..tension .75 and infinity..bod2­..bod3; kde je pořadí vyšší a nižší tenze opačné a jsou zde uplatněny obě extrémní hodnoty.
Napeti 2

Na dalším obrázku je totéž s tím, že jde o cesty se zadaným směrem v horních bodech.

  • Tence je vykreslena cesta3 z prvního obrázku a následují tence nestejnými čárkami
  • cesta9:=bod0.­.{dir90}bod1.­.tension 10 and .75..bod2{dir270­}..bod3;
  • a tlustěji čarami stejné délky cesta10:=bod0­..{dir90}bod1­..tension .75 and infinity..bod2{dir270­}..bod3;:
Napeti 3

A opět program, generující uvedené obrázky:

Napeti z

Příkaz curl

Dalším příkazem je curl, který se vkládá k poslednímu nebo prvnímu bodu cesty (případně oběma). Nemá tedy význam u uzavřených cest a neměl by se projevit při vložení kamkoli jinam (ale metapost alespoň podle mých zkušeností na to nereaguje chybovým hlášením).

Příkaz způsobí zakřivení na konci cesty, které je derivováno od kružnice a jeho odchylku od ideální části kružnice ovlivňuje vedle dir a tension také velikost parametru, který může nabývat hodnoty 0 – infinity.

Na obrázku k tomuto příkazu jsou čtyři cesty.

  • cesta0:=bod0.. {dir0}bod1..bod2; nemá zadán parametr curl a je vykreslena tečkovaně.
  • cesta1:=bod0{curl 0}..{dir0}bod1­..{curl 0}bod2; má zadán na obou koncích curl s nulovou hodnotou (tenká čára). Můžeme vidět, že k oběma koncovým bodům směřuje příměji.
  • cesta2:=bod0{curl 100}..{dir0}bod1­..{curl 1000}bod2;, čárkovaná nestejnými čárkami má vlevo parametr 100 a vpravo 1000,
  • následující cesta3:=bod0{curl 10}..{dir0}bod1­..{curl infinity}bod2; má vlevo parametr 10, vpravo infinity.

Vlevo můžeme pozorovat, že mezi curl 10 acurl 100 je pozorovatelný rozdíl, zatímco pravé části těchto cest s curl 1000 a curl infinity prakticky splývají.

Kudrlinka

Program, generující uvedený obrázek vypadá takto:

Kudrlinka z

Kontrolní body – controls

Posledním parametrem, který ovlivňuje průběh cesty mezi dvěma body, je parametr controls. Vyžaduje zadat dva kontrolní body (souřadnicemi nebo jako proměnné typu pair). Tyto body vstupují do parametrů výpočtu příslušných Beziérových křivek a ovlivňují jejich konečnou podobu. Vkládá se mezi dva body v definici cesty s následující syntaxí ..controls bod1 and bod2.., kdy bod1 a bod2 jsou právě ony zmíněné kontrolní (asi přesněji by bylo ovlivňovací, ovlivňující) body.

Na obrázku vidíme křivky, ovlivňované dvěma body. Pozice jednoho z nich je pro všechny tři stejná (kroužek s tečkou uprostřed). Pozicí druhého se křivky liší.

  • Křivka čerchovaná (kombinace delších a kratších čárek) jej má označenu menším černým kolečkem,
  • křivka čárkovaná kratšími čárkami ji má označenu větším černým kolečkem
  • a křivka čárkovaná delšími čárkami ji má označenu kroužkem.
Kontrol

Program, generující příklad, vypadá takto:

Kontrol z

Kombinací uvedených parametrů můžeme „přinutit“ křivku, aby procházela, kudy potřebujeme. Pro začátečníky může být jednodušší zhustit řadu bodů, které křivku definují, v některých případech je to i obecně efektivnější. V řadě případů je ovšem přinejmenším přehlednější ovlivňování průběhu křivky parametry, zejména pokud využijeme maker.

Standardní cesty

Metapost má přednastaveny standardní cesty, a to jednotkový čtverec, kružnici, půlkružnici a čtvrtkružnici.

Jednotkový čtverec

Jednotkový čtverec zadáme příkazem unitsquare. Musíme zadat jeho velikost (= jednotku, od níž je odvozen). Celý příkaz pak zní:

draw unitsquare scaled unit;

unit je přitom jakákoli délková jednotka nebo násobek (obvykle užívané) jednotky u, ať už zadané jako proměnná typu numeric nebo i matematický vztah (složitější může metapost „požadovat“ umístit do závorky).

Zadaná jednotka představuje délku strany čtverce a jeho levý dolní roh leží v bodě origin (=(0,0)).

Jednotková kružnice, její polovina a čtvrtina

Jednotkovou kružnici zadáme příkazem fullcircle, polovinu příkazem halfcircle a čtvrtinu příkazem quartercircle. I zde musíme zadat jednotku, představující v tomto případě průměr kružnice. Střed kružnice (části kružnice) leží v bodě origin.

Příklad:

Kruznice

ukazuje základní čtverec a kružnici škálované stejným parametrem, současně půl a čtvtkružnici škálované na větší velikost, aby s kružnici nesplynuly. Program, generující uvedený příklad následuje:

Kruznice z

Použití standardních cest

Takto, jak byly v základním příkladu uvedeny, nevypadají standardní cesty nějak užitečně. Nicméně pomocí transformací (datový typ transform, společný pro úpravu cest path i obrázků picture, který probereme po těchto datových typech), s nimi můžeme po pracovní ploše libovolně posouvat, měnit poměr x a y (tedy ze čtverce udělat obdélník a z kružnice elipsu) a rotovat je (takže obdélník nemusí mít strany a elipsa osy rovnoběžné s osami x a y), případně ze čtverce nebo obdélníka udělat lichoběžník. Lze proto např. jednoduše udělat sloupcový graf jen posouváním obdélníků, zvětšených podél osy y.

bitcoin_skoleni

V případě kružnic zpravidla moc nevystačíme s půlkružnicí nebo čtvrtkružnicí (zejména pokud potřebujeme vyrobit koláčový graf). V takovém případě (a mnoha dalších) potřebujeme podle nějakých kritérií vyříznout kus cesty a vymalovat jenom tu. Kusy cest můžeme také spojovat a vytvořit z nich novou cestu (což není moc využitelné), kterou můžeme uzavřít (a to je pak vysoce využitelné, protože můžeme posléze tyto uzavřené cesty vyplňovat barvami a vzory – a jsme zase u grafů, ale i spousty další grafiky). Na zakřivených cestách lze také definovat různými způsoby body a v nich nalézt tečny příslušné cesty. Takto řečeno to vypadá nezajímavě, ale díky této funkci můžeme například konstruovat nápis, jehož písmenka sledují určitou křivku a otáčejí se tak, aby jejich osa byla kolmá na tuto vodící křivku. A nemusejí to být jen nějaké extravagantní nápisy, ale např. popisky kruhových znaků ve stylu mincí a medailí.

Co bude v dalším dílu

Předchozí odstavec napověděl, že se budeme zabývat částmi cest, body na cestách, průsečíky, způsoby spojování dílčích cest do uzavřených cest a probereme standardní funkce spojené s tímto datovým typem.

Autor článku