Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad...

44
Aspecte de programare cu PostScript (eseu) Vlad Bazon iunie 2019 Nu avem aici, un „alt tutorial” – că nu plecăm de la Hello, world!, sau „iată un pătrat (ca pentru cazul când n-ai avut de-a face cu nici un limbaj de programare). Prezentăm doar o experienţă proprie (şi pe cât este posibil - originală) de investigare şi înţelegere a lim- bajului PS (PostScript ), considerând de la bun început că mate- matica elementară (şi deprinderea de a pune şi analiza „probleme”) este inevitabilă şi asumând (iarăşi, fără cine ştie ce griji didactice) deprinderea de a folosi diverse programe utilitare şi interpretoa- re (uzuale pe un sistem Ubuntu-Linux), având în vedere că PS este cumva „intim” legat de ecosistemul TeX. Avem mai degrabă un eseu; elementele de limbaj PS nu sunt expuse în mod sistematic şi cu exemplificări simple (ca în tu- toriale), ci sunt investigate pe măsură ce ele trebuie practicate pentru a avansa în realizarea proiectului propus iniţial: a con- stitui o anumită figură geometrică (dar mai complicată decât un pătrat) şi a o eticheta astfel încât să poată fi integrată onorabil (plecând de la un fişier LaTeX) într-un document PDF. [email protected] 1

Transcript of Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad...

Page 1: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Aspecte de programare cu PostScript (eseu)

Vlad Bazonlowast

iunie 2019

Nu avem aici un bdquoalt tutorialrdquo ndash că nu plecăm de la Hello worldsau bdquoiată un pătratrdquo (ca pentru cazul cacircnd n-ai avut de-a face cu niciun limbaj de programare) Prezentăm doar o experienţă proprie(şi pe cacirct este posibil - originală) de investigare şi icircnţelegere a lim-bajului PS (PostScript) consideracircnd de la bun icircnceput că mate-matica elementară (şi deprinderea de a pune şi analiza bdquoproblemerdquo)este inevitabilă şi asumacircnd (iarăşi fără cine ştie ce griji didactice)deprinderea de a folosi diverse programe utilitare şi interpretoa-re (uzuale pe un sistem Ubuntu-Linux) avacircnd icircn vedere că PS estecumva bdquointimrdquo legat de ecosistemul TeX

Avem mai degrabă un eseu elementele de limbaj PS nu suntexpuse icircn mod sistematic şi cu exemplificări simple (ca icircn tu-toriale) ci sunt investigate pe măsură ce ele trebuie practicatepentru a avansa icircn realizarea proiectului propus iniţial a con-stitui o anumită figură geometrică (dar mai complicată decacirct unpătrat) şi a o eticheta astfel icircncacirct să poată fi integrată onorabil(plecacircnd de la un fişier LaTeX) icircntr-un document PDF

lowastvladbazongmailcom

1

Cuprins1 Componentele programului (sau proiectului) 3

2 Discuţie despre operatori variabile şi transformări (pe sea-ma producerii elipsei dintr-un cerc) 4

3 Producerea şi trasarea liniilor (fişierul graficeps) 731 Eroare experiment şi descoperire 1132 De la semicardioidă la cardioidă cu pathforall 1233 De la semicardioidă la cardioidă simetrizacircnd faţă de axă 15

4 Etichetarea directă folosind un font obişnuit 16

5 Icircncapsularea icircn figură a notaţiilor matematice 1851 Citirea valorilor BoundingBox 2052 Poziţionarea etichetelor pe figură 22

6 Arcele de parabolă sunt curbe Beacutezier pătratice 25

7 Arcele de parabolă prin cubice Beacutezier 26

8 Instrucţiunea curveto 2781 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo) 29

9 Aproximarea unei curbe prin cubice Beacutezier 31

10 Aproximarea semicardioidei prin cubice Beacutezier 33

11 Aproximarea semicardioidei folosind MetaPost 36

Anexă 41

A De la cerc la cardioidă 41

B Proprietăţile semicardioidei 42

2

1 Componentele programului (sau proiectului)

Elipsa E este tangentă axei semicardioidei K icircn nodul acesteia O are focareleKt şi K1minust situate pe K iar centrul ei Ct este situat pe arcul de parabolă P

(unde t isin [0 1] generează icircntr-un anumit mod punctele lui K)

Kt

K1minust

Ct

KE

P

O

Vom mai preciza pe parcurs contextul matematic al figurii (expus şiseparat icircn Anexa B) Programul PostScript care a produs figura postată maisus este compus astfel

bull fişierul principal lsquograficepsrsquo prin care se generează şi se traseazăcurbele (elipsa cardioida şi parabola) segmentele şi arcele importantevom viza două moduri de generare bdquoprin puncterdquo (cu instrucţiunilineto) respectiv prin cubice Beacutezier (folosind curveto)

bull un anumit număr de fişiere EPS asociate etichetelor matematice pecare vrem să le plasăm pe grafic - fişiere pe care le vom obţine bdquoauto-matrdquo printr-un script Bash care iterează pe etichetele respective unanumit şablon de fişier LaTeX invocacircnd compilatorul latex şi progra-mul dvips

bull fişierul lsquopackepsrsquo care icircncapsulează icircn final fişierele EPS menţionatemai sus pasacircndu-l programului ps2pdf rezultă fişierul PDF precumcel vizualizat grafic mai sus

Urmează faţă de acest plan iniţial de lucru să detaliem să investigămşi desigurhellip să divagăm

Limbajul PostScript (PS) serveşte pentru a descrie o pagină de regulăimprimanta va ejecta pagina rezultată prin interpretarea fişierului care i-afost transmis EPS rezolvă problema icircncapsulării de fişiere PS permiţacircndincluderea icircn siguranţă (fără ejectare şi fără conflicte icircntre parametrii grafici)a unor pagini PS icircntr-o alta Pentru a respecta formatul EPS mai icircntacircideclarăm la icircnceputul fişierelor noastre

3

PS-Adobe-20 EPSF-20BoundingBox 75 80 320 248

Vom arăta la momentul potrivit cum obţinem valorile necesare pentruBoundingBox (nu neapărat cele precizate mai sus) şi cum le folosim icircn vedereaicircncapsulării finale a fişierelor respective

2 Discuţie despre operatori variabile şi transfor-mări (pe seama producerii elipsei dintr-un cerc)

Definim icircntacirci o procedură pentru a obţine E o elipsă tangentă icircn O axei Oxavacircnd centrul Ct şi semiaxa mică b date cu semiaxa mare fixată a = 1 şiastfel icircncacirct panta axei mari este tg

radicba

e l l i p s e tangentă icircn O axei Ox cu semiaxele şi centrul dateSb exch def Preia din stivă semiaxa mică b Semiaxa mare este a=1yC exch def Coordonatele centrului (preluate pe racircndxC exch def din stiva operanzilor) savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctg

radicba

1 Sb scale scalează orizontal cu a=1 şi vertical cu b0 0 1 0 360 arc centru (00) bdquorazărdquo 1 (=a pe Ox =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

Icircn limbajele uzuale definiţia de mai sus ar arăta cam aşa ellipse(xCyC Sb) un apel ca ellipse(5 7 075) creează icircn memorieun bdquocadru-stivărdquo icircn care se depun valorile 5 7 şi respectiv 075 şi apoi puneicircn execuţie blocul de instrucţiuni identificat prin rsquoellipsersquo icircn interiorulacestuia variabilele locale rsquoxCrsquo etc vor fi asignate cu valorile transmise laapel icircn cadrul-stivă la icircncheierea executării codului respectiv cadrul-stivăasociat la apel va fi eliminat şi controlul va reveni programului apelant

Spre deosebire de limbajele obişnuitemdashicircn care bdquocadrele-stivărdquo sunt aso-ciate icircn mod implicit şi sunt bdquoinvizibilerdquomdashicircn PostScript stiva are o naturăexplicită şi sunt prevăzute şi menţinute pe parcursul execuţiei mai multe sti-ve icircntre care o stivă pentru operanzi una pentru operatori sau procedurişi o stivă (sau bdquodicţionarrdquo) de fonturi

Definiţia de mai sus este depusă icircntacirci termen după termen pe stivaoperanzilor ellipse şi cacircnd se va icircntacirclni apoi def interpretorulva proceda astfel va accesa dicţionarul operatorilor şi va căuta aici termenulrsquoellipsersquo dacă acesta nu există atunci va crea o nouă intrare de formabdquocheie 7rarr valoarerdquo punacircnd drept bdquocheierdquo numele ellipse şi drept bdquovaloarerdquosecvenţa de instrucţiuni cuprinsă icircntre rsquorsquo şi rsquorsquoDe aici icircncolo cacircnd va fi icircntacirclnit ulterior icircn programul curent termenulrsquoellipsersquo va fi interpretat ca bdquopointerrdquo la secvenţa de instrucţiuni asociatăastfel icircn dicţionarul operatorilor (conducacircnd la executarea acestor instrucţiuni)

4

dar aceasta nu scuteşte etapa prealabilă de căutare a termenului icircntacirclniticircn dicţionarul operatorilor ndash cu această excepţie dacă icircnainte de def esteicircntacirclnit bind (ca şi icircn cazul de faţă) atunci operatorii PS predefiniţi icircntacirclniţiicircn spate sunt icircnlocuiţi imediat prin bdquopointerirdquo la codul asociat lor ca bdquovaloarerdquoicircn dicţionarul operatorilor (scutind icircn acest caz căutarea ulterioară icircn dicţionarse accelerează astfel execuţia procedurii icircn care sunt invocaţi)

Dacă după definiţia de mai sus ar urma o invocare ca de exemplu 5 7075 ellipse interpretorul ar depista cheia rsquoellipsersquo icircn dicţionarul ope-ratorilor şi ar icircncepe să execute instrucţiunile care i-au fost asociate primeletrei instrucţiuni Sb exch def etc sunt interpretate conform mecanismu-lui general descris mai sus dar cu o anumită modificare (de observat că acumlipsesc acoladele care icircncadrează de obicei blocul de instrucţiuni al procedurii) seicircnfiinţează icircn dicţionarul operatorilor cacircte o nouă cheie (rsquoSbrsquo etc) căreia ise asociază ca bdquovaloarerdquo nu pointerul la codul operatorului predefinit exch(ca icircn cazul cacircnd s-ar fi icircntacirclnit exch) ci efectul executării acestuia urma-tă de descărcarea din stiva operanzilor determinată de operatorul final defSunt modelate astfel atribuirile uzuale Sb = 075 etc

Ne putem clarifica mecanismele folosite icircn PostScript experimentacircnd icircnsesiuni de lucru cu Ghostscript De exemplu să introducem pe stivă coor-donatele unui punct (5 7) şi să imităm mecanismul de bdquoatribuirerdquo tocmaidescris pentru a crea o variabilă y legată la ordonata punctului (modelacircndatribuirea uzuală y=7)vbHome~ keps$ gs minusqGSgt 5 7 yGSlt3gt pstack afişează conţinutul stivei icircncepacircnd din vacircrful acesteiay75GSlt3gt exch pstack rsquoexchrsquo schimbă icircntre ele primele două valori din stivă7y5GSlt3gt def pstack rsquodefrsquo mută icircn stiva operatorilor cheia rsquoyrsquo asociindu-i valoarea 75 icircn stivă a rămas doar abscisa punctuluiGSlt1gt y = operatorii rsquo=rsquo şi rsquo==rsquo afişează valoarea asociată cheii indicate7GSlt1gt quit

Icircn procedura ellipse redată mai sus elipsa este descrisă pe baza opera-torului predefinit arc acesta are sintaxa bdquoxc yc r α1 α2 arcrdquo şi are ca efectvizual producerea unui arc de cerc de rază r cu centrul (xc yc) icircncepacircndicircn sens antiorar de la α

1 şi pacircnă la α2 pentru α1 = 0 şi α2 = 360 se obţi-

ne icircntregul cerc (bdquoefectulrdquo real este crearea unei variabile de memoriemdashde tipulrsquopathrsquo sau bdquoconturrdquomdashconţinacircnd coordonatele punctelor pe baza cărora se vor trasacurbele Beacutezier necesare trasarea efectivă se declanşează prin invocarea ulterioarăa operatorului stroke)

Dar cacirct de bdquomarerdquo să fie cercul constituit astfel Raza r este un număr

5

(abstract icircn matematică) şi n-avem decacirct să-l mărim dacă vrem un cerc bdquomaimarerdquo dar icircn tipografie cacircnd avem de-a face cu o pagină de hacircrtie (sau cu opagină de ecran) unitatea de măsură devine esenţială Icircn PostScript paginade hacircrtie este asociată cadranului icircntacirci al unui sistem de coordonate xOy cuaxa Ox peste marginea de jos a paginii şi axa Oy peste marginea stacircngă aacesteia unitatea de măsură este 1 bp = 1

72 inch (1 inch = 254 centimetri)arcele sunt măsurate icircn grade

Sunt prevăzute transformări ale sistemului de coordonate icircn două vari-ante (aparent distincte) putem utiliza matrici (de legătură icircntre coordona-tele vechi şi cele noi) avacircnd astfel şi un procedeu simplu pentru a salva şi arestaura sistemul de coordonate curent (salvăm bdquomatricea de transformarecurentărdquo) sau putem folosi operatorii specializaţi translate (care mutăoriginea icircn punctul indicat) rotate (care roteşte axele icircn jurul originii ac-tuale cu unghiul indicat) şi scale (prin care se poate stabili o nouă unitatede măsură pe o axă pe cealaltă sau pe ambele axe de coordonate)

Operatorul arc produce un cerc (sau un arc de cerc) icircn sistemul decoordonate iniţial dar dacă scalăm icircn prealabil cu a pe orizontală şi cu b peverticală atunci icircn sistemul de coordonate rezultat va fi produsă o elipsă cusemiaxele a şi b

Icircn cazul nostru a fost necesar să rotim elipsa icircn jurul centrului său cu unanumit unghi şi a trebuit să ţinem seama de faptul că rotate roteşte axeleicircn jurul originii sistemului de coordonate curent (nu icircn jurul unui alt punct) -ordonacircnd transformările necesare astfel icircntacirci am translatat originea iniţialăicircn punctul ale cărui coordonate le preluasem de pe stivă icircn xC şi yC apoi amrotit icircn jurul noii origini cu unghiul arctan

radicb apoi am folosit 1 Sb scale

lăsacircnd unitatea de măsură pe orizontală egală cu 1 pentru că semiaxa mareeste 1 şi punacircnd-o egală cu Sb (semiaxa mică) pe verticală icircn final aminvocat 0 0 1 0 360 arc - obţinacircnd bdquocercrdquo cu centrul (00) (adică origineasistemului de coordonate curent) şi de bdquorazărdquo 1 (dar 1 pe verticală icircnseamnăacum valoarea din Sb deci rezultă nu cerc ci elipsă)

De icircncă un lucru a trebuit să mai ţinem seama cu ce grosime urmea-ză să trasăm elipsa obţinută Grosimea implicită a liniei este de 1bp1 şipoate fi setată altfel prin operatorul setlinewidth dar valoarea respectivăse raportează la scalarea curentă astfel că icircn cazul nostru (cacircnd unitateade măsură diferă icircntre cele două axe) elipsa ar fi trasată (cacircnd se va invocastroke) cu o bdquopeniţărdquo de grosime variabilă Pentru a evita aceasta icircnaintede a efectua transformările arătate mai sus am salvat matricea transformăriicurente (desemnată prin CTM) şi am restaurat-o icircn final după producereaelipsei procedacircnd astfel scalările icircntreprinse icircn interior sunt uitate

Pentru a testa procedura ellipse adăugăm icircn fişierul rsquograficepsrsquo deexemplu72 72 scale noua unitate de măsură este de 72bp (= 1 inch = 254cm)

1icircntr-adevăr GSgt currentlinewidth pstack ne dă 10)

6

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 2: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Cuprins1 Componentele programului (sau proiectului) 3

2 Discuţie despre operatori variabile şi transformări (pe sea-ma producerii elipsei dintr-un cerc) 4

3 Producerea şi trasarea liniilor (fişierul graficeps) 731 Eroare experiment şi descoperire 1132 De la semicardioidă la cardioidă cu pathforall 1233 De la semicardioidă la cardioidă simetrizacircnd faţă de axă 15

4 Etichetarea directă folosind un font obişnuit 16

5 Icircncapsularea icircn figură a notaţiilor matematice 1851 Citirea valorilor BoundingBox 2052 Poziţionarea etichetelor pe figură 22

6 Arcele de parabolă sunt curbe Beacutezier pătratice 25

7 Arcele de parabolă prin cubice Beacutezier 26

8 Instrucţiunea curveto 2781 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo) 29

9 Aproximarea unei curbe prin cubice Beacutezier 31

10 Aproximarea semicardioidei prin cubice Beacutezier 33

11 Aproximarea semicardioidei folosind MetaPost 36

Anexă 41

A De la cerc la cardioidă 41

B Proprietăţile semicardioidei 42

2

1 Componentele programului (sau proiectului)

Elipsa E este tangentă axei semicardioidei K icircn nodul acesteia O are focareleKt şi K1minust situate pe K iar centrul ei Ct este situat pe arcul de parabolă P

(unde t isin [0 1] generează icircntr-un anumit mod punctele lui K)

Kt

K1minust

Ct

KE

P

O

Vom mai preciza pe parcurs contextul matematic al figurii (expus şiseparat icircn Anexa B) Programul PostScript care a produs figura postată maisus este compus astfel

bull fişierul principal lsquograficepsrsquo prin care se generează şi se traseazăcurbele (elipsa cardioida şi parabola) segmentele şi arcele importantevom viza două moduri de generare bdquoprin puncterdquo (cu instrucţiunilineto) respectiv prin cubice Beacutezier (folosind curveto)

bull un anumit număr de fişiere EPS asociate etichetelor matematice pecare vrem să le plasăm pe grafic - fişiere pe care le vom obţine bdquoauto-matrdquo printr-un script Bash care iterează pe etichetele respective unanumit şablon de fişier LaTeX invocacircnd compilatorul latex şi progra-mul dvips

bull fişierul lsquopackepsrsquo care icircncapsulează icircn final fişierele EPS menţionatemai sus pasacircndu-l programului ps2pdf rezultă fişierul PDF precumcel vizualizat grafic mai sus

Urmează faţă de acest plan iniţial de lucru să detaliem să investigămşi desigurhellip să divagăm

Limbajul PostScript (PS) serveşte pentru a descrie o pagină de regulăimprimanta va ejecta pagina rezultată prin interpretarea fişierului care i-afost transmis EPS rezolvă problema icircncapsulării de fişiere PS permiţacircndincluderea icircn siguranţă (fără ejectare şi fără conflicte icircntre parametrii grafici)a unor pagini PS icircntr-o alta Pentru a respecta formatul EPS mai icircntacircideclarăm la icircnceputul fişierelor noastre

3

PS-Adobe-20 EPSF-20BoundingBox 75 80 320 248

Vom arăta la momentul potrivit cum obţinem valorile necesare pentruBoundingBox (nu neapărat cele precizate mai sus) şi cum le folosim icircn vedereaicircncapsulării finale a fişierelor respective

2 Discuţie despre operatori variabile şi transfor-mări (pe seama producerii elipsei dintr-un cerc)

Definim icircntacirci o procedură pentru a obţine E o elipsă tangentă icircn O axei Oxavacircnd centrul Ct şi semiaxa mică b date cu semiaxa mare fixată a = 1 şiastfel icircncacirct panta axei mari este tg

radicba

e l l i p s e tangentă icircn O axei Ox cu semiaxele şi centrul dateSb exch def Preia din stivă semiaxa mică b Semiaxa mare este a=1yC exch def Coordonatele centrului (preluate pe racircndxC exch def din stiva operanzilor) savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctg

radicba

