%!PS-Adobe-2.0 %%BoundingBox: 0 0 400 400 %%Page: 1 1 1.5 setlinewidth /width 400 def % Largeur du dessin % point de fuite du dessin (Changez `y` pour voir le dessin se transformer, ex : 150) /perspectivex width 2 div def /perspectivey 165 def % Note : On suppose l'horizon à 140 pour le reste du programme (tout les calculs lié sont déjà fait) % Note : On suppose la hauteur constante pour une determination des constantes "magiques" plus facile, alors que le programme s'adapte en largeur (cependant pas de maniere parfaite) % Il est recommandé de lire les fonctions dans le sens dans lequelles elles sont dessinées (voir tout en bas du fichier) /pavage { % Pavage (lignes bleues sur le sol) gsave % Clip sur le rectangle du bas newpath 0 0 moveto width 0 rlineto 0 140 rlineto % 140 -> horizon 0 width sub 0 rlineto closepath clip 18 1 40 { % Lignes horizontales, je commence a 18 car les lignes d'avants sont hors du cadre /i exch def /i i dup mul def % i = i^2 % y = 250*(1 - 323.395 / i), la constante magique "323.395" a été determinée à la main en faisant de petits changements % Mais ce qui est interessant c'est que la distance entres les lignes horizontales est proportionnelle à 1/x comme d'apres les loi de la perspective /y 250 1 323.395 i div sub mul def newpath 0 y moveto width 0 rlineto closepath 37 255 div % r = (37) / 255 (Le color picker que j'utilisais pour trouver les couleurs me les donnait dans le format entier) 132 y 2 div add 255 div % g = (132 + y/2) / 255 (g tend vers 255 quand y tends vers +inf) 1 % b = 1 setrgbcolor 4 y 75 div sub setlinewidth % width = 4 - y/75 (les lignes sont de plus en plus fines quand y augmente) stroke } for -10 1 20 { % Lignes verticales (qui partent du point de perspective et vont vers l'infini) /i exch def % x = -295 + i*90, autrement dit chaque ligne est espacée de 90 pixels au niveau de y = 0 (c'est le deuxième point) /x -295 i 90 mul add def /lastx perspectivex def /lasty perspectivey def % Le for suivant est une technique pour faire une ligne en couleur dégradée % On décompose la ligne en sous parties (ici de 1% de la taille de base) que l'on dessine bout par bout avec une couleur qui varie 0 .01 1.01 { /ratio exch def % ratio correspond à l'étape (il varie entre 0 et 1 par step de 0.01) /newx perspectivex 1 ratio sub mul x ratio mul add def % new = perspectivex * (1-ratio) + x * ratio, interpolation linéaire (car c'est une droite) entre x et perspectivex /newy perspectivey 1 ratio sub mul def % idem entre 0 et perspectivey newpath lastx lasty moveto newx newy lineto closepath % On dessine le petit bout.. 37 255 div % r = 37 / 255 132 newy 100 div 50 mul add 255 div % g = (132 + 50*newy/100) (même formule que pour les lignes horizontales) 1 % b = 1 setrgbcolor 2.5 newy 140 div sub setlinewidth % linewidth = 2.5 - newy/140 (La taille des lignes diminue quand y augmente) stroke /lastx newx def % On se rappelle des coordonnées actuelles /lasty newy def } for } for grestore } def /arbre { % utilisation : x y x2 y2 recur arbre luminance /luminance exch def % Eclaircissement de l'arbre 5 dict begin % On fait un dict car on va utiliser "arbre" recursivement, donc on veut définir les variables comme locales /recur exch def % Valeur de recursion, qui baisse de branche en branche /y2 exch def % Point d'arrivée /x2 exch def /y exch def % Point de départ /x exch def /diffx x2 x sub def % Vecteur de différence (arrivee-depart) /diffy y2 y sub def /normx 0 diffy sub def % Normal au ve cteur de différence (utilisé pour les branches filles) /normy diffx def newpath % On set le path avec les coordonnées données x y moveto x2 y2 lineto closepath % Pour le dessin de la branche je le décompose en deux strokes, l'exterieur et l'interieur qui ont deux couleurs différente /linewidth 3 recur add def % linewidth = 3 + recur .. quand recur est grand c'est qu'on est haut dans l'arbre (pres du tronc), donc les lignes sont plus epaisses gsave linewidth setlinewidth 232 luminance add 255 div % r = (232 + luminance) / 255 On voit que luminance est utilisé pour ajuster la luminosité (une grande valeur va rendre l'arbre plus blanc 45 luminance add 255 div % g = ( 45 + luminance) / 255 89 luminance add 255 div % b = ( 89 + luminance) / 255 setrgbcolor stroke % Premier trait (trait exterieur) grestore linewidth 1.5 div setlinewidth % Taille du second trait = 2/3*linewidth 50 recur 25 mul add luminance add 255 div % r = ( 50 + recur*25 + luminance) / 255 Les feuilles sont moins rouge que le tronc 255 recur 25 mul sub luminance add 255 div % g = (255 - recur*25 + luminance) / 255 Les feuilles sont plus vertes que les branches 50 luminance add 255 div % b = ( 50 + luminance) / 255 on garde la meme teinte de bleu setrgbcolor stroke recur 0 ge % On recursionne si recur >= 0 { % On définit les coordonnées "d'envoie" en faisant la moyenne du vecteur de différence et de la normale, ce qui est censé donner un angle de 45 degrés % Note : On fait une petite multiplication par 0.95 pour faire un arbre un peu plus compact (la taille de la branche d'après décroit exponentiellement) /sendx x2 diffx normx add 2 div 0.95 mul add def % sendx = x2 + (diffx + normx) / 2 * 0.95 /sendy y2 diffy normy add 2 div 0.95 mul add def % sendy = y2 + (diffy + normy) / 2 * 0.95 x2 y2 sendx sendy recur 1 sub luminance arbre % On fait la branche avec une recursion = recursion-1 /normx 0 normx sub def % On oppose la normale pour faire une branche dans l'autre sens /normy 0 normy sub def % normey = -normey /sendx x2 diffx normx add 2 div 0.95 mul add def % sendx = x2 + (diffx + normx) / 2 * 0.95 (meme calcul) /sendy y2 diffy normy add 2 div 0.95 mul add def % sendy = y2 + (diffy + normy) / 2 * 0.95 x2 y2 sendx sendy recur 1 sub luminance arbre % On envoie la deuxieme branche } if end % On relache les variables locales } def /arbres { % Pour aligner les arbres selon la perspective (Et donc faire une sorte d'allée) j'ai utilisé le meme code que le tracé des lignes verticales pour le pavage. /i 2 def % On prend la deuxieme ligne /x -295 i 90 mul add def /lastx perspectivex def /lasty perspectivey def /size 10 def % Taille de l'arbre .25 .35 1.01 { % Meme code que les lignes.. sauf qu'on mets 3 arbres au lieu de 100 petits bouts /ratio exch def /newx perspectivex 1 ratio sub mul x ratio mul add def /newy perspectivey 1 ratio sub mul def /size size 30 add def % Les arbres qui sont plus pres de nous sont plus gros newx newy newx newy size add 5 ratio 5 mul add 105 size sub arbre % On note le recur = 5 + ratio * 5, les arbres plus pres de nous sont plus complexes % Ainsi que le luminance = 105 - size, les arbres plus petits sont plus clairs (ils sont aussi plus loin) } for /i 9 def % On fait exactement le meme code pour une autre rangée (ici la 9e) /x -295 i 90 mul add def /lastx perspectivex def /lasty perspectivey def /size 10 def .25 .35 1 { /ratio exch def /newx perspectivex 1 ratio sub mul x ratio mul add def /newy perspectivey 1 ratio sub mul def /size size 30 add def newx newy newx newy size add 5 ratio 5 mul add 105 size sub arbre } for } def /spirale { /size exch def % Nombre d'itérations a effectuer (angle total) /speed exch def % Inverse de la vitesse à laquelle la spirale s'éloigne du centre /baseangle exch def % Décalage d'angle /basey exch def % Point centrale de la spirale /basex exch def gsave basex basey moveto % On va au point centrale /dist 0 def % On est a 0 du centre au début /lastangle 0 def /lastdist 0 def 0 3 size { % On itere en degré 3 par 3 /angle exch baseangle add def % Angle = baseangle + stack (qui correspond a l'iteration) /dist angle speed div def % dist = angle / speed newpath basex lastangle cos lastdist mul add % x = basex + cos(lastangle)*lastdist basey lastangle sin lastdist mul add % y = basey + sin(lastangle)*lastdist moveto basex angle cos dist mul add % x = basex + cos(angle)*dist basey angle sin dist mul add % y = basey + sin(angle)*dist lineto closepath 2 setlinewidth % Largeur de la spirale /ratio 1 angle size div sub def % Le ratio correspond a la distance du centre ratio .05 le {/ratio 0 def} if % if(ratio < 0.05) ratio = 0 /ratio ratio dup dup mul mul def % ratio = ratio^3 (la transition est donc cubique pour un dégradé plus agréable) /y basey angle sin dist mul add def % y = basey + sin(angle)*dist % y est utilisé pour le calcul des couleurs % Calcul de la couleur de la spirale par interpolation en utilisant ratio % r = ratio*couleur + (1-ratio)*couleur2 % Ici couleur est une constante et couleur2 correspond a la couleur de fond % Ainsi, plus la spirale s'éloigne du centre plus elle prend la couleur du fond (ratio tends vers 0) 238 255 div ratio mul % r = 238 / 255 (couleur au centre de la spirale) .1 170 y sub 170 div y 50 mul sin 50 div add add 1 ratio sub mul % Couleur de fond qui dépend de y % Voir la fonction "fond" pour la formule traduite en infix add % Idem pour le bleu 98 255 div ratio mul .1 1 ratio sub mul % Couleur de fond add % Et pour le vert 139 255 div ratio mul 188 255 108 sub y 300 div mul sub 255 div 1 ratio sub mul % Couleur de fond add setrgbcolor stroke % On dessine le petit bout /lastangle angle def /lastdist dist def } for grestore } def /aureole { % Correspond à la spirale derrière le soleil gsave newpath % On clip sur la partie supérieur 0 400 moveto width 0 rlineto 0 -260 rlineto 0 width sub 0 rlineto closepath clip width 2 div 170 0 50 12000 spirale % On dessine la spirale avec comme paramètres : % x (centre) = width/2 % y (centre) = 170 % baseangle = 0 % speed = 50 % size = 12000 (l'angle va varier de 0 à 12000) grestore } def /point % Dessine un point sur le dessin aux coordonnées x, y { /y exch def % Arguments /x exch def newpath x y moveto x .5 add y lineto closepath % Petite ligne horizontale de taille 0.5 1 setgray .5 setlinewidth stroke } def /couleurfond { % Renvoie la couleur de fond en fonction de y 1 dict begin /y exch def .1 200 y sub 200 div y 50 mul sin 30 div add add %r = (200 - y)/200 + sin(y*50)/30 + .1 %C'est un dégradé classique avec une subtilité grace au sin .1 %g = .1 188 255 108 sub y 300 div mul sub 255 div %b = (188-(255-108)*(y/300))/255 % Dégradé classique b part de 188 puis tends vers 0 quand y augmente (mais plus lentement que le rouge end } def /soleil { % Dessin du soleil /basey 170 def % Hauteur du soleil (ici un peu au dessus de l'horizon) -29 1 60 { % On dessine le soleil ligne à ligne (permet de faire un dégradé) /y exch def % le for donne la valeur de la hauteur relative à la base % width = 60*sqrt(1-(y/60)^2) Largeur de la ligne en fonction de la hauteur % Formule obtenue grâce au fait que la fonction y=sqrt(1-x^2) dessine un demi cercle /sunwidth 60 1 y 60 div dup mul sub sqrt mul def newpath width 2 div sunwidth sub % x = width/2 - sunwidth (rappel : width correspond à la largeur de la fenetre) basey y add % y = basey+y moveto sunwidth 2 mul % decalagex = 2*sunwidth 0 % decalagey = 0 rlineto closepath 1.5 setlinewidth /ratio y 30 add 90 div def % ratio = (y + 30)/90, ratio correspond au pourcentage de soleil dessiné % Ce ifelse permet de faire les "trous" dans le soleil, en dessinant le fond à la place du soleil selon une fonction qui devient négative sur les intervalles que je voulais. % C'est donc pour ça qu'il y a un 0 le (<= 0) à la fin % La fonction dépend de la hauter et est donc % sin(y*((y / 2) + 50) + 20) + .2 (rappel : sin est en degré) % Visualisation de la fonction : % https://www.google.fr/?q=sin(pi*(y*((y+%2F+2)+%2B+50)+%2B+20)%2F180)+%2B+.2 y 50 y 2 div add mul 20 add sin .2 add 0 le y 15 le and % On ne coupe que si y <= 15 { basey y add couleurfond % On rempli le trou avec la couleur de fond (pour écraser la spirale derrière le soleil) } { % Pour la couleur du soleil en lui meme on fait juste une interpolation linéaire entre deux couleurs prises à la main % couleur1 = 254, 246, 0 (une sorte de violet) % couleur2 = 255, 45, 149 (un jaune) 254 255 div ratio mul 255 255 div 1 ratio sub mul add 246 255 div ratio mul 45 255 div 1 ratio sub mul add 0 255 div ratio mul 149 255 div 1 ratio sub mul add } ifelse setrgbcolor % on applique donc la couleur choisis stroke } for } def /fond { % Fonction qui dessine le dégradé de fond 0 0 moveto 0 1 width { % On dessine ligne à ligne /y exch def gsave newpath 0 y moveto width 0 rlineto closepath % On mets le path pour la ligne y couleurfond setrgbcolor stroke grestore } for } def /etoiles { % Dessin des étoiles en haut de l'image % Pour le dessin des étoiles, on coupe le ciel en 10 parties, puis plus on est haut dans le ciel plus cette partie à d'étoiles, celon la relation nb d'étoiles = (numéro_partie)^2 0 1 11 { % on boucle sur les parties /i exch def /basey 200 i 20 mul add def % Le y de base vaut donc 200 + i*20 (la hauteur de l'image vaut 400 en tout, et les étoiles partent du millieu) i i mul { % On boucle i^2 fois /x rand width mod def % On prend x au hasard entre 0 et width (x=rand(0, width)) /y basey rand 20 mod add def % On prend y = basey + rand(0, 20) x y point % On dessine l'étoile } repeat } for } def % Pipeline de render fond % Couleur de fond aureole % Spirale derrière le soleil pavage % Pavage en perspective soleil % Dessin du soleil arbres % Dessin des arbres en allée etoiles % Dessin des étoiles en haut de l'écran showpage