粒子と線要素の接触
基本的な流れは、以下です。
・線と円の距離を算出し、線と触れる範囲か判定する
・線分と円の接触判定し、接点の座標を取得する
接触点の座標を取得するのは、のちの処理のためです。
この手の処理を実装する際、一般に、ベクトル演算の内積・外積という
概念が登場するのですが、よくわからないので、
三角関数(sin,cos,tan)で実装しました。
三角関数は処理が遅いので、ほんとは使わない方が良いです。
線と円の接触判定
線と円の最短距離(垂線)の長さを算出し、円の半径以下か判定します。 線分の始点をベースに、始点と円の中点を結ぶ線と線分の角度Θをatanで求め、 始点と円の距離×sinΘで、円の中点と線との距離を算出しました。
- p = particles[i]
- l = lines[j]
- th0 = math.atan2(l.y2-l.y1, l.x2-l.x1)
- th1 = math.atan2(p.y-l.y1, p.x-l.x1)
- a = math.sqrt((p.x-l.x1)**2+(p.y-l.y1)**2)
- d = abs(a*math.sin(th1-th0))
- if d < p.r:
- print('touched!')
線分と円の接触判定と接点座標の取得
この処理では、触れている箇所が線分上か、始点か、終点かに分岐します。
線分上の内、円が始点に接している条件での終点と円の中点の長さSを求めます。 また、始点と円の中点との長さAと、終点と円の中点の長さBを求めます。 AとBがどちらもSより短い条件が、線分と接している条件になります。
それよりも外側に出ていて、始点に点接触している条件は、 始点と円の中点との長さが円の半径以下になっている時です。 円が始点よりかどうかは、長さAが長さBより小さいかで判定します。 終点の場合は、その逆です。
- if d < p.r:
- a = math.sqrt((p.x-l.x1)**2+(p.y-l.y1)**2)
- b = math.sqrt((p.x-l.x2)**2+(p.y-l.y2)**2)
- s = math.sqrt((l.x2-l.x1)**2+(l.y2-l.y1)**2)
- s = math.sqrt(s**2 + p.r**2)
- if a < s and b < s:
- c = math.sqrt(a**2-d**2)
- x = l.x1 + c*math.cos(th0)
- y = l.y1 + c*math.sin(th0)
- elif a < b and a < p.r:
- x = l.x1
- y = l.y1
- elif b < p.r:
- x = l.x2
- y = l.y2
線要素と粒子間の力
線要素と粒子間の力の処理は、粒子同士の処理と一緒です(同じ関数)。 異なる点は、法線方向を円の中点同士ではなく、接点とするので、上記の処理の座標と することと、バネ定数などのパラメータです。