1 Sb scale scalează orizontal cu a=1 şi vertical cu b0 0 1 0 360 arc centru (00) bdquorazărdquo 1 (=a pe Ox =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

Icircn limbajele uzuale definiţia de mai sus ar arăta cam aşa ellipse(xCyC Sb) un apel ca ellipse(5 7 075) creează icircn memorieun bdquocadru-stivărdquo icircn care se depun valorile 5 7 şi respectiv 075 şi apoi puneicircn execuţie blocul de instrucţiuni identificat prin rsquoellipsersquo icircn interiorulacestuia variabilele locale rsquoxCrsquo etc vor fi asignate cu valorile transmise laapel icircn cadrul-stivă la icircncheierea executării codului respectiv cadrul-stivăasociat la apel va fi eliminat şi controlul va reveni programului apelant

Spre deosebire de limbajele obişnuitemdashicircn care bdquocadrele-stivărdquo sunt aso-ciate icircn mod implicit şi sunt bdquoinvizibilerdquomdashicircn PostScript stiva are o naturăexplicită şi sunt prevăzute şi menţinute pe parcursul execuţiei mai multe sti-ve icircntre care o stivă pentru operanzi una pentru operatori sau procedurişi o stivă (sau bdquodicţionarrdquo) de fonturi

Definiţia de mai sus este depusă icircntacirci termen după termen pe stivaoperanzilor ellipse şi cacircnd se va icircntacirclni apoi def interpretorulva proceda astfel va accesa dicţionarul operatorilor şi va căuta aici termenulrsquoellipsersquo dacă acesta nu există atunci va crea o nouă intrare de formabdquocheie 7rarr valoarerdquo punacircnd drept bdquocheierdquo numele ellipse şi drept bdquovaloarerdquosecvenţa de instrucţiuni cuprinsă icircntre rsquorsquo şi rsquorsquoDe aici icircncolo cacircnd va fi icircntacirclnit ulterior icircn programul curent termenulrsquoellipsersquo va fi interpretat ca bdquopointerrdquo la secvenţa de instrucţiuni asociatăastfel icircn dicţionarul operatorilor (conducacircnd la executarea acestor instrucţiuni)

4

dar aceasta nu scuteşte etapa prealabilă de căutare a termenului icircntacirclniticircn dicţionarul operatorilor ndash cu această excepţie dacă icircnainte de def esteicircntacirclnit bind (ca şi icircn cazul de faţă) atunci operatorii PS predefiniţi icircntacirclniţiicircn spate sunt icircnlocuiţi imediat prin bdquopointerirdquo la codul asociat lor ca bdquovaloarerdquoicircn dicţionarul operatorilor (scutind icircn acest caz căutarea ulterioară icircn dicţionarse accelerează astfel execuţia procedurii icircn care sunt invocaţi)

Dacă după definiţia de mai sus ar urma o invocare ca de exemplu 5 7075 ellipse interpretorul ar depista cheia rsquoellipsersquo icircn dicţionarul ope-ratorilor şi ar icircncepe să execute instrucţiunile care i-au fost asociate primeletrei instrucţiuni Sb exch def etc sunt interpretate conform mecanismu-lui general descris mai sus dar cu o anumită modificare (de observat că acumlipsesc acoladele care icircncadrează de obicei blocul de instrucţiuni al procedurii) seicircnfiinţează icircn dicţionarul operatorilor cacircte o nouă cheie (rsquoSbrsquo etc) căreia ise asociază ca bdquovaloarerdquo nu pointerul la codul operatorului predefinit exch(ca icircn cazul cacircnd s-ar fi icircntacirclnit exch) ci efectul executării acestuia urma-tă de descărcarea din stiva operanzilor determinată de operatorul final defSunt modelate astfel atribuirile uzuale Sb = 075 etc

Ne putem clarifica mecanismele folosite icircn PostScript experimentacircnd icircnsesiuni de lucru cu Ghostscript De exemplu să introducem pe stivă coor-donatele unui punct (5 7) şi să imităm mecanismul de bdquoatribuirerdquo tocmaidescris pentru a crea o variabilă y legată la ordonata punctului (modelacircndatribuirea uzuală y=7)vbHome~ keps$ gs minusqGSgt 5 7 yGSlt3gt pstack afişează conţinutul stivei icircncepacircnd din vacircrful acesteiay75GSlt3gt exch pstack rsquoexchrsquo schimbă icircntre ele primele două valori din stivă7y5GSlt3gt def pstack rsquodefrsquo mută icircn stiva operatorilor cheia rsquoyrsquo asociindu-i valoarea 75 icircn stivă a rămas doar abscisa punctuluiGSlt1gt y = operatorii rsquo=rsquo şi rsquo==rsquo afişează valoarea asociată cheii indicate7GSlt1gt quit

Icircn procedura ellipse redată mai sus elipsa este descrisă pe baza opera-torului predefinit arc acesta are sintaxa bdquoxc yc r α1 α2 arcrdquo şi are ca efectvizual producerea unui arc de cerc de rază r cu centrul (xc yc) icircncepacircndicircn sens antiorar de la α

1 şi pacircnă la α2 pentru α1 = 0 şi α2 = 360 se obţi-

ne icircntregul cerc (bdquoefectulrdquo real este crearea unei variabile de memoriemdashde tipulrsquopathrsquo sau bdquoconturrdquomdashconţinacircnd coordonatele punctelor pe baza cărora se vor trasacurbele Beacutezier necesare trasarea efectivă se declanşează prin invocarea ulterioarăa operatorului stroke)

Dar cacirct de bdquomarerdquo să fie cercul constituit astfel Raza r este un număr

5

(abstract icircn matematică) şi n-avem decacirct să-l mărim dacă vrem un cerc bdquomaimarerdquo dar icircn tipografie cacircnd avem de-a face cu o pagină de hacircrtie (sau cu opagină de ecran) unitatea de măsură devine esenţială Icircn PostScript paginade hacircrtie este asociată cadranului icircntacirci al unui sistem de coordonate xOy cuaxa Ox peste marginea de jos a paginii şi axa Oy peste marginea stacircngă aacesteia unitatea de măsură este 1 bp = 1

72 inch (1 inch = 254 centimetri)arcele sunt măsurate icircn grade

Sunt prevăzute transformări ale sistemului de coordonate icircn două vari-ante (aparent distincte) putem utiliza matrici (de legătură icircntre coordona-tele vechi şi cele noi) avacircnd astfel şi un procedeu simplu pentru a salva şi arestaura sistemul de coordonate curent (salvăm bdquomatricea de transformarecurentărdquo) sau putem folosi operatorii specializaţi translate (care mutăoriginea icircn punctul indicat) rotate (care roteşte axele icircn jurul originii ac-tuale cu unghiul indicat) şi scale (prin care se poate stabili o nouă unitatede măsură pe o axă pe cealaltă sau pe ambele axe de coordonate)

Operatorul arc produce un cerc (sau un arc de cerc) icircn sistemul decoordonate iniţial dar dacă scalăm icircn prealabil cu a pe orizontală şi cu b peverticală atunci icircn sistemul de coordonate rezultat va fi produsă o elipsă cusemiaxele a şi b

Icircn cazul nostru a fost necesar să rotim elipsa icircn jurul centrului său cu unanumit unghi şi a trebuit să ţinem seama de faptul că rotate roteşte axeleicircn jurul originii sistemului de coordonate curent (nu icircn jurul unui alt punct) -ordonacircnd transformările necesare astfel icircntacirci am translatat originea iniţialăicircn punctul ale cărui coordonate le preluasem de pe stivă icircn xC şi yC apoi amrotit icircn jurul noii origini cu unghiul arctan

radicb apoi am folosit 1 Sb scale

lăsacircnd unitatea de măsură pe orizontală egală cu 1 pentru că semiaxa mareeste 1 şi punacircnd-o egală cu Sb (semiaxa mică) pe verticală icircn final aminvocat 0 0 1 0 360 arc - obţinacircnd bdquocercrdquo cu centrul (00) (adică origineasistemului de coordonate curent) şi de bdquorazărdquo 1 (dar 1 pe verticală icircnseamnăacum valoarea din Sb deci rezultă nu cerc ci elipsă)

De icircncă un lucru a trebuit să mai ţinem seama cu ce grosime urmea-ză să trasăm elipsa obţinută Grosimea implicită a liniei este de 1bp1 şipoate fi setată altfel prin operatorul setlinewidth dar valoarea respectivăse raportează la scalarea curentă astfel că icircn cazul nostru (cacircnd unitateade măsură diferă icircntre cele două axe) elipsa ar fi trasată (cacircnd se va invocastroke) cu o bdquopeniţărdquo de grosime variabilă Pentru a evita aceasta icircnaintede a efectua transformările arătate mai sus am salvat matricea transformăriicurente (desemnată prin CTM) şi am restaurat-o icircn final după producereaelipsei procedacircnd astfel scalările icircntreprinse icircn interior sunt uitate

Pentru a testa procedura ellipse adăugăm icircn fişierul rsquograficepsrsquo deexemplu72 72 scale noua unitate de măsură este de 72bp (= 1 inch = 254cm)

1icircntr-adevăr GSgt currentlinewidth pstack ne dă 10)

6

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 3: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

1 Componentele programului (sau proiectului)

Elipsa E este tangentă axei semicardioidei K icircn nodul acesteia O are focareleKt şi K1minust situate pe K iar centrul ei Ct este situat pe arcul de parabolă P

(unde t isin [0 1] generează icircntr-un anumit mod punctele lui K)

Kt

K1minust

Ct

KE

P

O

Vom mai preciza pe parcurs contextul matematic al figurii (expus şiseparat icircn Anexa B) Programul PostScript care a produs figura postată maisus este compus astfel

bull fişierul principal lsquograficepsrsquo prin care se generează şi se traseazăcurbele (elipsa cardioida şi parabola) segmentele şi arcele importantevom viza două moduri de generare bdquoprin puncterdquo (cu instrucţiunilineto) respectiv prin cubice Beacutezier (folosind curveto)

bull un anumit număr de fişiere EPS asociate etichetelor matematice pecare vrem să le plasăm pe grafic - fişiere pe care le vom obţine bdquoauto-matrdquo printr-un script Bash care iterează pe etichetele respective unanumit şablon de fişier LaTeX invocacircnd compilatorul latex şi progra-mul dvips

bull fişierul lsquopackepsrsquo care icircncapsulează icircn final fişierele EPS menţionatemai sus pasacircndu-l programului ps2pdf rezultă fişierul PDF precumcel vizualizat grafic mai sus

Urmează faţă de acest plan iniţial de lucru să detaliem să investigămşi desigurhellip să divagăm

Limbajul PostScript (PS) serveşte pentru a descrie o pagină de regulăimprimanta va ejecta pagina rezultată prin interpretarea fişierului care i-afost transmis EPS rezolvă problema icircncapsulării de fişiere PS permiţacircndincluderea icircn siguranţă (fără ejectare şi fără conflicte icircntre parametrii grafici)a unor pagini PS icircntr-o alta Pentru a respecta formatul EPS mai icircntacircideclarăm la icircnceputul fişierelor noastre

3

PS-Adobe-20 EPSF-20BoundingBox 75 80 320 248

Vom arăta la momentul potrivit cum obţinem valorile necesare pentruBoundingBox (nu neapărat cele precizate mai sus) şi cum le folosim icircn vedereaicircncapsulării finale a fişierelor respective

2 Discuţie despre operatori variabile şi transfor-mări (pe seama producerii elipsei dintr-un cerc)

Definim icircntacirci o procedură pentru a obţine E o elipsă tangentă icircn O axei Oxavacircnd centrul Ct şi semiaxa mică b date cu semiaxa mare fixată a = 1 şiastfel icircncacirct panta axei mari este tg

radicba

e l l i p s e tangentă icircn O axei Ox cu semiaxele şi centrul dateSb exch def Preia din stivă semiaxa mică b Semiaxa mare este a=1yC exch def Coordonatele centrului (preluate pe racircndxC exch def din stiva operanzilor) savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctg

radicba

1 Sb scale scalează orizontal cu a=1 şi vertical cu b0 0 1 0 360 arc centru (00) bdquorazărdquo 1 (=a pe Ox =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

Icircn limbajele uzuale definiţia de mai sus ar arăta cam aşa ellipse(xCyC Sb) un apel ca ellipse(5 7 075) creează icircn memorieun bdquocadru-stivărdquo icircn care se depun valorile 5 7 şi respectiv 075 şi apoi puneicircn execuţie blocul de instrucţiuni identificat prin rsquoellipsersquo icircn interiorulacestuia variabilele locale rsquoxCrsquo etc vor fi asignate cu valorile transmise laapel icircn cadrul-stivă la icircncheierea executării codului respectiv cadrul-stivăasociat la apel va fi eliminat şi controlul va reveni programului apelant

Spre deosebire de limbajele obişnuitemdashicircn care bdquocadrele-stivărdquo sunt aso-ciate icircn mod implicit şi sunt bdquoinvizibilerdquomdashicircn PostScript stiva are o naturăexplicită şi sunt prevăzute şi menţinute pe parcursul execuţiei mai multe sti-ve icircntre care o stivă pentru operanzi una pentru operatori sau procedurişi o stivă (sau bdquodicţionarrdquo) de fonturi

Definiţia de mai sus este depusă icircntacirci termen după termen pe stivaoperanzilor ellipse şi cacircnd se va icircntacirclni apoi def interpretorulva proceda astfel va accesa dicţionarul operatorilor şi va căuta aici termenulrsquoellipsersquo dacă acesta nu există atunci va crea o nouă intrare de formabdquocheie 7rarr valoarerdquo punacircnd drept bdquocheierdquo numele ellipse şi drept bdquovaloarerdquosecvenţa de instrucţiuni cuprinsă icircntre rsquorsquo şi rsquorsquoDe aici icircncolo cacircnd va fi icircntacirclnit ulterior icircn programul curent termenulrsquoellipsersquo va fi interpretat ca bdquopointerrdquo la secvenţa de instrucţiuni asociatăastfel icircn dicţionarul operatorilor (conducacircnd la executarea acestor instrucţiuni)

4

dar aceasta nu scuteşte etapa prealabilă de căutare a termenului icircntacirclniticircn dicţionarul operatorilor ndash cu această excepţie dacă icircnainte de def esteicircntacirclnit bind (ca şi icircn cazul de faţă) atunci operatorii PS predefiniţi icircntacirclniţiicircn spate sunt icircnlocuiţi imediat prin bdquopointerirdquo la codul asociat lor ca bdquovaloarerdquoicircn dicţionarul operatorilor (scutind icircn acest caz căutarea ulterioară icircn dicţionarse accelerează astfel execuţia procedurii icircn care sunt invocaţi)

Dacă după definiţia de mai sus ar urma o invocare ca de exemplu 5 7075 ellipse interpretorul ar depista cheia rsquoellipsersquo icircn dicţionarul ope-ratorilor şi ar icircncepe să execute instrucţiunile care i-au fost asociate primeletrei instrucţiuni Sb exch def etc sunt interpretate conform mecanismu-lui general descris mai sus dar cu o anumită modificare (de observat că acumlipsesc acoladele care icircncadrează de obicei blocul de instrucţiuni al procedurii) seicircnfiinţează icircn dicţionarul operatorilor cacircte o nouă cheie (rsquoSbrsquo etc) căreia ise asociază ca bdquovaloarerdquo nu pointerul la codul operatorului predefinit exch(ca icircn cazul cacircnd s-ar fi icircntacirclnit exch) ci efectul executării acestuia urma-tă de descărcarea din stiva operanzilor determinată de operatorul final defSunt modelate astfel atribuirile uzuale Sb = 075 etc

Ne putem clarifica mecanismele folosite icircn PostScript experimentacircnd icircnsesiuni de lucru cu Ghostscript De exemplu să introducem pe stivă coor-donatele unui punct (5 7) şi să imităm mecanismul de bdquoatribuirerdquo tocmaidescris pentru a crea o variabilă y legată la ordonata punctului (modelacircndatribuirea uzuală y=7)vbHome~ keps$ gs minusqGSgt 5 7 yGSlt3gt pstack afişează conţinutul stivei icircncepacircnd din vacircrful acesteiay75GSlt3gt exch pstack rsquoexchrsquo schimbă icircntre ele primele două valori din stivă7y5GSlt3gt def pstack rsquodefrsquo mută icircn stiva operatorilor cheia rsquoyrsquo asociindu-i valoarea 75 icircn stivă a rămas doar abscisa punctuluiGSlt1gt y = operatorii rsquo=rsquo şi rsquo==rsquo afişează valoarea asociată cheii indicate7GSlt1gt quit

Icircn procedura ellipse redată mai sus elipsa este descrisă pe baza opera-torului predefinit arc acesta are sintaxa bdquoxc yc r α1 α2 arcrdquo şi are ca efectvizual producerea unui arc de cerc de rază r cu centrul (xc yc) icircncepacircndicircn sens antiorar de la α

1 şi pacircnă la α2 pentru α1 = 0 şi α2 = 360 se obţi-

ne icircntregul cerc (bdquoefectulrdquo real este crearea unei variabile de memoriemdashde tipulrsquopathrsquo sau bdquoconturrdquomdashconţinacircnd coordonatele punctelor pe baza cărora se vor trasacurbele Beacutezier necesare trasarea efectivă se declanşează prin invocarea ulterioarăa operatorului stroke)

Dar cacirct de bdquomarerdquo să fie cercul constituit astfel Raza r este un număr

5

(abstract icircn matematică) şi n-avem decacirct să-l mărim dacă vrem un cerc bdquomaimarerdquo dar icircn tipografie cacircnd avem de-a face cu o pagină de hacircrtie (sau cu opagină de ecran) unitatea de măsură devine esenţială Icircn PostScript paginade hacircrtie este asociată cadranului icircntacirci al unui sistem de coordonate xOy cuaxa Ox peste marginea de jos a paginii şi axa Oy peste marginea stacircngă aacesteia unitatea de măsură este 1 bp = 1

72 inch (1 inch = 254 centimetri)arcele sunt măsurate icircn grade

Sunt prevăzute transformări ale sistemului de coordonate icircn două vari-ante (aparent distincte) putem utiliza matrici (de legătură icircntre coordona-tele vechi şi cele noi) avacircnd astfel şi un procedeu simplu pentru a salva şi arestaura sistemul de coordonate curent (salvăm bdquomatricea de transformarecurentărdquo) sau putem folosi operatorii specializaţi translate (care mutăoriginea icircn punctul indicat) rotate (care roteşte axele icircn jurul originii ac-tuale cu unghiul indicat) şi scale (prin care se poate stabili o nouă unitatede măsură pe o axă pe cealaltă sau pe ambele axe de coordonate)

Operatorul arc produce un cerc (sau un arc de cerc) icircn sistemul decoordonate iniţial dar dacă scalăm icircn prealabil cu a pe orizontală şi cu b peverticală atunci icircn sistemul de coordonate rezultat va fi produsă o elipsă cusemiaxele a şi b

Icircn cazul nostru a fost necesar să rotim elipsa icircn jurul centrului său cu unanumit unghi şi a trebuit să ţinem seama de faptul că rotate roteşte axeleicircn jurul originii sistemului de coordonate curent (nu icircn jurul unui alt punct) -ordonacircnd transformările necesare astfel icircntacirci am translatat originea iniţialăicircn punctul ale cărui coordonate le preluasem de pe stivă icircn xC şi yC apoi amrotit icircn jurul noii origini cu unghiul arctan

radicb apoi am folosit 1 Sb scale

lăsacircnd unitatea de măsură pe orizontală egală cu 1 pentru că semiaxa mareeste 1 şi punacircnd-o egală cu Sb (semiaxa mică) pe verticală icircn final aminvocat 0 0 1 0 360 arc - obţinacircnd bdquocercrdquo cu centrul (00) (adică origineasistemului de coordonate curent) şi de bdquorazărdquo 1 (dar 1 pe verticală icircnseamnăacum valoarea din Sb deci rezultă nu cerc ci elipsă)

De icircncă un lucru a trebuit să mai ţinem seama cu ce grosime urmea-ză să trasăm elipsa obţinută Grosimea implicită a liniei este de 1bp1 şipoate fi setată altfel prin operatorul setlinewidth dar valoarea respectivăse raportează la scalarea curentă astfel că icircn cazul nostru (cacircnd unitateade măsură diferă icircntre cele două axe) elipsa ar fi trasată (cacircnd se va invocastroke) cu o bdquopeniţărdquo de grosime variabilă Pentru a evita aceasta icircnaintede a efectua transformările arătate mai sus am salvat matricea transformăriicurente (desemnată prin CTM) şi am restaurat-o icircn final după producereaelipsei procedacircnd astfel scalările icircntreprinse icircn interior sunt uitate

Pentru a testa procedura ellipse adăugăm icircn fişierul rsquograficepsrsquo deexemplu72 72 scale noua unitate de măsură este de 72bp (= 1 inch = 254cm)

1icircntr-adevăr GSgt currentlinewidth pstack ne dă 10)

6

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 4: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

PS-Adobe-20 EPSF-20BoundingBox 75 80 320 248

Vom arăta la momentul potrivit cum obţinem valorile necesare pentruBoundingBox (nu neapărat cele precizate mai sus) şi cum le folosim icircn vedereaicircncapsulării finale a fişierelor respective

2 Discuţie despre operatori variabile şi transfor-mări (pe seama producerii elipsei dintr-un cerc)

Definim icircntacirci o procedură pentru a obţine E o elipsă tangentă icircn O axei Oxavacircnd centrul Ct şi semiaxa mică b date cu semiaxa mare fixată a = 1 şiastfel icircncacirct panta axei mari este tg

radicba

e l l i p s e tangentă icircn O axei Ox cu semiaxele şi centrul dateSb exch def Preia din stivă semiaxa mică b Semiaxa mare este a=1yC exch def Coordonatele centrului (preluate pe racircndxC exch def din stiva operanzilor) savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctg

radicba

