def _create_earth(self, entity: Entity, texture: str) -> \ vpython.sphere: ground = vpython.sphere( pos=vpython.vector(0, 0, 0), axis=calc.angle_to_vpy(entity.heading), up=vpython.vector(0, 0, 1), # So the planet doesn't intersect the landing graphic radius=entity.r * 0.9, make_trail=True, retain=10000, texture=texture, bumpmap=vpython.bumpmaps.gravel, shininess=0.3 # Planet.SHININESS=0.3 ) clouds_texture = texture.replace(f'{entity.name}.jpg', 'Clouds.png') clouds_bumpmap = texture.replace('Clouds.png', 'Clouds-bumpmap.png') if entity.atmosphere_thickness is not None: clouds_radius = entity.r * entity.atmosphere_thickness * 0.9 else: clouds_radius = entity.r * 1.28 * 0.9 ground.clouds = vpython.sphere( pos=ground.pos, axis=ground.axis, up=ground.up, radius=clouds_radius, texture=clouds_texture, bumpmap=clouds_bumpmap, opacity=0.1, # Cloud layer mostly transparent shininess=0.1) return ground
def _update_obj(self, entity: Entity, state: PhysicsState, origin: Entity) -> None: # update planet objects self._obj.pos = entity.screen_pos(origin) / self._scale_factor self._obj.axis = calc.angle_to_vpy(entity.heading) # update label objects self._label.text = self._label_text(entity) self._label.pos = entity.screen_pos(origin) / self._scale_factor
def _create_obj(self, entity: Entity, origin: Entity, texture: Optional[str]) -> vpython.sphere: return vpython.sphere(pos=entity.screen_pos(origin), axis=calc.angle_to_vpy(entity.heading), up=DEFAULT_UP, forward=DEFAULT_FORWARD, radius=entity.r, make_trail=True, retain=10000, texture=texture, bumpmap=vpython.bumpmaps.gravel, shininess=Planet.SHININIESS)
def _create_obj(self, entity: Entity, origin: Entity, texture: Optional[str]) -> vpython.sphere: return vpython.sphere( pos=entity.screen_pos(origin), axis=calc.angle_to_vpy(entity.heading), up=vpython.vector(0, 0, 1), # So the planet doesn't intersect the landing graphic radius=entity.r * 0.9, make_trail=True, retain=10000, texture=texture, bumpmap=vpython.bumpmaps.gravel, shininess=Planet.SHININIESS)
def _update_obj(self, entity: Entity, state: PhysicsState, origin: Entity) -> None: # update planet objects self._obj.pos = entity.screen_pos(origin) self._obj.axis = calc.angle_to_vpy(entity.heading) # update label objects self._label.text = self._label_text(entity) self._label.pos = entity.screen_pos(origin) # update landing graphic objects self._update_landing_graphic(self._small_landing_graphic, entity, state.craft_entity()) self._update_landing_graphic(self._large_landing_graphic, entity, state.craft_entity())
def _create_obj(self, entity: Entity, origin: Entity, texture: Optional[str]) -> vpython.sphere: main_body = vpython.box() side_panels = vpython.box(height=2, width=0.5, length=0.6) obj = vpython.compound([main_body, side_panels], make_trail=True, texture=texture, bumpmap=vpython.textures.gravel) obj.pos = entity.screen_pos(origin) obj.axis = calc.angle_to_vpy(entity.heading) obj.length = entity.r * 2 obj.height = entity.r * 2 obj.width = entity.r * 2 # A compound object doesn't actually have a radius, but we need to # monkey-patch this for when we recentre the camera, to determine the # relevant_range of the space station obj.radius = entity.r return obj
def _create_obj(self, entity: Entity, origin: Entity, texture_path: Optional[str]) -> vpython.sphere: ship = vpython.cone(pos=vpython.vector(5, 0, 0), axis=vpython.vector(5, 0, 0), radius=3) entrance = vpython.extrusion( path=[vpython.vec(0, 0, 0), vpython.vec(4, 0, 0)], shape=[ vpython.shapes.circle(radius=3), vpython.shapes.rectangle(pos=[0, 0], width=0.5, height=0.5) ], pos=vpython.vec(3, 0, 0)) docking_arm = vpython.extrusion( path=[ vpython.vec(0, 0, 0), vpython.vec(1.5, 0, 0), vpython.vec(1.5, 0.5, 0) ], shape=[vpython.shapes.circle(radius=0.03)]) obj = vpython.compound([ship, entrance, docking_arm], make_trail=True, texture=vpython.textures.metal, bumpmap=vpython.bumpmaps.gravel) obj.pos = entity.screen_pos(origin) obj.axis = calc.angle_to_vpy(entity.heading) obj.length = entity.r * 2 obj.height = entity.r * 2 obj.width = entity.r * 2 # A compound object doesn't actually have a radius, but we need to # monkey-patch this for when we recentre the camera, to determine the # relevant_range of the space station obj.radius = entity.r return obj
def _create_hab(self, entity: Entity, texture: str) -> \ vpython.compound: def vertex(x: float, y: float, z: float) -> vpython.vertex: return vpython.vertex(pos=vpython.vector(x, y, z)) # See the docstring of ThreeDeeObj._create_obj for why the dimensions # that define the shape of the habitat will not actually directly # translate to world-space. body = vpython.cylinder(pos=vpython.vec(0, 0, 0), axis=vpython.vec(-5, 0, 0), radius=10) head = vpython.cone(pos=vpython.vec(0, 0, 0), axis=vpython.vec(2, 0, 0), radius=10) wing = vpython.triangle(v0=vertex(0, 0, 0), v1=vertex(-5, 30, 0), v2=vertex(-5, -30, 0)) wing2 = vpython.triangle(v0=vertex(0, 0, 0), v1=vertex(-5, 0, 30), v2=vertex(-5, 0, -30)) hab = vpython.compound([body, head, wing, wing2], make_trail=True, texture=texture) hab.axis = calc.angle_to_vpy(entity.heading) hab.radius = entity.r / 2 hab.shininess = 0.1 hab.length = entity.r * 2 boosters: List[vpython.cylinder] = [] body_radius = entity.r / 8 for quadrant in range(0, 4): # Generate four SRB bodies. normal = vpython.rotate(vpython.vector(0, 1, 1).hat, angle=quadrant * vpython.radians(90), axis=vpython.vector(1, 0, 0)) boosters.append( vpython.cylinder(radius=self.BOOSTER_RADIUS, pos=(self.BOOSTER_RADIUS + body_radius) * normal)) boosters.append( vpython.cone( radius=self.BOOSTER_RADIUS, length=0.2, pos=((self.BOOSTER_RADIUS + body_radius) * normal + vpython.vec(1, 0, 0)))) # Append an invisible point to shift the boosters down the fuselage. # For an explanation of why that matters, read the # ThreeDeeObj._create_obj docstring (and if that doesn't make sense, # get in touch with Patrick M please hello hi I'm always free!) boosters.append(vpython.sphere(opacity=0, pos=vpython.vec(1.2, 0, 0))) booster_texture = texture.replace(f'{entity.name}.jpg', 'SRB.jpg') hab.boosters = vpython.compound(boosters, texture=booster_texture) hab.boosters.length = entity.r * 2 hab.boosters.axis = hab.axis parachute: List[vpython.standardAttributes] = [] string_length = entity.r * 0.5 parachute_texture = texture.replace(f'{entity.name}.jpg', 'Parachute.jpg') # Build the parachute fabric. parachute.append( vpython.extrusion( path=vpython.paths.circle(radius=0.5, up=vpython.vec(-1, 0, 0)), shape=vpython.shapes.arc(angle1=vpython.radians(5), angle2=vpython.radians(95), radius=1), pos=vpython.vec(string_length + self.PARACHUTE_RADIUS / 2, 0, 0))) parachute[0].height = self.PARACHUTE_RADIUS * 2 parachute[0].width = self.PARACHUTE_RADIUS * 2 parachute[0].length = self.PARACHUTE_RADIUS for quadrant in range(0, 4): # Generate parachute attachment lines. string = vpython.cylinder(axis=vpython.vec(string_length, self.PARACHUTE_RADIUS, 0), radius=0.2) string.rotate(angle=(quadrant * vpython.radians(90) - vpython.radians(45)), axis=vpython.vector(1, 0, 0)) parachute.append(string) parachute.append( vpython.sphere(opacity=0, pos=vpython.vec( -(string_length + self.PARACHUTE_RADIUS), 0, 0))) hab.parachute = vpython.compound(parachute, texture=parachute_texture) hab.parachute.visible = False return hab
def _update_obj(self, entity: Entity, state: PhysicsState, origin: Entity): super()._update_obj(entity, state, origin) self._obj.boosters.pos = self._obj.pos self._obj.boosters.axis = self._obj.axis # Attach the parachute to the forward cone of the habitat. self._obj.parachute.pos = ( self._obj.pos + calc.angle_to_vpy(entity.heading) * entity.r * 0.8) parachute_is_visible = ((state.craft == entity.name) and state.parachute_deployed) if parachute_is_visible: drag = calc.drag(state) drag_mag = np.inner(drag, drag) for parachute in [self._obj.parachute, self._small_habitat.parachute]: if not parachute_is_visible or drag_mag < 0.00001: # If parachute_is_visible == False, don't show the parachute. # If the drag is basically zero, don't show the parachute. parachute.visible = False continue if drag_mag > 0.1: parachute.width = self.PARACHUTE_RADIUS * 2 parachute.height = self.PARACHUTE_RADIUS * 2 else: # Below a certain threshold the parachute deflates. parachute.width = self.PARACHUTE_RADIUS parachute.height = self.PARACHUTE_RADIUS parachute.axis = -vpython.vec(*drag, 0) parachute.visible = True if not self._broken and entity.broken: # We weren't broken before, but looking at new data we realize # we're now broken. Change the habitat texture. new_texture = self._obj.texture.replace('Habitat.jpg', 'Habitat-broken.jpg') assert new_texture != self._obj.texture, \ f'{new_texture!r} == {self._obj.texture!r}' self._obj.texture = new_texture self._small_habitat.texture = new_texture self._broken = entity.broken elif self._broken and not entity.broken: # We were broken before, but we've repaired ourselves somehow. new_texture = self._obj.texture.replace('Habitat-broken.jpg', 'Habitat.jpg') assert new_texture != self._obj.texture, \ f'{new_texture!r} == {self._obj.texture!r}' self._obj.texture = new_texture self._small_habitat.texture = new_texture self._broken = entity.broken # Set reference and target arrows of the minimap habitat. same = state.reference == entity.name default = vpython.vector(0, 0, -1) ref_arrow_axis = (entity.screen_pos(state.reference_entity()).norm() * entity.r * -1.2) v = entity.v - state.reference_entity().v velocity_arrow_axis = \ vpython.vector(*v, 0).norm() * entity.r self._ref_arrow.axis = default if same else ref_arrow_axis self._velocity_arrow.axis = default if same else velocity_arrow_axis self._small_habitat.axis = self._obj.axis self._small_habitat.boosters.axis = self._obj.axis # Invisible-ize the SRBs if we ran out. if state.srb_time == common.SRB_EMPTY and self._obj.boosters.visible: self._obj.boosters.visible = False self._small_habitat.boosters.visible = False
def _update_obj(self, entity: Entity, state: PhysicsState, origin: Entity): super()._update_obj(entity, state, origin) self._obj.clouds.pos = self._obj.pos self._obj.clouds.axis = calc.angle_to_vpy( entity.heading * calc.windspeed_multiplier(entity, windspeed=100))