Coverage for src/ensae_teaching_cs/special/image/image_synthese_base.py: 88%
168 statements
« prev ^ index » next coverage.py v7.1.0, created at 2023-04-28 06:23 +0200
« prev ^ index » next coverage.py v7.1.0, created at 2023-04-28 06:23 +0200
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief définition des objets permettant de construire une image de synthèse
5"""
6import math
7import copy
10class Vecteur:
11 """définit ce qu'est un point"""
12 __slots__ = "x", "y", "z"
14 def __str__(self):
15 """pour l'affichage"""
16 return f"({self.x:3.2f},{self.y:3.2f},{self.z:3.2f})"
18 def __init__(self, x, y, z):
19 """initialisation"""
20 self.x, self.y, self.z = float(x), float(y), float(z)
22 def __add__(self, p):
23 """addition de deux points"""
24 return Vecteur(self.x + p.x, self.y + p.y, self.z + p.z)
26 def __neg__(self):
27 """retourne l'opposé d'un vecteur"""
28 return Vecteur(-self.x, -self.y, -self.z)
30 def __iadd__(self, p):
31 """addition de deux points"""
32 self.x += p.x
33 self.y += p.y
34 self.z += p.z
35 return self
37 def __sub__(self, p):
38 """soustraction de deux points"""
39 return Vecteur(self.x - p.x, self.y - p.y, self.z - p.z)
41 def __isub__(self, p):
42 """soustraction de deux points"""
43 self.x -= p.x
44 self.y -= p.y
45 self.z -= p.z
46 return self
48 def __mul__(self, x):
49 """multiplication par un scalaire"""
50 return Vecteur(self.x * x, self.y * x, self.z * x)
52 def __imul__(self, x):
53 """multiplication par un scalaire"""
54 self.x *= x
55 self.y *= x
56 self.z *= x
57 return self
59 def __truediv__(self, x):
60 """division par un scalaire"""
61 return Vecteur(self.x / x, self.y / x, self.z / x)
63 def __itruediv__(self, x):
64 """division par un scalaire"""
65 self.x /= x
66 self.y /= x
67 self.z /= x
68 return self
70 def norme2(self):
71 """retourne la norme du vecteur au carré"""
72 return self.x * self.x + self.y * self.y + self.z * self.z
74 def scalaire(self, v):
75 """calcule le produit scalaire entre self et v"""
76 return self.x * v.x + self.y * v.y + self.z * v.z
78 def vectoriel(self, v):
79 """calcule le produit vectoriel entre self et v"""
80 res = Vecteur(0, 0, 0)
81 res.x = self.y * v.z - self.z * v.y
82 res.y = self.z * v.x - self.x * v.z
83 res.z = self.x * v.y - self.y * v.x
84 return res
86 def norme(self):
87 """retourne la norme du vecteur"""
88 return math.sqrt(self.norme2())
90 def renorme(self):
91 """renorme ce vecteur"""
92 n = self.norme()
93 if n > 0:
94 return self / n
95 else:
96 return copy.copy(self)
98 def cosinus(self, v):
99 """retourne le cosinus de entre le vecteur self et le vecteur r"""
100 sc = self.scalaire(v)
101 n1 = self.norme()
102 n2 = v.norme()
103 n = n1 * n2
104 if n == 0:
105 return 0
106 return float(sc) / float(n)
108 def sinus(self, v, norm):
109 """retourne le sinus de entre le vecteur self et le vecteur r,
110 norm est un vecteur normal et de norme 1 permettant d'orienter
111 le plan dans lequel se trouve les deux vecteurs dont il faut mesurer le sinus"""
112 sc = self.vectoriel(v)
113 n1 = self.norme()
114 n2 = v.norme()
115 n = n1 * n2
116 if n == 0:
117 return 0
118 return sc.scalaire(norm) / float(n)
120 def angle(self, v, norm):
121 """retourne l'angle entre les vecteur self et v,
122 retourne un angle compris entre -pi et pi,
123 norm est la direction du vecteur normal au plan des deux vecteurs"""
124 cos = self.cosinus(v)
125 sin = self.sinus(v, norm)
126 angle = math.atan2(sin, cos)
127 if angle > math.pi:
128 angle -= math.pi * 2
129 return angle
131 def diff_abs(self, v):
132 """retourne la somme des valeurs absolues des différentes entre coordonnées"""
133 r = abs(self.x - v.x)
134 r += abs(self.y - v.y)
135 r += abs(self.z - v.z)
136 return r
138 def __eq__(self, v):
139 """définit l'égalité entre deux vecteurs"""
140 if v is None:
141 return False
142 return self.diff_abs(v) < 1e-10
144 def __ne__(self, v):
145 """définit l'égalité entre deux vecteurs"""
146 if v is None:
147 return True
148 return self.diff_abs(v) > 1e-10
151class Couleur (Vecteur):
152 """une couleur est un vecteur dont les coordonnées sont comprises entre 0 et 1,
153 x <--> rouge, y <--> vert, z <--> bleu"""
155 def __init__(self, x, y, z):
156 Vecteur.__init__(self, x, y, z)
157 self.borne()
159 def borne(self):
160 """si une couleur est hors bornes, réajuste la couleur, prend le maximum devient 1,
161 les autres intensités sont ajustées selon ce facteur d'échelle"""
162 if self.x < 0:
163 self.x = 0
164 if self.y < 0:
165 self.y = 0
166 if self.z < 0:
167 self.z = 0
168 m = max(self.x, self.y)
169 m = max(m, self.z)
170 if m > 1:
171 self.x /= m
172 self.y /= m
173 self.z /= m
175 def __add__(self, p):
176 """addition de deux couleurs"""
177 return Couleur(self.x + p.x, self.y + p.y, self.z + p.z)
179 def produit_terme(self, v):
180 """effectue un produit terme à terme"""
181 return Couleur(self.x * v.x, self.y * v.y, self.z * v.z)
183 def __mul__(self, x):
184 """multiplication par un scalaire"""
185 return Couleur(self.x * x, self.y * x, self.z * x)
188class Repere:
189 """définition d'un repère orthonormé"""
191 def __init__(self, origine=Vecteur(0, 0, 0),
192 axex=Vecteur(1, 0, 0),
193 axey=Vecteur(0, 1, 0),
194 axez=Vecteur(0, 0, 1)):
195 """initialisation, origine et les trois axes"""
196 self.origine = origine
197 self.x = axex
198 self.y = axey
199 self.z = axez
201 def coordonnees(self, v):
202 """on suppose que les coordonnées de v sont exprimées dans ce repère,
203 calcule les coordonnées de v dans le repère d'origine"""
204 res = copy.copy(self.origine)
205 res.x += v.x * self.x.x + v.y * self.y.x + v.z * self.z.x
206 res.y += v.x * self.x.y + v.y * self.y.y + v.z * self.z.y
207 res.z += v.x * self.x.z + v.y * self.y.z + v.z * self.z.z
208 return res
210 def __str__(self):
211 """affichage"""
212 s = "origine : " + str(self.origine) + "\n"
213 s += "axe des x : " + str(self.x) + "\n"
214 s += "axe des y : " + str(self.y) + "\n"
215 s += "axe des z : " + str(self.z) + "\n"
216 return s
219class Pixel:
220 """définit ce qu'est un pixel"""
221 __slots__ = "x", "y"
223 def __init__(self, x, y):
224 """initialisation"""
225 self.x, self.y = int(x), int(y)
227 def __str__(self):
228 """pour l'affichage"""
229 return "(%d, %d)" % (self.x, self.y)
232class Rayon:
233 """définit ce qu'est un rayon"""
234 __slots__ = "origine", "direction", "pixel", "couleur"
236 def __init__(self, origine, direction, pixel, couleur):
237 """initialisation"""
238 self.origine, self.direction, self.pixel, self.couleur = origine, direction, pixel, couleur
240 def __str__(self):
241 """pour l'affichage"""
242 s = "origine : " + str(self.origine)
243 s += " direction : " + str(self.direction)
244 s += " pixel : " + str(self.pixel)
245 s += " couleur : " + str(self.couleur)
246 return s
249class Objet:
250 """définit l'interface pour un objet à dessiner dans une image de synthese"""
252 def intersection(self, r):
253 """retourne le point d'intersection avec le rayon r,
254 retourne None s'il n'y pas d'intersection"""
255 return None
257 def normale(self, p, rayon):
258 """retourne la normale au point de coordonnée p, et connaissant le rayon"""
259 return None
261 def couleur_point(self, p):
262 """retourne la couleur au point de coordonnée p"""
263 return None
265 def rayon_refracte(self, rayon, p):
266 """retourne le rayon réfracté au point p de la surface,
267 si aucune, retourne None"""
268 return None
270 def rayon_reflechi(self, rayon, p):
271 """retourne le rayon réfléchi au point p de la surface,
272 si aucune, retourne None"""
273 return None
275 def phong_coefficient(self):
276 """retourne un coefficient propre à l'objet pour
277 le modèle d'illumination de Phong"""
278 return float(0)
281class Source:
282 """définition d'une source ponctuelle"""
283 __slots__ = "origine", "couleur"
285 def __init__(self, origine, couleur):
286 """initialisation"""
287 self.origine, self.couleur = origine, couleur
289 def __str__(self):
290 """affichage"""
291 return "source : " + str(self.origine) + " couleur : " + str(self.couleur)