%% ATTENTION : nb_points est une variable globale %% syntaxe : t p Hobby_function /Hobby_function { 2 dict begin /@phi exch def /@theta exch def %% numerateur @theta cos @phi cos sub @phi sin @theta sin 16 div sub mul @theta sin @phi sin 16 div sub mul 1.414 mul 2 add %% denominateur @theta cos 5 sqrt 1 sub mul 2 div @phi cos 3 5 sqrt sub 2 div mul add 1 add 3 mul %% le resultat div end } def %% syntaxe : z0 w0 alpha beta w1 z1 compute_control_points --> u v /compute_control_points { 8 dict begin /@z1 defpoint /@w1 defpoint /b@t@ exch def /@lph@ exch def /@w0 defpoint /@z0 defpoint /thet@ @w0 @z1 @z0 subc divc argc def /@phi @z1 @z0 subc @w1 divc argc def %% le point de controle no 1 @z1 @z0 subc thet@ @phi Hobby_function @lph@ div mulv thet@ cos thet@ sin mulc @z0 addc %% le point de controle no 2 @z1 @z1 @z0 subc @phi thet@ Hobby_function b@t@ div mulv @phi cos @phi neg sin mulc subc end } def /.. {1 1} def /-- (straight) def /curl {(curl)} def %% [A 30 dir .. right B right .. up C] general_to_bezier bezier_curve %%%%%%%%%%%%% La c'est le bordel... %% compter les points d'un chemin /compte_points { 5 dict begin /liste exch def /liste_length liste length def /nb_points 0 def /i 0 def /lexeme 0 def { /nb_points nb_points 1 add store %% le 1er est un point /i i 2 add store liste i get isarray %% est ce une direction ? { %% oui /i i 1 add store %% on passe au suivant } if /lexeme liste i get store lexeme isstring %% est une chaine ? { %% oui, c'est (controls) ou (straight) lexeme 0 get 99 eq { %% c'est (controls) /i i 5 add store %% on shunte les 2 points } { %% c'est (straight) /i i 1 add store } ifelse } { %% non, donc on a les tensions /i i 2 add store %% on les shunte } ifelse %% on passe au suivant (le dernier) liste i get isarray %% si c'est une direction {/i i 1 add store} %% on passe a la suite if i 3 add liste_length gt %% a-t-on fini ? { %% oui /nb_points nb_points 1 add store exit } if } loop nb_points end } def %% syntaxe : array index point pput ou array estun tableau de points /pput { 2 dict begin /y exch def /x exch def 2 copy 2 mul 1 add y put 2 mul x put end } def /declare_tableaux { /points_controle nb_points 1 sub 4 mul array def /tensions nb_points 1 sub 2 mul array def /directions nb_points 1 sub 4 mul array def /points_cles nb_points 2 mul array def /pbm nb_points array def %% on initialise les tableaux 'directions', 'points_controle' et 'pbm' /i 0 def nb_points 1 sub { pbm i 0 put %% pbm i 2 mul 0 put %% obsolete ? %% pbm i 2 mul 1 add 0 put %% obsolete ? directions i 2 mul () () pput directions i 2 mul 1 add () () pput points_controle i 2 mul () () pput points_controle i 2 mul 1 add () () pput /i i 1 add store } repeat pbm nb_points 1 sub 0 put /i_ctrl 0 def /i_tens 0 def /i_dir 0 def /i_term 0 def %% (pbm) pbm aload pop (fin pbm) prout } def /debug_remplit false def %% remplir les tableaux /remplit_tableaux { 2 dict begin /i 0 def /lexeme 0 def { debug_remplit {(term)} if points_cles i_term %% le 1er est un point liste i get liste i 1 add get pput debug_remplit {(fin_term)} if %% mais on n'augmente son indice %% qu'a la fin de la boucle /i i 2 add store liste i get isarray %% est ce une direction ? { %% oui debug_remplit {(dir_1)} if directions i_term 2 mul %% on la stocke liste i get exec pput /i i 1 add store %% on passe au suivant debug_remplit {(fin_dir_1)} if } if /lexeme liste i get store lexeme isstring %% est une chaine ? { %% oui, c'est (controls) ou (straight) lexeme 0 get 99 eq { %% c'est (controls) debug_remplit {(ctrl)} if /i i 1 add store %% on stocke les 2 points points_controle i_term 2 mul liste i get liste i 1 add get pput /i i 2 add store %% on stocke le 2eme point points_controle i_term 2 mul 1 add liste i get liste i 1 add get pput /i i 2 add store %% on passe a la suite debug_remplit {(fin ctrl)} if } { %% c'est (straight) /i i 1 add store } ifelse } { %% non, donc on a les tensions debug_remplit {(tension)} if tensions i_term 2 mul %% on les stocke lexeme put /i i 1 add store tensions i_term 2 mul 1 add liste i get put debug_remplit {(fin tension)} if /i i 1 add store } ifelse %% on passe au suivant (le dernier) liste i get isarray %% si c'est une direction { directions i_term 2 mul 1 add %% on la stocke liste i get exec pput /i i 1 add store %% on passe a la suite } if debug_remplit {i longueur_liste (i)} if i 3 add longueur_liste gt %% a-t-on fini ? { %% oui exit } if /i_term i_term 1 add store %% non, on augmente l'indice et } loop %% on recommence %% mais on recupere quand meme le dernier point /i_term i_term 1 add store %% on augmente l'indice points_cles i_term liste i get liste i 1 add get pput end } def /debug_straight false def %% gestion des (straight) /gere_straight { 3 dict begin /i 0 def /i_term 0 store /lexeme 0 def { /i i 2 add store %% le 1er est un point %% mais on n'augmente son indice %% qu'a la fin de la boucle liste i get isarray %% est ce une direction ? { %% oui /i i 1 add store %% on passe au suivant } if /lexeme liste i get store lexeme isstring %% est une chaine ? { %% oui, c'est (controls) ou (straight) lexeme 0 get 99 eq { %% c'est (controls) /i i 5 add store %% on passe a la suite } { %% c'est (straight) %% on est au point i_term %% il faut gerer les points de controle debug_straight {i_term (straight)} if points_controle i_term 2 mul points_cles i_term getp points_cles i_term 1 add getp milieu pput points_controle i_term 2 mul 1 add points_cles i_term getp points_cles i_term 1 add getp milieu pput %% ainsi que les directions directions i_term 2 mul points_cles i_term getp points_cles i_term 1 add getp vecteur pput directions i_term 2 mul 1 add points_cles i_term getp points_cles i_term 1 add getp vecteur pput /i i 1 add store %% on passe a la suite } ifelse } { %% non, donc on a les tensions /i i 2 add store %% on passe a la suite } ifelse %% on passe au suivant (le dernier) liste i get isarray %% si c'est une direction { /i i 1 add store %% on passe a la suite } if i 3 add longueur_liste gt %% a-t-on fini ? { %% oui exit } if /i_term i_term 1 add store %% non, on augmente l'indice et } loop %% on recommence end } def %% k ind_dir_avt --> donne l'indice ds le tableau 'directions' de %% la direction avt pour le point terminal d'indice k (k>0) /ind_dir_avt { 1 sub 2 mul 1 add } def %% k ind_dir_ap --> donne l'indice ds le tableau 'directions' de %% la direction ap pour le point terminal d'indice k (k si pt de ctrl avant, ok %% --> si direction apres, on la recopie avant %% --> si point de controle apres, on calcule la nvelle direction %% --> sinon, pbm... 1 dict begin /i 1 def %% on attaque le point d'indice 1 nb_points 2 sub { directions i 1 sub 2 mul 1 add getp %% la direction avant pop isstring %% initialisee ? { %% non debug_gdir {i (dir avt nil)} if points_controle i 1 sub %% le pt de ctrl avant 2 mul 1 add getp pop isstring { %% non initialise debug_gdir {(ctrl avt nil)} if directions i 2 mul getp %% la direction apres pop isstring not %% initialisee ? { %% oui debug_gdir {(dir ap ok)} if directions %% ==> on la recopie i 1 sub 2 mul 1 add directions i 2 mul getp pput } { %% non debug_gdir {(dir ap nil)} if points_controle i 2 mul getp pop isstring %% pt de ctrl apres ? { %% non debug_gdir {(ctrl ap nil)} if %% y a un pbm, on le note %% pbm i 2 mul 1 sub 1 put %% obsolete ? pbm i 1 put } { %% oui debug_gdir {(ctrl ap ok)} if directions %% ok pour la dir avant i 1 sub 2 mul 1 add points_cles i getp points_controle i 2 mul getp vecteur pput } ifelse } ifelse } { debug_gdir {(ctrl avt ok)} if directions %% la direction consideree i 1 sub 2 mul 1 add points_controle i 1 sub %% le pt de ctrl avant 2 mul 1 add getp points_cles i %% le pt terminal correspondant getp vecteur pput } ifelse } if %% si un point non extremal n'a pas de direction apres %% --> si pt de ctrl apres, ok %% --> si direction avant, on la recopie apres %% --> si point de controle avant, on calcule la nvelle direction %% --> sinon, pbm... directions i 2 mul getp %% la direction apres pop isstring %% initialisee ? { %% non debug_gdir {i (dir ap nil)} if points_controle i %% le pt de ctrl apres 2 mul getp pop isstring { %% non initialise debug_gdir {(ctrl ap nil)} if directions i 1 sub %% la direction avant 2 mul 1 add getp pop isstring not %% initialisee ? { %% oui debug_gdir {(dir av ok)} if directions %% ==> on la recopie i 2 mul directions i 1 sub 2 mul 1 add getp pput } { %% non debug_gdir {(dir av nil)} if points_controle i 1 sub 2 mul 1 add getp pop isstring %% pt de ctrl avant ? { %% non debug_gdir {(ctrl av nil)} if %% y a un pbm, on le note %% pbm i 2 mul 1 put %% obsolete ? pbm i 1 put %% XXX } { %% oui debug_gdir {(ctrl av ok)} if directions %% ok pour la dir apres i 2 mul points_cles i getp points_controle i 2 mul 1 sub getp vecteur pput } ifelse } ifelse } { debug_gdir {(ctrl ap ok)} if directions i 2 mul %% la direction consideree points_controle i %% le pt de ctrl apres 2 mul getp points_cles i getp %% le pt terminal apres vecteur pput } ifelse } if /i i 1 add store } repeat %% si le dernier point n'a pas de direction mais qu'il y a un point de %% controle, alors on a la direction directions nb_points 1 sub ind_dir_ap getp pop isstring %% initialisee ? { %% non points_controle nb_points 2 mul 3 sub getp %% pt de controle avant pop isstring %% initialise ? { %% non } { %% oui directions %% on calcule la direction nb_points 1 sub ind_dir_avt points_controle nb_points 2 mul 3 sub getp points_cles nb_points 1 sub getp vecteur pput } ifelse } if end } def /debug_gctrl false def /gestion_points_controle { %% si les points de controle existent ok, sinon on les calcule et on %% les stocke. pre-requis : toutes les directions sont connues 3 dict begin /i 0 def { points_controle i 2 mul getp %% le pt de ctrl avant pop isstring %% initialise ? { %% non debug_gctrl {i (ptctrl nil)} if points_cles i getp directions i 2 mul getp tensions i 2 mul get tensions i 2 mul 1 add get directions i 2 mul 1 add getp points_cles i 1 add getp compute_control_points /ctrl_pt_tw@ defpoint /ctrl_pt_@ne defpoint points_controle i 2 mul ctrl_pt_@ne pput points_controle i 2 mul 1 add ctrl_pt_tw@ pput } if /i i 1 add store %% on passe a la suite debug_gctrl {i (endloop)} if i 1 add nb_points eq {exit} if %% c'est fini } loop end } def %% l'operation terminale : on reconstruit le tableau du chemin avec %% tous les points de controle pour obtenir un objet 'bezier_curve' /construit_path { /i 0 def [ nb_points 1 sub { points_cles i getp points_controle i 2 mul getp points_controle i 2 mul 1 add getp /i i 1 add store } repeat points_cles i getp ] } def %% si on a des directions, ok. %% si on a des points de controle, ok. %% sinon on a des curls et il y 'pbm' et %% il faut calculer les points de controle. ici on se contente de marquer %% les problemes et de mettre des curls s'il n'y en a pas /gestion_curl { %% on regarde le point 0 directions 1 get isstring points_controle 0 get isstring and { %% ni direction ni pts de ctrl pbm 0 1 put %% donc pbm directions 1 get %% mais peut-etre un curl ? length 0 eq %% si <> 0, y a curl { directions 0 1 put %% sinon on le met directions 1 (curl) put } if } if %% on regarde le dernier point directions nb_points 1 sub 4 mul 1 sub get isstring points_controle nb_points 1 sub 4 mul 1 sub get isstring and { %% ni direction ni pt de ctrl pbm %% nb_points 1 sub 2 mul 1 sub %% obsolete ? nb_points 1 sub 1 put %% donc pbm directions nb_points 1 sub 4 mul 1 sub get %% mais peut-etre un curl ? length 0 eq %% si <> 0, y a curl { directions nb_points 1 sub 4 mul 2 sub 1 put %% sinon on le met directions nb_points 1 sub 4 mul 1 sub (curl) put } if } if } def %% renvoie true si le tableau 'pbm' contient un terme non nul, %% autrement dit s'il reste des directions a calculer /problem { /i 0 def false nb_points { pbm i get 1 eq { pop true exit } if /i i 1 add store } repeat } def %% syntaxe : i get_alpha --> alpha_i ou alpha est la tension 'avant' %% stockee dans le tableau global 'tensions' /get_alpha { tensions exch 2 mul get } def %% syntaxe : i get_beta --> beta_i ou beta est la tension 'apres %% stockee dans le tableau global 'tensions' /get_beta { tensions exch 2 mul 1 sub get } def %% syntaxe : A k ligne_identite --> on remplit la ligne d'indice k de la matrice A /ligne_identite { 2 dict begin /k exch def /A exch def %% d'abord la matrice A A k [ k {0} repeat 1 nb_points k sub 1 sub {0} repeat ] put_Li end } def %% syntaxe : k ligne_identite --> la direction d'indice k est %% connue. on remplit la ligne d'indice k de la matrice A ainsi que la %% ligne d'indice k de la matrice B /cree_ligne_identite { 1 dict begin /k exch def %% d'abord la matrice A A k [ k {0} repeat 1 nb_points k sub 1 sub {0} repeat ] put_Li %% puis la matrice B B k I_k k get put end } def %% cree la ligne d'indice 0 de A et la ligne d'indice 0 de B /cree_ligne_0 { debug_pbm {(ligne 0)} if A 0 [ %% coeff A_0,0 0 get_alpha dup mul 1 1 get_beta div 3 sub mul directions 0 get %% c'est gamma_0 1 get_beta dup mul mul 0 get_alpha div sub %% coeff A_0,1 directions 0 get %% c'est gamma_0 1 get_beta dup mul mul 0 get_alpha div 0 get_alpha dup mul 1 get_beta div sub directions 0 get %% c'est gamma_0 3 mul 1 get_beta dup mul mul sub %% la fin de la ligne nb_points 2 sub {0} repeat ] %% debug %% (ligne 0) exch aload pop (fin ligne 0) prout put_Li B 0 %% le coeff B_0 directions 0 get %% c'est gamma_0 3 mul 1 get_beta dup mul mul 0 get_alpha dup mul 3 mul add A_k 0 get neg mul put debug_pbm {(fin ligne 0)} if } def %% cree la ligne d'indice k de A et la ligne d'indice k de B /cree_ligne_k { 1 dict begin /k exch def debug_pbm {k (ligne k)} if /lk %% inverse de |z_k - z_k-1| 1 points_cles k getp points_cles k 1 sub getp distance div def /lk+1 %% inverse de |z_k+1 - z_k| 1 points_cles k 1 add getp points_cles k getp distance div def A k [ k 1 sub {0} repeat %% le coeff A_k,k-1 k get_beta dup mul lk mul k 1 sub get_alpha div %% le coeff A_k,k k get_beta dup mul lk mul 3 1 k 1 sub get_alpha div sub mul 1 k 1 add get_beta div 3 sub k get_alpha dup mul lk+1 mul mul sub %% le coeff A_k,k+1 k get_alpha dup mul lk+1 mul k 1 add get_beta div nb_points k sub 2 sub {0} repeat ] put_Li B k %% le coeff B_k k get_beta dup mul 3 mul lk mul A_k k 1 sub get mul A_k k get 3 mul k get_alpha dup mul mul lk+1 mul add put debug_pbm {(fin ligne k)} if end } def %% cree la ligne d'indice n de A et la ligne d'indice n de B /cree_ligne_n { 1 dict begin debug_pbm {(ligne n)} if /n nb_points 1 sub def A n [ nb_points 2 sub {0} repeat %% le coeff A_n,n-1 n get_beta dup mul n 1 sub get_alpha div 1 n get_beta div 3 sub n 1 sub get_alpha dup mul mul directions 4 n mul 2 sub get %% c'est gamma_n mul sub %%%%% MODIF %% le coeff A_n,n n get_beta dup mul 3 1 n 1 sub get_alpha div sub mul directions 4 n mul 2 sub get %% c'est gamma_n n 1 sub get_alpha dup mul mul n get_beta div add ] put_Li B n %% le coeff B_n 3 A_k n 1 sub get mul n get_beta dup mul % n 1 sub get_alpha div directions 4 n mul 2 sub get %% c'est gamma_n n 1 sub get_alpha dup mul mul add mul put debug_pbm {(fin ligne n)} if end } def /debug_pbm false def %% calcul les directions manquantes /gere_pbm { %% on pose le pbm sous la forme %% A I = B %% ou A est une matrice carree, I le vecteur des directions inconnues %% (angles en degres) et B un vecteur connu %% on a besoin des a_k = arg (z_k+1 - z_k) %% on note I_k = (i_k) = (arg (w_k)) le vecteur des inconnues debug_pbm {(pbm)} if %% les matrices utiles /A_k nb_points 1 sub array def /I_k nb_points array def /B nb_points array def /A nb_points array def %% on initialise A a la matrice nulle /A [ nb_points { [ nb_points {0} repeat ] } repeat ] def debug_pbm {(a_k)} if %% on commence par calculer les a_k = arg (z_k - z_k-1) /k 0 def nb_points 1 sub { A_k k points_cles k getp points_cles k 1 add getp vecteur arg put /k k 1 add store } repeat %% debug %% (Ak) A_k aload pop (fin Ak) debug_pbm {(i_k)} if %% puis on initialise I_k en tenant compte des directions deja connues %% les points extremaux ont un traitement particulier /k 0 def nb_points { pbm k get 1 eq { %% la direction n'est pas connue I_k k () put %% on initialise a () %k (OK!!) } { %% la direction est connue I_k k %% on initialise directions k 0 eq %% gestion de l'indice des directions {0} %% 1er point { k nb_points 1 sub eq { %% dernier point nb_points 2 sub 2 mul 1 add } { %% point intermediaire k 2 mul 1 sub } ifelse } ifelse getp argc put %k (OK!!) } ifelse /k k 1 add store } repeat %% debug %nb_points (nb) %(dirs) directions aload pop (fin dirs) %(Ik) I_k aload pop (fin Ik) %(pbm) pbm aload pop (fin pbm) %prout %% reste a creer la matrice des coeffs %% la matrice du resultat, et la matrice des inconnues (dont certaines %% sont... connues) %% il y a nb_points equations debug_pbm {(A)} if pbm 0 get 0 eq {0 cree_ligne_identite} {cree_ligne_0} ifelse /i 1 def nb_points 2 sub { pbm i get 0 eq {i cree_ligne_identite} {i cree_ligne_k} ifelse /i i 1 add store } repeat pbm nb_points 1 sub get 0 eq {nb_points 1 sub cree_ligne_identite} {cree_ligne_n} ifelse %% debug %% (B) B aload pop (fin B) %% debug %% A view_square_matrix %% debug %% prout debug_pbm {(solve syst)} if B A solve_syst %% maintenant on a toutes les directions %% debug %% aload pop (fin sols) /I_k exch def %% reste a remplir les directions qui manquent pbm 0 get 1 eq { directions 0 I_k 0 get dir pput } if /i 1 def nb_points 2 sub { pbm i get 1 eq { directions i 2 mul I_k i get dir pput directions i 2 mul 1 sub I_k i get dir pput } if /i i 1 add store } repeat pbm nb_points 1 sub get 1 eq { directions nb_points 2 mul 3 sub I_k nb_points 1 sub get dir pput } if debug_pbm {(fin pbm)} if } def %% syntaxe : chemin_mf make_path --> l'objet 'bezier_curve' correspondant /make_path { 19 dict begin /liste exch def /longueur_liste liste length def liste compte_points /nb_points exch def declare_tableaux remplit_tableaux gere_straight gestion_directions % (pbm avt curl) pbm aload pop (fin pbm avt curl) gestion_curl % (pbm) pbm aload pop (fin pbm) problem {gere_pbm} if gestion_points_controle construit_path end } def %% %% syntaxe : chemin_mf draw --> trace l'objet 'bezier_curve' correspondant %% /draw { %% make_path %% % (ici) exch aload pop boum %% bezier_curve %% } def /draw { 2 dict begin dup isstring { /option exch def } if /arg {argc} def make_path % (ici) exch aload pop boum currentdict /option known { option } if bezier_curve end } def %% syntaxe : chemin_mf draw --> trace l'objet 'bezier_curve' correspondant /draw* { make_path % (ici) exch aload pop boum bezier_curve* } def %% syntaxe : chemin_mf draw --> trace l'objet 'bezier_curve' correspondant /draw_ { make_path % (ici) exch aload pop boum bezier_curve_ } def