def radial_slice(points, center, start_angle, end_angle): """ >>> points = circle((0, 0), 2.3) >>> print(format_points(offset_points(points))) ### ##### ##### ##### ### >>> points = radial_slice(points, (0, 0), -90, 45) >>> print(format_points(offset_points(points))) ## ### ### ## >>> points = radial_slice(points, (0, 0), 0, 30) >>> print(format_points(offset_points(points))) # ### """ start_point = (1, 0) start_point = vec.rotate(start_point, math.radians(start_angle)) start_point = vec.add(center, start_point) start_line = (start_point, center) # Pointing inward, so partition goes counter-clockwise. end_point = (1, 0) end_point = vec.rotate(end_point, math.radians(end_angle)) end_point = vec.add(center, end_point) end_line = (center, end_point) # Pointing outward, so partition goes clockwise. return ( set(partition(points, *start_line)) & set(partition(points, *end_line)) )
def arc_to(self, endpoint, center=None, start_slant=None, end_slant=None): """ Draw an arc ending at the specified point, starting tangent to the current position and heading. """ if points_equal(self._position, endpoint): return # Handle unspecified center. # We need to find the center of the arc, so we can find its radius. The # center of this arc is uniquely defined by the intersection of two # lines: # 1. The first line is perpendicular to the pen heading, passing # through the pen position. # 2. The second line is the perpendicular bisector of the pen position # and the target arc end point. v_pen = self._vector() v_perp = vec.perp(self._vector()) v_chord = vec.vfrom(self._position, endpoint) if center is None: midpoint = vec.div(vec.add(self._position, endpoint), 2) v_bisector = vec.perp(v_chord) center = intersect_lines( self._position, vec.add(self._position, v_perp), midpoint, vec.add(midpoint, v_bisector), ) # Determine true start heading. This may not be the same as the # original pen heading in some circumstances. assert not points_equal(center, self._position) v_radius_start = vec.vfrom(center, self._position) v_radius_perp = vec.perp(v_radius_start) if vec.dot(v_radius_perp, v_pen) < 0: v_radius_perp = vec.neg(v_radius_perp) start_heading = math.degrees(vec.heading(v_radius_perp)) self.turn_to(start_heading) # Refresh v_pen and v_perp based on the new start heading. v_pen = self._vector() v_perp = vec.perp(self._vector()) # Calculate the arc angle. # The arc angle is double the angle between the pen vector and the # chord vector. Arcing to the left is a positive angle, and arcing to # the right is a negative angle. arc_angle = 2 * math.degrees(vec.angle(v_pen, v_chord)) radius = vec.mag(v_radius_start) # Check which side of v_pen the goes toward. if vec.dot(v_chord, v_perp) < 0: arc_angle = -arc_angle radius = -radius self._arc( center, radius, endpoint, arc_angle, start_slant, end_slant, )
def update_snowballs(lobby): changed_healths = [] destroyed_snowballs = [] player_hit = False ground_hit = False for id, snowball in lobby.snowballs.items(): new_vel = vec.add(snowball.velocity, (0, GRAVITY_ACCELERATION)) new_pos = vec.add(snowball.position, new_vel) new_x, new_y = new_pos hit_object, can_move = level.can_move_to(SNOWBALL_SIZE, SNOWBALL_SIZE, round(new_x), round(new_y), all_players(lobby.clients)) if can_move: snowball.velocity = new_vel snowball.position = new_pos else: destroyed_snowballs.append(id) if isinstance(hit_object, player.Player): player_hit = True speed = vec.length(snowball.velocity) hit_object.health = max( 0, hit_object.health - speed * SNOWBALL_DAMAGE) changed_healths.append(hit_object) else: ground_hit = True lobby.snowballs = { id: v for id, v in lobby.snowballs.items() if id not in destroyed_snowballs } return changed_healths, destroyed_snowballs, player_hit, ground_hit
def update(self, elapsed_seconds, force=None, extra_drag=0): # Apply force if necessary. if force is not None: self.velocity = vec.add( self.velocity, vec.mul(force, (elapsed_seconds / self.mass)), ) # Apply drag. # Decrease the magnitude of the velocity vector by # the amount of drag. drag = (self.drag_rate + extra_drag) * elapsed_seconds if drag > self.speed: self.velocity = (0, 0) elif drag != 0 and self.velocity != (0, 0): drag_vector = vec.norm(self.velocity, -drag) self.velocity = vec.add( self.velocity, drag_vector, ) # Limit to maximum speed. if self.speed > c.max_speed: self.velocity = vec.norm(self.velocity, c.max_speed) # Update position based on velocity. self.last_pos = self.pos self.pos = vec.add( self.pos, vec.mul(self.velocity, elapsed_seconds), )
def collide_particles(p1, p2): restitution = p1.restitution * p2.restitution # Don't collide immovable particles. if p1.immovable and p2.immovable: return # Test if p1 and p2 are actually intersecting. if not intersect(p1, p2): return # If one particle is immovable, make it the first one. if not p1.immovable and p2.immovable: p1, p2 = p2, p1 # Vector spanning between the centers, normal to contact surface. v_span = vec.vfrom(p1.pos, p2.pos) # Split into normal and tangential components and calculate # initial velocities. normal = vec.norm(v_span) tangent = vec.perp(normal) v1_tangent = vec.proj(p1.velocity, tangent) v2_tangent = vec.proj(p2.velocity, tangent) p1_initial = vec.dot(p1.velocity, normal) p2_initial = vec.dot(p2.velocity, normal) # Don't collide if particles were actually moving away from each other, so # they don't get stuck inside one another. if p1_initial - p2_initial < 0: return # Handle immovable particles specially. if p1.immovable: p2_final = -p2_initial * restitution p2.velocity = vec.add( v2_tangent, vec.mul(normal, p2_final), ) return # Elastic collision equations along normal component. m1, m2 = p1.mass, p2.mass m1plusm2 = (m1 + m2) / restitution p1_final = (p1_initial * (m1 - m2) / m1plusm2 + p2_initial * (2 * m2) / m1plusm2) p2_final = (p2_initial * (m2 - m1) / m1plusm2 + p1_initial * (2 * m1) / m1plusm2) # Tangential component is unchanged, recombine. p1.velocity = vec.add( v1_tangent, vec.mul(normal, p1_final), ) p2.velocity = vec.add( v2_tangent, vec.mul(normal, p2_final), )
def update_physics(self, elapsed_seconds): # Handle turning. if self.turning_time >= c.player_start_turn_time: turn_rate = c.player_turn_rate_radians else: turn_rate = interpolate( c.player_start_turn_rate_radians, c.player_turn_rate_radians, self.turning_time / c.player_start_turn_time, ) self.heading += self.turn_direction * turn_rate * elapsed_seconds self.direction = heading_to_vector(self.heading) # Handle thrust. force = (0, 0) if self.do_thrust: # We vary the thrust depending on how fast the player is # already moving. thrust = curve_value(self.speed, c.player_thrust_curve) force = vec.add( force, vec.mul(self.direction, thrust), ) # Handle braking. extra_drag = 0 if self.do_brake: extra_drag = c.player_braking_drag # Handle boost. if self.boost_time_remaining > 0.0: force = vec.add( force, vec.mul(self.direction, c.player_boost_strength), ) # Get heavy while boosting. if self.boost_heavy_time_remaining > 0.0: self.mass = self.original_mass * c.player_boost_heavy_multiplier self.restitution = ( self.original_restitution * c.player_boost_restitution_multiplier ) else: self.mass = self.original_mass self.restitution = self.original_restitution # Handle rudder. self.rudder_force = (0, 0) if self.velocity != (0, 0): # Only use the rudder if the player is thrusting or turning. if self.do_thrust or self.turn_direction != 0: self.rudder_force = self.calc_rudder_force() force = vec.add(force, self.rudder_force) return force, extra_drag
def update_physics(self, elapsed_seconds): # Handle turning. if self.turning_time >= c.player_start_turn_time: turn_rate = c.player_turn_rate_radians else: turn_rate = interpolate( c.player_start_turn_rate_radians, c.player_turn_rate_radians, self.turning_time / c.player_start_turn_time, ) self.heading += self.turn_direction * turn_rate * elapsed_seconds self.direction = heading_to_vector(self.heading) # Handle thrust. force = (0, 0) if self.do_thrust: # We vary the thrust depending on how fast the player is # already moving. thrust = curve_value(self.speed, c.player_thrust_curve) force = vec.add( force, vec.mul(self.direction, thrust), ) # Handle braking. extra_drag = 0 if self.do_brake: extra_drag = c.player_braking_drag # Handle boost. if self.boost_time_remaining > 0.0: force = vec.add( force, vec.mul(self.direction, c.player_boost_strength), ) # Get heavy while boosting. if self.boost_heavy_time_remaining > 0.0: self.mass = self.original_mass * c.player_boost_heavy_multiplier self.restitution = (self.original_restitution * c.player_boost_restitution_multiplier) else: self.mass = self.original_mass self.restitution = self.original_restitution # Handle rudder. self.rudder_force = (0, 0) if self.velocity != (0, 0): # Only use the rudder if the player is thrusting or turning. if self.do_thrust or self.turn_direction != 0: self.rudder_force = self.calc_rudder_force() force = vec.add(force, self.rudder_force) return force, extra_drag
def set_slants(self, start_slant, end_slant): if start_slant is not None: start_slant = Heading(start_slant) if end_slant is not None: end_slant = Heading(end_slant) self.start_slant = start_slant self.end_slant = end_slant # Intersect the slant lines with the left and right offset circles # to find the corners. center_left, radius_left = self.offset_circle_left() center_right, radius_right = self.offset_circle_right() # Start corners. if start_slant is None: v_slant = vec.vfrom(self.center, self.a) else: v_slant = vec.from_heading(start_slant.rad) a = self.a b = vec.add(self.a, v_slant) points_left = intersect_circle_line(center_left, radius_left, a, b) points_right = intersect_circle_line(center_right, radius_right, a, b) if len(points_left) == 0 or len(points_right) == 0: self.start_joint_illegal = True return self.a_left = Point(*closest_point_to(self.a, points_left)) self.a_right = Point(*closest_point_to(self.a, points_right)) # End corners. if end_slant is None: v_slant = vec.vfrom(self.center, self.b) else: v_slant = vec.from_heading(end_slant.rad) a = self.b b = vec.add(self.b, v_slant) points_left = intersect_circle_line(center_left, radius_left, a, b) points_right = intersect_circle_line(center_right, radius_right, a, b) if len(points_left) == 0 or len(points_right) == 0: self.end_joint_illegal = True return self.b_left = Point(*closest_point_to(self.b, points_left)) self.b_right = Point(*closest_point_to(self.b, points_right)) self.check_degenerate_segment()
def set_slants(self, start_slant, end_slant): if start_slant is not None: start_slant = Heading(start_slant) if end_slant is not None: end_slant = Heading(end_slant) self.start_slant = start_slant self.end_slant = end_slant # Intersect the slant lines with the left and right offset lines # to find the corners. line_left = self.offset_line_left() line_right = self.offset_line_right() # Start corners. if start_slant is None: v_slant = vec.perp(self._vector()) else: v_slant = vec.from_heading(start_slant.rad) a = self.a b = vec.add(self.a, v_slant) left = intersect_lines(a, b, line_left[0], line_left[1]) right = intersect_lines(a, b, line_right[0], line_right[1]) if left is None or right is None: self.start_joint_illegal = True else: self.a_left = Point(*left) self.a_right = Point(*right) # End corners. if end_slant is None: v_slant = vec.perp(self._vector()) else: v_slant = vec.from_heading(end_slant.rad) a = self.b b = vec.add(self.b, v_slant) left = intersect_lines(a, b, line_left[0], line_left[1]) right = intersect_lines(a, b, line_right[0], line_right[1]) if left is None or right is None: self.end_joint_illegal = True else: self.b_left = Point(*left) self.b_right = Point(*right) # Done, make sure we didn't cross self.check_degenerate_segment()
def intersect_circles(center1, radius1, center2, radius2): radius1 = abs(radius1) radius2 = abs(radius2) if radius2 > radius1: return intersect_circles(center2, radius2, center1, radius1) transverse = vec.vfrom(center1, center2) dist = vec.mag(transverse) # Check for identical or concentric circles. These will have either # no points in common or all points in common, and in either case, we # return an empty list. if points_equal(center1, center2): return [] # Check for exterior or interior tangent. radius_sum = radius1 + radius2 radius_difference = abs(radius1 - radius2) if (float_equal(dist, radius_sum) or float_equal(dist, radius_difference)): return [ vec.add(center1, vec.norm(transverse, radius1)), ] # Check for non intersecting circles. if dist > radius_sum or dist < radius_difference: return [] # If we've reached this point, we know that the two circles intersect # in two distinct points. # Reference: # http://mathworld.wolfram.com/Circle-CircleIntersection.html # Pretend that the circles are arranged along the x-axis. # Find the x-value of the intersection points, which is the same for both # points. Then find the chord length "a" between the two intersection # points, and use vector math to find the points. dist2 = vec.mag2(transverse) x = (dist2 - radius2**2 + radius1**2) / (2 * dist) a = ((1 / dist) * sqrt( (-dist + radius1 - radius2) * (-dist - radius1 + radius2) * (-dist + radius1 + radius2) * (dist + radius1 + radius2))) chord_middle = vec.add( center1, vec.norm(transverse, x), ) perp = vec.perp(transverse) return [ vec.add(chord_middle, vec.norm(perp, a / 2)), vec.add(chord_middle, vec.norm(perp, -a / 2)), ]
def rebound(self, normal, point=None, restitution=1): # Split into normal and tangential components. tangent = vec.perp(normal) v_tangent = vec.proj(self.velocity, tangent) v_normal = vec.proj(self.velocity, normal) # Invert normal component and recombine, with restitution. v_normal = vec.neg(v_normal) self.velocity = vec.add(v_tangent, vec.mul(v_normal, restitution)) # If the particle is partially inside the wall, move it out. if point is not None: v = vec.vfrom(point, self.pos) if vec.mag2(v) < self.radius ** 2: v = vec.norm(v, self.radius) self.pos = vec.add(point, v)
def intersect_lines(a, b, c, d, segment=False): """ Find the intersection of lines a-b and c-d. If the "segment" argument is true, treat the lines as segments, and check whether the intersection point is off the end of either segment. """ # Reference: # http://geomalgorithms.com/a05-_intersect-1.html u = vec.vfrom(a, b) v = vec.vfrom(c, d) w = vec.vfrom(c, a) u_perp_dot_v = vec.dot(vec.perp(u), v) if float_equal(u_perp_dot_v, 0): return None # We have collinear segments, no single intersection. v_perp_dot_w = vec.dot(vec.perp(v), w) s = v_perp_dot_w / u_perp_dot_v if segment and (s < 0 or s > 1): return None u_perp_dot_w = vec.dot(vec.perp(u), w) t = u_perp_dot_w / u_perp_dot_v if segment and (t < 0 or t > 1): return None return vec.add(a, vec.mul(u, s))
def put(position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program): y = stack_pop(stack) x = stack_pop(stack) v = stack_pop(stack) location = vec.add((x, y), storage_offset) program.set(location, chr(v)) return position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program, True
def arc_left( self, arc_angle, radius=None, center=None, start_slant=None, end_slant=None, ): if ( (radius is None and center is None) or (radius is not None and center is not None) ): raise TypeError('You must specify exactly one of center or radius.') arc_angle = Angle(arc_angle) # Create a radius vector, which is a vector from the arc center to the # current position. Subtract to find the center, then rotate the radius # vector to find the arc end point. if center is None: if arc_angle < 0: radius = -abs(radius) v_radius = vec.neg(vec.perp(self._vector(radius))) center = vec.sub(self._position, v_radius) elif radius is None: v_radius = vec.vfrom(center, self._position) radius = vec.mag(v_radius) if arc_angle < 0: radius = -radius endpoint = vec.add(center, vec.rotate(v_radius, arc_angle.rad)) self._arc( center, radius, endpoint, arc_angle, start_slant=start_slant, end_slant=end_slant, )
def update(s, gs, dt): #print(s.vel) if s.thrusting: force = s.thrustForce * dt facing = vec.fromAngle(s.facing + 180) f = vec.mul(facing, force) s.applyForce(f) offset = vec.fromAngle(s.facing) offset = vec.mul(offset, s.radius) loc = vec.add(s.loc, offset) # v = vec.invert(s.vel) s.driveEmitter.emit(gs, dt, loc, s.facing, vel=s.vel) if not s.engineSoundPlayer.playing: s.engineSoundPlayer.seek(0.0) s.engineSoundPlayer.eos_action = s.engineSoundPlayer.EOS_LOOP s.engineSoundPlayer.play() else: s.engineSoundPlayer.eos_action = s.engineSoundPlayer.EOS_PAUSE # Turning should be either 0, -1 or +1 if s.turning != 0: force = s.turnForce * dt * s.turning s.applyRforce(force) Planet.update(s, gs, dt)
def GF2_span(D, L): ''' >>> from GF2 import one >>> D = {'a', 'b', 'c'} >>> L = [Vec(D, {'a': one, 'c': one}), Vec(D, {'b': one})] >>> len(GF2_span(D, L)) 4 >>> Vec(D, {}) in GF2_span(D, L) True >>> Vec(D, {'b': one}) in GF2_span(D, L) True >>> Vec(D, {'a':one, 'c':one}) in GF2_span(D, L) True >>> Vec(D, {x:one for x in D}) in GF2_span(D, L) True ''' l = [] multiplied =[] for e in L: a= scalar_mul(e, 0) multiplied.append(a) b = scalar_mul(e, 1) multiplied.append(b) for i in multiplied: for j in multiplied: final = add(i,j) if final not in l: l.append(final) return l
def draw(self, screen): self.surface.lock() self.surface.fill(self.clear) pg.draw.line( self.surface, self.green, (14-10, 14), (14+10, 14), 2, ) pg.draw.line( self.surface, self.green, (14, 14-10), (14, 15+10), 2, ) joypos = vec.mul((self.input.x_axis, -self.input.y_axis), 8) pg.draw.circle( self.surface, self.red, vec.add(joypos, (15,15)), 4, ) self.surface.unlock() _width, height = self.display.screen_size x = 10 + 30 * self.number y = height - self.surface.get_height() - 10 screen.blit(self.surface, (x, y))
def draw(self, screen): self.surface.lock() self.surface.fill(self.clear) pg.draw.line( self.surface, self.green, (14 - 10, 14), (14 + 10, 14), 2, ) pg.draw.line( self.surface, self.green, (14, 14 - 10), (14, 15 + 10), 2, ) joypos = vec.mul((self.input.x_axis, -self.input.y_axis), 8) pg.draw.circle( self.surface, self.red, vec.add(joypos, (15, 15)), 4, ) self.surface.unlock() _width, height = self.display.screen_size x = 10 + 30 * self.number y = height - self.surface.get_height() - 10 screen.blit(self.surface, (x, y))
def collide_particles(p1, p2): restitution = p1.restitution * p2.restitution # Don't collide immovable particles. if p1.immovable and p2.immovable: return # Test if p1 and p2 are actually intersecting. if not intersect(p1, p2): return # If one particle is immovable, make it the first one. if not p1.immovable and p2.immovable: p1, p2 = p2, p1 # Vector spanning between the centers, normal to contact surface. v_span = vec.vfrom(p1.pos, p2.pos) # Split into normal and tangential components and calculate # initial velocities. normal = vec.norm(v_span) tangent = vec.perp(normal) v1_tangent = vec.proj(p1.velocity, tangent) v2_tangent = vec.proj(p2.velocity, tangent) p1_initial = vec.dot(p1.velocity, normal) p2_initial = vec.dot(p2.velocity, normal) # Don't collide if particles were actually moving away from each other, so # they don't get stuck inside one another. if p1_initial - p2_initial < 0: return # Handle immovable particles specially. if p1.immovable: p2_final = -p2_initial * restitution p2.velocity = vec.add(v2_tangent, vec.mul(normal, p2_final)) return # Elastic collision equations along normal component. m1, m2 = p1.mass, p2.mass m1plusm2 = (m1 + m2) / restitution p1_final = p1_initial * (m1 - m2) / m1plusm2 + p2_initial * (2 * m2) / m1plusm2 p2_final = p2_initial * (m2 - m1) / m1plusm2 + p1_initial * (2 * m1) / m1plusm2 # Tangential component is unchanged, recombine. p1.velocity = vec.add(v1_tangent, vec.mul(normal, p1_final)) p2.velocity = vec.add(v2_tangent, vec.mul(normal, p2_final))
def rebound(self, normal, point=None, restitution=1): # Split into normal and tangential components. tangent = vec.perp(normal) v_tangent = vec.proj(self.velocity, tangent) v_normal = vec.proj(self.velocity, normal) # Invert normal component and recombine, with restitution. v_normal = vec.neg(v_normal) self.velocity = vec.add( v_tangent, vec.mul(v_normal, restitution), ) # If the particle is partially inside the wall, move it out. if point is not None: v = vec.vfrom(point, self.pos) if vec.mag2(v) < self.radius**2: v = vec.norm(v, self.radius) self.pos = vec.add(point, v)
def create_snowball(lobby, pos, angle, force): ball_id = create_snowball_id(lobby) snowball = player.Snowball(ball_id) direction = vec.from_direction(angle, 1) velocity = vec.mul(direction, force * MAX_THROWING_FORCE) snowball.position = vec.add(pos, vec.mul(direction, SNOWBALL_SPAWN_DISTANCE)) snowball.velocity = velocity lobby.snowballs[ball_id] = snowball
def canCapture(s, point, distance, targetPlanet): if s.isParent(targetPlanet): #print "Nope, is parent" return False if targetPlanet.parent != None: #print "Nope, has parent" return False if targetPlanet == s: #print "Nope, self" return False if s in targetPlanet.children: #print "Nope, is a child already" return False vecBetweenPlanets = vec.sub(targetPlanet.loc, s.loc) # Adjust distance to measure from surface to surface, not center # to center distance += s.radius + targetPlanet.radius if vec.magSquared(vecBetweenPlanets) > (distance * distance): #print "Nope, out of range" return False # Okay we are close enough to an eligible planet, are we facing it? angleBetweenPlanets = vec.toAngle(vecBetweenPlanets) # Urrrrrg I hate this, -180 to 180 and 0-360 behave differently and both are # awful in different situations so neither one is really correct. point = (point + 360) % 360 angleBetweenPlanets = (angleBetweenPlanets + 360) % 360 #print "Point and angle:", point, angleBetweenPlanets if abs(angleBetweenPlanets - point) < 10: #print "Yep!" return True #print "Nope, angle too great", angleBetweenPlanets, point, abs(angleBetweenPlanets - point) return False vecBetweenPlanets = vec.sub(targetPlanet.loc, s.loc) vecBPU = vec.unit(vecBetweenPlanets) vecToPlanetEdge = vec.mul(vec.perpendicular(vecBPU), targetPlanet.radius) #print("Vec between planets: {0}, vec to planet edge: {1}".format(vecBPU, vec.unit(vecToPlanetEdge))) angularSize = vec.angleBetween( vecBetweenPlanets, vec.add(vecBetweenPlanets, vecToPlanetEdge)) vecToPoint = vec.mul(vec.fromAngle(point), s.radius) angularDistance = vec.angleBetween(vecBetweenPlanets, vecToPoint) #print("Angular size: {0}, angular distance: {1}".format(angularSize, angularDistance)) if angularDistance > abs(angularSize): return False else: # Check distance between planets surfaces distance = distance + (s.radius + targetPlanet.radius) # Can't capture a planet if you're overlapping it # XXX: Doesn't seem to work, but... if distance < 0: return False return vec.within(s.loc, targetPlanet.loc, distance)
def repeat(position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program): instruction = program.get(vec.add(position, velocity)) if instruction in INSTRUCTIONS: operation = INSTRUCTIONS[instruction] else: operation = DEFAULT_INSTRUCTION result = position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program, True for _ in xrange(stack_pop(stack)): result = operation(position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program) return result
def to_screen(self, pos): """Convert pos to screen coordinates. Takes a tuple a world position, and returns a tuple for the screen position. """ x, y = vec.add( self.screen_origin, vec.mul(pos, self.pixels_per_unit), ) return (int(x), int(y))
def emit(s, gs, dt, loc, facing, vel=vec.ZERO): s.timer += dt while s.timer > s.interval: s.timer -= s.interval for i in range(s.count): variance = + (s.angle * random.random()) - (s.angle / 2.0) angle = facing + variance v = vec.mul(vec.fromAngle(angle), s.speed) v = vec.add(vel, v) part = s.particleType(loc, v) gs.addParticle(part)
def draw_graph(graph): gap_size = 0.25 p = canoepaddle.Pen() p.stroke_mode(0.1, 'black') for a, b in graph_edges(graph): gap = vec.norm(vec.vfrom(a, b), gap_size) p.move_to(vec.add(a, gap)) p.line_to(vec.sub(b, gap)) return p.paper
def create_shield(self): self.shield_pieces = [] for i in range(8): d = DIRECTIONS[i] pos = vec.add(self.pos, d) piece = HeroPiece() piece.pos = pos piece.display_character = '-\|/'[i % 4] self.world.register_entity(piece) self.shield_pieces.append(piece) Polyomino([self] + self.shield_pieces) self.shield((0, 0))
def project(self, points, reverse=False): if reverse: if self.H_ is None: self.H_ = mtx.lu([r[:] for r in self.H]) qs = [ mtx.solve(self.H_, vec.sub(p, self.offset) + [1]) for p in points ] return [vec.div(q[:-1], q[-1]) for q in qs] else: qs = [mtx.mul(self.H, p + [1]) for p in points] return [vec.add(self.offset, vec.div(q[:-1], q[-1])) for q in qs]
def balls_collisions(balls): collided = False for b1 in balls: for b2 in balls: if b1 is b2: continue d = vec.sub(b1.pos, b2.pos) penetration = (b1.radius + b2.radius) - vec.len(d) if penetration < 0: continue collided = True n = vec.unit(d) b1.pos = vec.add(b1.pos, vec.scale(n, penetration / 2 + 1)) b2.pos = vec.add(b2.pos, vec.scale(n, -penetration / 2 - 1)) j = vec.dot(vec.sub(b2.speed, b1.speed), n) b1.speed = vec.add(b1.speed, vec.scale(n, j)) b2.speed = vec.add(b2.speed, vec.scale(n, -j)) return collided
def update(self, elapsed_seconds, force=None, extra_drag=0): # Apply force if necessary. if force is not None: self.velocity = vec.add(self.velocity, vec.mul(force, (elapsed_seconds / self.mass))) # Apply drag. # Decrease the magnitude of the velocity vector by # the amount of drag. drag = (self.drag_rate + extra_drag) * elapsed_seconds if drag > self.speed: self.velocity = (0, 0) elif drag != 0 and self.velocity != (0, 0): drag_vector = vec.norm(self.velocity, -drag) self.velocity = vec.add(self.velocity, drag_vector) # Limit to maximum speed. if self.speed > c.max_speed: self.velocity = vec.norm(self.velocity, c.max_speed) # Update position based on velocity. self.last_pos = self.pos self.pos = vec.add(self.pos, vec.mul(self.velocity, elapsed_seconds))
def draw(s, gs): rot = s.parent.facing + s.loc totalAngle = vec.fromAngle(rot) offsetVec = vec.mul(totalAngle, s.radius) location = vec.add(s.parent.loc, offsetVec) (scx, scy) = gs.screenCoords(location) #print "rot: %s, totalAngle: %s, offsetVec: %s, location: %s, sc: %s" % (rot, totalAngle, offsetVec, location, (scx, scy)) # Add a slight offset to center the image rather than drawing # it from the lower-left corner... # Also add oregano. s.sprite.rotation = s.loc + s.parent.facing #print s.sprite.rotation, s.loc, s.parent.facing s.sprite.position = (scx, scy) s.sprite.draw()
def join_with_arc(self, other): # Special case coincident arcs. if points_equal(self.center, other.center): if not ( float_equal(self.radius, other.radius) and float_equal(self.width, other.width) ): self.end_joint_illegal = True other.start_joint_illegal = True return r = vec.vfrom(self.center, self.b) if self.radius < 0: r = vec.neg(r) v_left = vec.norm(r, self.radius - self.width / 2) self.b_left = other.a_left = Point(*vec.add(self.center, v_left)) v_right = vec.norm(r, self.radius + self.width / 2) self.b_right = other.a_right = Point(*vec.add(self.center, v_right)) return c1, r1 = self.offset_circle_left() c2, r2 = other.offset_circle_left() points_left = intersect_circles(c1, r1, c2, r2) if len(points_left) > 0: p = Point(*closest_point_to(self.b, points_left)) self.b_left = other.a_left = p c1, r1 = self.offset_circle_right() c2, r2 = other.offset_circle_right() points_right = intersect_circles(c1, r1, c2, r2) if len(points_right) > 0: p = Point(*closest_point_to(self.b, points_right)) self.b_right = other.a_right = p if len(points_left) == 0 or len(points_right) == 0: self.end_joint_illegal = True other.start_joint_illegal = True
def generate_castle_position(): if not castles: return (0, 0) it = 0 while True: r1 = random.randint(-1 - it, 1 + it) r2 = random.randint(-1 - it, 1 + it) direction = (r1 * SPAWN_DISTANCE, r2 * SPAWN_DISTANCE) for castle in castles.values(): pos = castle.position_tuple() new_pos = vec.add(direction, pos) if is_castle_position_free(new_pos): # print('FOUND!') return new_pos it += 1
def update(s, gs, dt): if s.parent == None: PhysicsObj.update(s, gs, dt) else: #print("parent offset: {0}, parent direction {1}, parent distance {2}, parent facing {3}".format(s.parentVec, vec.toAngle(p), vec.mag(p), s.parent.facing)) # To figure out the current facing we must know what our parent's facing is, # where we were facing when captured, and where the parent was facing when captured. s.facing = s.capturedFacing + (s.parent.facing - s.capturedParentFacing) rotation = s.parent.facing - s.capturedParentFacing + 180 p = vec.rotate(s.parentVec, -rotation) # THAT F*****G SIMPLE AAAAAAAAAAH relativePosition = vec.add(s.parent.loc, p) s.loc = relativePosition
def draw(s, gs): sx, sy = gs.screenCoords(s.loc) s.sprite.x = sx s.sprite.y = sy s.sprite.rotation = s.facing s.sprite.draw() if s.parent != None: #parentSloc = gs.screenCoords(s.parent.loc) vecToParent = vec.sub(s.parent.loc, s.loc) angle = vec.toAngle(vecToParent) centerPointVec = vec.div(vecToParent, 2) actualVec = vec.add(s.loc, centerPointVec) s.captureSprite.position = gs.screenCoords(actualVec) s.captureSprite.rotation = angle s.captureSprite.draw()
def draw(s, gs): swingSpeed = 190.0 # Degrees per second startingFacing = 90.0 if s.direction > 0: swing = startingFacing + -(s.lifetime * swingSpeed) else: swing = (s.lifetime * swingSpeed) - startingFacing rot = s.parent.facing + s.loc totalAngle = vec.fromAngle(rot) offset = vec.mul(totalAngle, s.radius) location = vec.add(s.parent.loc, offset) s.sprite.position = gs.screenCoords(location) #print location s.sprite.rotation = rot + swing s.sprite.draw()
def draw_player(self, player): # Show whether or not the player is thrusting. if player.do_thrust: trailing_point = vec.add( player.pos, vec.norm(player.direction, -1.5 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, .5 * player.radius) if player.boost_heavy_time_remaining > 0.0: trailing_point = vec.add( player.pos, vec.norm(player.direction, -2.0 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, 1.5 * player.radius) # Show braking and boosting charge up. if player.do_brake: # Redden the brake color as we charge. color = vec.add( BRAKE_COLOR, vec.mul(THRUST_COLOR, player.boost_charge_time / c.player_boost_ready_time)) # Vibrate if we are fully charged. r = 1.2 if player.boost_charge_time == c.player_boost_ready_time: r += 0.1 * math.sin(6 * (2 * math.pi) * pg.time.get_ticks() / 1000) self.circle(color, player.pos, r) # Body. self.circle(PLAYER_COLORS[player.number], player.pos, player.radius) # Show the player pointing towards a direction. leading_point = vec.add( player.pos, vec.norm(player.direction, player.radius), ) self.line(DIRECTION_COLOR, player.pos, leading_point, .2 * player.radius) if SHOW_RUDDER_FORCE: point = vec.add( player.pos, vec.mul(player.rudder_force, .1), ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius) if SHOW_INTENDED_DIRECTION and hasattr(player, 'intended_direction'): point = vec.add( player.pos, player.intended_direction, ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius)
def bounds(self): # We use the outside radius, because the inside of the arc cannot be # tangent to the boundary. This is not a perfect approximation, as # setting end slants could fail to shrink the bounding box as # they should. r = abs(self.radius) if self.width is not None: r += self.width / 2 # Find the four "compass points" around the center. compass_points = [ vec.add(self.center, direction) for direction in [ (r, 0), # East, heading = 0. (0, r), # North, heading = 90. (-r, 0), # West, heading = 180. (0, -r), # South, heading = 270. ] ] # Check which compass points are in the body of the circle. if self.arc_angle < 0: start = self.end_heading + 90 end = self.start_heading + 90 else: start = self.start_heading - 90 end = self.end_heading - 90 occupied_points = [] for i, h in enumerate([0, 90, 180, 270]): h = Heading(h) if h == start or h == end or h.between(start, end): occupied_points.append(compass_points[i]) # The bounding box of the arc is the combined bounding box of the start # point, the end point, and the compass points occupied by the body of # the arc. If the arc is a thick arc, then the edge points also can # push the boundary. if self.width is None: endpoints = [self.a, self.b] else: endpoints = [self.a_left, self.a_right, self.b_left, self.b_right] return Bounds.union_all([ Bounds.from_point(p) for p in endpoints + occupied_points ])
def intersect_circle_line(center, radius, line_start, line_end): """ Find the intersection of a circle with a line. """ radius = abs(radius) # First check whether the line is too far away, or if we have a # single point of contact. # Reference: # http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html r = vec.vfrom(center, line_start) v = vec.perp(vec.vfrom(line_start, line_end)) d = vec.proj(r, v) dist = vec.mag(d) if float_equal(dist, radius): # Single intersection point, because the circle and line are tangent. point = vec.add(center, d) return [point] elif dist > radius: return [] # Set up parametric equations for the line and the circle, and solve them. # Reference: # http://www.cs.cf.ac.uk/Dave/CM0268/PDF/circle_line_intersect_proof.pdf xc, yc = center x0, y0 = line_start x1, y1 = line_end line_x, line_y = (x1 - x0), (y1 - y0) # f, g dx, dy = (x0 - xc), (y0 - yc) a = line_x**2 + line_y**2 b = 2 * (line_x * dx + line_y * dy) c = dx**2 + dy**2 - radius**2 t0, t1 = quadratic_formula(a, b, c) return [ ( x0 + line_x * t0, y0 + line_y * t0, ), ( x0 + line_x * t1, y0 + line_y * t1, ), ]
def draw_player(self, player): # Show whether or not the player is thrusting. if player.do_thrust: trailing_point = vec.add( player.pos, vec.norm(player.direction, -1.5 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, .5 * player.radius) if player.boost_heavy_time_remaining > 0.0: trailing_point = vec.add( player.pos, vec.norm(player.direction, -2.0 * player.radius), ) self.line(THRUST_COLOR, player.pos, trailing_point, 1.5 * player.radius) # Show braking and boosting charge up. if player.do_brake: # Redden the brake color as we charge. color = vec.add( BRAKE_COLOR, vec.mul(THRUST_COLOR, player.boost_charge_time / c.player_boost_ready_time) ) # Vibrate if we are fully charged. r = 1.2 if player.boost_charge_time == c.player_boost_ready_time: r += 0.1 * math.sin(6 * (2*math.pi) * pg.time.get_ticks() / 1000) self.circle(color, player.pos, r) # Body. self.circle(PLAYER_COLORS[player.number], player.pos, player.radius) # Show the player pointing towards a direction. leading_point = vec.add( player.pos, vec.norm(player.direction, player.radius), ) self.line(DIRECTION_COLOR, player.pos, leading_point, .2 * player.radius) if SHOW_RUDDER_FORCE: point = vec.add( player.pos, vec.mul(player.rudder_force, .1), ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius) if SHOW_INTENDED_DIRECTION and hasattr(player, 'intended_direction'): point = vec.add( player.pos, player.intended_direction, ) self.line(THRUST_COLOR, player.pos, point, .1 * player.radius)
def start_block(position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program): n = stack_pop(stack) soss = stack if n < 0: toss = [0] * (n * -1) elif n > len(soss): i = n - len(soss) toss = [0] * i + soss soss = [] else: s = len(soss) - n assert s >= 0 toss = soss[s:] soss = soss[:s] sx, sy = storage_offset soss += [sx, sy] storage_offset = vec.add(position, velocity) stack_of_stacks.append(soss) stack = toss return position, velocity, storage_offset, stack, stack_of_stacks, push_mode, program, True
def partition(points, l1, l2, s=None): """ Partition a set of points by a line. The line is defined by l1, l2. The desired side of the line is given by the point s. If s is not given, return points to the right of the line. If eq is True, also include points on the line. >>> sorted(partition([(-1,0), (0,0), (1,0)], (0,1), (0,-1), (2,0))) [(0, 0), (1, 0)] >>> sorted(partition([(-1,0), (0,0), (1,0)], (0,1), (0,-1), (-2,0))) [(-1, 0), (0, 0)] >>> points = [(-2,2), (-1,0), (0,0), (1,0)] >>> sorted(partition(points, (-1,0), (0,1), (3,0))) [(-1, 0), (0, 0), (1, 0)] >>> sorted(partition(points, (-1,0), (0,1), (-3,0))) [(-2, 2), (-1, 0)] You can omit the argument "s" if you don't care. >>> sorted(partition([(-1,0), (0,0), (1,0)], (0,1), (0,-1))) [(-1, 0), (0, 0)] """ if s is None: s = vec.add(l1, vec.perp(vec.vfrom(l1, l2))) if l1 == l2: raise ValueError('l1 equals l2') sign = sign_of(cmp_line(l1, l2, s)) if sign == 0: raise ValueError('s is on the line l1 l2') for p in points: c = cmp_line(l1, l2, p) if c == sign: yield p elif c == 0: yield p
def partition(points, l1, l2, s=None): """ Partition a set of points by a line. The line is defined by l1, l2. The desired side of the line is given by the point s. >>> partition([(-1,0), (0,0), (1,0)], (0,1), (0,-1), (2,0))[0] {(1, 0)} >>> partition([(-1,0), (0,0), (1,0)], (0,1), (0,-1), (-2,0))[0] {(-1, 0)} >>> points = [(-2,2), (-1,0), (0,0), (1,0)] >>> sorted(partition(points, (-1,0), (0,1), (3,0))[0]) [(0, 0), (1, 0)] >>> sorted(partition(points, (-1,0), (0,1), (-3,0))[0]) [(-2, 2)] You can omit the argument "s" if you don't care. >>> partition([(-1,0), (0,0), (1,0)], (0,1), (0,-1)) ({(-1, 0)}, {(1, 0)}) """ if s is None: s = vec.add(l1, vec.perp(vec.vfrom(l1, l2))) if l1 == l2: raise ValueError('l1 equals l2') sign = cmp_line(l1, l2, s) if sign == 0: raise ValueError('s is on the line l1 l2') forward = set() reverse = set() for p in points: c = cmp_line(l1, l2, p) if c == sign: forward.add(p) elif c == -sign: reverse.add(p) return forward, reverse
[0, 0], [2, -2], [4, -6], [2, 2], [6, 4], [16, 10], [14, -10], [10, 8], [12, -8], ] # 290 mm / 15 sqaures paper_points = [vec.mul(q, 290 / 15) for q in paper_squares] offset = [305, 0] # floor origin is 305 mm in front world_points = [vec.add(p, offset) for p in paper_points] p = Planar(H, offset=offset) # Should be equal print(world_points) print(p.project(image_points)) # Should be equal print(image_points) print(p.project(world_points, reverse=True)) # Make sure H did not get changed print(world_points) print(p.project(image_points))
def _calc_forward_to_x(self, x_target): x, y = self.position x_diff = x_target - x y_diff = x_diff * math.tan(self._heading.rad) return vec.add(self.position, (x_diff, y_diff))
def _calc_forward_to_y(self, y_target): x, y = self.position y_diff = y_target - y x_diff = y_diff / math.tan(self._heading.rad) return vec.add(self.position, (x_diff, y_diff))
def _calc_forward_position(self, distance): return vec.add( self.position, self._vector(distance), )
def to_screen(self, pos): return vec.add(pos, self.origin)
def move_relative(self, offset): self.move_to(vec.add(self.position, offset))
def start_move(self, direction): self.pos = vec.add(self.pos, direction)