def draw_gradient_grid(self, sampler, filename=None): """draw_gradient_grid""" gradient_grid = self.get_gradient_grid(sampler) fig, ax = plt.subplots() ax.set_xlim([-1.2, 1.2]) ax.set_ylim([-1.2, 1.2]) ax.imshow(utils.torch_img_to_np_img( self.input[0]), extent=[-1, 1, -1, 1]) total_angle = 0 target_mo = self.target_mo[0].cpu().numpy() for gradient in gradient_grid: base_loc = gradient['motion'][0].neg().cpu().numpy() gradient = gradient['gradient'][0].neg().cpu().numpy() gradient_dir = utils.unit_vector(gradient) gt_dir = utils.unit_vector(target_mo - base_loc) angle = utils.angle_between(gradient_dir, gt_dir) total_angle += angle try: cur_color = utils.angle_to_color(angle) except ValueError: cur_color = [0., 0., 0.] ax.arrow(*base_loc, *(gradient_dir/10), head_width=0.05, head_length=0.1, color=cur_color) # plt.show() if filename is None: filename = sampler.sampling_mode print(filename, 'mean error angle:', total_angle/len(gradient_grid)) plt.savefig('./%s.png' % filename) plt.close(fig)
def __init__(self, lookfrom, lookat, vup, vfov, aspect, aperture, focus_dist): """ Initialize camera position, orientation, field of view and aperture. Args: lookfrom: camera location within scene lookat: coordinates towards which camera is oriented vup: "up" direction vfov: "field of view" angle, in rad aspect: aspect ratio (width / height) of focus window aperture: aperture (diameter) of camera lense focus_dist: distance of focus plane from camera """ self._lens_radius = aperture / 2 # vfov is top to bottom in rad half_height = np.tan(vfov/2) half_width = aspect * half_height self._origin = lookfrom # orthonormal basis self._w = unit_vector(lookfrom - lookat) self._u = unit_vector(np.cross(vup, self._w)) self._v = np.cross(self._w, self._u) # define the focus plane window self._lower_left_corner = self._origin \ - half_width *focus_dist*self._u \ - half_height*focus_dist*self._v \ - focus_dist*self._w self._horizontal = 2*half_width *focus_dist*self._u self._vertical = 2*half_height*focus_dist*self._v
def __init__(self, lookfrom, lookat, vup, vfov, aspect, aperture, focus_dist): self.lens_radius = aperture / 2 theta = vfov * math.pi / 180 half_height = math.tan(theta / 2) half_width = aspect * half_height self.origin = lookfrom self.w = unit_vector(lookfrom - lookat) self.u = unit_vector(np.cross(vup, self.w)) self.v = np.cross(self.w, self.u) self.lower_left_corner = self.origin \ - half_width * self.u * focus_dist \ - half_height * self.v * focus_dist \ - self.w * focus_dist self.horizontal = 2 * half_width * self.u * focus_dist self.vertical = 2 * half_height * self.v * focus_dist
def ray_color(ray, scene, depth): """ Perform ray tracing and return color of ray. Args: ray: to-be traced ray scene: geometric scene depth: how often the ray is allowed to scatter Returns: numpy.ndarray: ray color as RGB values """ rec, _ = scene.hit(ray, 0.001, 1e6) if rec is not None: scattered, attenuation = rec.material.scatter(ray, rec) if depth > 0 and scattered is not None: # pointwise multiplication between attenuation and # return value of recursive function call return attenuation * ray_color(scattered, scene, depth - 1) else: return np.zeros(3) else: # blue background sky unitdir = unit_vector(ray.direction) t = 0.5*(unitdir[1] + 1) return (1 - t)*np.array([1.0, 1.0, 1.0]) + t*np.array([0.5, 0.7, 1.0])
def test_dielectric_scatter(self): dielmat = Dielectric(0.2) # ray specified by origin and direction ray = Ray(np.array([0.2, 0., 0.3]), np.array([0.1, -0.05, -1.1])) # hit record point = np.array([0.3, 0.4, -0.5]) normal = unit_vector(np.array([0.2, 0.9, -0.1])) rec = HitRecord(point, normal, dielmat) scattered, att = dielmat.scatter(ray, rec) self.assertEqual( np.linalg.norm(scattered.origin - point), 0, msg='origin of scattered ray must agree with hit record point') # reference directions of scattered ray (can be either reflected or refracted) reflect_ref = np.array( [0.054686541501393009, -0.20612619488986597, -0.97699609720757918]) refract_ref = np.array( [0.22585143494322246, 0.92588833091527412, -0.30285628276298776]) err_reflect = np.linalg.norm(scattered.direction - reflect_ref) err_refract = np.linalg.norm(scattered.direction - refract_ref) self.assertAlmostEqual( min(err_reflect, err_refract), 0, delta=1e-14, msg='direction of scattered ray must agree with reference')
def __init__(self, lookfrom, lookat, vup, vfov, aspect, aperture, focus_dist): self.lens_radius = aperture / 2.0 theta = vfov * math.pi / 180 half_height = math.tan(theta * 0.5) half_width = aspect * half_height self.origin = lookfrom w = unit_vector(lookfrom - lookat) u = unit_vector(np.cross(vup, w)) v = np.cross(w, u) self.low_left_corner = lookfrom - half_width * u * focus_dist - half_height * v * focus_dist - w * focus_dist self.horizontal = 2 * half_width * u * focus_dist self.vertical = 2 * half_height * v * focus_dist self.u = u self.v = v self.w = w
def __init__(self, master, pos, direction, color=None): self.pos = np.array(pos) if color is None: color = [255 for i in range(3)] self.color = color self.master = master self.radius = 10 self.dir = utils.unit_vector(direction) self.speed = 0
def refract(v, n, ni_over_nt, refracted): uv = unit_vector(v) dt = np.dot(uv, n) discriminant = 1.0 - ni_over_nt * ni_over_nt * (1 - dt**2) if discriminant > 0: refracted = ni_over_nt * (uv - n * dt) - n * math.sqrt(discriminant) return True, refracted else: return False, refracted
def scatter(self, ray, rec): nraydir = unit_vector(ray.direction) reflected = reflect(nraydir, rec.normal) scattered = Ray(rec.point.copy(), reflected + self._fuzz * random_in_unit_sphere()) if np.dot(scattered.direction, rec.normal) > 0: return (scattered, self._albedo) else: return (None, self._albedo)
def inertial2orbital(self): """ Takes the intertial positions and velocity and turns that into the LVLH distances and relative speeds. This gives excellent estimations of the horizontal (ie vbar) distance, but fails in the rbar direction. Issue with linearisation of the fact that the trajectory is a curve? .. note:: This *does work* when the chaser and target are very close :return: delta r, delta v (both 3d vector) .. note:: this method is currently unused... """ Rchaser = np.array([0,self.chaser.x, self.chaser.y]).reshape((1,3)) Rtarget = np.array([0,self.target.x, self.target.y]).reshape((1,3)) deltaR = (Rchaser - Rtarget) Vchaser = np.array([0,self.chaser.u, self.chaser.v]).reshape((1,3)) Vtarget = np.array([0,self.target.u, self.target.v]).reshape((1,3)) deltaV = (Vchaser - Vtarget) Ht = np.cross(Rtarget, Vtarget) Roi = np.zeros([3,3]) Roi[:,0] = utils.unit_vector(np.cross(Ht,Rtarget)) Roi[:,1] = -utils.unit_vector(Ht) Roi[:,2] = -utils.unit_vector(Rtarget) omegaI = np.cross(Rtarget, Vtarget) / np.linalg.norm(Rtarget) / np.linalg.norm(Rtarget) deltaro = np.matmul(deltaR, Roi) OmegaR = np.cross(omegaI, deltaR) deltaVo = np.matmul(deltaV, Roi) - np.matmul(OmegaR, Roi) return deltaro, deltaVo
def __init__(self): # Initialise pygame os.environ["SDL_VIDEO_CENTERED"] = "1" pygame.init() s_width = 1600 s_height = 800 # Set up the display self.screen = pygame.display.set_mode((s_width, s_height)) self.clock = pygame.time.Clock() # define cornerpoints wall_thickness = 20.0 c_depth = 250.0 p0 = (wall_thickness, wall_thickness) p1 = (s_width - wall_thickness, wall_thickness) p2 = (s_width - wall_thickness, s_height - wall_thickness) p3 = (wall_thickness, s_height - wall_thickness) self.walls = [ RectWall((p0, p1), (0.0, 0.0), (wall_thickness, s_height)), RectWall((p1, p2), (s_width - wall_thickness, 0.0), (wall_thickness, s_height)), RectWall((p2, p3), (0.0, s_height - wall_thickness), (s_width, wall_thickness)), RectWall((p3, p0), (0.0, 0.0), (s_width, wall_thickness)), PolyWall(((0, c_depth), (c_depth, 0.0), (0.0, 0.0))), PolyWall(((s_width - c_depth, 0.0), (s_width, c_depth), (s_width, 0.0))), PolyWall(((s_width, s_height - c_depth), (s_width - c_depth, s_height), (s_width, s_height))), PolyWall(((0, s_height - c_depth), (c_depth, s_height), (0.0, s_height))) ] self.orbits = [ orbit.Orbit((500, 600), 100, [40 for i in range(3)]), orbit.Orbit((900, 500), 100, [40 for i in range(3)]), orbit.Orbit((200, 400), 100, [40 for i in range(3)]) ] self.orbs = [] self.players = [ head.Head(self, (400.0, 400.0), utils.unit_vector((-1, -1.01))) ] # self.players = [head.Head(self, (random.randrange(200.0, 1400.0), random.randrange(200.0, 600.0)), utils.unit_vector((random.random()*2 - 1, random.random() * 2 - 1))) for i in range(10)] # self.players = [orb.Orb(self, (701.0, 200.0), utils.unit_vector((-1, 0))), orb.Orb(self, (100.0, 259.0), utils.unit_vector((1, 0)))] self.tail = False
def color(r, world, depth): boolean, rec = world.hit(r, 0.001, float('inf'), hit_record()) if boolean: flag, attenuation, scattered = rec.mat_ptr.scatter( r, rec, np.array([0.0, 0.0, 0.0], dtype=float)) if depth < 50 and flag: return attenuation * color(scattered, world, depth + 1) else: return np.zeros([3], dtype=float) else: unit_direction = unit_vector(r.direction()) t = 0.5 * (unit_direction[1] + 1.0) return (1.0 - t) * np.array([1.0, 1.0, 1.0]) + t * np.array( [0.5, 0.7, 1.0])
def scatter(self, ray, rec): # normalized ray direction nraydir = unit_vector(ray.direction) reflected = reflect(nraydir, rec.normal) cosine = np.dot(nraydir, rec.normal) if cosine > 0: refracted = refract(nraydir, -rec.normal, self._ref_idx) else: refracted = refract(nraydir, rec.normal, 1.0 / self._ref_idx) cosine = -cosine if refracted is not None: reflect_prob = schlick(cosine, self._ref_idx) else: reflect_prob = 1.0 # randomly choose between reflection or refraction if np.random.rand() < reflect_prob: return (Ray(rec.point.copy(), reflected), np.ones(3)) else: return (Ray(rec.point.copy(), refracted), np.ones(3))
def sky(ray): unit_dir = unit_vector(ray.direction) t = 0.5 * (unit_dir[1] + 1.0) return (1.0 - t) * np.array([1.0, 1.0, 1.0]) + t * np.array( [0.5, 0.7, 1.0])
def compute(self, pos, dir): v0 = pos - self.orbit_centre v1 = np.matmul(self.rot_matrix, v0) p1 = self.orbit_centre + v1 return p1, utils.unit_vector(p1 - pos)
def __init__(self, collision_vector, color=(255, 255, 255)): self.coll_v = np.array(collision_vector) self.coll_norm = utils.perp( utils.unit_vector(self.coll_v[1] - self.coll_v[0])) print(self.coll_v, self.coll_norm) self.color = color
def circle_vertices(pos, r, n=32): result = [] a = 2 * pi / n for i in range(n): result.append(pos + r * unit_vector(a * i)) return result
def plot(self, time_ticks=1, save=True, highlight_new_orbit=True): """ A lot of things here could be computed only once """ t = np.arange(len(self.target.speed_x)) * self.dt / self.chaser.P vtgt = np.hypot(self.target.speed_x, self.target.speed_y) * 1e-3 vcha = np.hypot(self.chaser.speed_x, self.chaser.speed_y) * 1e-3 ################################# chaserspeed = np.array([self.chaser.speed_x, self.chaser.speed_y]).T vch = np.hypot(chaserspeed[:,0], chaserspeed[:,1])# * 1e-3 chxy = np.array([self.chaser.trajectory_x, np.array(self.chaser.trajectory_y)]) r = u.unit_vector(chxy).T aalpha = u.vangle_between(chaserspeed, r) dxo = 3. * np.pi * (self.target.a - self.chaser.a) v_bar = np.zeros_like(aalpha) for jjk in range(len(chxy[0])): try: vb = (self.distances.trajectory_x[jjk-1] - self.distances.trajectory_x[jjk]) / (self.dt) except: vb = np.nan if jjk == 0: vb = np.nan v_bar[jjk] = vb vz_bar = vch * np.cos(aalpha) * 1e-3 #v_bar *= dxo / (np.nanmean((v_bar[:self.idch])) * 1e3 * self.chaser.P) ############################## if self.chaser.hp == self.chaser.ha: txtch = r"$\mathrm{%s:\,%d\,km\,alt.}$" % (self.chaser.name, self.chaser.hp) else: txtch = r"$\mathrm{%s}:\,%d\times%d\mathrm{\,km\,alt.}$" % (self.chaser.name, self.chaser.hp, self.chaser.ha) txttgt = r"$\mathrm{%s:\,%d\,km\,alt.}$" % (self.target.name, self.target.hp) nimg = 0 for ii in range(len(self.target.speed_x)-1): if not ii % time_ticks == 0: continue #if ii > len(self.target.speed_x): continue fig = plt.figure(figsize=(18,10)) plt.subplots_adjust(wspace=0.) plt.subplots_adjust(bottom=0.01) plt.subplots_adjust(top=0.95) plt.subplots_adjust(right=0.98) plt.subplots_adjust(left=0.) gs = gridspec.GridSpec(4, 3) # This where we plot the Earth orbit at the right scale ax0 = fig.add_subplot(gs[:2,0]) #ax0.plot([1,2,3,4,5], [10,5,10,5,10], 'r-') ax0.set_aspect("equal") circle1 = plt.Circle((0, 0), constants.radiusE, color='b', alpha=0.5) ax0.add_artist(circle1) ax0.plot(self.target.trajectory_x[:self.idtgt], -1 * np.array(self.target.trajectory_y[:self.idtgt]), c='k') ax0.plot(self.chaser.trajectory_x[:self.idch], -1 * np.array(self.chaser.trajectory_y[:self.idch]), c='r') ax0.scatter(self.target.trajectory_x[ii], -1 * np.array(self.target.trajectory_y[ii]), c='k') ax0.scatter(self.chaser.trajectory_x[ii], -1 * np.array(self.chaser.trajectory_y[ii]), c='r') ax0.set_xticks([]) ax0.set_yticks([]) ax0.axis('off') ax1 = fig.add_subplot(gs[0,1:]) #t = np.arange(len(self.target.speed_x)) * self.dt / self.chaser.P #vtgt = np.hypot(self.target.speed_x, self.target.speed_y) * 1e-3 #vcha = np.hypot(self.chaser.speed_x, self.chaser.speed_y) * 1e-3 ax1.plot(t, vtgt, c='k', label=self.target.name) ax1.plot(t, vcha, c='r', label=self.chaser.name) xmin1, xmax1 = ax1.get_xlim() ymin1, ymax1 = ax1.get_ylim() ax1.scatter(t[ii], vtgt[ii], c='k') ax1.scatter(t[ii], vcha[ii], c='r') #ax1.plot(t, vcha-vtgt, c='b', label=r"$\Delta v$") ax1.legend(fontsize=self.txtsize - 2) ax1.xaxis.set_ticklabels([]) ax1.set_ylabel(r"$v\,\mathrm{[km/s]}$") ax1.grid() ax1.set_xlim([xmin1, xmax1]) ax1.set_ylim([ymin1, ymax1]) ax2 = fig.add_subplot(gs[2:,0]) ax2.set_aspect("equal") r, theta = u.cart2polar(self.target.trajectory_x, self.target.trajectory_y) r -= constants.radiusE x, y = u.polar2cart(r, theta) ax2.plot(x[:self.idtgt] * 1e-3, -1e-3 * y[:self.idtgt], c='k') ax2.scatter(x[ii] * 1e-3, -1e-3 * y[ii], c='k') r, theta = u.cart2polar(self.chaser.trajectory_x, self.chaser.trajectory_y) r -= constants.radiusE x, y = u.polar2cart(r, theta) lim2 = 1.15 * np.amax([self.chaser.ha, self.target.ha]) ax2.set_xlim([-lim2, lim2]) ax2.set_ylim([-lim2, lim2]) ax2.plot(x[:self.idtgt] * 1e-3, -1e-3 * y[:self.idtgt], c='r') ax2.scatter(x[ii] * 1e-3, -1e-3 * y[ii], c='r') ax2.set_xticklabels([]) ax2.set_yticks([]) ax2.axis('off') ax3 = fig.add_subplot(gs[1, 1:])#, sharex=ax1) ax3.set_xlabel("$\mathrm{Time\,[Orbits\,of\,chaser]}$") ax3.plot(t, v_bar*1e3, c='gold', label=r"$\bar{V}$") ax3.plot(t, vz_bar*1e3, c='g', label=r"$v_R$") ymin3, ymax3 = ax3.get_ylim() ax3.scatter(t[ii], v_bar[ii]*1e3, c='gold') ax3.scatter(t[ii], vz_bar[ii]*1e3, c='g') ax3.set_xlim([xmin1, xmax1]) ax3.set_ylim([ymin3, ymax3]) ax3.legend(fontsize=self.txtsize - 2) ax3.grid() ax3.axhline(0, c='k', ls='--') ax3.set_ylabel(r"$\bar{V},\,v_R\,\mathrm{[m/s]}$") ax4 = fig.add_subplot(gs[2:,1:]) ax4.spines['left'].set_position('zero') ax4.spines['right'].set_color('none') ax4.spines['bottom'].set_position('zero') ax4.spines['top'].set_color('none') # remove the ticks from the top and right edges ax4.xaxis.set_ticks_position('bottom') ax4.yaxis.set_ticks_position('left') ax4.invert_xaxis() ax4.invert_yaxis() ax4.plot(-np.array(self.distances.trajectory_x), -np.array(self.distances.trajectory_y)) ax4.scatter(-np.array(self.distances.trajectory_x)[ii], -np.array(self.distances.trajectory_y)[ii]) # For correctly plotting the vbar axis ax4.plot([0], [0], c='k') xmin, xmax = ax4.get_xlim() ymin, ymax = ax4.get_ylim() if t[ii] > 1 and highlight_new_orbit: ax4.axvline(-self.distances.trajectory_x[0], c='k', ls='--') ax4.axvline(-self.distances.trajectory_x[int(np.ceil(self.chaser.P / self.dt))], c='k', ls='--') x4t = -(self.distances.trajectory_x[0] + self.distances.trajectory_x[int(np.ceil(self.chaser.P / self.dt))])/2. y4t = (ymax - ymin) * 0.5 + ymin y4tt = (ymax - ymin) * 0.51 + ymin ax4.plot([-self.distances.trajectory_x[0], -self.distances.trajectory_x[int(np.ceil(self.chaser.P / self.dt))]], [y4t, y4t], ls='--', c='k') ax4.annotate(r'$1\,\mathrm{orbit\,}\Delta x = 3\pi\Delta a\approx %3.0f\,\mathrm{km}$' % (dxo/1e3), xy=(x4t, y4tt), ha='center') xx = ((1. - xmax / (xmax - xmin)) * 1.005 * (xmax - xmin) + xmin) yy = ((1. - ymax / (ymax - ymin)) * 1.015 * (ymax - ymin) + ymin) ax4.annotate(r'$\bar{V}\,\mathrm{[km]}$', xy=((xmax - xmin) * 0.01 + xmin, yy)) ax4.annotate(r'$\bar{R}\,\mathrm{[km]}$', xy=(xx, (ymax - ymin) * 0.02 + ymin)) if self.ax4_xmin is None: self.ax4_xmin = xmin self.ax4_xmax = xmax self.ax4_ymin = ymin self.ax4_ymax = ymax gs.update(wspace=0.05, hspace=0.3) ax4.set_xlim([self.ax4_xmin, self.ax4_xmax]) ax4.set_ylim([self.ax4_ymin, self.ax4_ymax]) plt.suptitle(txtch + r"$\quad$--$\quad$" + txttgt + r"$\quad$--$\quad$" + r"Time {:03d} min".format(int(self.dt*ii/60.))) if not os.path.exists(self.outdir): os.mkdir(self.outdir) if save: fig.savefig(os.path.join(self.outdir, "img_{:05d}.png".format(nimg)), dpi=200) plt.close() else: plt.show() nimg += 1
def scatter(self, r_in, rec, attenuation): reflected = reflect(unit_vector(r_in.direction()), rec.normal) scattered = ray(rec.p, reflected + self.fuzz * random_in_unit_sphere()) attenuation = self.albedo return np.any(np.dot(scattered.direction(), rec.normal)) > 0, attenuation, scattered
def update(refresh_rate): # Controls first, see if anything has happened # zoom functionality if controller[key.DOWN]: transform.zoom *= 0.975 for body in bodies: body.zoom(0.975) if controller[key.UP]: transform.zoom *= 1.025 for body in bodies: body.zoom(1.025) # Boosting if controller[key.W] and sol.m[0] > DRY_MASS: # perform boost in direction of spacecraft orientation = np.radians(player.rotation) boost = utils.unit_vector(orientation) * THRUST / sol.m[ 0] # acceleration sol.v[0] = sol.v[0] + boost * VARS['dt'] sol.m[0] = sol.m[0] - FLOW_RATE * VARS['dt'] mass_label.text = f'Fuel: %.3E' % (sol.m[0] - DRY_MASS) elif sol.m[0] < DRY_MASS: mass_label.text = f'Fuel: Empty' # Ship rotation if controller[key.D]: # rotate clockwise player.rotation = utils.bound_angles(player.rotation + DTHETA) if controller[key.A]: # rotate counterclockwise player.rotation = utils.bound_angles(player.rotation - DTHETA) # Change simulation speed if controller[key.COMMA]: VARS['dt'] *= 0.98 sim_label.text = 'Sim. Speed: %.3f' % (VARS['dt']) if controller[key.PERIOD]: VARS['dt'] *= 1.02 sim_label.text = 'Sim. Speed: %.3f' % (VARS['dt']) VARS['time'] = time.time() - t_zero #VARS['dt'] # update time time_label.text = 'Time: %.2f' % (VARS['time']) # this is where we update the window, and the game actually happens sol.update(VARS['dt']) # update solar system motions with time step dt # then shift from solar system coordinates to screen coordinates screen_coordinates = transform(sol.r) # update the sprites (icons) accordingly background_sprite.update( sol.v[1] * VARS['dt'] * transform.scale / transform.zoom) # update background to follow star for j, body in enumerate(bodies): body.update(screen_coordinates[j]) # Collision detection + fuel conversion # Check if any object is close enough to be converted to fuel dist_to_player = np.linalg.norm( sol.r[1:], axis=1) - sol.radius[1:] # distance to surface ################################# Add sol.r[0] - ... for different reference frames! close_enough = np.any(dist_to_player < EAT_DISTANCE) # Change player sprite to indicate that planet is in range if VARS['was_close'] == True and close_enough == False: player.image = player_icon VARS['was_close'] = False elif close_enough and VARS['was_close'] == True: too_close = dist_to_player < 0 # inside surface --> collision if np.any(too_close): player.image = explosion_animation #sys.exit() # if too close, game over if controller[key.SPACE]: object_id = np.argmin(dist_to_player) + 1 consumed = sol.convert_to_fuel( object_id, DM) # and remove object from calculations mass_label.text = f'Fuel: %.3E' % (sol.m[0] - DRY_MASS) if consumed: bodies[object_id].delete() # remove sprite del (bodies[object_id]) # and list entry objects_consumed = n_bodies - len(bodies) progress_label.text = f'Objects Consumed: {objects_consumed}/{n_bodies - 1}' elif close_enough: VARS['was_close'] = True player.image = player_eat_icon