2024/07/07

クラス化に挑戦: #13)クラス機能の追加

前回までの Google マップ - Place API を利用する機能をクラス化しました。スマホ用の Nomad と組み合わせると、現在地を中心に近隣を検索できるようになります(HCL Nomad で GPS 座標の取得)。最寄りのお店や施設を検索するなどさまざまな利用方法が考えられますね。

このような機能を実現すると、情報として現在位置からの距離が欲しくなります。そこで、地点情報を表す Location クラスに距離を計算する機能を追加します。


作成するメソッド

作成するメソッドの使い方は次の通りとします。

   dDistance = oLoc1.CalcDistance(oLoc2)

oLoc1、oLoc2 は座標を表す Location クラスのインスタンスです。距離を計算するメソッド CalcDistance を実行すると 2 点間の距離を計算して返す機能となります。


距離の計算

緯度経度で表される座標は球面を前提としています。そのため距離に変換するためには、地球の大きさなどを利用して計算する必要があります。

先輩ブロガーの中野さんが下記の記事で関数を公開されています。この記事で紹介されている distance という関数を流用させていただきます。

Nomad で GPS を使う

LotusScript で記述されているので、そのまま使えます。ありがたいですね!


クラスの修正と確認

コード量の多いクラスではありませんので、クラス全体のコードを掲載します。

赤字の部分がオリジナルの追加コードです。青字の部分がブログから拝借した関数なのですが、クラス内部の関数として使用していますので private 宣言だけ追加しています。

Public Class Location
   Private zdLatitude As Double '緯度
   Private zdLongitude As Double '経度

   Public Sub New(ByVal vdLatitude As Double, ByVal vdLongitude As Double)
      zdLatitude = vdLatitude
      zdLongitude = vdLongitude
   End Sub

   Public Property Get Latitude As Double
      Latitude = zdLatitude
   End Property

   Public Property Get Longitude As Double
      Longitude = zdLongitude
   End Property


   Public Function CalcDistance(voDestination As Location) As Double
      CalcDistance = distance(zdLatitude, zdLongitude, voDestination.Latitude, voDestination.Longitude)
   End Function

   Private
Function distance( lat1 As Double, lng1 As Double, lat2 As Double, lng2 As Double ) As Double
      Dim radLat1 As Double, radLng1 As Double
      Dim radLat2 As Double, radLng2 As Double
      Dim aveLat As Double, aveLng As Double
      Dim c As Double
      Const r = 6378137.0
'赤道半径

      '円弧の長さを扱うため、角度(緯度経度)をラジアンへ変換
      c = 180 / PI
      radLat1 = lat1 / c
      radLng1 = lng1 / c
      radLat2 = lat2 / c
      radLng2 = lng2 / c

      aveLat = ( radLat1 - radLat2 ) / 2
      aveLng = ( radLng1 - radLng2 ) / 2

      distance = r * 2 * ASin( Sqr( Sin( aveLat ) ^ 2 + Cos( radLat1 ) * Cos( radLat2 ) * Sin( aveLng ) ^ 2 ) )
   End Function
End Class


動作検証として簡単単なエージェントを作成します。

Option Declare
Use "lsGoogleMAP"

Sub Initialize
   Dim oLoc1 As Location
   Dim oLoc2 As Location

   Set oLoc1 = New Location(34.68374, 135.49698)
   Set oLoc2 = New Location(34.68354, 135.49616)

    MsgBox CStr(Format(oLoc1.CalcDistance(oLoc2), "0.00")) & "m"
End Sub

適当な 2 つの座標 oLoc1 と oLoc2 を用意し、CalcDistance メソッドを実行します。これで 2 地点間の距離が求められますので、それをメッセージボックスで表示しています。


まとめ

クラスに機能(メソッド)を追加する方法を紹介しました。以前作成したクラスに具体的な機能を追加したので、イメージしやすかったと思います。この作業を材料に、クラス化の効果について整理します。

例えば Location クラスとして提供した機能を通常の関数群として開発したとします。追加機能である CalcDistance 関数は、スクリプトライブラリ内に Public な関数として定義が必要です。スクリプトライブラリを利用するプログラムからアクセスできる必要があるからですね。

Public な関数はプログラム全体で一意である必要があります。もし、このスクリプトライブラリを利用するエージェントやフォームで別の CalcDistance 関数が存在すると、エラーとなります。このライブラリを利用するには、ライブラリ外で名称を変える調整(修正)が発生することになります。

クラス化した場合は oLoc1.CalcDistance(oLoc2) のような記述になります。通常の関数とはスコープが違うので、文法エラーにはなりません。

このように、クラス化しておくと既存プログラムに対する影響を低減させる効果があります。また、この二次的な効果としてメソッドやプロパティ名をシンプルにできる効果があります。クラス内で名称が一意であればよく、別のクラスで同名があっても別扱いになるからですね。

クラス化したほうがより部品化が進めやすくなるということですね。


前回 クラス化に挑戦


0 件のコメント:

コメントを投稿