1 Sb scale scalează orizontal cu a=1 şi vertical cu b0 0 1 0 360 arc centru (00) bdquorazărdquo 1 (=a pe Ox =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

Icircn limbajele uzuale definiţia de mai sus ar arăta cam aşa ellipse(xCyC Sb) un apel ca ellipse(5 7 075) creează icircn memorieun bdquocadru-stivărdquo icircn care se depun valorile 5 7 şi respectiv 075 şi apoi puneicircn execuţie blocul de instrucţiuni identificat prin rsquoellipsersquo icircn interiorulacestuia variabilele locale rsquoxCrsquo etc vor fi asignate cu valorile transmise laapel icircn cadrul-stivă la icircncheierea executării codului respectiv cadrul-stivăasociat la apel va fi eliminat şi controlul va reveni programului apelant

Spre deosebire de limbajele obişnuitemdashicircn care bdquocadrele-stivărdquo sunt aso-ciate icircn mod implicit şi sunt bdquoinvizibilerdquomdashicircn PostScript stiva are o naturăexplicită şi sunt prevăzute şi menţinute pe parcursul execuţiei mai multe sti-ve icircntre care o stivă pentru operanzi una pentru operatori sau procedurişi o stivă (sau bdquodicţionarrdquo) de fonturi

Definiţia de mai sus este depusă icircntacirci termen după termen pe stivaoperanzilor ellipse şi cacircnd se va icircntacirclni apoi def interpretorulva proceda astfel va accesa dicţionarul operatorilor şi va căuta aici termenulrsquoellipsersquo dacă acesta nu există atunci va crea o nouă intrare de formabdquocheie 7rarr valoarerdquo punacircnd drept bdquocheierdquo numele ellipse şi drept bdquovaloarerdquosecvenţa de instrucţiuni cuprinsă icircntre rsquorsquo şi rsquorsquoDe aici icircncolo cacircnd va fi icircntacirclnit ulterior icircn programul curent termenulrsquoellipsersquo va fi interpretat ca bdquopointerrdquo la secvenţa de instrucţiuni asociatăastfel icircn dicţionarul operatorilor (conducacircnd la executarea acestor instrucţiuni)

4

dar aceasta nu scuteşte etapa prealabilă de căutare a termenului icircntacirclniticircn dicţionarul operatorilor ndash cu această excepţie dacă icircnainte de def esteicircntacirclnit bind (ca şi icircn cazul de faţă) atunci operatorii PS predefiniţi icircntacirclniţiicircn spate sunt icircnlocuiţi imediat prin bdquopointerirdquo la codul asociat lor ca bdquovaloarerdquoicircn dicţionarul operatorilor (scutind icircn acest caz căutarea ulterioară icircn dicţionarse accelerează astfel execuţia procedurii icircn care sunt invocaţi)

Dacă după definiţia de mai sus ar urma o invocare ca de exemplu 5 7075 ellipse interpretorul ar depista cheia rsquoellipsersquo icircn dicţionarul ope-ratorilor şi ar icircncepe să execute instrucţiunile care i-au fost asociate primeletrei instrucţiuni Sb exch def etc sunt interpretate conform mecanismu-lui general descris mai sus dar cu o anumită modificare (de observat că acumlipsesc acoladele care icircncadrează de obicei blocul de instrucţiuni al procedurii) seicircnfiinţează icircn dicţionarul operatorilor cacircte o nouă cheie (rsquoSbrsquo etc) căreia ise asociază ca bdquovaloarerdquo nu pointerul la codul operatorului predefinit exch(ca icircn cazul cacircnd s-ar fi icircntacirclnit exch) ci efectul executării acestuia urma-tă de descărcarea din stiva operanzilor determinată de operatorul final defSunt modelate astfel atribuirile uzuale Sb = 075 etc

Ne putem clarifica mecanismele folosite icircn PostScript experimentacircnd icircnsesiuni de lucru cu Ghostscript De exemplu să introducem pe stivă coor-donatele unui punct (5 7) şi să imităm mecanismul de bdquoatribuirerdquo tocmaidescris pentru a crea o variabilă y legată la ordonata punctului (modelacircndatribuirea uzuală y=7)vbHome~ keps$ gs minusqGSgt 5 7 yGSlt3gt pstack afişează conţinutul stivei icircncepacircnd din vacircrful acesteiay75GSlt3gt exch pstack rsquoexchrsquo schimbă icircntre ele primele două valori din stivă7y5GSlt3gt def pstack rsquodefrsquo mută icircn stiva operatorilor cheia rsquoyrsquo asociindu-i valoarea 75 icircn stivă a rămas doar abscisa punctuluiGSlt1gt y = operatorii rsquo=rsquo şi rsquo==rsquo afişează valoarea asociată cheii indicate7GSlt1gt quit

Icircn procedura ellipse redată mai sus elipsa este descrisă pe baza opera-torului predefinit arc acesta are sintaxa bdquoxc yc r α1 α2 arcrdquo şi are ca efectvizual producerea unui arc de cerc de rază r cu centrul (xc yc) icircncepacircndicircn sens antiorar de la α

1 şi pacircnă la α2 pentru α1 = 0 şi α2 = 360 se obţi-

ne icircntregul cerc (bdquoefectulrdquo real este crearea unei variabile de memoriemdashde tipulrsquopathrsquo sau bdquoconturrdquomdashconţinacircnd coordonatele punctelor pe baza cărora se vor trasacurbele Beacutezier necesare trasarea efectivă se declanşează prin invocarea ulterioarăa operatorului stroke)

Dar cacirct de bdquomarerdquo să fie cercul constituit astfel Raza r este un număr

5

(abstract icircn matematică) şi n-avem decacirct să-l mărim dacă vrem un cerc bdquomaimarerdquo dar icircn tipografie cacircnd avem de-a face cu o pagină de hacircrtie (sau cu opagină de ecran) unitatea de măsură devine esenţială Icircn PostScript paginade hacircrtie este asociată cadranului icircntacirci al unui sistem de coordonate xOy cuaxa Ox peste marginea de jos a paginii şi axa Oy peste marginea stacircngă aacesteia unitatea de măsură este 1 bp = 1

72 inch (1 inch = 254 centimetri)arcele sunt măsurate icircn grade

Sunt prevăzute transformări ale sistemului de coordonate icircn două vari-ante (aparent distincte) putem utiliza matrici (de legătură icircntre coordona-tele vechi şi cele noi) avacircnd astfel şi un procedeu simplu pentru a salva şi arestaura sistemul de coordonate curent (salvăm bdquomatricea de transformarecurentărdquo) sau putem folosi operatorii specializaţi translate (care mutăoriginea icircn punctul indicat) rotate (care roteşte axele icircn jurul originii ac-tuale cu unghiul indicat) şi scale (prin care se poate stabili o nouă unitatede măsură pe o axă pe cealaltă sau pe ambele axe de coordonate)

Operatorul arc produce un cerc (sau un arc de cerc) icircn sistemul decoordonate iniţial dar dacă scalăm icircn prealabil cu a pe orizontală şi cu b peverticală atunci icircn sistemul de coordonate rezultat va fi produsă o elipsă cusemiaxele a şi b

Icircn cazul nostru a fost necesar să rotim elipsa icircn jurul centrului său cu unanumit unghi şi a trebuit să ţinem seama de faptul că rotate roteşte axeleicircn jurul originii sistemului de coordonate curent (nu icircn jurul unui alt punct) -ordonacircnd transformările necesare astfel icircntacirci am translatat originea iniţialăicircn punctul ale cărui coordonate le preluasem de pe stivă icircn xC şi yC apoi amrotit icircn jurul noii origini cu unghiul arctan

radicb apoi am folosit 1 Sb scale

lăsacircnd unitatea de măsură pe orizontală egală cu 1 pentru că semiaxa mareeste 1 şi punacircnd-o egală cu Sb (semiaxa mică) pe verticală icircn final aminvocat 0 0 1 0 360 arc - obţinacircnd bdquocercrdquo cu centrul (00) (adică origineasistemului de coordonate curent) şi de bdquorazărdquo 1 (dar 1 pe verticală icircnseamnăacum valoarea din Sb deci rezultă nu cerc ci elipsă)

De icircncă un lucru a trebuit să mai ţinem seama cu ce grosime urmea-ză să trasăm elipsa obţinută Grosimea implicită a liniei este de 1bp1 şipoate fi setată altfel prin operatorul setlinewidth dar valoarea respectivăse raportează la scalarea curentă astfel că icircn cazul nostru (cacircnd unitateade măsură diferă icircntre cele două axe) elipsa ar fi trasată (cacircnd se va invocastroke) cu o bdquopeniţărdquo de grosime variabilă Pentru a evita aceasta icircnaintede a efectua transformările arătate mai sus am salvat matricea transformăriicurente (desemnată prin CTM) şi am restaurat-o icircn final după producereaelipsei procedacircnd astfel scalările icircntreprinse icircn interior sunt uitate

Pentru a testa procedura ellipse adăugăm icircn fişierul rsquograficepsrsquo deexemplu72 72 scale noua unitate de măsură este de 72bp (= 1 inch = 254cm)

1icircntr-adevăr GSgt currentlinewidth pstack ne dă 10)

6

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 5: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

dar aceasta nu scuteşte etapa prealabilă de căutare a termenului icircntacirclniticircn dicţionarul operatorilor ndash cu această excepţie dacă icircnainte de def esteicircntacirclnit bind (ca şi icircn cazul de faţă) atunci operatorii PS predefiniţi icircntacirclniţiicircn spate sunt icircnlocuiţi imediat prin bdquopointerirdquo la codul asociat lor ca bdquovaloarerdquoicircn dicţionarul operatorilor (scutind icircn acest caz căutarea ulterioară icircn dicţionarse accelerează astfel execuţia procedurii icircn care sunt invocaţi)

Dacă după definiţia de mai sus ar urma o invocare ca de exemplu 5 7075 ellipse interpretorul ar depista cheia rsquoellipsersquo icircn dicţionarul ope-ratorilor şi ar icircncepe să execute instrucţiunile care i-au fost asociate primeletrei instrucţiuni Sb exch def etc sunt interpretate conform mecanismu-lui general descris mai sus dar cu o anumită modificare (de observat că acumlipsesc acoladele care icircncadrează de obicei blocul de instrucţiuni al procedurii) seicircnfiinţează icircn dicţionarul operatorilor cacircte o nouă cheie (rsquoSbrsquo etc) căreia ise asociază ca bdquovaloarerdquo nu pointerul la codul operatorului predefinit exch(ca icircn cazul cacircnd s-ar fi icircntacirclnit exch) ci efectul executării acestuia urma-tă de descărcarea din stiva operanzilor determinată de operatorul final defSunt modelate astfel atribuirile uzuale Sb = 075 etc

Ne putem clarifica mecanismele folosite icircn PostScript experimentacircnd icircnsesiuni de lucru cu Ghostscript De exemplu să introducem pe stivă coor-donatele unui punct (5 7) şi să imităm mecanismul de bdquoatribuirerdquo tocmaidescris pentru a crea o variabilă y legată la ordonata punctului (modelacircndatribuirea uzuală y=7)vbHome~ keps$ gs minusqGSgt 5 7 yGSlt3gt pstack afişează conţinutul stivei icircncepacircnd din vacircrful acesteiay75GSlt3gt exch pstack rsquoexchrsquo schimbă icircntre ele primele două valori din stivă7y5GSlt3gt def pstack rsquodefrsquo mută icircn stiva operatorilor cheia rsquoyrsquo asociindu-i valoarea 75 icircn stivă a rămas doar abscisa punctuluiGSlt1gt y = operatorii rsquo=rsquo şi rsquo==rsquo afişează valoarea asociată cheii indicate7GSlt1gt quit

Icircn procedura ellipse redată mai sus elipsa este descrisă pe baza opera-torului predefinit arc acesta are sintaxa bdquoxc yc r α1 α2 arcrdquo şi are ca efectvizual producerea unui arc de cerc de rază r cu centrul (xc yc) icircncepacircndicircn sens antiorar de la α

1 şi pacircnă la α2 pentru α1 = 0 şi α2 = 360 se obţi-

ne icircntregul cerc (bdquoefectulrdquo real este crearea unei variabile de memoriemdashde tipulrsquopathrsquo sau bdquoconturrdquomdashconţinacircnd coordonatele punctelor pe baza cărora se vor trasacurbele Beacutezier necesare trasarea efectivă se declanşează prin invocarea ulterioarăa operatorului stroke)

Dar cacirct de bdquomarerdquo să fie cercul constituit astfel Raza r este un număr

5

(abstract icircn matematică) şi n-avem decacirct să-l mărim dacă vrem un cerc bdquomaimarerdquo dar icircn tipografie cacircnd avem de-a face cu o pagină de hacircrtie (sau cu opagină de ecran) unitatea de măsură devine esenţială Icircn PostScript paginade hacircrtie este asociată cadranului icircntacirci al unui sistem de coordonate xOy cuaxa Ox peste marginea de jos a paginii şi axa Oy peste marginea stacircngă aacesteia unitatea de măsură este 1 bp = 1

72 inch (1 inch = 254 centimetri)arcele sunt măsurate icircn grade

Sunt prevăzute transformări ale sistemului de coordonate icircn două vari-ante (aparent distincte) putem utiliza matrici (de legătură icircntre coordona-tele vechi şi cele noi) avacircnd astfel şi un procedeu simplu pentru a salva şi arestaura sistemul de coordonate curent (salvăm bdquomatricea de transformarecurentărdquo) sau putem folosi operatorii specializaţi translate (care mutăoriginea icircn punctul indicat) rotate (care roteşte axele icircn jurul originii ac-tuale cu unghiul indicat) şi scale (prin care se poate stabili o nouă unitatede măsură pe o axă pe cealaltă sau pe ambele axe de coordonate)

Operatorul arc produce un cerc (sau un arc de cerc) icircn sistemul decoordonate iniţial dar dacă scalăm icircn prealabil cu a pe orizontală şi cu b peverticală atunci icircn sistemul de coordonate rezultat va fi produsă o elipsă cusemiaxele a şi b

Icircn cazul nostru a fost necesar să rotim elipsa icircn jurul centrului său cu unanumit unghi şi a trebuit să ţinem seama de faptul că rotate roteşte axeleicircn jurul originii sistemului de coordonate curent (nu icircn jurul unui alt punct) -ordonacircnd transformările necesare astfel icircntacirci am translatat originea iniţialăicircn punctul ale cărui coordonate le preluasem de pe stivă icircn xC şi yC apoi amrotit icircn jurul noii origini cu unghiul arctan

radicb apoi am folosit 1 Sb scale

lăsacircnd unitatea de măsură pe orizontală egală cu 1 pentru că semiaxa mareeste 1 şi punacircnd-o egală cu Sb (semiaxa mică) pe verticală icircn final aminvocat 0 0 1 0 360 arc - obţinacircnd bdquocercrdquo cu centrul (00) (adică origineasistemului de coordonate curent) şi de bdquorazărdquo 1 (dar 1 pe verticală icircnseamnăacum valoarea din Sb deci rezultă nu cerc ci elipsă)

De icircncă un lucru a trebuit să mai ţinem seama cu ce grosime urmea-ză să trasăm elipsa obţinută Grosimea implicită a liniei este de 1bp1 şipoate fi setată altfel prin operatorul setlinewidth dar valoarea respectivăse raportează la scalarea curentă astfel că icircn cazul nostru (cacircnd unitateade măsură diferă icircntre cele două axe) elipsa ar fi trasată (cacircnd se va invocastroke) cu o bdquopeniţărdquo de grosime variabilă Pentru a evita aceasta icircnaintede a efectua transformările arătate mai sus am salvat matricea transformăriicurente (desemnată prin CTM) şi am restaurat-o icircn final după producereaelipsei procedacircnd astfel scalările icircntreprinse icircn interior sunt uitate

Pentru a testa procedura ellipse adăugăm icircn fişierul rsquograficepsrsquo deexemplu72 72 scale noua unitate de măsură este de 72bp (= 1 inch = 254cm)

1icircntr-adevăr GSgt currentlinewidth pstack ne dă 10)

6

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 6: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

(abstract icircn matematică) şi n-avem decacirct să-l mărim dacă vrem un cerc bdquomaimarerdquo dar icircn tipografie cacircnd avem de-a face cu o pagină de hacircrtie (sau cu opagină de ecran) unitatea de măsură devine esenţială Icircn PostScript paginade hacircrtie este asociată cadranului icircntacirci al unui sistem de coordonate xOy cuaxa Ox peste marginea de jos a paginii şi axa Oy peste marginea stacircngă aacesteia unitatea de măsură este 1 bp = 1

72 inch (1 inch = 254 centimetri)arcele sunt măsurate icircn grade

Sunt prevăzute transformări ale sistemului de coordonate icircn două vari-ante (aparent distincte) putem utiliza matrici (de legătură icircntre coordona-tele vechi şi cele noi) avacircnd astfel şi un procedeu simplu pentru a salva şi arestaura sistemul de coordonate curent (salvăm bdquomatricea de transformarecurentărdquo) sau putem folosi operatorii specializaţi translate (care mutăoriginea icircn punctul indicat) rotate (care roteşte axele icircn jurul originii ac-tuale cu unghiul indicat) şi scale (prin care se poate stabili o nouă unitatede măsură pe o axă pe cealaltă sau pe ambele axe de coordonate)

Operatorul arc produce un cerc (sau un arc de cerc) icircn sistemul decoordonate iniţial dar dacă scalăm icircn prealabil cu a pe orizontală şi cu b peverticală atunci icircn sistemul de coordonate rezultat va fi produsă o elipsă cusemiaxele a şi b

Icircn cazul nostru a fost necesar să rotim elipsa icircn jurul centrului său cu unanumit unghi şi a trebuit să ţinem seama de faptul că rotate roteşte axeleicircn jurul originii sistemului de coordonate curent (nu icircn jurul unui alt punct) -ordonacircnd transformările necesare astfel icircntacirci am translatat originea iniţialăicircn punctul ale cărui coordonate le preluasem de pe stivă icircn xC şi yC apoi amrotit icircn jurul noii origini cu unghiul arctan

radicb apoi am folosit 1 Sb scale

lăsacircnd unitatea de măsură pe orizontală egală cu 1 pentru că semiaxa mareeste 1 şi punacircnd-o egală cu Sb (semiaxa mică) pe verticală icircn final aminvocat 0 0 1 0 360 arc - obţinacircnd bdquocercrdquo cu centrul (00) (adică origineasistemului de coordonate curent) şi de bdquorazărdquo 1 (dar 1 pe verticală icircnseamnăacum valoarea din Sb deci rezultă nu cerc ci elipsă)

De icircncă un lucru a trebuit să mai ţinem seama cu ce grosime urmea-ză să trasăm elipsa obţinută Grosimea implicită a liniei este de 1bp1 şipoate fi setată altfel prin operatorul setlinewidth dar valoarea respectivăse raportează la scalarea curentă astfel că icircn cazul nostru (cacircnd unitateade măsură diferă icircntre cele două axe) elipsa ar fi trasată (cacircnd se va invocastroke) cu o bdquopeniţărdquo de grosime variabilă Pentru a evita aceasta icircnaintede a efectua transformările arătate mai sus am salvat matricea transformăriicurente (desemnată prin CTM) şi am restaurat-o icircn final după producereaelipsei procedacircnd astfel scalările icircntreprinse icircn interior sunt uitate

Pentru a testa procedura ellipse adăugăm icircn fişierul rsquograficepsrsquo deexemplu72 72 scale noua unitate de măsură este de 72bp (= 1 inch = 254cm)

1icircntr-adevăr GSgt currentlinewidth pstack ne dă 10)

6

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 7: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

2 6 2 e l l i p s e centrul este la 2in de marginea stacircngă şi 6in de baza paginii 3 setlinewidth grosimea bdquorealărdquo a liniei este 0372=216bp 4 setgray nuanţa de negru pentru trasarea linieistroke trasează conturul (pe ecran sau pe hacircrtie)

Transmiţacircnd fişierul imprimanteimdashlpr graficepsmdashobţinem o paginăconţinacircnd elipsa respectivă2 Am prevăzut o grosime aşa de mare (216bp =0762 milimetri) pentru trasarea elipsei icircn scopul de a testa cum arată elipsadacă n-am mai salvarestaura CTM

Icircn stacircnga imaginii avem elipsa produsă prin programul de mai sus (cusalvare şi restaurare CTM) iar icircn dreapta aceeaşi elipsă (deplasată puţin spredreapta prin translate) produsă printr-o dublură a programului icircn care icircnsăam eliminat cele două linii pentru salvarerestaurare CTM Desigur aici amredat imaginea cu o anumită micşorare (pe hacircrtie grosimea liniei pentru primaelipsă este de 7-8 milimetri) dar se vede suficient de bine că icircn cazul elipseidin dreapta grosimea liniei este variabilă (ajungacircnd de două ori mai mare peaxa mare decacirct pe axa mică)

3 Producerea şi trasarea liniilor (fişierul graficeps)

Icircn sect2 am descris elipsa asumacircnd că semiaxa mică şi centrul ei sunt trans-mise prin stivă (vracircnd să experimentăm şi să lămurim aspecte privitoare la stiveproceduri variabile şi transformări PS) De fapt toate elementele necesare pro-gramului lsquograficepsrsquo planificat icircn sect1 decurg din descrierea parametrică apunctelor semicardioidei K (v Anexa B)

K(t) =(

X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t))

t isin [0 1]

