%% 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
/ind_dir_ap {
dup 0 eq
{1}
{2 mul 1 sub}
ifelse
} def
/debug_gdir false def
/gestion_directions {
%% si le 1er point n'a pas de direction mais qu'il y a un point de
%% controle, alors on a la direction
%% si un point non extremal n'a pas de direction avant
%% --> 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
|