Javaプログラミング学習サイト ゆるゆるプログラミング

2021/03/10 公開

・最も近い座標を探す

ここでは、基準とする座標に最も近い座標を複数の座標から探す方法を解説します。

以下の図は、そのイメージです。

最も近い点の探索

基準の座標からの近さの判定には直線距離を使います。基準の座標と結んだ直線距離が最短の座標が最も近い座標です。

具体的には以下のようなプログラムになります。

 ①基準の座標を決めます。(ox,oy)

 ②探索する座標列を配列に格納します。(x0,y0)~(xn,yn)

 ③基準の座標(ox,oy)から探索座標(x0,y0)~(xn,yn)の直線距離2乗を計算します。

 ④③で計算した値のうち、1番小さい値を格納する配列添え字を結果として出力します。

以下が、上記の内容をJavaのソースコードにしたものです。

このソースは基準の座標(500.0,500.0)から1番近い座標を求めるものです。探索する座標は、乱数を使ってxyそれぞれ0.0以上、1000.0未満の範囲で自動作成しています。

ClosestCoordinates1.java ← クリックしてダウンロードページに移動
001:    public class ClosestCoordinates1 {
002:    	// 最も近い座標の配列の添え字を戻すメソッド
003:    	// (ox,oy)が基準座標
004:    	// (x[],y[])が探索座標
005:    	static int closest_coordinates( double ox, double oy, double[] x, double[] y )
006:    	{
007:    		// 引数に不備がある場合、-1を戻す
008:    		if ( null == x ) return -1;
009:    		if ( null == y ) return -1;
010:    		if ( 1 > x.length ) return -1;
011:    		if ( 1 > y.length ) return -1;
012:    		if ( x.length != y.length ) return -1;
013:    
014:    		// 調べる座標数
015:    		int crdnum = x.length;
016:    
017:    		// 調べる座標が1つの場合、0を戻す。
018:    		if ( 1 == crdnum ) return 0;
019:    
020:    		// 距離の最小値を格納する変数
021:    		// 初期値 : doubleの最大
022:    		double dist2_min = Double.MAX_VALUE;
023:    
024:    		// 距離の最小値が格納される配列の添え字を格納する変数
025:    		// 初期値 : -1
026:    		int crd_min = -1;
027:    
028:    		// 最も近い座標を求める
029:    		for ( int i = 0; i < crdnum; i++ ) {
030:    			// 距離の2乗を計算
031:    			double dx = x[ i ] - ox;
032:    			double dy = y[ i ] - oy;
033:    			double dist2 = dx * dx + dy * dy;
034:    
035:    			// 距離の最小値の比較
036:    			if ( dist2 < dist2_min ) {
037:    				// 距離の最小値を配列の添え字の更新
038:    				dist2_min = dist2;
039:    				crd_min = i;
040:    			}
041:    		}
042:    
043:    		// 距離の最小値が格納される配列の添え字を戻す
044:    		return crd_min;
045:    	}
046:    
047:    
048:    	// メイン
049:    	public static void main(String[] args) {
050:    		// 調べる座標を配列に格納
051:    		// x,yは0.0以上~1000.0の乱数で作成
052:    		double[] x = new double[ 10 ];
053:    		double[] y = new double[ 10 ];
054:    
055:    		for ( int i = 0; i < x.length; i++ ) {
056:    			x[ i ] = Math.random() * 1000.0;
057:    			y[ i ] = Math.random() * 1000.0;
058:    		}
059:    
060:    		// 基準の座標を設定
061:    		double ox = 500.0;
062:    		double oy = 500.0;
063:    		int ans = closest_coordinates( ox, oy, x, y );
064:    		if ( 0 > ans ) {
065:    			System.out.println( "配列番号の取得に失敗しました!" );
066:    		}
067:    
068:    		// 結果を出力
069:    		System.out.println( "最も近い座標の配列番号 : " + ans );
070:    		System.out.println( "最も近い座標 : " + x[ ans ] + " " + y[ ans ] );
071:    		System.out.println();
072:    
073:    		// 調べた座標を出力
074:    		for ( int i = 0; i < x.length; i++ ) {
075:    			System.out.println( i + " " + x[ i ] + " " + y[ i ] );
076:    		}
077:    	}
078:    }