Semiaxa mare a lui E este a = 1 semiaxa mică este b = 4t(1 minus t)iar focarele sunt punctele K(t) şi K(1 minus t) Centrele elipselor E (cacircnd t

variază) aparţin arcului de parabolă P ale cărui puncte sunt date de ecuaţiay =

radic1 minus x pentru x isin [0 1]

Corespunzător icircn graficeps am avea aceste definiţii iniţiale2precizarea bdquodacă imprimanta dispune de un interpretor propriu de PSrdquo a devenit

inutilă icircn zilele noastre

7

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 8: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

PS-Adobe-20 EPSF-20BoundingBox 50 53 387 165

K(t) are ecuaţiile X(t) = 2t(2t minus 1) Y (t) = 4tradic

t(1 minus t) t isin [0 1]X 2 mul dup 1 sub mul bind def t este dat icircn vacircrful stiveiY dup dup 1 exch sub mul sqrt mul 4 mul bind def

focarele K(t) şi K(1-t) semiaxa mică centrul elipsei şi arcele razelor focaletL 025 def un t icircntre 0 şi 1 (vizacircnd arcul lui K(t) din stacircnga axei Oy)tR 1 tL sub bind def 1-t (vizacircnd arcul lui K(t) din dreapta axei Oy)Sb 4 tL tR mul mul bind def semiaxa mică a elipsei Sb = 4t(1-t)x1 tL X def y1 tL Y def coordonatele punctului K(tL)x2 tR X def y2 tR Y def coordonatele punctului K(tR)xC x1 x2 add 2 div bind def coordonatele mijlocului C(t) alyC y1 y2 add 2 div bind def segmentului K(tL)mdashK(tR) arc2 y2 x2 atan bind def arcul dintre Ox şi raza focarului K(tR)

vom marca unele puncte prin mici discurirp 12 72 div bind def raza discului prin care marcăm un punctpunct 03 setgray rp 0 360 arc f i l l bind def

Am ales pentru t o valoare convenabilă tL=025 am obţinut coordona-tele punctelor K(tL) şi K(tR=1-tL) (aflate pe K icircn stacircnga şi icircn dreapta axeiOy) aplicacircnd operatorii X şi Y valorilor tL şi tR

y2 x2 atan dă α2 = arctg y2

x2 astfel că 0 0 025 0 arc2 arc va pro-duce arcul de cerc cu centrul icircn originea sistemului curent de coordonate curaza 025 (faţă de unitatea de măsură aflată icircn uz icircn momentul trasării ulterioareprin stroke) icircncepacircnd icircn sens antiorar de la axa Ox şi icircncheiat la α

2 Arceleproduse astfel prin arc2 şi arc1=180-arc2 vor marca unghiurile cu Oxale razelor polare corespunzătoare focarelor lui E (unghiuri care sunt egaleicircnsemnacircnd că E este tangentă icircn O la Ox)

Pentru a putea marca anumite puncte am definit procedura punct (nuexistă un operator predefinit care să bdquotrasezerdquo un punct) folosind arc fillse trasează un disc (cerc umplut cu o nuanţă de gri icircnchis) cu raza foartemică (puţin peste 1bp) avacircnd centrul icircn punctul ale cărui coordonate vor fipreluate de pe stivă

Procedurile introduse mai sus xC yC şi Sb ne dau pentru E coordonatelecentrului şi semiaxa mică - icircncacirct putem acum icircnlocui procedura rsquoellipsersquodin sect2 cu elipsa cu semiaxele a=1 şi b=Sb centrată icircn (xCyC) tangentă icircn O la Ox E l l i p s e

savematrix matrix currentmatrix def salvează CTMxC yC translate translatează icircn centrul elipseiSb sqrt 1 atan rotate roteşte cu arctan

radicba

1 Sb scale scalează orizontal cu a şi vertical cu b0 0 1 0 360 arc bdquocercrdquo de centru (00) bdquorazărdquo 1 (=a pe Ox şi =b pe Oy)savematrix setmatrix restaurează CTM (bdquocurrent transform matrixrdquo)

bind def

8

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 9: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Producem semicardioida prin puncte cacirct mai apropiate (unite prin seg-mente) generacircnd (prin repeat) N=1000 de puncte ale lui K aproximare poligonală (cu N=1000 de segmente) a semicardioideiKardioid

N 1000 defdt 1 N div def pasul dt = 0001 t 0 def t va parcurge intervalul (01) cu pasul dt0 0 movetoN t t dt add def t = t+dt

t X t Y lineto segment de la K(t) la K(t+dt) repeat

bind def

Generăm (tot bdquopunct cu punctrdquo) şi P unind punctul curent (iniţializat icircnvacircrful parabolei) cu cel corespunzător prin

radic1 minus x abscisei depuse pe stivă

la iteraţia următoare (prin mecanismul asigurat de for) coboracircnd abscisa cucacircte 001 dinspre 1 spre 0 (obţinacircnd o aproximare cu 100 de segmente a lui P) arcul de parabolă y =

radica(a minus x) x isin [0 a] unde aici a = 1

Parabola 1 0 moveto vacircrful parabolei este punctul (10)1 minus01 0

dup neg 1 add sqrt lineto for

bind def

Precizăm că From Step To Proc for decurge cam aşa se depune pestivă valoarea iniţială From (aici abscisa 1) şi se execută Proc apoi valoareadin vacircrful stivei este bdquomajoratărdquo cu Step (aici cu -001 rezultacircnd abscisautilizată icircn următoarea iteraţie icircn Proc) şi dacă astfel nu se bdquodepăşeşterdquo Tose repetă executarea secvenţei Proc şamd Pe parcurs icircn vacircrful stiveigăsim abscisa x curentă (1 apoi 099 098 hellip 0) pe care Proc o poatefolosi adăugacircnd-o icircncă o dată icircn stivă (prin dup)

Bineicircnţeles că putem testa graficeps icircn orice moment adăugacircnd osecvenţă icircn care mărim convenabil unitatea de măsură translatăm mai sprecentrul paginii setăm o anumită grosime de trasare şi apoi invocăm proce-durile pentru E K şi P bdquoprogramul principalrdquo scalează poziţionează trasează liniileum 60 def unitatea de măsurăum um scale1 5 1 translate originea figurii 15um de marginea stacircngă 1um de jos

01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke

005 setlinewidth 0 1 setgray E l l i p s e stroke0 0 1 setrgbcolor 005 setlinewidth Parabola stroke

Obţinem prima figură dintre cele două redate mai jos ne-a rămas deadăugat focarele şi centrul elipsei segmentele aferente acestora şi cele douăarce egale prin care sugerăm că E este tangentă axei orizontale ca să evităm

9

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 10: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

bdquoapelareardquo separată constituim o procedură rsquoother_linesrsquo care să conţinătoate aceste construcţii other_l ines

marchează individual punctele K(t) K(1-t) şi C(t)x1 y1 punctx2 y2 punctxC yC punct

triunghiul K(tL) mdash K(tR) mdash origine (mdash closepath)x1 y1 moveto K(t)x2 y2 lineto K(1-t)0 0 lineto closepath

axele Ox Oy uneşte vacircrful parabolei cu centrul elipsei205 0 minus035 0 moveto lineto Ox (de la abscisa -03 pacircnă la 205)0 1 5 0 minus01 moveto lineto Oy (vertical -01 15)1 0 xC yC moveto lineto segmentul C(t)mdash(10)

arcele dintre razele focarelor şi Ox0 0 025 0 arc2 arc stroke0 0 025 180 arc2 sub 180 arc stroke

bind def

Translatacircnd sistemul de coordonate spre dreapta (de exemplu prin 290 translate) repetacircnd cele trei linii din programul principal prin care setrasează K E şi P şi adăugacircnd linia 0 setlinewidth other_lines strokeobţinem şi a doua figură

Rămacircne să etichetăm focarele centrul elipsei şi eventual curbele respec-tive desigur fontul angajat pentru etichete ar trebui să se potrivească (catip de literă şi ca mărime) celui folosit icircn text

Dar icircnainte de aceasta să precizăm că figura inserată mai sus este unfişier PDF (şi nu o copie-ecranmdashfişier PNGmdashcare arăta mai rău pe lacircngă faptulcă ar fi fost de cacircteva ori mai voluminos) obţinut icircntr-o manieră tipicăvbHome~ keps$ gs minusq minuso dev nu l l minussDEVICE=bbox g r a f i c eps

BoundingBox 50 53 387 165

vbHome~ keps$ ps2pdf g r a f i c eps rezultă rsquograficpdfrsquo

