図形内にある円とその辺の接触に関するプログラム
pythonにて、円と辺の接触判定について書いています。
挙動としては図形の中に円を挿入し、その円が図形からはみ出ている場合、移動させて図形内に描画し直すというものです。
発生している問題
方法としましては、図形の座標データ、円の中心座標データ、半径をそれぞれ持っており、中心座標からの距離が半径以下である辺を発見すると移動を開始するというものです。
具体的な計算としては、中心座標から一番近い辺の座標データから垂線の足をもとめ、中心座標と推薦の足を結んだ直線の角度を求めます。
そののち、numpyよりsinとcosを用いて円周上の点の座標を求め、先に求めた垂線の足との差分中心座標をずらすという形になっています。
該当のソースコード
python
1import matplotlib.pyplot as plt 2import matplotlib.patches as patch 3import numpy as np 4import math 5import cv2 6import point_plot 7import itertools 8import ex_circle 9 10data = np.array([[0,0],[10,0],[10,10],[0,10]]) 11 12single = np.array([[1,1]]) 13 14r = 4 15 16#点と直線の距離 17def pt_to_line(data, pt, rudius): 18 info = [] 19 20 info.append(ex_circle.line_distance(data,pt)) 21 22 print("info:" + str(info[0][0][0]) + "rudius" + str(rudius)) 23 24 if info[0][0][0] < rudius: 25 print("-----------辺との接触------------") 26 27 a = info[0][1][1][1] - info[0][1][0][1] 28 b = -(info[0][1][1][0] - info[0][1][0][0]) 29 c = info[0][1][0][1] * (info[0][1][1][0] - info[0][1][0][0]) - info[0][1][0][0] * (info[0][1][1][1] - info[0][1][0][1]) 30 31 print("直線方程式" + str(a) + " " + str(b) + " " + str(c)) 32 33 x=(b**2*pt[0]-a*b*pt[1]-a*c)/(a**2+b**2) 34 y=(a**2*pt[1]-a*b*pt[0]-b*c)/(a**2+b**2) 35 36 print("接触した点:" + str(pt)) 37 print("接触した辺:" + str(info[0][1])) 38 print('垂線の足:(' + str(x) + "," + str(y) + ")") 39 40 vec = ([x, y] - pt) 41 print("vec:" + str(vec)) 42 rad = np.arctan2(vec[0], vec[1]) 43 degree = math.degrees(rad) 44 45 print("rad:" + str(rad)) 46 print("degree:" + str(degree)) 47 rsinθ = rudius * np.sin(rad) 48 rcosθ = rudius * np.cos(rad) 49 t = np.array([pt[0] + rsinθ, pt[1] + rcosθ]) 50 print("円周上の座標:" + str(t)) 51 52 print([x,y] - t) 53 (x_di, y_di) = ([x,y] - t) 54 print("x_dis:" + str(x_di)) 55 print("y_dis:" + str(y_di)) 56 pt[0] = pt[0] + x_di 57 pt[1] = pt[1] + y_di 58 return pt 59 60print("出力結果:" + str(pt_to_line(data, single[0], r))) 61 62single[0] = pt_to_line(data, single[0], r) 63 64point_plot.plot_shape(data, single, r)
python
1#辺と点との距離を求める関数 2def line_distance(data, pt): 3 line_dis = [] 4 line_coor = [] 5 min_line_distance = [] 6 (x, y) = pt 7 8 #座標データから辺との距離を見る 9 for j in range(len(data)): 10 if(j == len(data) - 1): 11 (x1, y1) = data[j] 12 (x2, y2) = data[0] 13 14 #点と直線の距離公式に必要な要素の格納 15 u = np.array([x2 - x1, y2 - y1]) 16 v = np.array([x - x1, y - y1]) 17 18 #距離と座標を格納 19 line_dis.append(abs(np.cross(u, v) / np.linalg.norm(u))) 20 line_coor.append([data[j],data[0]]) 21 22 else: 23 (x1, y1) = data[j] 24 (x2, y2) = data[j + 1] 25 26 #点と直線の距離公式に必要な要素の格納 27 u = np.array([x2 - x1, y2 - y1]) 28 v = np.array([x - x1, y - y1]) 29 30 #距離と座標を格納 31 line_dis.append(abs(np.cross(u, v) / np.linalg.norm(u))) 32 line_coor.append([data[j],data[j + 1]]) 33 34 #最小距離の値とその座標を格納 35 min_line_distance.append(min(line_dis)) 36 index = np.where(np.array(line_dis) == np.array(min_line_distance))[0][0] 37 38 # print("最小距離:" + str(min_line_distance)) 39 # print("最小座標" + str(line_coor[index])) 40 41 #最短距離を返却 42 return min_line_distance, line_coor[index]
出力結果
info:1.0rudius4 -----------辺との接触------------ 直線方程式0 -10 0 接触した点:[1 1] 接触した辺:[array([0, 0]), array([10, 0])] 垂線の足:(1.0,0.0) vec:[ 0. -1.] rad:3.141592653589793 degree:180.0 円周上の座標:[ 1. -3.] [-4.4408921e-16 3.0000000e+00] x_dis:-4.440892098500626e-16 y_dis:3.0 出力結果:[0 4] info:0.0rudius4 -----------辺との接触------------ 直線方程式-10 0 0 接触した点:[0 4] 接触した辺:[array([ 0, 10]), array([0, 0])] 垂線の足:(0.0,4.0) vec:[0. 0.] rad:0.0 degree:0.0 円周上の座標:[0. 8.] [ 0. -4.] x_dis:0.0 y_dis:-4.0
###試したこと
非常に見づらくて申し訳ないのですが、中心座標の値(変数single)を[1,7]や[4,3]などに変更した場合は想定通りの挙動になっていました。
わかっている問題としては、一つ目のコードに記載されている円周上の座標として出力されている変数tと垂線の足として出力されている変数[x,y]の計算”print([x,y] - t)”の結果が整数しか出てこないような簡単な計算にもかかわらず-4.4408921e-16になっていることが挙げられるのですが、どうしてこうなったのかわかりません。
補足情報(FW/ツールのバージョンなど)
他に必要な情報がございましたら、お伝えいただけると幸いです。
同じ挙動をもう少しスマートに書く方法もあるかと思われますので、併せてそこも教えていただけるとありがたいです。
よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー