質問
移動する2次元の円形物体(質量と速度の属性を持つ)が完全な弾性で互いに衝突する閉鎖系では、システム内のすべての物体の総速度速度(速度の大きさ)は保存されていますか?
バックグラウンド
このStackOverflowの質問で概説されている衝突解決方法に基づいて、Pythonで単純な2次元物理エンジンを実装しています。私の期待は、合計速度(各物体に関連付けられた速度ベクトルの長さの合計)が衝突したときに2つの物体間で一定のままである必要があることであり、この期待に基づいて解決方法の単体テストを設計しました。しかし、テストが失敗しました。ですから、最初に私の仮定が正しいことを確認したいと思います。
正しければ、コードを確認して、テストが失敗する理由を説明してください。
衝突の解決
class Physics:
@staticmethod
def reflect_colliding_circles(
(c1_x, c1_y, c1_vx, c1_vy, c1_r, c1_m, c1_e),
(c2_x, c2_y, c2_vx, c2_vy, c2_r, c2_m, c2_e)):
# inverse masses, mtd, restitution
im1 = 1.0 / c1_m
im2 = 1.0 / c2_m
mtd = Physics.calculate_mtd((c1_x, c1_y, c1_r), (c2_x, c2_y, c2_r))
normal_mtd = mtd.normalized()
restitution = c1_e * c2_e
# impact speed
v = vec2d(c1_vx, c1_vy) - vec2d(c2_vx, c2_vy)
vn = v.dot(normal_mtd)
# circle moving away from each other already -- return
# original velocities
if vn > 0.0:
return vec2d(c1_vx, c1_vy), vec2d(c2_vx, c2_vy)
# collision impulse
i = (-1.0 * (1.0 + restitution) * vn) / (im1 + im2)
impulse = normal_mtd * i
# change in momentun
new_c1_v = vec2d(c1_vx, c1_vy) + (impulse * im1)
new_c2_v = vec2d(c2_vx, c2_vy) - (impulse * im2)
return new_c1_v, new_c2_v
@staticmethod
def calculate_mtd((c1_x, c1_y, c1_r), (c2_x, c2_y, c2_r)):
"""source: https://stackoverflow.com/q/345838/1093087"""
delta = vec2d(c1_x, c1_y) - vec2d(c2_x, c2_y)
d = delta.length
mtd = delta * (c1_r + c2_r - d) / d
return mtd
単体テスト
def test_conservation_of_velocity_in_elastic_collisions(self):
for n in range(10):
r = 2
m = 10
e = 1.0
c1_pos = vec2d(0, 0)
c1_v = vec2d(random.randint(-100,100), random.randint(-100,100))
c2_delta = vec2d(random.randint(-100,100), random.randint(-100,100))
c2_delta.length = random.randint(50, 99) * r / 100.0
c2_pos = c1_pos + c2_delta
c2_v = vec2d(random.randint(-100,100), random.randint(-100,100))
c1_np, c2_np = Physics.translate_colliding_circles(
(c1_pos.x, c1_pos.y, r, m),
(c2_pos.x, c2_pos.y, r, m))
c1_nv, c2_nv = Physics.reflect_colliding_circles(
(c1_np.x, c1_np.y, c1_v.x, c1_v.y, r, m, e),
(c2_np.x, c2_np.y, c2_v.x, c2_v.y, r, m, e))
old_v = c1_v.length + c2_v.length
new_v = c1_nv.length + c2_nv.length
self.assertTrue(Physics.circles_overlap(
(c1_pos.x, c1_pos.y, r), (c2_pos.x, c2_pos.y, r)))
self.assertTrue(old_v - new_v < old_v * .01)
私はこのpygameベクトルクラスを使用しています:http ://www.pygame.org/wiki/2DVectorClass