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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

1回答

1297閲覧

3次元の点と線分の距離

Von_1234

総合スコア0

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2023/01/27 14:05

編集2023/01/28 01:26

前提

C言語のVisual studioで3次元の点と線分の距離を求めるプログラムを書いてます。ネットに合った2次元のプログラムを無理やり3次元にしてみました。
計算のやり方もいまいちわかってません。修正点などわかる方いたら情報が欲しいです。

実現したいこと

点と線分の距離の数値を的確に出したい。

発生している問題・エラーメッセージ

エラーは起こしていないが数値が正しくない このプログラムでは(0,0,0)と(10,0,0)の線分と(5,10,15)との距離が13.1037と出ます。 2個目は6.29961と出るのですが、実際の計算では、1個目は18.028で2個目は18.7085になりました。

該当のソースコード

C言語

1#include <iostream> 2 3struct Point 4{ 5 double x; 6 double y; 7 double z; 8}; 9 10struct LineSegment 11{ 12 Point start; 13 Point end; 14}; 15 16/** 17 @brief 線分と点の距離を計算する。 18 @param line 線分 19 @param point 点 20 @return ユークリッド距離 21 */ 22double calc_dist(const LineSegment& line, const Point& point) 23{ 24 double x0 = point.x, y0 = point.y, z0 = point.z; 25 double x1 = line.start.x, y1 = line.start.y, z1 = line.start.z; 26 double x2 = line.end.x, y2 = line.end.y, z2 = line.end.z; 27 28 double a = x2 - x1; 29 double b = y2 - y1; 30 double c = z2 - z1; 31 double a2 = a * a * a; 32 double b2 = b * b * b; 33 double c2 = c * c * c; 34 double r2 = a2 + b2 + c2; 35 double tt = -(a * (x1 - x0) + b * (y1 - y0) + c * (z1 - z0)); 36 37 if (tt < 0) 38 return cbrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0) + (z1 - z0) * (z1 - z0)); 39 else if (tt > r2) 40 return cbrt((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0) + (z2 - z0) * (z2 - z0)); 41 42 double f1 = a * (y1 - y0) * (z1 - z0) - b * (x1 - x0) * (z1 - z0) - c * (x1 - x0) * (y1 - y0); 43 return cbrt((f1 * f1) / r2); 44} 45 46int main() 47{ 48 Point point1 = { 5, 10 ,15 }; 49 LineSegment line1 = { {0, 0, 0}, {10, 0, 0} }; 50 double dist = calc_dist(line1, point1); 51 std::cout << "dist1: " << dist << std::endl; 52 53 54 Point point2 = { 20, 10, 5 }; 55 LineSegment line2 = { {0, 0, 0}, {10, 0, 0} }; 56 dist = calc_dist(line2, point2); 57 std::cout << "dist2: " << dist << std::endl; 58}

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

元の2次元のプログラムはこれです。
https://teratail.com/questions/155180

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

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

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

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

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

actorbug

2023/01/27 22:14

元の「ネットに合った2次元のプログラム」のURLを載せてください。 わからないまま無理やり3次元にしたコードを見せられても、何をやっているのか分かりません。
actorbug

2023/01/28 02:11

元ソースでは外積を使っているようなので、「点と線分の距離 外積」あたりで検索すれば、解説など見つかるかと思います。
fana

2023/01/28 03:20

> 計算のやり方もいまいちわかってません 数学の部分が解決してない状態なのであれば,その状態でてきとーなコードを書いてても仕方ない. 「距離の求め方」そのものが不明点だというなら「中学か高校レベルの数学の話を教えてください」っていうことになるから「プログラミングに関係ない話」ということになるような予感.
fana

2023/01/28 03:24

ものすごくざっくりと説明するなら: その点から線分(を無限に延長した直線)に対して垂線を下ろすことを考えればいい. 下ろした先が線分の範囲内にあるならば垂線の長さがそのまま求める距離ということになるし, そうでないなら線分の端点と点との距離を求めればいい.
guest

回答1

0

質問文の書き出しは

C言語の

とされているが,示されているコードはどう見てもC++なので,C++で回答.
(演算内容は関数 calc_dist のコードからわかると思うので説明は割愛する.)

  • 線分のデータ表現は質問者のそれとは異なっている.(コード内 LineSeg 型の注釈を参照のこと)

C++

1//3次元のベクトル 2struct Vec3 3{ 4 double v[3]; 5 Vec3( double x=0, double y=0, double z=0 ) : v{x,y,z} {} 6 //必要なoperatorだけを実装した 7 Vec3 operator +( const Vec3 &rhs ) const { return Vec3( v[0]+rhs[0], v[1]+rhs[1], v[2]+rhs[2] ); } 8 Vec3 operator -( const Vec3 &rhs ) const { return Vec3( v[0]-rhs[0], v[1]-rhs[1], v[2]-rhs[2] ); } 9 Vec3 operator *( double s ) const { return Vec3(s*v[0],s*v[1],s*v[2]); } 10 double operator[]( int i ) const { return v[i]; } 11}; 12 13//内積 14inline double InnerProd( const Vec3 &A, const Vec3 &B ) 15{ return A[0]*B[0] + A[1]*B[1] + A[2]*B[2]; } 16 17//L2ノルム 18inline double L2Norm( const Vec3 &V ) 19{ return sqrt( InnerProd( V,V ) ); } 20 21//線分. 22//一方の端点をP0, 他方の端点は P0+U*t. 23struct LineSeg 24{ 25 Vec3 P0; //一方の端点 26 Vec3 U; //線分に沿う(P0からもう一方の端点に向かう方向の)単位ベクトル 27 double t; //線分の長さ 28 29 //他方の端点を得る 30 Vec3 P1() const { return P0 + U*t; } 31}; 32 33//件の計算 34double calc_dist(const LineSeg &LS, const Vec3 &Point) 35{ 36 Vec3 P = Point - LS.P0; 37 double k = InnerProd( LS.U, P ); 38 39 if( k <= 0 ){ return L2Norm( P ); } 40 if( k >= LS.t ){ return L2Norm( Point - LS.P1() ); } 41 return L2Norm( P - LS.U*k ); //PointからLSに下した垂線の長さ 42} 43 44//main 45int main( /*int argc, char *argv[]*/ ) 46{ 47 LineSeg LS; 48 LS.P0 = Vec3{ 0,0,0 }; 49 LS.U = Vec3{ 1,0,0 }; 50 LS.t = 10; 51 52 std::cout << calc_dist( LS, { 5, 10, 15 } ) << std::endl; //18.0278 53 std::cout << calc_dist( LS, { 20, 10, 5 } ) << std::endl; //15 54 55 return 0; 56}

投稿2023/02/07 07:06

fana

総合スコア11658

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問