from time import * class polyscr: w, h = 0, 0 has_show_screen = False # color mode : # 0: (R8, G8, B8) # 1: int RGB-565 color_mode = 0 show_screen = lambda self: None def color(self, r, g=0, b=0): if not self.color_mode: return (isinstance(r, tuple) or isinstance(r,list)) and r or (r,g,b) else: if isinstance(r, tuple) or isinstance(r,list): r, g, b = r[0], r[1], r[2] return r<<11 | g<<5 | b def __init__(self): try: from nsp import Texture as scr self.w, self.h = 320, 240 scr = scr(self.w, self.h, None) self.get_pixel = scr.getPx self._set_pixel = scr.setPx self.show_screen = scr.display self.has_showScreen = True self.color_mode = 1 except: try: import ti_graphics as scr self.get_pixel = scr.getPixel self._set_pixel = scr.setPixel except ImportError: try: import casioplot as scr self.show_screen = scr.show_screen self.has_show_screen = True except ImportError: import kandinsky as scr self.get_pixel = scr.get_pixel self._set_pixel = scr.set_pixel if self.color_mode: self.set_pixel = lambda x, y, c=(0,0,0): self._set_pixel(x, y, (isinstance(c, list) or isinstance(c, tuple)) and c or self.color(c)) else: self.set_pixel = lambda x, y, c=0: self._set_pixel(x, y, (isinstance(c, list) or isinstance(c, tuple)) and self.color(c) or c) if self.w <= 0: def isRealPixel(x, y): c = self.get_pixel(x, y) if c == self.color(0,0,0): self.set_pixel(x, y, self.color(255,0,0)) c = self.get_pixel(x, y) return c is not None and c != self.color(0, 0, 0) self.w,self.h,dw,dh = 0,0,1,1 while dw or dh: if not isRealPixel(self.w-(dw==0),self.h-(dh==0)): if isRealPixel(self.w,self.h-1): dh = 0 elif isRealPixel(self.w-1,self.h): dw = 0 else: dw,dh=0, 0 self.w+=dw self.h+=dh plt = polyscr() import math def inputintminmax(s, v_min, v_max, show=False): if show: s+="? ("+str(v_min)+"-"+str(v_max)+")\n" v = v_min - 1 while v<v_min or v>v_max: v = int(input(s)) return v l = inputintminmax("Language / langue:\n0: english\n1: francais\nChoix / choice? ", 0, 1) lang=[ ["Rendering size h*w:\nh=", "w=", "Sphere type:\n0: blue\n1: mirror\nChoice? ", "Refresh display:\n0: at the end\n1: each new line\n2: each new pixel\nChoice? "], ["Taille rendu h*L:\nh=", "L=", "Type sphere:\n0: bleue\n1: mirroir\nChoix? ", "Rafraichissement:\n0: a la fin\n1: chaque ligne\n2: chaque pixel\nChoix? "]] start = monotonic() h = inputintminmax(lang[l][0], 1, plt.h, True) w = inputintminmax(lang[l][1], 1, plt.w, True) sphere_status = inputintminmax(lang[l][2], 0, 1) progress = plt.has_show_screen and inputintminmax(lang[l][3], 0, 2) or 0 sphere = (0,7,1,2, sphere_status) plane = (0,0,-0.25,-1) light = (2,2,10) inter_sph = [0,0,0] diam_vec = [0, 0, 0] ray = [0,0,0] light_ray = [0,0,0] a = 0 b = 0 c = 0 cam_vec = [0,1,0,math.pi / 4,math.pi / 4] cam_vec[3] += math.acos(cam_vec[0] / math.sqrt(2)) cam_vec[4] += math.asin(cam_vec[1] / math.sqrt(2)) cor_x = math.cos(cam_vec[3]) * math.sqrt(2) cor_y = math.cos(cam_vec[4]) * math.sqrt(2) cor_z = math.cos(cam_vec[2] / math.sqrt(2) + math.pi / 4) * math.sqrt(2) for i in range(3): ray[i] = cam_vec[i] + (cor_x,cor_y,cor_z)[i] def calc_r(n): return (-2*sum([inter_sph[i]*light_ray[i] - light_ray[i]*sphere[i] for i in range(3)]) + ((n==2) - (n==1)) * math.sqrt(delta_2)) / 2*sum([light_ray[i]**2 for i in range(3)]) def calc_delta_2(): return 4*sum([inter_sph[i]*light_ray[i] - light_ray[i]*sphere[i] for i in range(3)])**2 - 4*sum([light_ray[i]**2 for i in range(3)])*(sum([(inter_sph[i] - sphere[i])**2 for i in range(3)]) - sphere[3]**2) def do_1(f): global color, delta_2 for i in range(3): inter_sph[i] = (a,b,c)[i]+t*ray[i] light_ray[i] = light[i] - inter_sph[i] if sphere[4] == 0 : delta_2 = calc_delta_2() color = [0,0,255] if delta_2 >= 0 : r_1 = calc_r(1) r_2 = calc_r(2) if abs(r_1) <= abs(r_2) : color[2] -= int(r_2*255/(abs(r_1)+r_2)) else : for i in range(3): diam_vec[i] = inter_sph[i] - sphere[i] k = sum([diam_vec[i]*((a,b,c)[i] - sphere[i]) for i in range(3)]) / sum([diam_vec[i]**2 for i in range(3)]) l = sum([diam_vec[i]**2 * k**2 + 2 * diam_vec[i]*((a,b,c)[i] - sphere[i]) + (sphere[i] - (a,b,c)[i])**2 for i in range(3)]) proj = [k*diam_vec[i] + sphere[i] for i in range(3)] refl = [2*(proj[i] - (a,b,c)[i]) + (a,b,c)[i] for i in range(3)] reflect = [refl[i] - inter_sph[i] for i in range(3)] if sum([plane[i]*reflect[i] for i in range(3)]) != 0 : t_2 = -(sum([plane[i]*inter_sph[i] for i in range(3)]) + plane[3]) / sum([plane[i] * reflect[i]]) if t_2 > 0 : color[(inter_sph[f]+t_2*reflect[f])%2<1 and (inter_sph[not f]+t_2*reflect[not f])%2>=1 or (inter_sph[f]+t_2*reflect[f])%2>=1 and (inter_sph[not f]+t_2*reflect[not f])%2<1] = 255 for i in range(3): inter_sph[i] = inter_sph[i]+t_2*reflect[i] light_ray[i] = light[i] - inter_sph[i] if calc_delta_2() >= 0 : color[color != [255, 0, 0]] = 100 def do_2(): color[(b+t_2*ray[1])%2<1 and (a+t_2*ray[0])%2>=1 or (b+t_2*ray[1])%2>=1 and (a+t_2*ray[0])%2<1] = 255 for i in range(3): inter_sph[i] = (a,b,c)[i]+t_2*ray[i] light_ray[i] = light[i] - inter_sph[i] if calc_delta_2() >= 0 : color[color != [255, 0, 0]] = 100 for y in range(h) : for x in range(w) : color = [0,0,0] ray[0] = x * 2/w + cor_x ray[2] = cor_z - y * 2/h delta = 4*(sum([(a,b,c)[i]*ray[i] for i in range(3)]) - sum([ray[i]*sphere[i] for i in range(3)]))**2 - 4*sum([ray[i]**2 for i in range(3)])*(sum([((a,b,c)[i] - sphere[i])**2 for i in range(3)]) - sphere[3]**2) if delta > 0 : t = (-2*sum([(a,b,c)[i]*ray[i] - ray[i]*sphere[i] for i in range(3)]) - math.sqrt(delta)) / 2*sum([ray[i]**2 for i in range(3)]) if sum([plane[i]*ray[i] for i in range(3)]) != 0 : t_2 = -(sum([plane[i]*(a,b,c)[i] for i in range(3)]) + plane[3]) / sum([plane[i]*ray[i] for i in range(3)]) if t_2 > 0 and delta > 0 and t_2 > t or delta >= 0 and t_2 <= 0: do_1(1 - (t_2 > 0 and delta > 0 and t_2 > t)) elif t_2 > 0 and (delta > 0 and t_2 <= t or delta < 0): do_2() plt.set_pixel(x, y, color) if progress>=2 or x == w-1 and progress>=1 or y == h-1 and x == w-1: plt.show_screen() stop = monotonic() print(stop-start)