vbHome~ keps$ gs minussDEVICE=pdfwrite minuso keps1 pdf minusf g r a f i c pdf minusc rdquo [ CropBox [50 53 387 165] PAGES pdfmarkrdquo

10

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 11: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Am invocat gs cu bbox pentru a obţine valoarea BoundingBox pentrufigura creată prin programul rsquograficepsrsquo şi apoi cu pdfwrite pentru ainsera (prin mecanismul rsquopdfmarkrsquo) declaraţia CropBox (corespunzătoare cuBoundingBox) icircn fişierul PDF rezultat prin ps2pdf

31 Eroare experiment şi descoperireSituaţiile de bdquoeroarerdquo icircn pofida aparenţei de bdquosurpriză neplăcutărdquo sunt in-structive provocacircnd chiar asemenea situaţii şi experimentacircnd icircn contextulrespectiv poţi ajunge să clarifici aspecte care de obicei sunt vizate expeditivici şi colo

Dacă icircn procedura Kardioid din rsquograficepsrsquo icircnlocuim bdquoN 1000 defrdquode exemplu cu bdquoN 10 defrdquo atunci obţinem un mesaj de eroarevbHome~ keps$ gs minusq g r a f i c epsError rangecheck in minusminussqrtminusminusOperand stack

2 0 1 0 minus119209eminus07Execution stack

Chiar neplăcuthellip pentru 1000 merge dar pentru 10 nu Dar să profi-tăm de faptul că N este mic (şi să ignorăm deocamdată mesajul afişat de GS)inserăm nişte instrucţiuni de afişare intermediară a unor valori curente fo-losind operatorul rsquo == rsquo (atenţie spaţiul iniţial şi cel final sunt obligatorii) Icircncazul de faţă am insera rsquot == rsquo icircn instrucţiunea repetitivă rsquoN repeatrsquo(unde acum N=10)

N t t dt add def t = t+dt (unde dt = 1N = 01)t == afişează valoarea t curentăt X t Y lineto segment de la P(t) la P(t+dt)

repeat

şi după aceasta putem vedea cum decurg lucrurilevbHome~ keps$ gs minusq g r a f i c eps0 10 20 30 40 50 60700000048 06 + 01 ()08000000720900000095100000012Error rangecheck in minusminussqrtminusminus

Procedura eşuează imediat după ce t ajunge la valoarea 100000012deci la calculul coordonatelor X(t) şi Y(t) ale capătului segmentului curentajunge să te uiţi la definiţiile iniţiale pentru a vedea despre ce este vorbaY(t) = 4t sqrt(t(1-t)) ori pentru ultima valoare a lui t avem 1-t lt 0

11

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 12: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

ndash ceea ce determină semnalarea de la icircnceputul mesajului de eroare pe careacum o putem şi simula directvbHome~ keps$ gs minusqGSgt 1 100000012 sub pstack sqrtminus11920929eminus07 rezultatul scăderii 1 - 100000012Error rangecheck in minusminussqrtminusminusOperand stack

minus119209eminus07

Dar altceva este interesant de observat icircn experimentul de mai sus tavea valoarea iniţială 0 şi este incrementat la fiecare iteraţie cu 01 icircnsă după06 urmează mai sus 0700000048 şi nu 07 Propagarea acestor erori deaproximare explică faptul că se depăşeşte limita 1 ajungacircndu-se icircn situaţiade eroare evidenţiată mai sus

Majoritatea limbajelor de programare (inclusiv PostScript) mizează pe oreprezentare floating point a numerelor reale (o excepţie notabilă este limbajulTeX creat pe cacircnd icircncă nu apăruse standardul bdquofloating pointrdquo pentru a repera cacirctmai fin bdquopunctelerdquo unei pagini de hacircrtie Knuth a introdus reprezentarea numerelorreale ca multipli icircntregi de 2minus16)

Din cauza erorilor de aproximare inerente se recomandă ca variabilacare asigură iterarea icircn cadrul unei secvenţe repetitive să fie de tip icircntreg

Şi icircn PostScript avem de distins icircntre reprezentarea (şi operarea) internăa numerelor şi pe de altă parte afişarea acestora - cum arată acest micexperimentvbHome~ keps$ gs minusqGSgt h 01 def h = 01GSgt g h 06 add def g = h + 06GSgt g =07 valoarea afişată pentru liniştea noastrăhellipGSgt g ==0700000048 valoarea utilizată intern

rsquo = rsquo afişează dacă se poate cam cum ne-am dori icircn schimb rsquo == rsquo (şiicircncă rsquo === rsquo pentru anumite alte obiecte PS) produce pe ecran valoarea internăexistentă (şi aceasta este cea utilizată icircn calcule)

32 De la semicardioidă la cardioidă cu pathforall

Kardioid instituie icircn memorie conturul poligonal al semicardioidei superi-oare vom arăta că prin pathforall putem obţine de aici conturul icircntregiicardioide

Să constituim un fişier nou rsquocardioidepsrsquo icircn care să rescriem deocam-dată procedura Kardioid avacircnd grijă de această dată să ghidăm iteraţiileprin icircntregi

12

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 13: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

PS coordonatele punctelor semicardioidei (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1)Y dup dup 1 exch sub mul sqrt mul 4 mul

bind def Y (t) = 4tradic

t(1 minus t)N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din t=0 (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

1 1 N N div dup X exch Y lineto for funcţionează cam aşa lafiecare iteraţie se depune pe stivă valoarea curentă a indexului i = 1NN div adaugă N pe stivă icircmparte i la N elimină cei doi operanzi din stivă şipune icircn loc rezultatul iN mai departe dup adaugă a doua oară icircn stivă iNiar X calculează abscisa punctului K(iN) şi pune rezultatul icircn locul acesteicopii - icircncacirct acum stiva conţine vechea valoare iN şi deasupra acesteiaabscisa rezultată exch interschimbă icircntre ele aceste două valori icircncacirct apoiY poate calcula ordonata lui K(iN) după aceasta icircn stivă avem abscisa şiordonata punctului K(iN) iar lineto va adăuga conturului segmentul dela ultimul său punct la K(iN)

bdquoConturulrdquo final este format din instrucţiunea rsquo0 0 movetorsquo şi N=1000de instrucţiuni lineto pentru segmentele care unesc K((i-1)N) cu K(iN)unde i=1N Putem bdquovedeardquo conturul (adică instrucţiunile constituente)folosind operatorul pathforall trebuie să-i transmitem pe stivă patruproceduri vizacircnd respectiv instrucţiunile moveto lineto curveto şiclosepath din componenţa conturului curent icircn fiecare caz sunt plasatepe stivă coordonatele punctelor angajate icircn instrucţiune şi apoi se executăprocedura transmisă pentru acel tip de instrucţiune

De exemplu dacă după ce am constituit un contur am invoca = = pathforall atunci s-ar afişa coordonatele din toate instruc-ţiunile moveto ale conturului respectiv (şi numai acestea fiindcă celelalte treiproceduri transmise sunt vide) pentru fiecare instrucţiune x y moveto exis-tentă icircn conturul curent pathforall va pune icircn stivă x y şi va executaprocedura indicată = = ceea ce extrage pe racircnd cele două valori dinstivă şi le afişează una sub alta (rsquo = rsquo este suficient pentru aceasta dar mai bineeste să folosim rsquo == rsquo ndash cum am arătat la sect31)Afişarea bdquouna sub altardquo a valorilor este foarte convenabilă dacă intenţionămsă le preluăm ulterior icircntr-un alt program (indiferent icircn ce limbaj) pentruanumite prelucrări independente dar putem să le afişăm şi icircntr-un formatmai bdquoconvenabilrdquo icircnlocuind rsquo = = rsquo cu [3 1 roll] == se adaugă icircnstivă obiectul (de tip bdquoarrayrdquo) [] icircncacirct acum stiva conţine x y [3 1roll] apoi se execută instrucţiunea din interior 3 1 roll prin care conţi-nutul stivei este rotit spre dreapta şi este icircnlocuit cu un singur bdquoarrayrdquoanume [x y] (pentru a cărui afişare este acum necesar rsquo == rsquo) Putem verifica

13

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 14: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

direct icircn GS de exemplu GSgt 72 56 [3 1 roll] == produce GSlt1gt[72 56]

Icircnsă pathforall poate fi utilizat şi icircn scopuri mai interesante decacirctsimpla afişare de valori ndash anume pentru modificarea sau extinderea con-turului curent Să adăugăm icircn fişierul cardioideps o secvenţă prin careprevedem o unitate de măsură şi o grosime de linie convenabile mutăm ori-ginea undeva mai la mijlocul paginii şi apoi invocăm procedura Kardioidobţinacircnd conturul semicardioidei superioare invocacircnd pathforall cu o pro-cedură pentru instrucţiunile x y lineto icircn care schimbăm semnul ordona-telor (folosind neg) conturului curent icirci vor fi adăugate noile instrucţiunix -y lineto icircncacirct icircn final conturul va conţine segmentele iniţiale ale semi-cardioidei superioare dar şi pe cele simetrice acestora faţă de Ox Icircn finalafişăm conturul astfel bdquoicircntregitrdquo folosind din nou pathforall90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea figurii 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

Kardioid constituie conturul poligonal al semicardioidei superioare

adaugă bdquoaceleaşirdquo segmente dar schimbacircnd semnul ordonatelormoveto [3 1 ro l l neg lineto ]

pathforall rezultă conturul icircntregii cardioide

afişează instrucţiunile conturului curent (după bdquoicircntregirerdquo) [3 1 ro l l ] == [x y] din instrucţiunile rsquomovetorsquo ale conturului [3 1 ro l l ( lineto ) ] == [x y lineto]

pathforall

clear curăţă stiva (cum-necum au rămas 4 tablouri vide)stroke trasează efectiv cardioida (nu numai semicardioida)

Pentru exemplu să redefinim N 4 def şi să lansăm programul sub GSvbHome~ keps$ gs minusq card io id eps[2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 0433032304 ( lineto ) ][2 53962298 eminus05 0999998689 ( lineto ) ][0 750012338 129901314 ( lineto ) ][1 99999058 161245898 eminus05 ( lineto ) ][2 53962298 eminus05 161245898 e minus05] moveto[ minus0250021845 minus0433051646 ( lineto ) ][2 53962298 eminus05 minus1000018 ( lineto ) ][0 750012338 minus129903245 ( lineto ) ][1 99999058 minus354741eminus05 ( lineto ) ]GSgt

Se vede că au rezultat nu numai cele 4 segmente care bdquoaproximeazărdquo semi-cardioida superioară dar şi simetricele acestora faţă de Ox de observat icircnsăcă neg nu a schimbat pur şi simplu semnele ci a şi evaluat cumva rezultacircnd

14

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 15: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

obişnuitele bdquoerori de aproximarerdquo (astfel 0433032304 a ajuns -0433051646ceea ce diferă de valoarea corectă -0433032304 cu vreo două sutimi de miime) Icircnorice caz pentru N=4 şi respectiv N=1000 obţinem (micşoracircnd icircnsă unitateade măsură la 30bp) imaginile următoare

Subliniem că trasarea conturului pentru N=1000 necesită execuţia a 2002instrucţiuni (două moveto şi 1000 + 1000 instrucţiuni lineto) vom arăta acuşică putem trasa cardioida (şi alte curbe) cam cu aceeaşi acurateţe (totuşihelliparătacircnd mai bine) dar cu un contur conţinacircnd mult mai puţine instrucţiuni(anume instrucţiuni curveto) Am avansa ideea cam aşa dacă icircn loc decele 4 segmente din prima figură am considera nişte arce curbate cumva bdquodinochirdquo sau din ecuaţiile curbei iniţiale atunci conturul constituit de acesteaar fi oricum bdquomai bunrdquo decacirct cel poligonal iniţial

33 De la semicardioidă la cardioidă simetrizacircnd faţă de axăMai sus am urmat o idee exotică am extins prin pathforall conturulsemicardioidei superioare obţinacircnd conturul icircntregii cardioide (pentru fiecareinstrucţiune x y lineto existentă am adăugat conturului iniţial şi x -y lineto)dar astfel am putut evidenţia ce este de fapt un bdquoconturrdquoSă revenim la calea firească bdquoicircntregimrdquo cardioida simetrizacircnd faţă de axaOx conturul semicardioidei (icircn loc să-l extindem cum am făcut anterior)

Icircntacirci avem de subliniat că nu merge o schemă de lucru icircn care conturulsă fie instanţiat o singură datăKardioid adaugă conturului curent şi semicardioida superioară Kgsave stroke grestore trasează conturul curent (K se păstrează)gsave

1 minus1 scale inversează sensul pe axa Oy (vracircnd semicardioida inferioară)stroke trasează conturul curent K nu este inversat

grestore

stroke trasează conturul curent şi trebuie să se ţină seama de situaţiaobişnuită cacircnd acesta conţine şi alte contururi nu numai pe acela căruia icircnprealabil ai vrea să-i aplici o anumită transformare Decurge firesc aceastăregulă după ce se indică transformarea trebuie precizat cumva şi conturulcăruia icirci va fi aplicată aceasta perechea de operatori gsave şi grestoredeservesc şi ei acest principiu de lucru (permiţacircnd comutarea temporară icircntr-un context grafic nou)

Ţinacircnd seama de regula menţionată programul din sect32 se rescrie astfel

15

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 16: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

PS coordonatele punctelor semicardioidei K(t) (t fiind icircn vacircrful stivei)X 2 mul dup 1 sub mul bind defY dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def N 4 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (vacircrful cardioidei)1 1 N N div dup X exch Y lineto for

bind def

90 90 scale 90bp = 72bp + 18bp = 125 inch (= 4175 cm)1 5 5 translate originea 135bp de marginea stacircngă 450bp de jos005 setlinewidth 0005 din 90bp

gsaveKardioid instanţază (şi trasează) conturul semicardioideistroke

grestore

gsave1 minus1 scale (xy) ndashgt (x-y) (simetrie faţă de axa Ox curentă)Kardioid instanţiază (pentru noul xOy) conturul semicardioidei1 0 0 setrgbcolor stroke

grestore

Iteracircnd programul pentru N=4 (caz icircn care este uşor de văzut conţinutulconturului icircnainte şi după simetrizare cu pathforall) şi N=1000 obţinem

N = 4 N = 1000

Acum fiindcă am folosit un acelaşi contur de două ori putem şi distinge(aici prin culoare) icircntre cele două semicardioide (spre deosebire de sect32 undeicircntacirci am bdquoicircntregitrdquo conturul şi apoi l-am plotat ca atare ceea ce exclude posibilitateamarcării separate a părţilor) Să observăm icircnsă că de executat sunt tot 2N+2instrucţiuni cacircte una moveto şi cacircte N lineto pentru fiecare dintre celedouă instanţe ale conturului

4 Etichetarea directă folosind un font obişnuitPentru a eticheta anumite elemente ale graficului poate fi suficient să anga-jăm un font obişnuit adăugăm icircn rsquograficepsrsquo de exemplu Helvet i ca findfont 018 scalefont setfont(F) x2 y2 004 add moveto show eticheta rsquoFrsquo pentru punctul K(tR)

16

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 17: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

(F rsquo ) x1 016 sub y1 006 sub moveto show dar bdquoprimrdquo va fi ca o virgulă(C) xC 006 sub yC 006 add moveto show

Am mărit puţin ordonata (cu 004 din unitatea de măsură curentă prevăzutăicircn bdquoprogramul principalrdquo din graficeps) am mutat aici bdquopunctul curentrdquo şiapoi show a afişat caracterul rămas icircn vacircrful stivei (F) am procedat analogpentru celelalte etichete Obţinem astfel prima dintre cele două figuri dinfişierul PDF vizualizat mai jos

Ar fi de făcut nişte precizări am indicat numele fontului rsquoHelveticarsquo(prefixat cu rsquorsquo icircncacirct să nu fie considerat ca invocare de operator) findfontcaută icircn dicţionarul de fonturi cheia indicată şi depune pe stivă dicţionarulasociat ei acesta conţine icircntre altele cacircte un operator pentru fiecare caracter(denumit ca şi caracterul rsquoArsquo rsquoBrsquo etc) acest operator bdquodeseneazărdquo caracterulrespectiv folosind ca de obicei cacircnd este de trasat un grafic moveto linetoşi curveto este asumat sistemul de coordonate curent şi fiindcă unitatea demăsură setată icircn graficeps era bdquomarerdquo (1 equiv 60bp) am folosit scalefont- obţinacircnd caractere cu o dimensiune bdquonormalărdquo 018times60bp asymp 11bp Dicţio-narul astfel setat icircn stiva operanzilor este apoi transferat prin setfont icircnvacircrful stivei dicţionarelor de fonturi devenind astfel bdquofontul curentrdquo pentruviitoarele instrucţiuni bdquo(text) showrdquo

F

Frsquo

C

K1-t

Kt

C

Pe de altă parte ar fi de dorit ca etichetele să nu fie nişte simple repereci să fie astfel formulate icircncacirct să reflecte cacirct mai bine contextul matematic alfigurii de exemplu notacircnd Kt şi K1-t icircn loc de Frsquo şi F ndash s-ar evidenţia faptulcă focarele sunt puncte ale semicardioidei K deduse dintr-o parametrizarea acesteia cu valori t simetrice faţă de mijlocul 05 al intervalului [0 1]

Pentru acest caz cacircnd ar trebui doar să adăugăm nişte indici este icircncăuşor să folosim un font obişnuit (rezultacircnd figura din dreapta)CourierminusBold findfont 018 scalefont setfont(K) x2 y2 004 add moveto show0 minus004 rmoveto coboară puţin punctul curent pentru a adăuga indicele tgsave 75 75 scale mărimea indicelui va fi 34 din mărimea curentă de caracter(1minust ) showgrestore(K) x1 0 2 sub y1 006 sub moveto show

17

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 18: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

002 minus004 rmovetogsave 75 75 scale( t ) showgrestore(C) xC 006 sub yC 006 add moveto show

Desigur am ambalat modificarea mărimii curente de caracter (rezultatăaici prin scalarea sistemului de coordonate) şi afişarea indicelui respectiv icircntregsave şi grestore (care salvează şi restaurează contextul grafic curent icircncacirctmodificările din interior sunt bdquoascunserdquo faţă de exterior)

Icircnsă dacă avem nevoie şi de alte tipuri de literă sau de expresii mate-matice mai complicate atunci icircn loc să ne jucăm ca mai sus cu un bdquofontobişnuitrdquo mai bine căutăm o metodă generală pe care să o putem aplicaicircntr-un mod standard pentru oricare figură şi pentru oricare necesităţi deetichetarehellip

5 Icircncapsularea icircn figură a notaţiilor matematiceBineicircnţeles că există o asemenea bdquometodă generalărdquo pentru a integra icircndocumente notaţia matematică icircn toată complexitatea specifică acesteia şicu asigurarea unei foarte bune calităţi tipografice sistemul de tipografiedigitală TEX folosit curent icircn mediile ştiinţifice (sistem creat prin 1970-80de către D Knuth)

Dar vracircnd să obţinem o figură bdquoindependentărdquo trebuie să combinămcumva fişierul nostru rsquograficepsrsquo (fără liniile experimentate icircn sect4) cu etiche-tele matematice pe care le-am obţine folosind direct TeXVom proceda cam aşa creem un document bdquotexrdquo minimal conţinacircnd ex-primarea TeX a etichetei dorite compilăm cu latex acest fişier obţinacircndfişierul corespunzător icircn formatul DVI de aici cu programul dvips ajun-gem la formatul bdquoepsrdquo al etichetei respective fişier pe care icircl vom puteabdquocombinardquo apoi cu rsquograficepsrsquoBineicircnţeles vom căuta să automatizăm această succesiune de operaţii avacircndicircn vedere şi faptul că sunt de montat mai multe etichete

Instituim un şablon minimal de fişier LaTeX rsquomathLabelstexrsquo icircn caresă putem scrie expresia TeX a unei etichetedocumentclass a r t i c l e usepackage xco lor icircn eventualitatea că vrem să colorăm o etichetăusepackage [ mathscr ] euscript majuscule caligrafice (existente şi icircn text)pagestyleemptybegindocument$ $ aici se va scrie eticheta (icircntre caracterele bdquodolarrdquo)enddocument

Nu este mai convenabil să scriem icircn acest fişier toate formulele arfi complicat de identificat zona din pagină asociată fiecăreia (şi de stabilitdimensiunile acesteia) icircn cadrul fişierului bdquoepsrdquo final

18

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 19: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Constituim un fişier-text rsquolabelstxtrsquo conţinacircnd etichetele noastre icircnnotaţia matematică TeX (fiecare pe cacircte o linie) dar fără delimitatori rsquo$rsquoK_tK_1minust C_tcolorred mathscrKmathscrEcolor blue mathscrP

Am avut grijă să dublăm caracterul rsquobackslashrsquo (folosit de TeX pentru a de-semna o comandă) fiindcă acest caracter are de obicei semnificaţie specialămdashcare se evită prefixacircnd cu rsquorsquomdashicircn diverse limbaje pe care le-am putea folosimai departe

Formulăm acum un program Bash rsquobuildEPSshrsquo prin care se preiacacircte o linie de text din fişierul labelstxt se scrie textul respectiv icircn fişie-rul mathLabelstex icircn locul rezervat etichetei (am ales să folosim sed pentruaceasta) apoi se lansează compilatorul latex şi se transmite rezultatul obţi-nut astfel programului dvipsbinbashl a b e l s =( lsquocat l a b e l s txt lsquo )i=1for lb in rdquo$ l a b e l s [] rdquodo

sed minus i rdquo s $ lowast $ $$lb $grdquo mathLabels texlatex mathLabels texdvips minusE mathLabels dvi minuso Label$ i eps( ( i++))

done

Putem folosi awk (de pe linia de comandă) pentru a extrage şi a afişa coor-donatele colţurilor boxei care conţine desenul etichetei din cadrul declaraţieirsquoBoundingBoxrsquo existente icircn fişierele bdquoLabelepsrdquo rezultate prin execuţiascriptului Bash de mai susawk rsquoBoundingBox pr int $2 $3 $4 $5 FILENAME rsquo Label lowast eps148 655 162 665 Label1 eps produce eticheta Kt

148 654 172 665 Label2 eps K1minust

148 655 161 665 Label3 eps Ct

148 656 158 665 Label4 eps K

148 656 156 665 Label5 eps E

148 656 156 665 Label6 eps P

Aceste coordonate ne sunt necesare pentru a stabili ce translaţie avemde făcut pentru a poziţiona eticheta respectivă icircn locul cuvenit icircn cadrul pa-ginii produse de graficeps de exemplu -148 -655 translate va aduceprima etichetă icircn colţul stacircnga-jos al paginii care conţine graficul produs degraficeps şi rămacircne de calculat (sau de estimat prin icircncercări) ce translaţiemai trebuie făcută icircncacirct s-o aducem lacircngă focarul Kt

Icircn rsquograficepsrsquo am icircnfiinţat deja operatori (x1 y1 etc) care ne dau coor-donatele punctelor pe care vrem acum să le etichetăm şi de aceea este firesc

19

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 20: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

să icircncercăm să icircncorporăm fişierele bdquoLabelepsrdquo chiar icircn rsquograficepsrsquo (icircnloc de a icircncorpora toate cele şapte fişiere EPS icircntr-un fişier nou bdquopackepsrdquocum ne propusesem iniţial icircn sect1)

Sunt de icircntacircmpinat două probleme cum obţinem icircn rsquograficepsrsquo co-ordonatele colţurilor etichetelor (evitacircnd să operăm direct cu valorile 148 655etc) cum modelăm calculele necesare aducerii etichetelor icircn locurile cuveni-te din figură avacircnd icircn vedere că sistemul de coordonate icircn care este produsăfigura diferă de cel icircn care sunt produse etichetele

51 Citirea valorilor BoundingBox

Fiind create automat (la fel) fişierele Labeleps au acelaşi bdquopreambulrdquo şiconţin BoundingBox pe a cincea liniePS-Adobe-20 EPSF-20Creator dvips(k) 5997 Copyright 2017 Radical Eye SoftwareTitle mathLabelsdviCreationDate Tue Jul 2 052739 2019BoundingBox 148 655 162 665

Pacircnă la icircnregistrarea colţurilor etichetei apar icircn total 166 de caracterefolosim operatorul file pentru a deschide icircn vederea citirii fişierul respectivfolosim setfileposition pentru a poziţiona citirea de la al 166-lea caracterşi bdquocitimrdquo de aici 15 caractere (cacircte 3 cifre de colţ şi 3 spaţii intermediare) apoifolosim ( ) search pentru a depune pe stivă pe racircnd fiecare grup de cacircte3 cifre consecutive transformacircndu-l imediat icircn număr icircntreg prin tokenreadBB numele fişierului este preluat din stivă

f l b exch ( r ) f i l e deff l b 166 setf i leposit ionf l b 15 string readstring popf l b c lose f i l e pstack (şirul de 15 caractere citit)3 ( ) search pop parcurge pacircnă la primul spaţiu şi icircncarcă pe stivă

token pop converteşte şirul de cifre icircn număr icircntreg3 1 ro l l pop pop exch repeat

token pop exch pop pstack (avem pe stivă cele 4 coordonate) bind def

Am folosit pop (de cacircteva ori) pentru a elimina din stivă informaţiilede care suntem siguri că nu avem nevoie de exemplu readstring şi tokenadaugă icircn stivă true sau false semnalacircnd că operaţia a reuşit sau nu iarsearch adaugă icircn stivă şi partea din şir rămasă după subşirul căutat (şiam folosit 3 1 roll pentru a aduce icircn vacircrful stivei subşirul de 3 cifre respectiveliminacircnd apoi celelalte subşiruri produse de search)

Aplicăm procedura rsquoreadBBrsquo fiecăruia dintre fişierele bdquoLabelepsrdquo fo-losind forall

20

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 21: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

[ ( Label6 eps ) ( Label5 eps ) ( Label4 eps )( Label3 eps ) ( Label2 eps ) ( Label1 eps ) ]

readBB4 array astore tablou (ldquoarrayrdquo) conţinacircnd cele 4 coordonate

fora l l pstack (cele 6 tablouri de coordonate)

Prin astore cele 4 valori rezultate icircn stivă (la fiecare iteraţie) sunt coma-sate icircntr-un tablou (icircncacirct vom putea accesa mai comod colţurile respective) Deobservat că am transmis numele fişierelor bdquoicircn ordine inversărdquo icircncepacircnd cursquoLabel6epsrsquo astfel cele 6 tablouri de coordonate vor fi aşezate icircn stivă icircnordinea firescă icircn care urmează să le prelucrăm icircncepacircnd (icircn vacircrful stivei)cu cel corespunzător lui rsquoLabel1epsrsquo

Desigur includem aceste secvenţe de program icircn fişierul rsquograficepsrsquo(undeva icircnainte de bdquoprogramul principalrdquo) putem constata rezultatul (decomen-tacircnd pstack de după forall pentru a afişa conţinutul final al stivei)vbHome~ keps$ gs minusq g r a f i c eps[148 655 162 665] colţurile etichetei din Label1eps[148 654 172 665][148 655 161 665][148 656 158 665][148 656 156 665][148 656 156 665] colţurile etichetei din Label6eps)

Aceste coordonate ne vor servi pentru a calcula dimensiunile boxelor (icircnvederea repoziţionării etichetelor) de exemplu obţinem lăţimea boxei extră-gacircnd cu get abscisele colţurilor de la bază şi scăzacircndu-le cum descriem icircnacest mic experimentvbHome~ keps$ gs minusqGSgt [148 655 162 665] Lx Ly Ux Uy (colţurile boxei)GSlt1gt dup pstack[148 655 162 665][148 655 162 665]GSlt2gt 2 get pstack abscisa colţului dreapta-jos (Ux)162 tabloul din vacircrful stivei este icircnlocuit cu valoarea extrasă[148 655 162 665]GSlt2gt exch pstack aduce tabloul iarăşi icircn vacircrful stivei[148 655 162 665]162GSlt2gt 0 get sub = extrage Lx (=148) face scăderea şi afişează rezultatul14 Ux - Lx = 14 = lăţimea boxeiGSgt quit

Putem reformula mai simplu instituind o variabilă de memorie care săpreia tabloul din vacircrful stiveivbHome~ keps$ gs minusqGSgt [148 655 162 665]GSlt1gt BB exch def variabila rsquoBBrsquo preia valoarea (tablou) din vacircrful stiveiGSgt BB 2 get BB 0 get sub = obţine lăţimea boxei (14)

Este de subliniat că fiecare nouă invocare a variabilei denumite mai susrsquoBBrsquo va produce ca valoare tabloul aflat la momentul respectiv icircn vacircrful stivei

21

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 22: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

(şi nu un acelaşi tablou) icircncacirct odată definită vom putea folosi o asemeneavariabilă pentru toate etichetele noastre

52 Poziţionarea etichetelor pe figurăMai sus am citit din fişierele bdquoLabelepsrdquo şi după ce am extras ce netrebuie le-am icircnchis (folosind closefile) dar ceea ce avem de făcut defapt este să icircncapsulăm programele EPS respective icircn rsquograficepsrsquoPentru aceasta icircn principiu trebuie să folosim operatorul run de exemplu(Label1eps) run icircncorporează şi execută instrucţiunile din lsquoLabel1epsrsquobdquoredesenacircndrdquo eticheta respectivăNumai că executarea instrucţiunilor bdquostrăinerdquo icircncorporate astfelmdashdacă estepermisămdashdecurge de regulă după ce pagina curentă este ştearsă (ejectată) şisistemul grafic este reiniţializat (icircncacirct bdquoredesenareardquo se face icircntr-o pagină nouăcu parametrii grafici prevăzuţi de programul icircncorporat)

Pentru a icircncorpora etichetele chiar icircn pagina produsă de lsquograficepsrsquo(evitacircnd ejectarea acesteia) minimul necesar constă icircn anularea efectului in-strucţiunii showpage redeclaracircnd-o (din timp) ca procedură bdquovidărdquoshowpage def ar fi descărcat pagina curentă reiniţializacircnd contextul grafic

Să icircnfiinţăm icircntacirci procedurile care decurg din sect51 pentru a prelua dinstivă tabloul BoundingBox şi a determina dimensiunile corespunzătoareBB exch def preia din stivă tabloul colţurilor etichetei curentewb BB 2 get BB 0 get sub bind def width (lăţimea etichetei)hb BB 3 get BB 1 get sub bind def height (icircnălţimea etichetei)

Icircn rsquoLabelepsrsquo era implicat sistemul de coordonate standard origineafiind icircn colţul stacircnga-jos iar unitatea de măsură 1 equiv 1bp = 172inch icircnrsquograficepsrsquo originea fusese fixată la 15um de marginea stacircngă şi 1um debaza paginii unde alesesem 1um = 60bpAvem de ales icircntre aceste două posibilităţi de lucru

1 Icircntacirci bdquoimportămrdquo etichetele şi le poziţionăm apoi abia executăm bdquopro-gramul principalrdquo (icircncepacircnd cu scalarea şi translatarea sistemului decoordonate) din rsquograficepsrsquo pentru poziţionare vom avea nevoiedoar de valoarea 1um

2 Icircntacirci executăm bdquoprogramul principalrdquo (icircncepacircnd cu scalarea şi transla-tarea sistemului de coordonate) din rsquograficepsrsquo şi după aceea bdquoim-portămrdquo şi poziţionăm etichetele

Să observăm că pentru a doua variantă calculele de poziţionare re-vin la cele din prima variantă dacă (după ce executăm bdquoprogramul principalrdquodin lsquograficepsrsquo) reconstituim sistemul de coordonate standard făcacircnd obdquotranslaţie inversărdquo şi o bdquoscalare inversărdquo prin instrucţiunile suplimenta-re -15 -1 translate şi 1 um div dup scale Desigur ne putem scuti

22

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 23: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

de o asemenea bdquoreconstituirerdquo ad-hoc ambalacircnd bdquoprogramul principalrdquo dinrsquograficepsrsquo icircntre gsave şi grestore

showpage def evită ejectarea paginii curenteum 72 def fixăm ca bdquounitate de măsurărdquo 1 equiv 72bp = 1 inch

gsave bdquoprogramul principalrdquo (produce figura geometrică)um um scale coordonatele vor fi amplificate cu 1um1 5 1 translate 15um spre dreapta 1um icircn susul paginii 01 setlinewidth 1 0 0 setrgbcolor Kardioid stroke K

005 setlinewidth 0 1 setgray E l l i p s e stroke elipsa E

0 0 1 setrgbcolor 005 setlinewidth Parabola stroke P

0 setlinewidth other_l ines stroke celelalte linii şi arcegrestore restaurează contextul grafic iniţial

Este importantă alegerea unităţii de măsură pentru construcţia figuriicu 60bp cacirct alesesem iniţial (icircn sect3) etichetele care vor completa acum figurase dovedesc a fi prea mari alegacircnd ca unitate 1inch vom avea o bdquopotrivirerdquomai bună icircntre mărimea de caracter a etichetelor şi mărimea figuriiAm bdquoascunsrdquo faţă de restul programului scalarea şi translatarea coordona-telor din blocul referit prin bdquoprogramul principalrdquo (introducacircndu-l icircntre gsaveşi grestore) dar acum apare o situaţie aproape ironică pentru poziţionareaetichetelor pe figură trebuie să ştim translaţia folosită la construcţia figurii(adică tocmai ceea cemdashchipurilemdashbdquoascunsesemrdquo)

Eticheta Kt (ca să ne referim la un exemplu concret) trebuie bdquoadusărdquodin poziţia indicată icircn BoundingBox-ul corespunzător ei (obţinut de pe sti-vă icircn variabila BB icircnfiinţată mai sus) icircntr-o poziţie din pagina figurii care săcorespundă punctului de coordonate (x1 y1) ndash unde x1 şi y1 invocă pro-cedurile icircnfiinţate icircn sect3 pentru determinarea abscisei şi ordonatei punctuluisemicardioidei corespunzător unei anumite valori a parametrului din ecua-ţiile acesteia Dar coordonatele rezultate sunt bdquonumere abstracterdquo poziţiadin pagină corespunzătoare acestora se obţine scalacircnd coordonatele cu 1umşi translatacircnd cu 15um pe orizontală şi cu 1um pe verticală

Să desemnăm prin [Lx Ly Ux Uy] valorile obţinute icircn variabila BB cal-culul de poziţionare a etichetei trebuie să decurgă astfel translatăm eti-cheta spre stacircnga cu (Lx Ly) (instrucţiunea ar fi -Lx -Ly translate)efectuăm apoi o a doua translaţie cu ((x1 + 15)um (y1 + 1)um) Astfelcolţul stacircnga-jos al etichetei ajunge acum icircn poziţia din pagină corespun-zătoare coordonatelor bdquoabstracterdquo (x1 y1) rămacircne de făcut o anumităcorecţie ţinacircnd seama de lăţimea şi icircnălţimea etichetei respective (icircncacirct icircnfinal eticheta să fie aşezată cumva lacircngă punct) calculul translaţiei etichetei pe orizontală şi pe verticalăTx 15 add um mul BB 0 get sub bind def

(x + 15)um - Lx (x fiind preluat din stivă)Ty 1 add um mul BB 1 get sub bind def

(y + 1)um - Ly (y din stivă)

icircncapsulează şi poziţionează etichetelegsave x1 Tx wb sub corecţie orizontală (-wb) pentru eticheta Kt

23

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 24: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

y1 Ty hb 075 mul sub corecţie verticală cu -hb075translate ( Label1 eps ) run grestore

gsave x2 Tx wb 10 div sub corecţie cu -01wb şi +01hby2 Ty hb 10 div addtranslate ( Label2 eps ) run grestore

gsave xC Tx wb 2 div subyC Ty hb 4 div addtranslate ( Label3 eps ) run grestore

gsave 1 8 Tx 5 sqrt Ty translate( Label4 eps ) run grestore

gsave 106 Tx 4 sqrt Ty translate( Label5 eps ) run grestore

gsave 068 Tx 3 sqrt Ty translate( Label6 eps ) run grestore

Pentru etichetarea curbelor am ales (prin calcule simple şi icircncercări) absci-sele 18 etc şi ordonatele

radic05 etc aplicacircndu-le Tx şi Ty pentru a obţine

poziţia din pagină corespunzătoare lor (şi nu am avut nevoie de bdquocorecţiirdquo)

Icircn final icircnsă (după atacircta muncă) am putea fi şi dezamăgiţi evince (saupoate şi vreun alt bdquoDocument Viewerrdquo) nu mai reuşeşte să interpreteze fişie-rul graficeps rezultat mai sus iar invocacircnd direct Ghostscript (prin gsgraficeps) am avut (icircntr-un anumit moment intermediar) surpriza de a obţi-ne o pagină care conţine numai figura produsă de rdquograficepsrdquo (nu şi eti-chetele icircncapsulate)hellipPe undeva este normal să fie aşa este periculos să permiţi includerea icircntr-unfişier a altor fişiere care conţin instrucţiuni executabile (bdquostrăinerdquo)Totuşi GS permite şi evitarea unor restricţii privitoare la fişiere şi fonturiprin opţiunea -dNOSAFER icircncacirct prin comanda gs -dNOSAFER graficepsobţinem vizualizarea pe ecran a figurii complete (incluzacircnd şi etichetele)

Desigur nu vom putea folosi rsquograficepsrsquo decacirct avacircnd alături şi fişiere-le Labeleps putem evita acest inconvenient (rezultacircnd şi alte avantaje)sintetizacircnd fişierele respective icircntr-un document PDFvbHome~ keps$ ps2pdf minusdNOSAFER g r a f i c eps g r a f i c pdf

Pentru a converti din EPS icircn PDF ps2pdf angajează de fapt interpre-torul GS icircncacirct putem beneficia ca şi mai sus de opţiunea -dNOSAFER

Fişierul obţinut graficpdf măsoară numai 149kB (icircn timp ce fişierelebdquoLabelepsrdquo obţinute prin dvipsmdashcacircnd am executat scriptul lsquobuildEPSshrsquomdashtotalizează aproape 200kB) vizualizacircnd de exemplu prin evince obţinem opagină care conţine figura noastră (cu tot cu etichete) icircn partea din stacircnga-josa ei Dar aceasta nu este chiar ce ne-am dorit icircn graficeps (v sect3) stabili-sem icircn declaraţia BoundingBox limitele boxei care conţine figura noastră -iar acum vedem că acestea nu au fost icircn final respectate vizualizacircnd cumvaca text fişierul graficpdf - găsim că pagina respectivă a fost setată cuMediaBox [0 0 595 842] (ceea ce corespunde formatului de pagină bdquoA4rdquo)

24

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 25: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Cum am arătat deja icircn sect3 putem folosi gs cu minussDEVICE=bbox pentru agăsi BoundingBox (trebuie recalculat fiindcă acum avem altă unitate de mă-sură decacirct aveam icircn sect3) şi apoi cu pdfwrite pentru a insera (prin mecanismulrsquopdfmarkrsquo) declaraţia CropBox corespunzătoare cu BoundingBox icircn fişie-rul rsquograficpdfrsquo rezultat mai sus obţinem astfel figura din sect1 (mai puţineticheta rsquoOrsquo pe care am adăugat-o ulterior)

Desigur scopul pentru care faci o figură sau alta nu este (icircn general)acela de a o arăta pur şi simplu pe ecran sau a o tipări pe hacircrtie ndash cide a o integra icircntr-un anumit text referitor de exemplu la contextul mate-matic asociat figurii Figura obţinută mai sus poate fi salvată de exempluicircn imageskeps3pdf şi va putea fi inclusă icircntr-un fişier LaTeX existentprin comanda includegraphicsimageskeps3pdf (prevăzacircnd icircn pream-bul usepackagegraphicx avacircnd CropBox compilatorul de LaTeX va puteasă constituie boxa necesară figurii icircn cadrul boxei pe care o asociază paginii)

6 Arcele de parabolă sunt curbe Beacutezier pătraticeIcircn procedura Parabola din sect3 am generat bdquopunct cu punctrdquo arcul de pa-rabolă P dat de y =

radic1 minus x x isin [0 1] se unea punctul curent (iniţializat

icircn vacircrful parabolei) cu cel corespunzător abscisei depuse pe stivă la iteraţiaurmătoare (prin mecanismul lui for) coboracircnd abscisa cu cacircte 001 (icircn sect31am arătat icircnsă că iterarea cu paşi fracţionari ar trebui evitată) icircn final avemo aproximare cu 100 de segmente a lui P ndash icircn fond un set de 100 de in-strucţiuni lineto care prin operatorul stroke vor produce pixeli vecini saupuncte suficient de apropiate formacircnd (pe ecran sau pe hacircrtie) o imaginegrafică acceptabilă a lui P

Vom arăta mai icircncolo că putem obţine o imagine la fel de bună a lui P (şide fapt a oricărui arc de parabolă) folosind o singură instrucţiune curveto(icircn loc de 100 lineto) dar pentru aceasta trebuie găsite icircn prealabil anu-mite bdquopuncte de controlrdquo

Să notăm cu P şi Q capetele arcului P (icircn cazul nostru P (0 1) şi Q(1 0))urmează să determinăm bdquopunctele de controlrdquo

Fie H intersecţia tangentelor icircn P şi Q la P Justificarea alegerii icircnacest fel a unui prim punct de control decurge dintr-o metodă generală deconstrucţie punctuală a unei conice (v Steinerrsquos generation of a conic)care icircn cazul nostru revine la această proprietate dacă punctele U şi Vicircmpart segmentele orientate PH şi HQ icircntr-un acelaşi raport t isin [0 1]atunci punctul care icircmparte UV icircn raportul t descrie (cacircnd t variază de la 0la 1) un arc de parabolă care este tangent dreptelor PH şi QH

Pentru demonstraţie să considerăm afixele punctelor folosind litere omo-nime Punctul care icircmparte UV icircn raportul t este z(t) = (1 minus t)U + tV dar- fiindcă U icircmparte PH icircn raportul t - avem u = (1 minus t)P + tH analog

25

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 26: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

v = (1 minus t)H + tQ Rezultă

z(t) = (1 minus t)2P + 2t(1 minus t)H + t2Q t isin [0 1]

Deci (fiind date de o funcţie de gradul doi icircn t) punctele z(t) se află pe o parabolăcare trece prin z(0) = P şi z(1) = QAvem zprime(t) = minus2(1minust)P+2(1minus2t)H+2tQ rezultă că zprime(0) = 2(HminusP) (adicătangenta icircn z(0) are aceeaşi direcţie ca vectorul PH) şi zprime(1) = 2(Q minus H)deci dreptele PH şi HQ sunt tangente parabolei icircn P şi respectiv icircn Q

Arcul de parabolă z(t) rezultat mai sus este curba Beacutezier pătratică defini-tă de capetele P Q şi de punctul de control H dacă am avea o instrucţiune(similară cu lineto) care să furnizeze această curbă Beacutezier (primind ca ar-gument capetele şi punctul de control) atunci am putea trasa P folosindnumai această instrucţiune Icircnsă pentru a viza şi alte curbe (nu numai pa-rabola) PostScript prevede implicit folosirea curbelor Beacutezier cubice carenecesită cacircte două puncte de control vom vedea mai jos că pentru cazulunui arc de parabolă acestea pot fi determinate plecacircnd de la punctul Hdefinit mai sus

Să verificăm icircntr-un caz concret că pătratica Beacutezier definită de capeteleunui arc de parabolă şi de intersecţia tangentelor acestuia icircn capete coincidecu arcul respectivPentru cazul nostru P y2 = 1minusx x isin [0 1] şi prin derivare avem 2yyprime = minus1deci yprime(0) = minus 1

2y(0) = minus12 icircncacirct ecuaţia tangentei icircn P (0 1) este yminus1 = minus1

2xtangenta icircn Q(1 0) este x = 1 Rezultă prin intersecţie H(1 1

2) şi curbaBeacutezier pătratică asociată mai sus este z(t) = (1minus t)2i+2t(1minus t)(1+ 1

2 i)+ t2adică separacircnd părţile (reală şi imaginară) x(t) = 2t(1 minus t) + t2 = t(2 minus t)şi y(t) = (1 minus t)2 + t(1 minus t) = 1 minus t eliminacircnd parametrul t rezultă exactecuaţia iniţială y2 = 1 minus x

7 Arcele de parabolă prin cubice BeacutezierAm văzut mai sus că ecuaţia arcului de parabolă de capete P şi Q dat fiindpunctul (bdquode controlrdquo) H icircn care se intersectează tangentele icircn capete este(icircn planul complex) z(t) = (1 minus t)2P + 2(1 minus t)tH + t2Q t isin [0 1] Avem degăsit două puncte F şi G cu aceeaşi proprietate ca H - adică FP şi GQ săfie tangente parabolei deci F şi G trebuie căutate pe dreptele HP şi HQ

Pe de altă parte vrem un polinom de gradul trei care să bdquoreprezinterdquocumva arcul de parabolă z(t) cubica respectivă ar trece prin capetele P şiQ (pentru t = 0 şi t = 1) dacă polinomul ar conţine monoamele (1 minus t)3P şit3Q iar celelalte două monoame ar conţine t(1 minus t) (icircncacirct ele să nu afectezevalorile icircn capetele t isin 0 1) Observacircnd că (1 minus t) + t = 1 putem satisfaceaceste cerinţe icircnmulţind z(t) cu (1 minus t) şi respectiv cu t şi adunacircnd apoirezultatele rezultă astfel această rescriere

z(t) = (1 minus t)3P + (1 minus t)2t(2H + P) + (1 minus t)t2(2H + Q) + t3Q

26

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 27: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

P

Q

H

F

G

P moveto F G Q curveto

Punctele de control căutate F şi G ar fi reprezentate de cei doi coeficienţidin mijloc dar nu direct - fiindcă (de exemplu pentru primul coeficient)punctul de afix 2H + P este exterior dreptei HP (originea planului fiindfixată arbitrar) Pentru ca F să se afle bdquola momentulrdquo t pe segmentul orientatPH şi icircn acelaşi timp să se afle pe raza polară a punctului 2H + P trebuieicircndeplinită pentru un anumit factor λ condiţia (1 minus t)P + tH = λ(2H + P)din care deducem 2λ = t şi λ = 1 minus t care adunate ne dau λ = 1

3 Prinurmare F = 1

3(2H + P) pentru celălalt coeficient este suficient să schimbămP cu Q (dar putem şi repeta analog calculul) şi avem G = 1

3(2H + Q)Pentru a evita factorul 1

3 putem amplifica monoamele din mijloc cu 3obţinacircnd o expresie mai obişnuită a cubicei Beacutezier

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1]