ClosestCoordinates1を実行

最も近い座標の配列番号 : 5
最も近い座標 : 522.6032407893074 529.1182157580057

0 877.7147009243795 718.844711996419
1 526.6243989932896 972.9817185296182
2 918.0303176324935 178.36544193189474
3 327.8529222496893 98.33227058715333
4 864.9148502306463 293.97241655453996
5 522.6032407893074 529.1182157580057
6 556.547189361226 99.08534083354937
7 507.57394473692665 420.918431684552
8 478.02958653506147 933.9869793183221
9 334.80064599857684 252.08397376586979

基準の座標(500.0,500.0)に1番近い座標を格納した配列添え字と座標、探索した全ての座標を出力しています。

探索する座標は乱数なので、実行する毎に結果は変わります。

ここからは、このJavaソースコードを上から順番に解説していきます。

001:    public class ClosestCoordinates1 {

クラス名を、ClosestCoordinates1としています。

002:    	// 最も近い座標の配列の添え字を戻すメソッド
003:    	// (ox,oy)が基準座標
004:    	// (x[],y[])が探索座標
005:    	static int closest_coordinates( double ox, double oy, double[] x, double[] y )

基準座標(ox,oy)から探索座標(x[],y[])の直線距離が最も近いものを戻すメソッドです。結果は配列添え字を戻します。

007:    		// 引数に不備がある場合、-1を戻す
008:    		if ( null == x ) return -1;
009:    		if ( null == y ) return -1;
010:    		if ( 1 > x.length ) return -1;
011:    		if ( 1 > y.length ) return -1;
012:    		if ( x.length != y.length ) return -1;

引数の検査です。引数に不備がある場合は、処理を中断して-1をreturn文で戻します。ここでは、探索座標xyの有無/xy配列要素数の一致を確認しています。

014:    		// 調べる座標数
015:    		int crdnum = x.length;

探索する座標の個数をint型変数crdnumに代入しています。引数の検査でxとyの配列要素数が同じことがわかっているので配列xの要素数を座標の個数としています。

017:    		// 調べる座標が1つの場合、0を戻す。
018:    		if ( 1 == crdnum ) return 0;

探索する座標の個数crdnumが1の場合、return文で0を戻してメソッドを抜けています。この0は配列添え字番号のことでx[0],y[0]が最も近い座標ということです。個数が1の場合、その1つが1番近い座標です。

020:    		// 距離の最小値を格納する変数
021:    		// 初期値 : doubleの最大
022:    		double dist2_min = Double.MAX_VALUE;

距離の最小値を格納するdouble型変数dist2_minの初期値にdouble型変数が持てるの最大値を代入しています。

変数の最小値/最大値はこちらの記事を参考にしてください。「変数の最小値・最大値」

024:    		// 距離の最小値が格納される配列の添え字を格納する変数
025:    		// 初期値 : -1
026:    		int crd_min = -1;

距離の最小値が格納される配列添え字を格納するinte型の変数crd_minの初期値に-1を代入しています。

028:    		// 最も近い座標を求める
029:    		for ( int i = 0; i < crdnum; i++ ) {

for文で探索座標xyの個数回のループを作成しています。

030:    			// 距離の2乗を計算
031:    			double dx = x[ i ] - ox;
032:    			double dy = y[ i ] - oy;
033:    			double dist2 = dx * dx + dy * dy;

基準座標(ox,oy)と探索座標(x[i],y[i])の直線距離2乗を計算しています。

このプログラムは一番近い座標を探すものなので、直線距離2乗でも比較することができます。もちろん直線距離で比較することもできますが、直線距離を求めるには平方根を計算する必要があり余分な処理時間がかかります。

直線距離の計算は、以下の図を参考にしてください。

ピタゴラスの定理
035:    			// 距離の最小値の比較
036:    			if ( dist2 < dist2_min ) {
037:    				// 距離の最小値を配列の添え字の更新
038:    				dist2_min = dist2;
039:    				crd_min = i;
040:    			}

計算で得られた距離の2乗の値dist2と現在の距離の最小値を格納した変数dist2_minを比較して、変数dist2の値が小さければ、変数dist2_minにdist2の値を代入します。さらに配列添え字crd_minに変数iの値を代入します。

この処理によって、最も近い座標を格納した配列添え字crd_minと、その距離の2の乗を格納した変数dist2_minが更新されていきます。

ちなみに変数i=0のとき、変数dist2_minの値はdouble値の最大なのでif文の条件( dist2 < dist2_min )を満たします。

043:    		// 距離の最小値が格納される配列の添え字を戻す
044:    		return crd_min;

return文で最も近い座標を格納した配列添え字crd_minを戻してメソッド終了です。

048:    	// メイン
049:    	public static void main(String[] args) {

このmainメソッドからプログラムを実行します。

050:    		// 調べる座標を配列に格納
051:    		// x,yは0.0以上~1000.0の乱数で作成
052:    		double[] x = new double[ 10 ];
053:    		double[] y = new double[ 10 ];
054:    
055:    		for ( int i = 0; i < x.length; i++ ) {
056:    			x[ i ] = Math.random() * 1000.0;
057:    			y[ i ] = Math.random() * 1000.0;
058:    		}

探索座標xyを10個作成しています。配列xyにはそれぞれ乱数を使って0.0以上1000.0未満の値を代入しています。

Math.randomメソッド

public static double Math.random()
■乱数を返します。

  パラメータ なし

  戻り値     0.0以上、1.0未満の乱数

060:    		// 基準の座標を設定
061:    		double ox = 500.0;
062:    		double oy = 500.0;
063:    		int ans = closest_coordinates( ox, oy, x, y );
064:    		if ( 0 > ans ) {
065:    			System.out.println( "配列番号の取得に失敗しました!" );
066:    		}

基準座標(ox,oy)と探索座標(x[],y[])をclosest_coordinatesメソッドに渡しています。戻り値ansに配列添え字が戻ります。

変数ansの値が0未満の場合、エラーで結果が得られなかったことを意味しています。

068:    		// 結果を出力
069:    		System.out.println( "最も近い座標の配列番号 : " + ans );
070:    		System.out.println( "最も近い座標 : " + x[ ans ] + " " + y[ ans ] );
071:    		System.out.println();
072:    
073:    		// 調べた座標を出力
074:    		for ( int i = 0; i < x.length; i++ ) {
075:    			System.out.println( i + " " + x[ i ] + " " + y[ i ] );
076:    		}

結果をprintlnで出力しています。

以上です。

■関連コンテンツ

ステンドグラス処理 ステンドグラス風画像の作り方を解説
2点間の距離 2点間の距離計算
値の2乗 値を2乗するメソッドの作り方を解説
Javaの配列 同じ型の変数をまとめた配列について解説
変数の最小値・最大値 変数の最小値と最大値を取得する方法を解説
値のコンソール表示 print()、println()とは?
繰り返し処理に使用するfor文について解説-画像

for文

繰り返し処理に使用するfor文をJavaのソースコードを使って説明しています。

四則演算(足し算/引き算/掛け算/割り算)について-画像

計算結果の表示

足し算(加法)/引き算(減法)/掛け算(乗法)/割り算(除法)の使い方を説明

条件による処理の分岐に使用するif文について解説-画像

if文

条件による処理の分岐に使用するif文について解説

■新着情報

2021.06.18 変数の初期値 変数に値を代入しないで計算
2021.05.28 短針と長針の角度 短針と長針の角度は?
2021.05.19 各位(くらい)を求める 1の位の値は?10の位は?

■広告

 

 

 

 

 

 

 

 

 

Topへ