Placesの検索
世界中の数億の 施設情報(POI )とポイントアドレスを集めた HERE のグローバルデータセットをソースとする HERE SDK for iOS を使用すると、すばやく簡単に検索できます。 HERE SDK を使用すると、検索に関連するさまざまなタスクを 1 つ のSearchEngine
内で解決できます。
- placesの検索: この巨大なデータベースから、カテゴリ別、または検索語を設定して、世界中のPlacesを検索して発見できます。
- Autosuggestを生成: 検索条件を入力して検索を完了するときに、Placesを検索します。
- 住所をリバースジオコード: 特定の地理座標に属する住所を検索します。
- 住所でのジオコード : 住所に属する地理座標を検索します。
- ID で検索: HERE Place IDで特定されたPlacesを検索します。
- ルートに沿って検索: ルート全体に沿ったPlacesを検索します。
- ルートに沿ってカテゴリで検索: ルート全体のカテゴリに基づいてPlacesを検索します。 この機能はベータ版です。
- 個人データの持ち込み( BYOD ): 独自の Places データを追加して、実行時に無条件の検索リクエストにアクセスできるようにします。
- オフラインで検索: インターネットに接続できない場合は、
OfflineSearchEngine
に切り替えて、キャッシュ済みのマップ データまたは事前にロードされたオフライン地図データを検索できます。
すべての検索バリアントに共通するフィーチャーの1つは、検索する場所または領域を指定できることです。 領域の設定は、GeoBox
で指定された矩形領域 、またはGeoCircle
で指定された円領域を通過することで行う ことができます。 指定した領域外にある潜在的な検索結果は、関連するグローバルな結果を除いて、優先度の低いものでランク付けされます。たとえば、ベルリンで「 Manhattan 」を検索する場合です。 基本となる検索アルゴリズムが最適化され、結果のリストを絞り込むことができるようになり、ユーザーに迅速でわかりやすい結果が提供されます。
注 : 各検索リクエストは非同期で実行されます。 オンライン接続が必要です。
HERE の位置情報サービスが提供する場所の大規模なデータベースは、 HERE SDK のSearchEngine
で簡単に見つけることができます。 例を見てみましょう。 まず、新しい SearchEngine
インスタンスを作成します。
do {
try searchEngine = SearchEngine()
} catch let engineInstantiationError {
fatalError("Failed to initialize SearchEngine. Cause: \(engineInstantiationError)")
}
新しい SearchEngine
インスタンスを作成すると、上の図のように処理する必要があるエラーがスローされることがあります。 このようなエラーは、たとえば、 HERE SDK の初期化が事前に失敗した場合に発生することがあります。
Placesの検索
デバイスに表示されている現在のマップのセンター周りにあるすべての「ピザ」の場所を探しているとします。 検索を開始する前に、詳細をいくつか指定する必要があります。
let searchOptions = SearchOptions(languageCode: LanguageCode.enUs,
maxItems: 30)
上記のコード スニペットから、目的のデータを保持する新しいオブジェクト SearchOptions
を作成しました。
-
LanguageCode
を設定することで、返される検索結果の言語を指定できます。 -
maxItems
は、応答で配信する結果アイテムの最大数を定義するように設定されています。 上の例では、結果を 30 に制限しています。 リクエストよりも多くの検索結果が見つかった場合、最も関連性の高い 30 件の検索結果のみが返されます。
現在のビューポイント内のすべての結果を検索するために、 1 つのボックスで検索を行います。 SearchEngine
では、次の 3 つの方法で検索場所を指定できます。
GeoCoordinates
検索場所:指定した座標系を中心に非同期の検索リクエストを実行し、近隣で最も関連性の高い検索結果を提供します。 GeoCircle
エリア内を検索 : 上記と似ていますが、指定した円領域内で結果を検索します。この領域は、中心地理座標およびメートル単位の半径で定義されます。 GeoBox
エリア内を検索 : 上記と同様ですが、指定した矩形領域内で結果を検索します。この領域は、パラメーターとして渡された南西および北東の座標によって定義されます。
One-Box検索 は、近隣のPlacesを探すのに最適です。 入力すると、さまざまな言語 ( ラテン語、キリル語、アラビア語、ギリシャ語など ) で自由形式のテキストを提供できます。
検索する語句と一緒に領域を指定できます。 たとえば queryString
、「 pizza 」のように設定できます。
let queryArea = TextQuery.Area(inBox: getMapViewGeoBox())
let textQuery = TextQuery(queryString, area: queryArea)
ここでは、 getMapViewGeoBox()
のコードを削除しました。 ユースケースに適した任意のGeoBox
を作成して渡すことができます。 実装の可能性については、付属のサンプルアプリを参照してください。
できれば、指定したマップ範囲内の結果が返されます。 検索結果が見つからなかった場合は、グローバル検索結果が返されることがあります。 ただし、指定した検索場所に関係なく、主要都市や州などの関連するグローバルな結果が含まれる場合があります。
注 : クエリー文字列には、検索するコンテンツの任意のテキスト記述を含めることができます。 複数の検索語を使用して、コンマで区切って検索結果を絞り込むことができます。 「ピザショーシー通り」と「ピザ、ショーシー通り」は同じ結果をもたらします。通り「チャウゼー通り」にあるピザレストランのみが見つかります。 また、空のクエリ文字列を渡すとエラーになります。この場合、検索は失敗します。
最後に、非同期で検索を開始できます。
_ = searchEngine.search(textQuery: textQuery,
options: searchOptions,
completion: onSearchCompleted)
...
func onSearchCompleted(error: SearchError?, items: [Place]?) {
if let searchError = error {
showDialog(title: "Search", message: "Error: \(searchError)")
return
}
showDialog(title: "Search in viewport for: 'Pizza'.",
message: "Found \(items!.count) results.")
for searchResult in items! {
}
}
注
また、完了ハンドラのインライン化には、終了条件式を使用できます。
_ = searchEngine.search(textQuery: textQuery,
options: searchOptions) { (searchError, searchResultItems) in
}
もちろん、 HERE SDK で利用できる他のすべての完了処理についても同じことが可能です。 このガイドでは、関数 呼び出し式 を使用して、すべての種類の情報を保持することをお勧めします。
提供されているすべての search()
メソッドが TaskHandle
を返します。このメソッドは、進行中のコールのステータスの確認、またはコールのキャンセルに任意で使用できます。 必要でない場合は、上に示したように、そのままにしておくことができます。
結果を確認する前に、可能なSearchError
を確認する必要があります。 たとえば、デバイスがオフラインの場合、検索項目のリストは nil になり、エラー 列挙型 (enum) が原因を示します。 この場合、ヘルパーメソッドshowDialog()
を呼び出して、エラーの説明をユーザーに表示します。 showDialog()
の実装の可能性は、付随する「検索」の例のソースコードからアクセスできます。このコードには、 HERE SDK 固有のコードは含まれていません。
エラーが発生した場合は事前に削除しておくため、検索アイテムリストの折り返しを安全に解除できます。
注
検索のレスポンスにはエラーまたは結果が含まれます。error
と items
が同時に nil になることも、非 nil になることもありません。
ここで、結果を確認しましょう。 一致する結果が見つからない場合は、事前にエラーが検出されている可能性があります。
showDialog(title: "Search in viewport for: 'Pizza'.",
message: "Found \(items!.count) results.")
for searchResult in items! {
let metadata = Metadata()
metadata.setCustomValue(key: "key_search_result", value: SearchResultMetadata(searchResult))
addPoiMapMarker(geoCoordinates: searchResult.geoCoordinates!, metadata: metadata)
}
...
private class SearchResultMetadata : CustomMetadataValue {
var searchResult: Place
init(_ searchResult: Place) {
self.searchResult = searchResult
}
func getTag() -> String {
return "SearchResult Metadata"
}
}
最後に、結果のリストについて反復処理を行います。 各Place
には、検索結果を説明するさまざまなフィールドが含まれています。
この例では、マップにマーカーを追加するために、そのPlacesの場所に関心があります。 さらに、Metadata
を保存できるオブジェクト SearchResult
を作成します。
注 : Metadata
オブジェクトには、マップ マーカーと結果データを簡単に関連付けることができるように、さまざまなデータ型を含めることができます。 このようにして、マップ マーカーに関連するすべての情報を 1 つのオブジェクトに保持できます。これは、ユーザーがマップ マーカーをタップした後などに、このデータを表示する場合に便利です。 上記 CustomMetadataValue
のように、インターフェイスを実装することで、複雑なデータオブジェクトも保存できます。
addPoiMapMarker()
の実装方法としては、付随する「検索」のサンプルソースコードからアクセス できます。このガイドの「マップマーカーについて」も参照してください。 選択したマップ マーカーを手元に置いておくと、前のステップで設定した情報Metadata
を取得できます。
if let searchResultMetadata =
topmostMapMarker.metadata?.getCustomValue(key: "key_search_result") as? SearchResultMetadata {
let title = searchResultMetadata.searchResult.title
let vicinity = searchResultMetadata.searchResult.address.addressText
showDialog(title: "Picked Search Result",
message: "Title: \(title), Vicinity: \(vicinity)")
return
}
すべてのマップマーカーにMetadata
が含まれているわけでは ありません。 事前にMetadata
を設定していない場合、getMetadata()
は nil を返します。 この例では、保存されているデータ "key_search_result"
が nil でないかどうかを確認するだけで、データに検索データが含まれている必要があることがわかります。 その後、 目的のPlace
を保持するカスタムタイプSearchResultMetadata
にダウンキャストできます。
使用可能なオプションのフィールドの詳細については、 API リファレンス を参照してください。
スクリーンショット: 選択した検索結果をタイトルと近隣で表示。 注
このセクションおよび以降のセクションのすべてのコードは Search
、 GitHubのサンプルアプリの一部として入手できます。
places にズーム
上記のコードでは、GeoBox
を使用 して、表示されているマップビューポイント を直接検索します。そのため、検索結果をズームする必要はありません。 GeoBox
の代わり に、CountryCode
値のリストを渡すことで、 GeoCircle
の内側、 GeoCorridor
に沿って、または内側の国を囲む位置を検索することもできます ( 「自分の周りを検索」 ) 。 サポートされているすべてのタイプについては、TextQuery.Area
を参照
検索領域が表示されているマップビューポイント と異なる場合 は、次のコードを使用してGeoCoordinates
の一覧からGeoBox
を作成し、結果をズームできます。 GeoBox
からGeoBox.containing(geoCoordinates: geoCoordinatesList)
を取得します。
camera.lookAt(area: geoBox,
orientation: GeoOrientationUpdate(bearing: nil, tilt: nil))
これでカメラが即座に移動します。 必要に応じて、さまざまなアニメーションスタイルを適用して、カメラを目的の領域にフライすることもできます。 このMapCamera
セクションを参照 して、 GitHub の CameraKeyframeTracks サンプルアプリ を確認します。
追加のパディングを適用する場合は、viewRectangle
を追加のパラメーターとして受け取るオーバーロードされたメソッドlookAt()
を使用します。 矩形は、GeoBox
が表示されている内部のマップ ビュー を参照するピクセル単位で指定されます。
let origin = Point2D(5, 5)
let sizeInPixels = Size2D(width: mapView.viewportSize.width - 10, height: mapView.viewportSize.height - 10)
let paddedViewRectangle = Rectangle2D(origin: origin, size: sizeInPixels)
上記のコードでは、 GeoBox
マップビューポイント に表示されている任意の周囲に 5 ピクセルのパディングを追加するために使用できる矩形を作成します。
Placesのカテゴリの検索
上記のようにTextQuery
をしてキーワード検索を行う代わりに、カテゴリを検索して結果を予想されるカテゴリPlace
に限定することもできます。
カテゴリ ID は特定の形式に従い、 HERE platform では 700 を超えるカテゴリを使用できます。 HERE SDK には、カテゴリ検索を簡単に使用できるように定義済みの値のセットが用意されています。 必要に応じて、 xxx-xxxx-xxxx の形式でカスタムカテゴリ文字列を渡すこともできます。各グループは、 1 、 2 、 3 の各レベルのカテゴリを表します。 1 番目のレベルがメインカテゴリを表し、 3 番目のレベルが 2 番目のレベルのサブカテゴリのサブカテゴリを表します。 各カテゴリレベルは 、placesカテゴリシステムで番号として定義されます。
例として、「飲食」カテゴリまたは「ショッピングエレクトロニクス」カテゴリに属するすべての場所を以下から検索します。
private func searchForCategories() {
let categoryList = [PlaceCategory(id: PlaceCategory.eatAndDrink),
PlaceCategory(id: PlaceCategory.shoppingElectronics)]
let queryArea = CategoryQuery.Area(areaCenter: GeoCoordinates(latitude: 52.520798,
longitude: 13.409408))
let categoryQuery = CategoryQuery(categoryList, area: queryArea)
let searchOptions = SearchOptions(languageCode: LanguageCode.enUs,
maxItems: 30)
_ = searchEngine.search(categoryQuery: categoryQuery,
options: searchOptions,
completion: onSearchCompleted)
}
public func onSearchCompleted(error: SearchError?, items: [Place]?) {
if let searchError = error {
print("Search Error: \(searchError)")
return
}
showDialog(title: "Search Result", message: "\(items!.count) result(s) found. See log for details.")
for place in items! {
let addressText = place.address.addressText
print(addressText)
}
}
PlaceCategory
は、String
を受け入れます。 HERE では、事前定義されたカテゴリ eatAndDrink
およびshoppingElectronics
を使用し ます。 この値String
には、placesカテゴリシステムで表される ID が含まれています。 ここでも、 SearchEngine
のオーバーロードされた search()
メソッドを使用して、カテゴリリストと場所を探す地理的座標を含む CategoryQuery
オブジェクトを渡します。
Auto Suggestionの検索
ほとんどの場合、Places検索を提供するアプリケーションでは、ユーザーが希望する検索用語を編集可能なテキストフィールドコンポーネントに入力可能です。 入力中に、可能性のある用語の予測を取得できると便利です。
エンジンによって提示された提案がランク付けされ、最も関連性の高い用語が結果リストの一番上に表示されます。 たとえば、最初のリストアイテムを使用して、ユーザーが現在入力している検索語のAutoSuggestを提供できます。 または - ユーザーの入力中に更新された一致候補のリストを表示できます。 ユーザーは、提案のリストから適切なキーワードを選択して、選択した用語の新しい検索を開始できます。または 、タイトル や 近隣などの結果の詳細情報をすでに取得し てユーザーに提示できます。
注
HERE SDKは 、UIや完全に統合されたAutosuggestソリューションを提供していません。 このようなソリューションは、必要に応じてアプリケーションによって実装できます。 このフィーチャーSuggestion
を使用すると、TextQuery
の条件に基づいて結果 Place
が得られます。 これらのPlacesから、タイトルテキスト(「Pizza XL」)またはその他の関連する場所情報(住所など)を使用して、ユーザーにフィードバックを提供できます。たとえば、クリック可能な完了結果を提案することができます。 しかし、そのようなソリューションはアプリケーションの個々の要件に依存し、プラットフォームAPIを使用してアプリケーション側で実装する必要があります。
通常のテキストクエリと比較して、候補の検索では、入力したクエリの用語について、優先度でランク付けされた高速な結果が提供されます。
エンジンを使用して提案を検索する方法を確認しましょう。
let centerGeoCoordinates = getMapViewCenter()
let autosuggestOptions = SearchOptions(languageCode: LanguageCode.enUs,
maxItems: 5)
let queryArea = TextQuery.Area(areaCenter: centerGeoCoordinates)
_ = searchEngine.suggest(textQuery: TextQuery("p", area: queryArea),
options: autosuggestOptions,
completion: onSearchCompleted)
_ = searchEngine.suggest(textQuery: TextQuery("pi", area: queryArea),
options: autosuggestOptions,
completion: onSearchCompleted)
_ = searchEngine.suggest(textQuery: TextQuery("piz", area: queryArea),
options: autosuggestOptions,
completion: onSearchCompleted)
ヘルパーメソッド getMapViewCenter()
は ここから削除され、付属のサンプルアプリで確認できます。 マップ ビューの中央に現在表示されているGeoCoordinates
を返すだけです。
新しいテキスト入力ごとに、次のリクエストを作成します。 ユーザーが「 Pizza 」と入力することを計画していると仮定します。まず「 p 」の結果を探し、次に「 pi 」の結果を探し、最後に「 piz 」の結果を探します。 ユーザーが実際に「pizza」を検索する場合は、 3 度目の呼び出しで十分な興味深い提案があるはずです。
SearchEngine
の他の search()
メソッドと同様に、 suggest()
メソッドは TaskHandle
を返します。このメソッドを使用すると、進行中のコールのステータスを確認したり、コールをキャンセルしたりできます。
結果の取得方法を確認しましょう。
func onSearchCompleted(error: SearchError?, items: [Suggestion]?) {
if let searchError = error {
print("Autosuggest Error: \(searchError)")
return
}
print("Autosuggest: Found \(items!.count) result(s).")
for autosuggestResult in items! {
var addressText = "Not a place."
if let place = autosuggestResult.place {
addressText = place.address.addressText
}
print("Autosuggest result: \(autosuggestResult.title), addressText: \(addressText)")
}
}
ここでは、Suggestion
で見つかったリストアイテムをログに記録する完了ハンドラを定義します 。 エラーがない場合、エンジンは結果のリストを保証します。エラーがない場合、結果は nil になります。
すべての提案があるわけではありません。 たとえば、「シスコ」などの一般的な用語を使用して、新しい検索に入力できます。 一般的な用語では、 結果Suggestion
にオブジェクト Place
は含まれませんが、特定の場所を参照せずにテキストを表すのは title
だけです。 Suggestion
結果の使用可能なすべてのフィールドについては、『 API リファレンス 』を参照してください。
結果の順序はランク付けされますが、完了イベントが到着する順序については保証がありません。 そのため、まれに、「 PI 」の結果よりも前に「 Piz 」の結果が表示されることがあります。
地理座標から住所をリバースジオコード
これで、マップ上の特定の場所または地域でPlacesを検索する方法を確認できました。 ただし、場所のみがわかっている場合は、どうすればよいのでしょうか。 このユースケースで最も一般的なのは、マップで何らかのアクションを実行しているユーザーです。 たとえば、長押しジェスチャを使用すると、ユーザーがマップを操作した場所の緯度座標と経度座標が表示されます。 ユーザーはマップ上の場所を参照できますが、その場所に属する住所情報などの他の属性は把握できません。
リバースジオ コーディング が役立つ場所です。
関心のある場所は GeoCoordinates
インスタンスで表されます。たとえば、マップをタップしたユーザーから取得できます。 その場所を「ジオコード」する方法については、次のコードを参照してください。
private func getAddressForCoordinates(geoCoordinates: GeoCoordinates) {
let reverseGeocodingOptions = SearchOptions(languageCode: LanguageCode.enGb,
maxItems: 1)
_ = searchEngine.search(coordinates: geoCoordinates,
options: reverseGeocodingOptions,
completion: onReverseGeocodingCompleted)
}
func onReverseGeocodingCompleted(error: SearchError?, items: [Place]?) {
if let searchError = error {
showDialog(title: "ReverseGeocodingError", message: "Error: \(searchError)")
return
}
let addressText = items!.first!.address.addressText
showDialog(title: "Reverse geocoded address:", message: addressText)
}
SearchEngine
によって提供される他の検索機能と同様に、必要な LanguageCode
を設定するための SearchOptions
インスタンスを提供する必要があります。 結果の住所の言語を指定します。 その後、エンジンのメソッドsearch()
を呼び出して、渡された座標のアドレスをオンラインで検索できます。 デバイスがオフラインのときなど、エラーが発生した場合は、 SearchError
は、エラーの原因を保持します。
注
リバースジオ コーディングのレスポンスには、エラーまたは結果のSearchError
が含まれています。また、アイテムリストは、同時に nil にすることも、非nil にすることもできません。
各 Place
インスタンス内に含まれるオブジェクトAddress
はデータクラスで、国、市区町村、番地などの生の場所の住所を記述する複数のフィールド String
が含まれています。 詳細については、 API リファレンス を参照してください。 読み取り可能なアドレス表現の受信のみに関心がある場合 addressText
は、上の例に示すようにににアクセスできます。 これは、その場所のタイトルを含む、最も関連性の高い住所の詳細String
を含みます。
スクリーンショット: 住所に解決された印刷機の長い座標を表示。 リバース ジオ コーディングでは、特定の検索領域は必要ありません。 世界中の住所に座標を解決できます。
住所を位置情報にジオコード
Reverse ジオ コーディング を使用すると、未加工の座標から住所を取得できますが 、 フィワードジオ コーディング では逆の処理が行われ、道路名や都市などの住所の詳細を入力するだけで、未加工の座標やその他の位置情報を検索できます。
注 : ほとんどの場合、リバースジオ コーディングでは 1 つの結果しか得られませんが、ジオ コーディングでは 1 つ以上の結果が得られます。
ここでその方法をご案内します。 まず、検索したい場所の近くの座標を指定する必要があります。queryString
として、正確な場所を見つけたい住所を設定します。
let query = AddressQuery(queryString, near: geoCoordinates)
let geocodingOptions = SearchOptions(languageCode: LanguageCode.deDe,
maxItems: 25)
_ = searchEngine.search(addressQuery: query,
options: geocodingOptions,
completion: onGeocodingCompleted)
この例では、 HERE の Berlin HQ "Invalidenstra ß e 116" の通りの名前をクエリー文字列として渡します ( 任意で都市を指定します ) 。 これはドイツ語の通り名な deDe
ので、ドイツの言語コードを入力します。 これにより、返される結果の言語も決まります。
注 : 結果は指定した場所から遠く離れていてもかまいませんが、指定した座標に近い結果が高い順にランク付けされ、可能であれば返されます。
次のステップでは、完了ハンドラを実装する必要があります。
func onGeocodingCompleted(error: SearchError?, items: [Place]?) {
if let searchError = error {
showDialog(title: "Geocoding", message: "Error: \(searchError)")
return
}
for geocodingResult in items! {
}
}
完了ハンドラがエラーを受信しなかったことを確認した後 、要素Place
の一覧表を確認します。
注
searchError
が nil の場合 、items
の結果は nil ではないことが保証され、その逆も同様です。 そのため、オプションの一覧表をラップ解除しても安全です。
結果は 、未加工の座標を含むPlaces
オブジェクトにラップ されます。また、Address
オブジェクトや、 HERE Places API 内の位置を特定する場所 ID など、その他の住所の詳細情報もラップされます。 以下では、一覧表について繰り返し、住所のテキストと座標を取得します。
for geocodingResult in items! {
let geoCoordinates = geocodingResult.geoCoordinates!
let address = geocodingResult.address
let locationDetails = address.addressText
+ ". Coordinates: \(geoCoordinates.latitude)"
+ ", \(geoCoordinates.longitude)"
}
ユーザーがマップからこのような結果を選択した場合の表示例については、以下のスクリーンショットを参照してください。 ご希望の場合は、添付の「検索」のサンプルアプリを参照して、住所のテキストを検索し、マップ上の見つかった場所にマップマーカーを配置する方法を確認してください。
スクリーンショット: 選択したジオ コーディング結果を表示。 ルート沿いの検索
SearchEngine
は、長方形または円の領域で検索せずに、GeoPolyline
および他のパラメーターで定義できるより複雑なGeoCorridor
領域で検索する場合に、特殊な検索ケースをサポートします。
このような場合の最も一般的なシナリオは、 Route
を検索してレストランを探すことです。 ルートオブジェクトがすでに計算されているとします。 経路の計算方法については、経路のセクションを参照してください。 TextQuery
を指定すると、ルート全体を含む長方形の領域を簡単に定義できます。
let textQuery = TextQuery("restaurants", in: route.boundingBox)
ただし、より長いルートの場合、およびルートの形状によっては、route.boundingBox
がルート全体を長方形の領域に包含する必要があるため、結果が実際のルートパスから非常に離れている場合があります。
HERE SDK は GeoCorridor
、ルートの実際の形状から検索領域を判断できるクラスを提供することで、より正確なソリューションを提供します。 この方法 では、パスの上または下にある検索結果のみが含まれます。
以下に、ルートに沿ってチャージステーションを検索する方法の例を示します。
private func searchAlongARoute(route: Route) {
let routeCorridor = GeoCorridor(polyline: route.geometry.vertices,
halfWidthInMeters: Int32(200))
let queryArea = TextQuery.Area(inCorridor: routeCorridor, near: mapView.camera.state.targetCoordinates)
let textQuery = TextQuery("charging station", area: queryArea)
let searchOptions = SearchOptions(languageCode: LanguageCode.enUs,
maxItems: 30)
searchEngine.search(textQuery: textQuery,
options: searchOptions,
completion: onSearchCompleted)
}
func onSearchCompleted(error: SearchError?, items: [Place]?) {
if let searchError = error {
if searchError == .polylineTooLong {
print("Route too long or halfWidthInMeters too small.")
} else {
print("No charging stations found along the route. Error: \(searchError)")
}
return
}
print("Search along route found \(items!.count) charging stations:")
for place in items! {
}
}
ご覧の ように、GeoCorridor
はルートGeoPolyline
と halfWidthInMeters を必要とします。 このパラメータでは、ポリライン上の任意のポイントから廊下の端までの最も遠いエッジを定義します。 小さな値を指定すると、実際のルートに沿って非常に近いエリアが結果の廊下によって定義されます。
スクリーンショット: ルートに沿って見つかった充電ステーションを表示 ルートの始点と終点の座標では、コリドーは丸い形になります。一定の厚さの曲線が始点と終点に丸いエッジを持つようなものを想像してください。 上記のスクリーンショットと混同しないでください。ルートの始点と終点を示す緑色の円が表示されます。
特に長いルートの場合、内部的に検索アルゴリズムが検索経路の最適化を試行します。 ただし、ポリラインが長すぎる可能性があります。 上記のコード スニペットに示されているように、このケースをキャッチして、最終的にはより複雑でないルートの検索を再トリガすることにします。 これは halfWidthInMeters
パラメータで制御できます。値を大きくすると、廊下の複雑さが軽減され、結果の精度が低下しますが、少なくともこの方法ではより多くの結果が得られます。
ルートの複雑さは、フードの下の複数の要因によって決まります。そのため、ルートの明確な長さは一般に指定できません。
エラーが発生しなかった場合は、上記のセクションにすでに示されているように結果のPlace
を処理できます。
注
このセクションのすべてのコードは 、EVRouting
GitHub のサンプルアプリの一部として入手できます。
個人データの持ち込み
HERE SDK は、場所を検索するときに、実行時に BYOD (個人データの持ち込み)をサポートします。 OfflineSearchEngine
で検索できる場所にカスタムデータを挿入できます。 このような個人的な場所は、定期的な問い合わせで見つけることができます。 結果は、 HERE から直接送られてきた他の場所としてランク付けされます。
GeoPlace
カスタムの Place データを含めることができる複数のインスタンスを作成できます。 これらのインスタンスは、データソースMyPlaces
に追加できます。
let geoPlaces = [
GeoPlace.makeMyPlace(title: "Pizza Pino", coordinates: GeoCoordinates(latitude: 52.518032, longitude: 13.420632)),
GeoPlace.makeMyPlace(title: "PVR mdh", coordinates: GeoCoordinates(latitude: 52.51772, longitude: 13.42038)),
GeoPlace.makeMyPlace(title: "Harley's bar", coordinates: GeoCoordinates(latitude: 52.51764, longitude: 13.42062))
]
myPlaces.addPlaces(places: geoPlaces) { taskOutcome in
if (taskOutcome == TaskOutcome.completed) {
} else {
}
}
このデータソースは、次の場所OfflineSearchEngine
に添付できます。
offlineSearchEngine.attach(dataSource: myPlaces) { taskOutcome in
if (taskOutcome == TaskOutcome.completed) {
} else {
}
}
addPlaces()
とattach()
は、アプリケーションによって一度に数千の場所が追加される可能性があるため、非同期で操作できます。 両方のメソッドがTaskHandle
を返し、それにより操作をキャンセルできます。 操作が完了すると、イベントTaskOutcome
が通知されます。
以下に、そのような場所を見つける方法の例を示します。
let queryArea = TextQuery.Area(inCircle: GeoCircle(center: GeoCoordinates(latitude: 52.518032, longitude: 13.420632),
radiusInMeters: 100.0))
let textQuery = TextQuery("Pizza Pino", area: queryArea)
offlineSearchEngine.search(textQuery: textQuery, options: SearchOptions()) { (searchError, placeList) in
}
インスタンス offlineSearchEngine
がアクティブである限り、追加された場所はメモリに残ります。
オフライン検索
SearchEngine
に加えて、オフラインの使用例にも相当するものがあります。 OfflineSearchEngine
:すでに上記で示したオンライン版と同じ方法で構築できます。
do {
try offlineSearchEngine = OfflineSearchEngine()
} catch let engineInstantiationError {
fatalError("Failed to initialize OfflineSearchEngine. Cause: \(engineInstantiationError)")
}
OfflineSearchEngine
は SearchEngine
とほぼ同じインターフェイスを提供しますが、結果は、 HERE バックエンドサービスへの新しい要求を開始するのではなく、すでにダウンロードまたはキャッシュされているマップ データから取得されたものであるため、若干異なる場合があります。
この方法 では、たとえば、SearchEngine
を使用しているときに受信したデータよりも古いデータを使用できます。 一方、このクラスでは、オンライン接続が不要なため、より迅速に結果を提供できます。
注
すでにキャッシュ されている か、または事前にロードされているオフラインの地図データのみを検索できます。 キャッシュされたマップ データのみを使用する場合、すべてのタイルがロードされているわけではありません。 この場合、これらのタイルもロードされるまで結果は見つかりません。 オフラインの地図では、この問題は発生しません。また、必要なマップ データがダウンロードした地域で利用可能であることが保証されます。 したがって、キャッシュされたマップ データに依存しないことをお勧めします。
使用可能 なOfflineSearchEngine
インターフェイスのほとんどはSearchEngine
で使用できますが 、それとは異なります。単に、すべてのオンライン機能がオフラインデータからもアクセスできるわけではありません。
また 、HERE Places API内の場所を特定するplaces ID は、オフライン検索結果とは異なります。
通常、自由形式な TextQuery
であれば、オフラインのplacesは少なくとも半径 62.5 km 以内にあります。 首都はどこからでもグローバルに見つけることができます。 クエリ文字列に都市名などの専用の場所を追加すると、その場所の近くを検索します。
注
現在、日本ではオフラインでの検索はできません。また、検索結果は見つかりません。
以下に、OfflineSearchEngine
で使用できるユースケースを示します 。 たとえば、移動中に接続が一時的に失われることがあります。 このような場合は、すでにダウンロードされているマップ データで検索することをお勧めします。
そのためには、まずデバイスの接続が失われていないかを確認する必要があります。 2 番目のステップとして、優先エンジンを使用できます。
if isDeviceConnected {
_ = searchEngine.search(textQuery: textQuery,
options: searchOptions,
completion: onSearchCompleted)
} else {
_ = offlineSearchEngine.search(textQuery: textQuery,
options: searchOptions,
completion: onSearchCompleted)
}
検索結果を処理するに onSearchCompleted
は、同じハンドラを設定します ( 前述のとおり ) 。
同様に、アドレスをリバースジオコードすることもできます。
if isDeviceConnected {
_ = searchEngine.search(coordinates: geoCoordinates,
options: reverseGeocodingOptions,
completion: onReverseGeocodingCompleted)
} else {
_ = offlineSearchEngine.search(coordinates: geoCoordinates,
options: reverseGeocodingOptions,
completion: onReverseGeocodingCompleted)
}
または、次のものを使用して、アドレスをジオコードして地理座標に変換できます。
if isDeviceConnected {
_ = searchEngine.search(addressQuery: query,
options: geocodingOptions,
completion: onGeocodingCompleted)
} else {
_ = offlineSearchEngine.search(addressQuery: query,
options: geocodingOptions,
completion: onGeocodingCompleted)
}
デバイスの接続を確認するための可能な解決策は、最初に実際の接続を試みることによって実装できます。それが失敗した場合は、OfflineSearchEngine
- またはその逆に切り替えることができます。まずオフライン検索を試すことができますが、マップ データが利用できない場合はオンラインで試すことができます。
注
このセクションのすべてのコードは 、SearchHybrid
GitHub のサンプルアプリの一部として入手できます。