asociate capetelor unui arc de curbă date de coeficienţii extremi şi punctelorde control date de coeficienţii din mijloc

8 Instrucţiunea curveto

Cubicele Beacutezier sunt modelate icircn PostScript prin operatorul curveto acestapresupune că punctul curent (stabilit de exemplu printr-o instrucţiune moveto)este capătul de start al arcului şi cere de pe stivă coordonatele punctelor decontrol şi pe cele ale capătului final De exemplu pentru arcul de parabolă P

avem din sect6 P (0 1) Q(1 0) şi H(1 05) iar după sect7 găsim F = 13(2H + P) =

(23 2

3) şi G = (1 13) deci pentru a obţine P sunt suficiente aceste două

instrucţiuni 0 1 moveto (care stabileşte P ca punct curent) şi apoi 066066 1 033 1 0 curveto desigur că n-am introduce bdquo066 066rdquo ci amprefera rsquo2 3 div duprsquo

Icircn programul următor redefinim faţă de sect3 rsquoParabolarsquo (folosind aceeaşimetodă ca la definiţia rsquoKardioidrsquo din sect32) aceasta produce un contur poligonalpentru P cu N=100 segmente (instrucţiuni lineto) Adăugăm apoi o proce-dură care produce P cu o singură instrucţiune curveto dar ne convingem

27

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 28: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

folosind pathforall şi flattenpath că de fapt această instrucţiune acope-ră la execuţie (prin stroke) un anumit număr (dar mic comparacircnd cu N=100)de instrucţiuni linetoPS-Adobe-20 EPSF-20N 100 defParabola prin N segmente

0 1 moveto0 1 N N div dup 1 exch sub sqrt lineto for iN

radic1 minus iN

bind def

Parabola3 drept cubică Beacutezier (o instrucţiune rsquocurvetorsquo)0 1 moveto2 3 div dup 1 1 3 div 1 0 curveto

bind def

108 108 scale 1 2 translate 004 setlinewidth

gsave 65 setgrayParabola f i l l bdquoumplerdquo conturul poligonal (de N segmente)

grestore

gsave 1 0 0 setrgbcolorParabola3 prin rsquocurvetorsquo [3 1 ro l l ] == [7 1 ro l l (curveto ) ] == pathforall(n) printflattenpath icircnlocuieşte rsquocurvetorsquo prin secvenţe rsquolinetorsquo echivalente [3 1 ro l l ] == [3 1 ro l l ( lineto ) ] == pathforallstroke intern rsquostrokersquo va aplica rsquoflattenpathrsquo

grestore

stroke (care controlează icircn final trasarea efectivă pe ecran sau pe hacircrtie)icircnlocuieşte automat conturul indicat icircntr-o instrucţiune curveto printr-uncontur (bdquoechivalentrdquo cubicei Beacutezier iniţiale) constituit din instrucţiuni linetondash probabil chiar acelea pe care le-am cerut prin pathforall (după ce amliniarizat direct invocacircnd flattenpath) şi pe care le putem vedea executacircndprogramul prin GSvbHome~ keps$ gs minusq par_bez eps[ minus173843237eminus05 0999990702] 0 1 moveto[0 666680694 066666311 100000823 0333335608 100000823

806229491 eminus06 (curveto ) ] flattenpath transformă conturul icircntr-o secvenţă (echivalentă) de lineto[ minus173843237eminus05 0999990702][0 0593211092 0970321417 ( lineto ) ][0 234326661 0874992847 ( lineto ) ][0 437496513 0749995053 ( lineto ) ][0 609363139 0624997199 ( lineto ) ][0 749969602 0499999374 ( lineto ) ][0 859358788 037500155 ( lineto ) ][0 937487841 0250003725 ( lineto ) ][0 984356642 0125005886 ( lineto ) ][1 00000823 00312682688 ( lineto ) ]

28

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 29: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

[1 00000823 806229491 eminus06 ( lineto ) ]gtgtshowpage p re s s ltreturngt to continueltlt

Dacă decupăm secvenţa celor 10 instrucţiuni rsquolinetorsquo afişate şi o icircn-corporăm (eliminacircnd desigur parantezele) la sfacircrşitul programului putemconstata că rezultă (suprapus) acelaşi contur ca şi cel produs de rsquoParabolarsquoşi de rsquoParabola3rsquo

Este interesant de comparat noi am generat segmentele (prin for) folo-sind (ceea ce este absolut uzual) un pas constant (aici 001) fără a distingeicircn vreun fel punctele curbei icircn schimb flattenpath (sau stroke) - atuncicacircnd liniarizează conturul indicat icircn curveto - distinge cumva (ceea ce estedesigur mai inteligent) icircntre părţile mai icircntinse şi cele mai bombate ale arcu-lui parcurgacircndu-le cu paşi ceva mai mari respectiv ceva mai mici (a vedeadiferenţele absciselor la primele şi respectiv la ultimele instrucţiuni rsquolinetorsquo dintrecele redate mai sus icircn [hellip])

Pare deci mai bine (pacircnă la vreo probă contrarie) să calculăm punctele decontrol necesare şi să folosim curveto decacirct să iterăm lineto pe 100 de paşiechidistanţi (şi de obicei mai mulţi) trasacircnd cacircte un segment de la punctulcurent la cel următor icircn cazul unei curbe mai bdquolargirdquo sau mai complicatene putem gacircndi să o segmentăm icircntacirci icircn cacircteva bucăţi şi să folosim curvetopentru fiecare dintre acestea

81 Raţiunea de a fi a instrucţiunii curveto (litera rsquoSrsquo)

lineto şi curveto nu sunt instrumente de bdquografică pe calculatorrdquo (precumde exemplu funcţiile plot() din R) ndash ci sunt instrucţiuni proprii pe carePostScript le foloseşte efectiv icircn scopul predeclarat de a formula o paginăastfel icircncacirct descrierea respectivă să poată fi interpretată la fel pe orice dis-pozitiv de redare a paginiiPunctele sunt văzute ca nişte perechi de numere (şi nu există instrucţiunipentru a le bdquotrasardquo ca atare) punctele vor putea arăta diferit de la un dispo-zitiv la altul după cum este bdquopixelulrdquo sau bdquopunctul tipograficrdquo al acestuiaDar ansamblul de puncte constituit de un segment sau un arc Beacutezier vaarăta bdquola felrdquo indiferent de dispozitiv sau scară ndash mai ales că transformărileposibile nu se aplică figurii ci sistemului de coordonate icircn care este exprimatconturul tocmai de aceea componentele paginii (inclusiv caracterele) suntdescrise folosind lineto şi curveto

Literele şi celelalte caractere sunt văzute ca fiind fiecare un anumit con-tur icircnchis format din segmente şi curbe Beacutezier astfel ele icircşi păstrează maibine forma dacă se aplică scalări sau alte transformări ndash spre deosebire decazul cacircnd ar fi reprezentate static prin matrici predefinite de puncte

Prin operatorul charpath putem obţine conturul existent pentru un ca-racter de exemplu (S) false charpath va adăuga conturului curent pecel asociat pentru litera rsquoSrsquo icircn cadrul fontului curent (dacă acest font nu esteunul protejat) Iar dacă folosim apoi pathforall (cum am mai arătat) putem

29

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 30: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

afişa secvenţa de instrucţiuni care conturează litera respectivă icircn următorulprogram am preluat din această secvenţă partea care corespunde conturuluiinterior al lui rsquoSrsquo icircn fontul Times-Roman (precizăm că icircn general vom redacoordonatele din instrucţiunile curveto rotunjindu-le la a 4-a zecimală)PS-Adobe-20 EPSF-20BoundingBox 152 136 270 240

TimesminusRoman findfont 18 scalefont setfont

144 144 translate 4 4 scale

extragem dintr-o sesiune de lucru cu Ghostscript conturul interior al lui rsquoSrsquo336217046 minus0464388192 moveto33993 02043 38266 07059 436524916 0705870092 curveto47553 07059 53498 05758 60370 03158 curveto73931 minus02043 88605 minus05015 102537 minus05015 curveto143960 minus05015 175353 23033 175353 60185 curveto175353 89348 155663 112010 108667 137645 curveto71144 157892 56098 173495 56098 193185 curveto56098 212689 71144 225878 93249 225878 curveto109224 225878 124270 219191 136716 206374 curveto147861 194857 152877 185755 158635 164765 curveto

