質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1139閲覧

円と線分の接触時の挙動について。

narimi

総合スコア18

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/12/10 08:37

編集2021/12/10 08:58

図形内にある円とその辺の接触に関するプログラム

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/ツールのバージョンなど)

他に必要な情報がございましたら、お伝えいただけると幸いです。

同じ挙動をもう少しスマートに書く方法もあるかと思われますので、併せてそこも教えていただけるとありがたいです。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jbpb0

2021/12/10 12:19

> 一つ目のコードに記載されている円周上の座標として出力されている変数tと垂線の足として出力されている変数[x,y]の計算”print([x,y] - t)”の結果が整数しか出てこないような簡単な計算にもかかわらず-4.4408921e-16になっている print(np.sin(np.arctan2(0, -1))) とか print(np.sin(np.pi)) とか計算しても0.0では無いので、そんなものです 参考 https://note.nkmk.me/python-math-isclose/
narimi

2021/12/10 12:44

y側の計算が3.000…と言った書き方になっているのでそれはわかるのですが、x側の計算式は約1-約1の計算になると思うのでどう転んでも約4.4になるのはどこが間違っているからなのか…と言った感じですね。 質問、わかりづらくて申し訳ないです。
jbpb0

2021/12/10 14:26 編集

> x側の計算式は約1-約1の計算になると思うのでどう転んでも約4.4になるのはどこが間違っているからなのか print([x,y] - t) のすぐ下に print(t[0]) を追加して実行したら、 1.0000000000000004 となります それの一番右(小数点以下16桁目)の「4」が、「-4.4408921e-16」の最初の桁の「4」です そうなる理由は、「π」が浮動小数点数で正確に表現できないため、「np.sin(np.arctan2(0, -1))」や「np.sin(np.pi)」がピッタリ「0.0」にならないためです 私が前のコメントで紹介したWebページにも、それと同様な例が記載されてますので、それ見てくれてたら分かったはずです それを引用します print(math.sin(math.pi)) # 1.2246467991473532e-16 【追記】 t[0] = pt[0] + rudius * np.sin(np.arctan2(0, -1)) の「np.sin(np.arctan2(0, -1))」が、最初のコメントで指摘したようにピッタリ0.0では無いため、t[0]がピッタリ1.0にはならず、「1.0000000000000004」と僅かですが誤差を持ちます
guest

回答1

0

ベストアンサー

4.440892098500626e-16
は指数表記ですので、
0.00000000000000004440892098500626
と同じです。

以下をご覧ください。

python

1>>> x_dis = 0.0000000000000004440892098500626 2>>> print(x_dis) 34.440892098500626e-16 4>>> print(format(x_dis, '.31f')) 50.0000000000000004440892098500626

これは誤差の範囲です。

投稿2021/12/10 13:12

ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

narimi

2021/12/10 13:23

勘違いしておりました。 お手巣お掛けしました、ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問