21 0 moveto punctul de start pentru următorul contur(S) fa lse charpath adaugă conturului de mai sus conturul literei rsquoSrsquo

1 setlinewidth 1 setgraystroke trasează efectiv cele două contururi

1 0 0 setrgbcolor436524916 0705870092 moveto punctează capătul final pentru prima rsquocurvetorsquo436524916 0705870092 2 0 360 arc f i l l

capătul final pentru a doua instrucţiune rsquocurvetorsquo a treia etc

Am marcat cu cacircte un mic disc roşu (produs prin arc fill) capătulfinal al fiecăreia dintre cele 9 bucăţi curveto ale conturului interior al lite-rei (coordonatele cerculeţului sunt date de ultimele două valori din instrucţiuneacurveto respectivă) acest contur este de două ori mai mare decacirct cel cores-punzător din conturul literei redat icircn partea dreaptă a imaginii fiindcă icircnsesiunea de lucru cu GS din care l-am preluat am folosit 36 scalefont icircntimp ce icircn programul de mai sus avem doar 18 scalefont

30

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 31: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

vbHome~ keps$ gs minusq sesiune de lucru interactiv icircn GhostscriptGSgt TimesminusRoman findfont 36 scalefont setfontGSgt 0 0 movetoGSgt (S) fa lse charpathGSgt [3 1 ro l l (moveto) ] == [3 1 ro l l ( lineto ) ] == GSlt2gt [7 1 ro l l (curveto ) ] == ( closepath ) == GSlt4gt pathforall[15 9749537 240367336 (moveto) ][15 2133579 240367336 ( lineto ) ][ 15 0648 232566 146747 228293 140802 228293 (curveto ) ] [ 6 3157 07802 41052 27306 23219 70773 (curveto ) ][1 50461781 707727623 ( lineto ) ][2 56342292 minus0464388192 ( lineto ) ][3 36217046 minus0464388192 ( lineto ) ][ 3 3993 02043 38266 07059 43652 07059 (curveto ) ] [ 14 7861 194857 152877 185756 158635 164765 (curveto ) ][16 755127 164764938 ( lineto ) ][15 9749537 240367336 ( lineto ) ]( closepath )[20 015131 0 0 (moveto) ]GSgt

Bineicircnţeles că am folosit [7 1 roll (curveto)] == avacircnd icircn ve-dere că curveto are 6 parametri Litera este un contur icircnchis (se icircncheieprin closepath) constituit dintr-un sub-contur bdquoexteriorrdquo (icircn cazul de fa-ţă cu 10 instrucţiuni curveto) şi unul bdquointeriorrdquo conectate şi completateprin cacircteva instrucţiuni lineto Icircn final 20015131 00 moveto stabileştebdquopunctul curentrdquo de la care să icircnceapă următoarea trasare de contur dacăexistă (icircncacirct icircn programul de mai sus am putut estima prin 21 0 movetounde să adaug conturul icircntreg al literei)

9 Aproximarea unei curbe prin cubice BeacutezierAm ilustrat mai icircnainte faptul că PostScript conturează literele folosindsecvenţe de instrucţiuni curveto icircn treacăt fie zis ndash şi noi facem la fel icircnclasa icircntacircia desenăm literele cu bdquobastonaşerdquo şi arce de legătură (angajacircndintuitiv şi anumite bdquopuncte de controlrdquo) Să vedem şi cum am putea folosi cubiceBeacutezier pentru a contura o curbă sau alta plecacircnd de la ecuaţiile acesteiasubliniem că nu graficul ca atare ne interesează (că atunci l-am obţine fărăbătaie de cap folosind R sau vreun alt pachet de grafică) vrem să vedem cumajungem la un program care să ne contureze curba respectivă cacirct se poatede exact şi cu cacirct mai puţine instrucţiuni curveto

Pentru cubica Beacutezier de capete P Q şi cu punctele de control F equiv(2H+P)3 şi G equiv (2H+Q)3 ndash unde H era intersecţia tangentelor icircn capete- ajunsesem la exprimarea (literele drepte desemnacircnd afixele punctelor omonime

31

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 32: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

icircn C )

z(t) = (1 minus t)3 P + 3(1 minus t)2t F + 3(1 minus t)t2 G + t3 Q t isin [0 1] (1)

Conturul asociat se obţine fixacircnd bdquopunctul curentrdquo icircn P şi indicacircnd ope-ratorului curveto coordonatele punctelor F G şi Q Icircnsă determinareapunctelor F şi G plecacircnd de la intersecţia H a tangentelor icircn capete esteincomodă

Putem ocoli determinarea prealabilă a lui H exprimacircnd coeficienţii F şiG chiar din ecuaţia lui z(t) derivacircnd găsim zprime(0) = minus3P + 3F şi zprime(1) =minus3G + 3Q deci

F = P + 13

zprime(0) G = Q minus 13

zprime(1) (2)

zprime(0) şi zprime(1) sunt pantele tangentelor curbei icircn capetele P şi Q (fiindcăavem z(0) = P şi z(1) = Q) Pentru unele bdquocazuri specialerdquo trebuie totuşi săangajăm H de exemplu dacă zprime(1) = infin şi zprime(0) = infin atunci determinămicircntacirci intersecţia H a tangentei icircn P cu verticala prin Q şi apoi căutămcumva G pe segmentul QH (bdquoteoreticrdquo adică ignoracircnd complet erorile deaproximare avem QG = 2

3QH)Pentru a aproxima conturul unei curbe oarecare C (dată fiind icircntr-o

formă sau alta ecuaţia acesteia) putem proceda astfel icircmpărţim C icircn cacirctevapărţi avacircnd fiecare cacircte un capăt iniţial P şi unul final Q determinămvalorile icircn P şi Q ale derivatei funcţiei asociate lui C şi găsim prin formulele(2) coeficienţii F şi G bdquoidentificămrdquo arcul lui C delimitat de P şi Q princubica Beacutezier dată de P F G şi Q

Desigur bdquogăsim F şi G prin formulele (2)rdquo trebuie regacircndit fiindcă Pşi Q de pe curba C se obţin din ecuaţia acesteia nu pentru t = 0 şi t = 1ci eventual pentru t = τ0 şi t = τ1 ndash indicacircnd subintervalul parcurs deparametrul icircn funcţie de care se obţine porţiunea lui C de capete P şi Q

Schimbarea de variabilă t = τ minus τ0τ1 minus τ0

transformă biunivoc t isin [0 1] icircnτ isin [τ0 τ1] Pentru (2) nu interesează ce devine (1) prin această substituţieci doar cum se transformă zprime(t) trecacircnd la noua variabilă τ plecacircnd de laregula de bdquoderivare icircnlănţuitărdquo avem dz

dt = dzdτ

dτdt = (τ1 minus τ0) dz

dτ Aceastaicircnseamnă că icircn loc de zprime(t) trebuie să punem h zprime(τ) notacircnd h = τ1 minus τ0deci formulele (2) se adaptează la intervalul [τ0 τ1] astfel

F = P + h

3zprime(τ0) G = Q minus h

3zprime(τ1) unde h = τ1 minus τ0 (3)

Conturul lui C va fi constituit dintr-un număr de instrucţiuni curvetoegal cu numărul părţilor considerate pentru a creşte calitatea bdquoidentificăriirdquocu arce Beacutezier trebuie să folosim o partiţionare a lui C cu un număr suficientde mare de părţi (avacircnd icircn vedere eventual şi anumite bdquopuncte specialerdquo cumar fi vacircrfurile şi punctele de inflexiune)

32

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 33: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

10 Aproximarea semicardioidei prin cubice BeacutezierReluăm din sect32 procedura Kardioid prin care conturul semicardioidei su-perioare K (pe care acum icircl vom bdquoumplerdquo folosind fill) este constituit prin1000 de instrucţiuni lineto (producacircnd un grafic suficient de exact)PS-Adobe-20 EPSF-20 coordonatele punctelor semicardioidei K(t) (t este implicit icircn vacircrful stivei)X 2 mul dup 1 sub mul bind def X(t) = 2t(2t minus 1) Y (t) = 4t

radict(1 minus t)

Y dup dup 1 exch sub mul sqrt mul 4 mul bind def

N 1000 def aproximare poligonală (cu N segmente) a semicardioidei superioareKardioid

0 0 moveto conturul pleacă din K(0) (nodul cardioidei)1 1 N N div dup X exch Y lineto for K(t)mdashK(t+1N) t=iN

bind def

108 108 scale 2 1 translateKardioid instanţiază semicardioida (pentru noul sistem de coordonate) 5 setgray f i l l bdquoicircnchiderdquo şi umple conturul cu pixeli gri

Dăm icircntacirci un mic exemplu de constituire manuală (calculacircnd direct dupăformulele (3)) a unor instrucţiuni curveto care să bdquoacopererdquo cumva semi-cardioida umplută cu gri obţinută prin programul de mai sus (vezi figura demai jos)

Cel mai simplu (pentru calcul manual - altfel vom vedea că nu este delocbine) ar fi să partiţionăm icircn două bucăţi arcul descris pentru t isin [0 1

2 ]avacircnd capetele O(0 0) (nodul cardioidei) şi B(0 1) respectiv pentru t isin [1

2 1]de capete B(0 1) şi A(2 0) (vacircrful cardioidei) Urmează să calculăm pentrufiecare arc punctele F şi G din (3)

Amintim că punctele lui K sunt date de

x(t) = 2t(2t minus 1) y(t) = 4tradic

t(1 minus t) t isin [0 1]

şi găsim uşor

xprime(t) = 2(4t minus 1) yprime(t) = 2(3 minus 4t)radic

t

1 minus t(t = 1 yprime(1) = infin)

Pentru capătul O avem zprimeO = (xprime(t) yprime(t))|t=0 = (minus2 0) deci după (3)

cu h = 12 avem F = O + h

3 zprimeO = (minus1

3 0)Pentru capătul B avem zprime

B = (xprime(t) yprime(t))|t=05 = (2 2) şi după (3) rezultăG = B minus h

3 zprimeB = (0 1) minus 1

6(2 2) = (minus13 2

3)Prin urmare cubica Beacutezier asociată primului arc va fi dată de O(00)

F(-130) G(-1323) B(01) curveto ceea ce adăugăm icircn programulde mai sus astfel0 0 moveto minus1 3 div 0 minus1 3 div 2 3 div 0 1 curveto

33

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 34: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Pentru arcul lui K dintre B şi A putem determina F = B + h3 zprime

B = (13 4

3)dar G nu mai poate fi obţinut prin (3) fiindcă yprime

A = yprime(1) = infin am dat deo dilemă tipică faţă de aplicarea formulelor (3) - cazul icircn care tangenta lacurbă icircntr-un capăt al arcului este verticală Soluţia ad-hoc (dar nici nu ştimalta) ar consta icircn a alege G undeva pe tangenta icircn A deci G(2 λ) luămλ = 2 şi adăugăm icircn program1 3 div 4 3 div 2 2 2 0 curveto0 0 1 setrgbcolor stroke cele două cubice sunt trasate cu roşu

Pentru comparaţie am repetat ultima instrucţiune curveto pentru ca-zurile λ isin 2 minus 1

3 2 minus 23 1 coloracircnd acum cu albastru

O

B

A

Contururile rezultate astfel (cel format din două arce roşu-roşu sau cele con-stituite din arcul roşu şi unul dintre cele albastre) sunt departe de o aproximareacceptabilă a semicardioidei şi chiar este greu de crezut că separacircnd icircn numaidouă arce am putea obţine una acceptabilă

Să ştergem instrucţiunile curveto calculate manual mai sus şi să adop-tăm acum ideea cea mai simplă icircmpărţim intervalul [0 1] icircn N bucăţi egale(cel puţin patru) şi pentru fiecare dintre acestea determinăm punctele decontrol necesare instrucţiunii curveto pentru aproximarea porţiunii cores-punzătoare a lui K Vom scrie programul necesar pentru aceasta fără cineştie ce elaborare doar ca să vedem cam bdquocum s-ar facerdquo dar oricum amelabora acest program va fi mult mai amplu (şi mai complicat) decacirct pro-cedura iniţială Kardioid (care practic are o singură linie de program) Cebdquoderanjardquo la Kardioid era faptul că producea 1000 de instrucţiuni linetoacum vom produce K icircntr-o aproximare acceptabilă (dar nu aşa de bună cafolosind Kardioid) cu numai N=6 instrucţiuni curveto (sau mai bine N=9şi mai bine N=12 cu flattenpath şi pathforall se va putea vedea căacestea acoperă maximum 50-60 de instrucţiuni lineto)

Introducem icircntacirci procedurile dX şi dY pentru a calcula xprime(t) şi yprime(t) (va-loarea t fiind preluată de pe stiva operanzilor) apoi fixăm N (a icircncerca va-lorile 269 pentru N=10 sau N=11 programul eşuează icircn urma propagării unorerori bdquode aproximarerdquo - cum am mai observat icircn sect31 pentru N=12 iarăşi bdquomer-gerdquo) Introducem variabilele h=1N şi h3=h3 fiindcă aceste valori vorinterveni frecvent icircn calcule apoi iniţializăm t0 fixăm punctul curent icircnO(0 0) şi repetăm de N ori secvenţa de instrucţiuni care plecacircnd de la capă-tul Pequiv(x(t0) y(t0)) determină Qequiv(x(t1) y(t1)) cu t1 = t0 + h şi

34

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 35: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

apoi calculează după formulele (3) punctele de control F şi G - producacircndinstrucţiunea curveto pentru P F G şi QAm icircntacircmpinat faptul că yprime(1) = infin folosind ifelse cacircnd t1 ge 099intersectăm tangenta icircn P cu verticala x=2 (tangenta icircn vacircrful cardioidei)găsind H la ordonata yH = y(t0) + yprime(t0)

xprime(t0)(2 minus x(t0)) punctul G are abscisa2 şi ar trebui să aibă ordonata 2

3yH - dar (cred că din cauza cumulării erorilorde aproximare) a trebuit să experimentez pentru a apropia mai mult cubicarespectivă de cardioidă mărind puţin ordonata lui G pacircnă la valoarea 26

3 yH

(optacircnd icircn final pentru 2583)dX 8 mul 2 sub bind def Xrsquo(t) = 8t - 2dY t exch def t == 6 8 t mul sub t 1 t sub div sqrt mul bind def Yrsquo(t) = 2(3-4t)SQRT(t(1-t))

N 9 defh 1 N div def 1Nh3 h 3 div def h3 t0 0 def t0 X t0 Y movetoN

t1 t0 h add def t1 = t0 + h (t0 referă capătul iniţial al arcului curent)t0 X h3 t0 dX mul add F (primul punct de control)t0 Y h3 t0 dY mul addt1 099 ge la t1==1 avem tangentă verticală şi trebuie găsit H

2 t0 Y t0 dY t0 dX div 2 t0 X sub mul add258 3 div mul G este pe segmentul QH icircncacirct QGGH asymp 23

t1 X h3 t1 dX mul sub G (al doilea punct de control) dacă t1 lt 099t1 Y h3 t1 dY mul sub i f e l s et1 X t1 Y Q (capătul final pentru arcul curent)curveto t0 t1 def t0 = t1

repeat1 0 0 setrgbcolor 0005 setlinewidth stroke

Am marcat şi punctele semicardioidei care sunt capetele finale ale celor9 cubice Beacutezier determinate prin secvenţa de mai sus adăugacircnd icircn final t0 0 def0 3 setgrayN t1 t0 h add def t1 = iN i=1N

t1 X t1 Y movetot1 X t1 Y 007 0 360 arc f i l l marchează punctul (x(t1) y(t1)) t0 t1 def

repeat

Icircn urma experienţei de lucru descrise mai sus devine totuşi clar că maitotdeauna este de preferat un program simplu modelacircnd aproximarea poli-gonală obişnuită (fie şi cu 1000 de lineto generate desigur printr-o instrucţiunerepetitivă) unuia care constituie şi icircnlănţuie cubice Beacutezier care să aproximezeporţiuni ale curbei (mai ales dacă vrem o reprezentare cacirct mai exactă) curvetoa fost introdusă nu pentru a trasa curbe pe baza ecuaţiilor acestora ci maidegrabă pentru a permite realizarea interactivă (pe ecran folosind mouse-ul)

35

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 36: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

aproximează K prin N = 9 cubice Beacutezier (t = i9 i = 19)

de figuri (sau caractere) prin intermediul unor aplicaţii ca Adobe Illustratorsau CorelDraw Inkscape etc

11 Aproximarea semicardioidei folosind MetaPostCare este (sau cum determinăm) numărul minim de instrucţiuni curveto(cubice Beacutezier) pentru a reprezenta o curbă indicată (cu diferenţe impercep-tibile la scară uzuală faţă de graficul trasat - pe ecran sau pe hacircrtie - printr-unnumăr mare de puncte)

Mai sus ajunsesem la o reprezentare cu 9 instrucţiuni curveto a lui Kprintr-un program PostScript generic (aplicabil mutatis mutandis şi altor curbe)care segmenta intervalul [0 1] icircn părţi egale şi determina pentru fiecare partepunctele de control necesare aproximării prin curveto a porţiunii corespun-zătoare a lui K calculam punctele de control folosind derivatele icircn capetelesubintervalului lovindu-ne astfel şi de situaţia dilematică yprime(1) = infin (cacircnd atrebuit să experimentăm asupra valorii bdquoteoreticerdquo)

A devenit clar că este mai bine dacă segmentăm curba nu prin punctelegate arbitrar la valorile iN i = 1N ale parametrului t ci prin unelepuncte caracteristice ei (puncte de extrem de inflexiune etc) Pe de altă par-te ne-a devenit clar că este mai avantajos să folosim MetaPost operatoruldesemnat prin rsquorsquo (denumit bdquopath_joinrdquo) creează o cubică Beacutezier care uneştecele două puncte care (icircmpreună eventual cu direcţia tangentei) icirci sunt indicateangajacircnd intern anumiţi algoritmi (destul de complicaţi pentru a ne feri să-i ex-plicăm noi) de determinare a punctelor de control (spre deosebire de PostScripticircn care avem doar posibilitatea elementară de a le specifica noi icircnşine)

Avem xprime(14) = 0 (cu yprime(1

4) = 0) deci icircn punctul (x(14) y(1

4)) = (minus14

radic3

4 )tangenta la K este verticalăyprime(1)xprime(1) = infin deci icircn (x(1) y(1)) = (2 0) tangenta este verticalăyprime(0) = yprime(3

4) = 0 deci tangentele icircn (0 0) şi (34 3

radic3

4 ) sunt direcţionateorizontal

Un alt punct important este (x(12) y(1

2)) fiindcă punctele lui K provenitedin valori ale parametrului t simetrice faţă de mijlocul 1

2 al intervalului [0 1]

36

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 37: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

sunt legate (două cacircte două) prin proprietăţi semnificative (suma distanţelorla origine este egală cu 2 Oy bisectează unghiul razelor polare etc)Avem xprime(1

2) = yprime(12) = 2 deci tangenta icircn (x(1

2) y(12)) este paralelă cu prima

bisectoare a sistemului de axeCele cinci bdquopuncte importanterdquo evidenţiate mai sus corespund icircmpărţirii

intervalului [0 1] icircn patru subintervale egale dar acum am ajuns la ele ple-cacircnd de la proprietăţi ale funcţiei (legate de direcţia tangentelor) icircn loc de aasuma din start ca icircn sect10 o partiţionare echidistantă pe [0 1] (independentăde funcţie)z1 hellip z5 fiind punctele lui K rezultate pentru t = i

4 i = 04 putem formulaconturul z1leftz2upz3dir 45z4rightdownz5 icircnsem-nacircnd icircn MetaPost constituirea şi icircmbinarea a patru cubice Beacutezier primapleacă orizontal spre stacircnga din z1 curbează după punctele sale de controlşi ajunge vertical icircn z2 a doua continuă spre z3 ajungacircnd aici la 45 degrade faţă de orizontală şamd

Un program MetaPost prin care să evidenţiem acest contur şi deaseme-nea (pentru comparaţie) conturul obţinut prin marcarea unui număr sufi-cient de mare de puncte ale lui K se poate formula icircntr-un fişier bdquosmcdmprdquoca definiţie de figură beginfig(1) hellip endfig Dar icircn principiu icircn prealabilavem de setat anumite aspecte grafice (fontul de utilizat pentru etichetareo scalare şi poziţionare icircn pagină convenabile etc) şi de formulat subru-tine generice sau macro-uri de care vom avea nevoie icircn diverse definiţii defigură (astfel smc_point(t) modelează ecuaţiile lui K scardioid foloseştesmc_point pentru a produce o variabilă de tip rsquopicturersquo care la instanţiereva marca un anumit număr de puncte ale lui K path_nodes eticheteazănodurile conturului primit ca argument poziţionacircnd eticheta pe direcţianormalei la contur icircn punctul respectiv)outputtemplate = rdquojminusc eps rdquo produce lsquosmcd-1epsrsquo lsquosmcd-2epsrsquo etcprologues = 3 asigură icircnglobarea fontului icircn fişierul EPS produsdefaultfont = rdquophvr8 r rdquo fontul rsquoHelveticarsquo (vom eticheta nodurile conturului)defaultscale = 1 2 măreşte caracterele de la 8 la 812 puncte tipografice măreşte de 200 de ori mută originea spre dreapta cu 10bp şi icircn sus cu 100bpdef s c a l e _ s h i f t = scaled 200 shifted (10 100) enddef

vardef smc_point (expr t ) = punctul semicardioidei asociat lui tisin[01](2lowast t lowast(2lowast t minus1) 4lowast t lowastsqrt ( tlowast(1minus t ) ) )

enddef def s ca rd i o id = trasează semicardioida prin 100 de puncte (instrucţiuni rsquolinetorsquo)

image(pickup pencircle scaled 2 3 for t = 0 step 01 until 1

draw smc_point ( t ) s c a l e _ s h i f t withcolor (1 0 3 0) endfor

) variabilă de tip rsquopicturersquo (o vom putea instanţia icircn oricare figură)enddef

def path_nodes (expr q) = marchează nodurile conturului

37

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 38: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

pickup pencircle scaled 3 pair Z for t=0 upto length (q)

Z = point t of q draw Z marchează nodul şi icircl etichetează pe direcţia normalei la curbălabel (decimal ( t+1) 7 unitvector ( direction t of q)

rotated(minus90) shifted Z) withcolor 1 black

endforenddef

beginfig (1) path p bdquoconturulrdquo este o variabilă de tip rsquopathrsquoz1 = (0 0) nodul cardioidei (tangentă orizontală)z2 = (minus14 sqrt (3) 4) cel mai din stacircnga punct (cu tangentă verticală)z3 = (0 1) pentru t=05 tangenta este paralelă cu prima bisectoarez4 = (34 (3lowast sqrt (3) ) 4) cel mai de sus punct (tangentă orizontală)z5 = (2 0) vacircrful cardioidei (tangentă verticală)p = ( z1 l e f t z2up z3dir 4 5 z4right downz5 )

s c a l e _ s h i f t pickup pencircle scaled 0 8 grosimea peniţeidraw p withcolor 78 blue cele 4 cubice Beacutezier (cu nuanţă de albastru)path_nodes (p) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

1

2

3

4

5

Invocacircnd compilatorul de MetaPost prin mpost smcdmp obţinem fişi-erul rsquosmcd-1epsrsquo reflectat (printr-un bdquoDocument Viewerrdquo ca evince) icircn ima-ginea de mai sus deschizacircnd icircntr-un editor de cod-sursă (ca gedit) putemidentifica uşor liniile asociate icircn PostScript (prin compilarea programului demai sus cu mpost) celor patru operatori rsquorsquonewpath 10 100 movetominus2674011 100 minus40 1442627 minus40 18660278 curvetominus40 22953186 minus2038635 26961365 10 300 curveto4955688 33955688 10402466 35980835 160 35980835 curveto29988953 35980835 410 24173889 410 100 curveto stroke

Dacă am icircnscrie deasupra acestor 5 linii PS (şi apoi linia 50 100translate avacircnd icircn vedere că prima instrucţiune curveto are punctul finalla abscisa -40) şi am salva fişierul ca bdquofig-1psrdquo atunci deschizacircndu-l icircnevince vom regăsi graficul celor 4 arce 1-2-3-4-5 din imaginea de mai sus

Acuma să observăm că arcul albastru care uneşte punctele 1 şi 2 (re-prezentacircnd prima instrucţiune curveto) diferă sensibil faţă de porţiunea

38

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 39: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

(marcată prin puncte colorate bdquoorangerdquo) din K pe care voia să o aproximezedeasemenea mărind figura (spre 200 prin operaţiile obişnuite icircntr-un bdquoDo-cument Viewerrdquo) putem sesiza că arcul albastru final 4ndash5 este puţin-puţinbdquodeasuprardquo punctelor orange ale lui K

Este clar că pe K există un punct pe arcul 1ndash2 şi unul pe arcul 4ndash5icircn care tangenta ajunge paralelă cu a doua bisectoare a sistemului de axepentru aceste puncte trebuie să avem yprime(t) = minusxprime(t) adică (3 minus 4t)

radict =

(1 minus 4t)radic

1 minus tSă observăm că această ecuaţie are bdquorădăcina străinărdquo 1

2 (bdquostrăinărdquo fiindcăduce la bdquo1=-1rdquo) ridicacircnd la pătrat şi ţinacircnd seama că astfel se introduceca rădăcină şi cea bdquostrăinărdquo obţinem 32t3 minus 48t2 + 18t minus 1 = 0 lArrrArr (2t minus1)(16t2 minus 16t + 1) = 0 Prin urmare valorile t care ne dau punctele lui K icircncare tangenta are panta egală cu minus1 sunt t12 = 1

2 plusmnradic

34

Adăugăm programului MetaPost de mai sus o a doua figură consideracircndacum - prin smc_point (t12) - şi cele două puncte ale lui K determinate maisusbeginfig (2)

numeric sq sq = sqrt (3) 4 pentru a evita repetarea calcululuiz1 = (0 0) z2 = smc_point (0 5 minus sq ) tangenta face 135 grade cu Oxz3 = ( minus025 sq ) tangenta ajunge icircn poziţie verticalăz4 = (0 1) tangenta este icircnclinată cu 45 gradez5 = (0 75 3lowast sq ) tangentă orizontalăz6 = smc_point (0 5 + sq ) tangenta are direcţia egală cu (-45) gradez7 = (2 0) path p q p = z1 l e f t z2dir 135 z3up z4dir

4 5 z5right z6dir minus45downz 7 show p afişează conturul constituit (variabila rsquoprsquo)q = p s c a l e _ s h i f t scalează rsquoprsquo icircn vederea trasării efectivepickup pencircle scaled 0 8 draw q withcolor 78 blue path_nodes (q) marchează şi etichetează capetele arcelor Beacutezierdraw s ca rd i o id instanţiază semicardioida conturată prin rsquolinetorsquo

endfig

end pentru a evita modul de lucru interactiv (bdquostop NU mai am figuriicircntrebărirdquo)

12

3

4

5

6

7

De data aceasta reprezentarea lui K (schiţat cu 100 de puncte orange)prin cele 6 cubice Beacutezier (colorate albastru) este destul de bdquofidelărdquo

39

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 40: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Fiind folosit show p compilatorul ne dezvăluie icircn fişierul lsquosmcdlogrsquo con-stituţia conturului (şi am optat pentru valorile dinaintea scalării acestuia) săpreluăm din acest fişier conturul p indicat şi să adăugăm (icircnaintea declaraţieirsquoendrsquo) o nouă figură icircn care să icircntruchipăm icircntreaga cardioidă (simetrizacircnd pfaţă de Ox cu reflectedabout şi folosind apoi buildcycle) şi să trasăm conturulpoligonal al punctelor de control pentru cele 6 cubice Beacutezier care formeazăsemicardioida superioarăbeginfig (3) cardioida poligonul punctelor de control

path p q h g Kp = (0 0) controls ( minus004654 0) and ( minus008301 003397)

( minus0 11603 0 06699) controls ( minus021149 016245) and( minus025 029778)

( minus0 25 0 43301) controls ( minus025 064766) and( minus015193 084807)

( 0 1 ) controls (0 19778 1 19778) and (0 47012 1 29904)

( 0 7 5 1 2 9 9 0 4 ) controls (1 07574 1 29904) and (1 3856 1 16344)

( 1 6 1 6 0 3 0 9 3 3 0 1 ) controls (1 86324 0 6858) and (2 0 34964)

( 2 0 ) semicardioida superioară (6 cubice Beacutezier)g = p reflectedabout ( (0 0 ) (2 0 ) ) semicardioida inferioarăK = buildcycle (p reverse g ) bdquoreuneşterdquo icircntruchipacircnd cardioidaf i l l (K s c a l e _ s h i f t ) withcolor 8 white q = p s c a l e _ s h i f t scaled 100 shifted (50 300)path_nodes (q) h = point 0 of q for t=1 upto length (q)

minusminuspostcontrol tminus1 of q minusminus precontrol t of q endforminusminuspoint ( length (q) ) of q conturul poligonal al punctelor de control

draw h withpen pencircle scaled 075 withcolor (1 0 3 0) endfig

12

3

4

5

6

7

Arcul 1ndash2 avacircnd lungimea foarte mică punctele de control ale sale n-auputut fi redate distinct (la scara folosită icircn program)

Punctele de control ale unei cubice Beacutezier se accesează prin postcontrolşi respectiv precontrol (bdquopostrdquo vizează pe cel care urmează nodului iniţial alarcului iar bdquoprerdquo pe cel dinaintea nodului final) Punctele de control au fostastfel alese icircncacirct segmentul care ar uni bdquoprecontrolulrdquo unui arc cu bdquopostcon-trolulrdquo arcului Beacutezier următor să fie tangent curbei pe care arcele respectiveo aproximează (cum se şi vede pe figură) de aici şi ideea aplicată mai suspentru a reprezenta o curbă cu un număr cacirct mai mic de cubice Beacutezier ale-gem cumva cacircteva puncte ale curbei icircn care cunoaştem direcţiile tangentelor

40

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 41: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

(şi montăm cacircte o instrucţiune curveto pentru fiecare două astfel de punctevecine la parcurgerea icircntr-un acelaşi sens a curbei)Icircn MetaPost acest mecanism de calcul este implicit ceracircndu-se doar capetelearcului şi eventual direcţia tangentei (la intrare sauşi la ieşire) icircntr-un capătsau altul el este implicit fiindcă nu se vizează o cubică Beacutezier ca atare (cumface curveto din PostScript) ci totdeauna un contur format eventual (prinbdquopath_joinrdquo) din mai multe cubice Beacutezier icircnlănţuite (bdquoicircnlănţuireardquo acestoranecesită corelarea tangentelor evidenţiată mai sus)

AnexăAdăugăm cacircteva consideraţii elementare proprii asupra cardioidei şi semi-cardioidei

A De la cerc la cardioidă

O A

R

P

Aprime

T prime

T

C

Cprime

Fixăm punctele O şi A şi fie C cerculde centru A cu raza AO notăm cu Aprime

simetricul lui O faţă de AFie R un punct oarecare pe C şi

fie T simetricul lui O faţă de R iar T prime

cealaltă intersecţie cu C a dreptei TAprimefie P simetricul lui T prime faţă de R

Ce curbe descriu T şi P cacircnd Rparcurge cercul C

Din construcţia indicată rezultăuşor că OT primeTP este un dreptunghiT primeR este mediană icircn triunghiul drept-unghic OT primeT (avem ∡OT primeAprime = 90fiindcă OAprime este diametru icircn C) deciT primeR = OR ndash prin urmare diagonalele T primeP şi OT sunt egale

Icircn plus TAprime = 2 OA (fiindcă AR este linie mijlocie icircn ∆OAprimeT iar AR =AO) deci locul lui T (cacircnd R parcurge C) este cercul Cprime de centru Aprime şi razăAprimeO = 2 OA

Obs Cprime provine din C prin omotetia de centru O şi raport 2 fiindcă pentruoricare puncte corespondente T şi R avem minusrarr

OT = 2minusminusrarrOR

Fiindcă PT perp TAprime şi Aprime este centrul cercului Cprime rezultă că PT estetangentă icircn T la Cprime altfel spus P este proiecţia lui O pe o tangentă acercului Cprime

Pentru a găsi ecuaţia curbei descrise de P să reperăm punctele faţă deoriginea O(0 0) şi punctul unitar A(1 0)

41

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 42: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Cercul Cprime (cu centrul Aprime(2 0) şi raza OAprime = 2) are ecuaţia (xminus2)2+y2 = 4care se mai scrie x2 +y2 minus4x = 0 Derivacircnd icircn raport cu x 2x+2yyprime minus4 = 0găsim panta tangentei icircn T (α β) isin Cprime m = dy

dx

∣∣∣x=α

= 2minusαβ

Deci ecuaţia tangentei la Cprime icircn T (α β) este y minus β = 2minusαβ (x minus α) care

(ţinacircnd cont imediat că avem α2 + β2 = 4α) se reduce la

α(x minus 2) + βy = 2x (1)

Perpendiculara din O(0 0) pe tangenta la Cprime icircn T (α β) are ecuaţia y =minus 1

mx sauαy minus βx = 2y (2)

Rezolvăm (cu bdquoregula lui Cramerrdquo) sistemul de ecuaţii (1) (2) şi obţinemα = 2(x2+y2)

x2+y2minus2xşi β = 4y

x2+y2minus2x icircnlocuind icircn α2 + β2 minus 4α = 0 găsim ecuaţia

locului intersecţiei P a tangentei icircn T la Cprime cu perpendiculara din O peaceasta (x2 + y2)2 + 4y2 minus 2(x2 + y2)(x2 + y2 minus 2x) = 0 sau icircntr-o formăechivalentă

(x2 + y2 minus 2x)2 minus 4(x2 + y2) = 0 (3)

şi recunoaştem că aceasta reprezintă cardioida cu nodul O(0 0) şi vacircrfulAprime(2 0)

Obs Locul proiecţiilor unui punct pe tangentele unei curbe date formeazăpodara acesteia faţă de punctul respectiv ceea ce am demonstrat mai sus revine laaceastă proprietate binecunoscută podara unui cerc faţă de un punct al său esteo cardioidă Podarele cercurilor (omotetice faţă de punctul comun O) Cprime şi C suntcardioide omotetice cu nodul comun O

B Proprietăţile semicardioideiPentru a gt 0 considerăm cardioida K (x2 minus ax + y2)2 minus a2(x2 + y2) = 0şi parabola P y2 = a(a minus x) notăm cu V vacircrful lui P şi cu M un punctcu abscisa icircntre 0 şi a al lui P Să se arate că perpendiculara icircn M pe V Mintersectează K icircn focarele unei elipse tangente icircn O axei Ox(Problema L361 Recreaţii Matematice nr 12019)

Notacircnd x2 + y2 = at2 (unde t gt 0) K devine (t2 minus x)2 minus at2 = 0 adică(t2 minus x minus

radicat)(t2 minus x +

radicat) = 0 dar posibilitatea t2 minus x +

radicat = 0 trebuie

exclusă fiindcă ar conduce la y2 le 0 (am găsi y2 = at2minusx2 = at2minus(t2+radic

at)2 =minust3(t + 2

radica) şi cu t gt 0 am avea y2 lt 0 absurd)

Deci neapărat t2 minus x minusradic

at = 0 - de unde x = t(t minusradic

a) iar icircn acestcaz avem y2 = at2 minus x2 = at2 minus t2(t minus

radica)2 = t2 middot t(2

radica minus t) şi y2 ge 0 hArr

t isin [0 2radic

a]

42

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 43: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Prin urmare cercurile x2 + y2 = at2 taie graficul K icircn cel mult douăpuncte care sunt simetrice faţă de Ox ceea ce icircnseamnă că punctele semi-cardioidei superioare pot fi exprimate icircn mod unic prin parametrul t

x = t(t minusradic

a) y = tradic

t(2radic

a minus t) t isin [0 2radic

a]

Dar să eliminăm dependenţa icircntre t şi a scalacircnd faţă de lungimea in-tervalului iniţial t = 2

radica λ cu λ isin [0 1] noua parametrizaremdashrenotacircnd

totuşi lsquoλrsquo cu lsquo t rsquomdasheste

x = 2at(2t minus 1) y = 4atradic

t(1 minus t) t isin [0 1] (1)

Considerăm punctele Kt şi K1minust provenite prin (1) din valori simetricefaţă de mijlocul 1

2 al intervalului [01] pe care variază t vom demonstra maijos următoarele proprietăţi ale acestora

(a) OKt + OK1minust = 2a(b) dreptele OKt şi OK1minust sunt egal icircnclinate faţă de axa orizontală(c) mijlocul segmentului KtK1minust aparţine arcului de parabolă dat de

y =radic

a(a minus x) x isin [0 a] iar mediatoarea acestui segment trece prin vacircrfulparabolei P

0 2a

a

a

y

xt 1

Kt

K1minust

M

y =radic

a(a minus x)

K

x(t) = 2at(2t minus 1)

y(t) = 4atradic

t(1 minus t)

Icircntr-adevăr din substituţiile iniţiale x2 + y2 = at2 şi t equiv 2radic

a t rezultăcă OKt = 2at deci OKt + OK1minust = 2at + 2a(1 minus t) = 2a

Panta dreptei OKt este 2radic

t(1minust)2tminus1 şi observacircnd că transformarea t rarr 1minus t

(prin care ajungem de la Kt la K1minust) schimbă doar semnul acestei expresiideducem că suma pantelor dreptelor OKt şi OK1minust este zero ceea ce esteechivalent cu (b)

Mijlocul Mt al segmentului KtK1minust are coordonatele x = a(2t minus 1)2 =a minus 4at(1 minus t) şi y = 2a

radict(1 minus t) şi se vede imediat că satisfac y2 = a(a minus x)

Pe de altă parte pentru distanţa de la vacircrful acestei parabole la punctul

43

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei
Page 44: Aspecte de programare cu PostScript - docerp.ro fileAspecte de programare cu PostScript (eseu) Vlad Bazon∗ iunie 2019 Nuavemaici,un„alt tutorial”–cănuplecămdelaHello,world!,

Kt avem dist2((a 0) Kt) = (2at(2t minus 1) minus a)2 + 16a2t2t(1 minus t) = a2(minus4t2 +4t + 1) observacircnd acum că expresia minus4t2 + 4t + 1 este invariantă faţă detransformarea t rarr 1 minus t deducem că dist((a 0) Kt) = dist((a 0) K1minust)ceea ce icircnseamnă că vacircrful parabolei P se află pe mediatoarea segmentuluiKtK1minust

Enunţul problemei rezultă interpretacircnd proprietăţile arătate mai sus (a)spune că Kt şi K1minust sunt focarele unei elipse care trece prin O şi are axamare de lungime 2a după (b) dreptele care unesc O cu focarele menţionatesunt egal icircnclinate faţă de Ox ndash deci Ox este tangentă icircn O elipsei Conform(c) centrul acestei elipse aparţine parabolei y2 = a(a minus x) iar axa mică aelipsei trece prin vacircrful (a 0) al parabolei (şi are lungimea MV = 4at(1 minus t) ndashceea ce rezultă din triunghiul dreptunghic KtMV icircn care avem V Kt = a iar catetaMKt se deduce plecacircnd de la (1))

Parabola y2 = a(aminusx) mediază icircntre arcele separate de Oy pe semicardi-oidă cele cacircte două puncte astfel asociate sunt focarele unei elipse tangenteicircn O axei Ox (iar panta axei focarelor este

radicba unde b = MV = 4at(1 minus t))

Obs Ultima figură a fost produsă folosind MetaPost (şi apoi ps2pdf)cu următorul bdquopreambulrdquoprologues =3verbatimtex

documentclass [ 11 pt ] a r t i c l e usepackagelmodernusepackageamssymb amsmathbegindocument

etex

Icircn baza acestui bdquopreambulrdquo mpost (compilatorul de MetaPost) cu opţiu-nea -tex=latex a bdquoştiutrdquo singur cum să integreze icircn figură notaţia matema-tică LaTeX prevăzută (prin comenzi label) icircntre btex şi etex (icircn timp celucracircnd icircn PostScript trebuia pentru aceasta să procedăm cum am arătaticircn sect5 şi mpost procedează cam tot ca icircn sect5 dar bdquoautomatrdquo fără inter-venţii suplimentare din afară) Din punct de vedere practic ar fi deci maiavantajosmdashpentru a realiza figuri geometrice adnotate matematicmdashsă folo-seşti MetaPost icircn loc să foloseşti direct PostScript (doar că fişierul rezultateste de 3ndash4 ori mai mare)

44

  • Componentele programului (sau proiectului)
  • Discuţie despre operatori variabile şi transformări (pe seama producerii elipsei dintr-un cerc)
  • Producerea şi trasarea liniilor (fişierul graficeps)
    • Eroare experiment şi descoperire
    • De la semicardioidă la cardioidă cu pathforall
    • De la semicardioidă la cardioidă simetrizacircnd faţă de axă
      • Etichetarea directă folosind un font obişnuit
      • Icircncapsularea icircn figură a notaţiilor matematice
        • Citirea valorilor BoundingBox
        • Poziţionarea etichetelor pe figură
          • Arcele de parabolă sunt curbe Beacutezier pătratice
          • Arcele de parabolă prin cubice Beacutezier
          • Instrucţiunea curveto
            • Raţiunea de a fi a instrucţiunii curveto (litera S)
              • Aproximarea unei curbe prin cubice Beacutezier
              • Aproximarea semicardioidei prin cubice Beacutezier
              • Aproximarea semicardioidei folosind MetaPost
              • Anexă
              • De la cerc la cardioidă
              • Proprietăţile semicardioidei