ガイド変更履歴HERE SDK API references
ガイド

検索機能とジオコーディング機能

HERE SDKは、地理データをシームレスに操作できる包括的な検索機能とジオコーディング機能を備えています。座標を人間が読み取り可能な住所に変換する場合でも、住所入力に基づいて位置を検索する場合でも、HERE SDK は対応できます。

地理座標から住所をリバース ジオコーディングする

SearchEngine を使用して、地図上の特定の位置やエリアの場所を簡単に検索できます。位置の座標しかない場合、一般的なユース ケースでは、ユーザーが地図を操作する必要があります。たとえば、長押しジェスチャーを実行すると、選択した位置の緯度と経度が表示されます。ユーザーは地図でこの位置を見ることができますが、対応する住所情報などの詳細はありません。

ここで、リバースジオコーディングが役に立ちます。

関心のある場所は、GeoCoordinates インスタンスによって表されます。これは、たとえば、ユーザーが地図をタップすることで取得できます。その場所を「リバース ジオコード」する方法を実際に試すには、次のメソッドを参照してください。

private void getAddressForCoordinates(GeoCoordinates geoCoordinates) {
  SearchOptions reverseGeocodingOptions = new SearchOptions();
  reverseGeocodingOptions.languageCode = LanguageCode.EN_GB;
  reverseGeocodingOptions.maxItems = 1;

    searchEngine.searchByCoordinates(geoCoordinates, reverseGeocodingOptions, addressSearchCallback);
}

private final SearchCallback addressSearchCallback = new SearchCallback() {
    @Override
    public void onSearchCompleted(@Nullable SearchError searchError, @Nullable List<Place> list) {
        if (searchError != null) {
            showDialog("Reverse geocoding", "Error: " + searchError.toString());
            return;
        }

        // If error is null, list is guaranteed to be not empty.
        showDialog("Reverse geocoded address:", list.get(0).getAddress().addressText);
    }
};
private fun getAddressForCoordinates(geoCoordinates: GeoCoordinates) {
    val reverseGeocodingOptions = SearchOptions()
    reverseGeocodingOptions.languageCode = LanguageCode.EN_GB
    reverseGeocodingOptions.maxItems = 1

    searchEngine!!.searchByCoordinates(
        geoCoordinates,
        reverseGeocodingOptions,
        addressSearchCallback
    )
}

private val addressSearchCallback =
    SearchCallback { searchError, list ->
        if (searchError != null) {
            showDialog("Reverse geocoding", "Error: $searchError")
            return@SearchCallback
        }
        // If error is null, list is guaranteed to be not empty.
        showDialog("Reverse geocoded address:", list!![0].address.addressText)
    }

SearchEngine によって提供される他の検索機能と同様に、目的の LanguageCode を設定するには、SearchOptions インスタンスを提供する必要があります。これにより、結果として得られる住所の言語が決まります。次に、エンジンの searchByAddress() メソッドを呼び出して、渡された座標の住所をオンラインで検索します。デバイスがオフラインの場合など、エラーが発生した場合、SearchError にエラーの原因が格納されます。

リバースジオコーディングの応答にはエラーまたは結果SearchErrorが含まれており、結果のリストを同時にnullにすることはできず、同時にnull以外にすることもできません。

Place インスタンス内に含まれる Address オブジェクトは、国、都市、通りの名前など、未処理の場所の住所を記述する複数の String フィールドを含むデータ クラスです。詳細については、「API リファレンス」を参照してください。読み取り可能な住所表現の受信にのみ興味がある場合は、上記の例に示すように、addressText にアクセスできます。これは、場所のタイトルなど、最も関連性の高い住所の詳細を含む String です。

Screenshot: Showing a long press coordinate resolved to an address.

リバースジオコーディングには特定の検索エリアは必要なく、座標を世界中の住所に変換できます。

住所を位置情報にジオコーディングする

リバースジオコーディングでは未処理の座標から住所を取得できますが、フォワードジオコーディングではその逆が行われるため、通りや都市の名前などの住所の詳細を渡すだけで未加工の座標やその他の場所の詳細を検索できます。

ほとんどの場合、リバースジオコーディングでは1つの結果しか得られませんが、ジオコーディングでは1つ以上の結果が得られる場合があります。

その方法は次のとおりです。まず、検索する場所の近くの座標を指定する必要があります。queryString として、正確な場所を見つける住所を設定します。

// The geoCoordinates act as a reference location to prioritize the search results.
// This helps the `SearchEngine` return addresses that are more relevant and closer to the user’s
// current location instead of global or less relevant matches.
AddressQuery query = new AddressQuery(queryString, geoCoordinates);

SearchOptions options = new SearchOptions();
options.languageCode = LanguageCode.DE_DE;
options.maxItems = 30;

searchEngine.searchByAddress(query, options, geocodeAddressSearchCallback);

...

private final SearchCallback geocodeAddressSearchCallback = new SearchCallback() {
    @Override
    public void onSearchCompleted(SearchError searchError, List<Place> list) {
        if (searchError != null) {
            showDialog("Geocoding", "Error: " + searchError.toString());
            return;
        }

        for (Place geocodingResult : list) {
            //...
        }

        showDialog("Geocoding result","Size: " + list.size());
    }
};
// The geoCoordinates act as a reference location to prioritize the search results.
// This helps the `SearchEngine` return addresses that are more relevant and closer to the user’s
// current location instead of global or less relevant matches.
val query = AddressQuery(queryString, geoCoordinates)

val options = SearchOptions()
options.languageCode = LanguageCode.DE_DE
options.maxItems = 30

searchEngine!!.searchByAddress(query, options, geocodeAddressSearchCallback)

...

private val geocodeAddressSearchCallback =
    SearchCallback { searchError, list ->
        if (searchError != null) {
            showDialog("Geocoding", "Error: $searchError")
            return@SearchCallback
        }
        for (geocodingResult in list!!) {
            // Note: getGeoCoordinates() may return null only for Suggestions.
            val geoCoordinates = geocodingResult.geoCoordinates
            val address = geocodingResult.address
            val locationDetails = (address.addressText
                    + ". GeoCoordinates: " + geoCoordinates!!.latitude
                    + ", " + geoCoordinates.longitude)

            Log.d(
                LOG_TAG,
                "GeocodingResult: $locationDetails"
            )
            addPoiMapMarker(geoCoordinates)
        }
        showDialog("Geocoding result", "Size: " + list.size)
    }

この例では、HERE のベルリン本社の通り名「Invalidenstraße 116」をクエリ文字列として渡します (オプションで都市名が続きます)。これはドイツ語の通りの名前であるため、ドイツ語の言語コード DE_DE を渡します。これにより、返される結果の言語も決まります。

結果は指定された位置から遠く離れた場所にある可能性がありますが、指定された座標に近い結果が上位にランク付けされ、優先的に返されます。

SearchCallback がエラーなしで完了したことを検証した後、リストで Place 要素を確認します。

searchError が null の場合、結果の list は null ではないことが保証され、その逆も同様です。

結果は、未処理の座標を含む Place オブジェクトにラップされます。Address オブジェクトや、HERE Places API で位置を識別する場所 ID など、その他の住所の詳細もこのオブジェクトには含まれます。以下では、リストを反復処理して、住所テキストと座標を取得します。

for (Place geocodingResult : list) {
    // Note: getGeoCoordinates() may return null only for Suggestions.
    GeoCoordinates geoCoordinates = geocodingResult.getGeoCoordinates();
    Address address = geocodingResult.getAddress();
    String locationDetails = address.addressText
            + ". GeoCoordinates: " + geoCoordinates.latitude
            + ", " + geoCoordinates.longitude;
    //...
}
for (geocodingResult in list!!) {
    // Note: getGeoCoordinates() may return null only for Suggestions.
    val geoCoordinates = geocodingResult.geoCoordinates
    val address = geocodingResult.address
    val locationDetails = (address.addressText
            + ". GeoCoordinates: " + geoCoordinates!!.latitude
            + ", " + geoCoordinates.longitude)
    //...
}

ユーザーが地図からそのような結果を選択した場合にどのように表示されるかを示す例については、以下のスクリーンショットを参照してください。ご興味がある場合は、付属の「Search」サンプル アプリを参照してください。このアプリでは、住所テキストを検索し、地図上の見つかった場所に地図マーカーを配置する方法を紹介しています。

Screenshot: Showing a picked geocoding result.

自動候補提示を取得する

ほとんどの場合、場所検索に対応したアプリケーションでは、ユーザーが編集可能なテキスト フィールド コンポーネントに目的の検索語を入力できます。通常、入力中に、考えられる語句の予測を取得すると便利です。

エンジンによって提供される候補は、最も関連性の高い語句が結果リストの上位に表示されるようにランク付けされます。たとえば、最初のリスト アイテムは、ユーザーが現在入力している検索語の自動完了を提供するために使用できます。ユーザーの入力中に更新される、一致する候補のリストを表示することもできます。ユーザーは候補のリストから適切なキーワードを選択し、選択した語句に対して新しい検索を開始できます。タイトルや周辺地などの結果の詳細をあらかじめ取得しておいてそれをユーザーに提示することも可能です。

HERE SDK には、UI や完全に統合された自動完了ソリューションはありません。このようなソリューションは、必要に応じてアプリケーションによって実装できます。Suggestion 機能を使用すると、TextQuery に基づいて考えられる Place の結果が得られます。これらの場所からタイトル テキスト (「Pizza XL」) またはその他の関連する場所情報 (住所など) を使用して、クリック可能な完了結果を提案するなど、ユーザーにフィードバックを提供できます。ただし、このようなソリューションはアプリケーションの個々の要件に依存するため、プラットフォーム API を使用してアプリ側で実装する必要があります。

通常のテキスト クエリと比較して、候補の検索では、入力されたクエリ語句に対して、優先順位に従ってランク付けされた結果を迅速に提供することに特化しています。

エンジンを使用して候補を検索する方法を見てみましょう。

GeoCoordinates centerGeoCoordinates = getMapViewCenter();

SearchOptions searchOptions = new SearchOptions();
searchOptions.languageCode = LanguageCode.EN_US;
searchOptions.maxItems = 5;

TextQuery.Area queryArea = new TextQuery.Area(centerGeoCoordinates);

// Simulate a user typing a search term.
searchEngine.suggestByText(
        new TextQuery("p", // User typed "p".
                queryArea),
        searchOptions,
        autosuggestCallback);

searchEngine.suggestByText(
        new TextQuery("pi", // User typed "pi".
                queryArea),
        searchOptions,
        autosuggestCallback);

searchEngine.suggestByText(
        new TextQuery("piz", // User typed "piz".
                queryArea),
        searchOptions,
        autosuggestCallback);
val centerGeoCoordinates = mapViewCenter

val searchOptions = SearchOptions()
searchOptions.languageCode = LanguageCode.EN_US
searchOptions.maxItems = 5

val queryArea = TextQuery.Area(centerGeoCoordinates)

// Simulate a user typing a search term.
searchEngine!!.suggestByText(
    TextQuery(
        "p",  // User typed "p".
        queryArea
    ),
    searchOptions,
    autosuggestCallback
)

searchEngine!!.suggestByText(
    TextQuery(
        "pi",  // User typed "pi".
        queryArea
    ),
    searchOptions,
    autosuggestCallback
)

searchEngine!!.suggestByText(
    TextQuery(
        "piz",  // User typed "piz".
        queryArea
    ),
    searchOptions,
    autosuggestCallback
)

ヘルパー メソッド getMapViewCenter() はここでは省略されていますが、付属のサンプル アプリで確認できます。現在マップ ビューの中央に表示されている GeoCoordinates を返すだけです。

新しいテキスト入力ごとに、次のリクエストを行います。ユーザーが「Pizza」と入力すると仮定すると、最初に「p」、次に「pi」、最後に「piz」の結果を探します。ユーザーが本当に「Pizza」を検索する場合は、3 回目の呼び出しで十分な興味深い候補が得られるはずです。

suggestByText() メソッドは、進行中の呼び出しのステータスを確認したり、呼び出しをキャンセルしたりするために必要に応じて使用できる TaskHandle を返すことに注意してください。

結果を取得する方法を見てみましょう。

private final SuggestCallback autosuggestCallback = new SuggestCallback() {
    @Override
    public void onSuggestCompleted(@Nullable SearchError searchError, @Nullable List<Suggestion> list) {
        if (searchError != null) {
            Log.d(LOG_TAG, "Autosuggest Error: " + searchError.name());
            return;
        }

        // If error is null, list is guaranteed to be not empty.
        Log.d(LOG_TAG, "Autosuggest results: " + list.size());

        for (Suggestion autosuggestResult : list) {
            String addressText = "Not a place.";
            Place place = autosuggestResult.getPlace();
            if (place != null) {
                addressText = place.getAddress().addressText;
            }

            Log.d(LOG_TAG, "Autosuggest result: " + autosuggestResult.getTitle() +
                    " addressText: " + addressText);
        }
    }
};
private val autosuggestCallback =
    SuggestCallback { searchError, list ->
        if (searchError != null) {
            Log.d(LOG_TAG, "Autosuggest Error: " + searchError.name)
            return@SuggestCallback
        }
        // If error is null, list is guaranteed to be not empty.
        Log.d(LOG_TAG, "Autosuggest results: " + list!!.size)
        for (autosuggestResult in list) {
            var addressText = "Not a place."
            val place = autosuggestResult.place
            if (place != null) {
                addressText = place.address.addressText
            }

            Log.d(
                LOG_TAG, "Autosuggest result: " + autosuggestResult.title +
                        " addressText: " + addressText
            )
        }
    }

ここでは、Suggestion で見つかったリスト アイテムを記録する SuggestCallback を定義します。エラーがない場合、エンジンによって結果のリストが保証されます。それ以外の場合は null になります。

すべての候補が場所になるわけではありません。たとえば、「disco」のような一般的な語を新しい検索に入力できます。一般的なキーワードを使用すると、Suggestion の結果には Place オブジェクトは含まれず、title のみが含まれます。これは、特定の場所を参照せずにテキストを表すためです。Suggestion の結果で使用できるすべてのフィールドについては、「API リファレンス」を参照してください。

結果の順序はランク付けされますが、コールバックが到着する順序は保証されません。したがって、まれに、「pi」の結果よりも先に「piz」の結果を受け取ることがあります。

注 (Navigateのみ)

OfflineSearchEngineでも提案を使用できます。この場合、SearchEngineOfflineSearchEngine のインスタンスと交換するだけです。これには、ダウンロードまたはキャッシュに保存されたマップデータが必要です。この例は、GitHubの「[SearchHybrid]」サンプルアプリ (Java版およびKotlin版) で確認できます。

場所カテゴリーを検索する

「ピザ」のように TextQuery を使用してキーワード検索を行う代わりに、カテゴリーを検索して、Place の結果を予想されるカテゴリーに限定することもできます。

カテゴリー ID は特定の形式に従い、HERE プラットフォームでは 700 を超えるさまざまなカテゴリーが利用可能です。幸いなことに、HERE SDK には、カテゴリー検索をより簡単に実行するための事前定義された値のセットが用意されています。必要に応じて、xxx​​-xxxx-xxxx の形式に従ってカスタム カテゴリー文字列を渡すこともできます。各グループは、第 1、第 2、第 3 レベルのカテゴリーを表します。第 1 レベルはメイン カテゴリーを表し、第 2 レベルと第 3 レベルは論理サブセットごとに整理されたサブ カテゴリーを表します。各カテゴリー レベルはプレース カテゴリー システムの数値として定義されます。 例: 100 - 「飲食店」メイン カテゴリー このカテゴリーには、カテゴリー「1000」 - 「レストラン」があります。 この第 2 レベルのカテゴリーには、カテゴリー「0001」「カジュアル ダイニング」があります。 完全なカテゴリー ID は、次のとおりです。100-1000-0001

例として、以下では「Eat and Drink」カテゴリーか「Shopping Electronics」カテゴリーに属する​​すべての場所を検索しています。

private void searchForCategories() {
    List<PlaceCategory> categoryList = new ArrayList<>();
    categoryList.add(new PlaceCategory(PlaceCategory.EAT_AND_DRINK));
    categoryList.add(new PlaceCategory(PlaceCategory.SHOPPING_ELECTRONICS));

    CategoryQuery.Area queryArea = new CategoryQuery.Area(new GeoCoordinates(52.520798, 13.409408));
    CategoryQuery categoryQuery = new CategoryQuery(categoryList, queryArea);

    SearchOptions searchOptions = new SearchOptions();
    searchOptions.languageCode = LanguageCode.EN_US;
    searchOptions.maxItems = 30;

    searchEngine.searchByCategory(categoryQuery, searchOptions, new SearchCallback() {
        @Override
        public void onSearchCompleted(SearchError searchError, List<Place> list) {
            if (searchError != null) {
                infoTextview.setText("Search Error: " + searchError.toString());
                return;
            }

            // If error is null, list is guaranteed to be not empty.
            String numberOfResults = "Search results: " + list.size() + ". See log for details.";
            infoTextview.setText(numberOfResults);

            for (Place searchResult : list) {
                String addressText = searchResult.getAddress().addressText;
                Log.d(TAG, addressText);
            }
        }
    });
}

PlaceCategory には String を使用できます。ここでは、事前定義されたカテゴリー EAT_AND_DRINKSHOPPING_ELECTRONICS を使用しています。String値には、プレースカテゴリーシステムで表されるIDが含まれます。ここでも、SearchEnginesearchByCategory()メソッドを使用し、カテゴリーリストと場所を検索する地理座標を含むCategoryQueryオブジェクトを渡します。

場所チェーンを検索する

場所チェーンを使用すると、特定のブランドに属するすべての場所を検索できます。たとえば、IDが「K-Supermarket」を表す場合は、「K-Supermarket」店舗のみに絞って検索することができます。PlaceCategoryが場所チェーンのカテゴリーと一致していることを確認します。

PlaceChain識別子は、場所チェーンを関連付けるために使用されます。サポートされている場所チェーンのリストはこのリンクにあります。

PlaceChain placeChain = new PlaceChain("1566");
List<PlaceChain> includeChains = new ArrayList<>();
includeChains.add(placeChain);
categoryQuery.includeChains = includeChains;

上記のチェーンID「1566」は「マクドナルド」の場所チェーンを識別し、EAT_AND_DRINKカテゴリーに属しています。複数の場所カテゴリーを指定した場合、少なくとも1つのカテゴリーが一致しないと結果は表示されません。

ルートに沿って検索する

SearchEngine では、長方形または円形のエリアではなく GeoPolyline やその他のパラメーターで定義できるより複雑な GeoCorridor に沿って検索するという特殊な検索ケースをサポートしています。

このようなケースの最も一般的なシナリオは、Route に沿ってレストランを検索することです。Route オブジェクトをすでに計算していると仮定します。ルートの計算方法については、「経路」セクションを参照してください。TextQuery を指定すると、ルート全体を囲む長方形のエリアを簡単に定義できます。

TextQuery textQuery = TextQuery("restaurants", route.getBoundingBox())

ただし、より長いルートの場合、ルートの形状によっては、route.boundingBox で長方形エリアのルート全体を囲む必要があるため、結果が実際のルート パスから非常に遠くなる場合があります。

HERE SDK にはルートの実際の形状から検索エリアを決定できる GeoCorridor クラスが用意されており、より正確なソリューションを提供しています。この方法では、パス上またはパスの下にある検索結果のみが含まれます。

以下に、ルート上の充電スタンドを検索する方法の例を示します。

// Perform a search for charging stations along the found route.
private void searchAlongARoute(Route route) {
    // We specify here that we only want to include results
    // within a max distance of xx meters from any point of the route.
    int halfWidthInMeters = 200;
    GeoCorridor routeCorridor = new GeoCorridor(route.getGeometry().vertices, halfWidthInMeters);
    PlaceCategory placeCategory = new PlaceCategory(PlaceCategory.BUSINESS_AND_SERVICES_EV_CHARGING_STATION);
    CategoryQuery.Area categoryQueryArea = new CategoryQuery.Area(routeCorridor, mapView.getCamera().getState().targetCoordinates);
    CategoryQuery categoryQuery = new CategoryQuery(placeCategory, categoryQueryArea);

    SearchOptions searchOptions = new SearchOptions();
    searchOptions.languageCode = LanguageCode.EN_US;
    searchOptions.maxItems = 30;

    searchEngine.searchByCategory(categoryQuery, searchOptions, new SearchCallback() {
        @Override
        public void onSearchCompleted(SearchError searchError, List<Place> items) {
            if (searchError != null) {
                Log.d("Search", "No charging stations found along the route. Error: " + searchError);
                return;
            }

            // If error is nil, it is guaranteed that the items will not be nil.
            Log.d("Search","Search along route found " + items.size() + " charging stations:");
            for (Place place : items) {
                // ...
            }
        }
    });
}

EV充電ステーションの利用状況ステータスを取得する

コネクターの総数、使用中および使用可能なコネクター、追加の詳細を含む利用状況情報です。enableEVChargingStationDetails()オプションを選択すると、個々の充電スタンドのステータスを含む、EV充電ステーションの利用状況をオンラインで取得できます。

有効な資格情報を使用せずにこの機能を使用しようとすると、SearchErrorが発生します。詳細については、APIリファレンスを参照してください。

この機能を使用するには、次の示すようなカスタムオプション呼び出しが必要です。

// Enable fetching online availability details for EV charging stations.
// It allows retrieving additional details, such as whether a charging station is currently occupied.
// Check the API Reference for more details.
private void enableEVChargingStationDetails() {
    // Fetching additional charging stations details requires a custom option call.
    SearchError error = searchEngine.setCustomOption("browse.show", "ev");
    if (error != null) {
        showDialog("Charging station",
                "Failed to enableEVChargingStationDetails.");
    } else {
        Log.d("ChargingStation", "EV charging station availability enabled successfully.");
    }
}

private void searchAlongARoute(Route route) {
    // We specify here that we only want to include results
    // within a max distance of xx meters from any point of the route.
    int halfWidthInMeters = 200;
    GeoCorridor routeCorridor = new GeoCorridor(route.getGeometry().vertices, halfWidthInMeters);
    PlaceCategory placeCategory = new PlaceCategory(PlaceCategory.BUSINESS_AND_SERVICES_EV_CHARGING_STATION);
    CategoryQuery.Area categoryQueryArea = new CategoryQuery.Area(routeCorridor, mapView.getCamera().getState().targetCoordinates);
    CategoryQuery categoryQuery = new CategoryQuery(placeCategory, categoryQueryArea);

    SearchOptions searchOptions = new SearchOptions();
    searchOptions.languageCode = LanguageCode.EN_US;
    searchOptions.maxItems = 30;

    enableEVChargingStationDetails();

    searchEngine.searchByCategory(categoryQuery, searchOptions, new SearchCallback() {
        @Override
        public void onSearchCompleted(SearchError searchError, List<Place> items) {
            if (searchError != null) {
                Log.d("Search", "No charging stations found along the route. Error: " + searchError);
                return;
            }
            // If error is nil, it is guaranteed that the items will not be nil.
            Log.d("Search","Search along route found " + items.size() + " charging stations:");
            for (Place place : items) {
                Details details = place.getDetails();
                Metadata metadata = getMetadataForEVChargingPools(details);
                boolean foundExistingChargingStation = false;
                for (MapMarker mapMarker : mapMarkers) {
                    if (mapMarker.getMetadata() != null) {
                        String id = mapMarker.getMetadata().getString(REQUIRED_CHARGING_METADATA_KEY);
                        if (id != null && id.equalsIgnoreCase(place.getId())) {
                            Log.d("Search", "Insert metdata to existing charging station: This charging station was already required to reach the destination (see red charging icon).");
                            mapMarker.setMetadata(metadata);
                            foundExistingChargingStation = true;
                            break;
                        }
                    }
                }

                if (!foundExistingChargingStation) {
                    addMapMarker(place.getGeoCoordinates(), R.drawable.charging, metadata);
                }
            }
        }
    });
}

private Metadata getMetadataForEVChargingPools(Details placeDetails) {
    Metadata metadata = new Metadata();
    if (placeDetails.evChargingPool != null) {
        for (EVChargingStation station : placeDetails.evChargingPool.chargingStations) {
            if (station.supplierName != null) {
                metadata.setString(SUPPLIER_NAME_METADATA_KEY, station.supplierName);
            }
            if (station.connectorCount != null) {
                metadata.setString(CONNECTOR_COUNT_METADATA_KEY, String.valueOf(station.connectorCount));
            }
            if (station.availableConnectorCount != null) {
                metadata.setString(AVAILABLE_CONNECTORS_METADATA_KEY, String.valueOf(station.availableConnectorCount));
            }
            if (station.occupiedConnectorCount != null) {
                metadata.setString(OCCUPIED_CONNECTORS_METADATA_KEY, String.valueOf(station.occupiedConnectorCount));
            }
            if (station.outOfServiceConnectorCount != null) {
                metadata.setString(OUT_OF_SERVICE_CONNECTORS_METADATA_KEY, String.valueOf(station.outOfServiceConnectorCount));
            }
            if (station.reservedConnectorCount != null) {
                metadata.setString(RESERVED_CONNECTORS_METADATA_KEY, String.valueOf(station.reservedConnectorCount));
            }
            if (station.lastUpdated != null) {
                metadata.setString(LAST_UPDATED_METADATA_KEY, String.valueOf(station.lastUpdated));
            }
        }
    }
    return metadata;
}

充電スタンドをクリックしたときに表示される例につい次のスクリーンショットを参照してください。ポップアップに充電スタンド名、コネクター数、使用可能なコネクター、最終更新時刻などが表示されます。

Screenshot: Showing charging station availability details.

ご覧のとおり、GeoCorridor にはルートの GeoPolylineおよび halfWidthInMeters パラメーターが必要です。この値は、ポリライン上の任意の地点からコリドーの端までの最も遠い端を定義します。値が小さい場合、最終的なコリドーでは実際のルートに沿った非常に近いエリアを定義します。

Screenshot: Showing found charging stations along a route.

ルートの出発地と目的地の座標ではコリドーが丸い形になります。ある程度の太さはあるが、頭と尾の端が丸いだけのヘビを想像してみてください。これはルートの出発地と目的地をわかりやすく示すために緑色の円をレンダリングしただけであるため、上記のスクリーンショットと混同しないでください。

非常に長いルートの場合、検索アルゴリズムは内部で検索コリドーの最適化を試みます。これは、アプリ側で halfWidthInMeters パラメーターを使って制御することもできます。値を大きくするとコリドーの複雑さは軽減しますが、結果の精度は低くなります。

エラーが発生しなかった場合は、上記のセクションですでに示したように Place の結果を処理できます。

このセクションの完全なコードは、GitHubにあるJava版およびKotlin版のEVRoutingサンプルアプリに含まれています。


EN 日本語

HERE documentation

Find answers to your product and technical questions

Documentation

What's new

Videos

EN 日本語

HERE ドキュメント

製品や技術に関する質問の答えを見つけましょう。より多くの内容と最新の情報については、英語版をご覧ください。

ドキュメント

ダイナミックマップ

動的コンテンツ関連のAPIをアプリやサービスに活用して、ドライバーが安全・快適かつ予定どおりに目的地へ到着できるよう支援します。

地図とデータ

世界中を走行する多数のマッピング車両から得られる最新の位置情報データを活用し、精度の高い地図やカスタムレイヤーを構築できます。

最新情報

動画

(function () { const input = document.querySelector('input[data-typeahead]'); if (!input) return; // Prevent the form from submitting/navigating input.closest('form')?.addEventListener('submit', e => e.preventDefault()); input.addEventListener('input', function () { const q = this.value.trim().toLowerCase(); document.querySelectorAll('.nav-group-name').forEach(group => { let anyVisible = false; group.querySelectorAll('.nav-group-task').forEach(task => { const text = task.textContent.trim().toLowerCase(); const show = !q || text.includes(q); task.style.display = show ? '' : 'none'; if (show) anyVisible = true; }); // Hide the whole group header if nothing matches group.style.display = anyVisible || !q ? '' : 'none'; }); }); })(); (function () { function onTokenClick(event) { var link = event.target.closest('.sdk-for-ios .item .token'); if (!link) return; event.preventDefault(); console.log('token clicked', link.textContent.trim()); var item = link.closest('.item'); if (!item) return; var content = item.querySelector('.height-container'); if (!content) { console.log('no .height-container found for item', item); return; } var isHidden = window.getComputedStyle(content).display === 'none'; content.style.display = isHidden ? 'block' : 'none'; link.classList.toggle('token-open', isHidden); var href = link.getAttribute('href'); if (href) { if (history.pushState) history.pushState({}, '', href); else location.hash = href; } } function openHashTarget() { var hash = window.location.hash.slice(1); if (!hash) return; var anchor = document.querySelector('.sdk-for-ios a[name="' + hash + '"]'); if (!anchor) return; var item = anchor.closest('.item'); if (!item) return; var link = item.querySelector('.token'); var content = item.querySelector('.height-container'); if (!link || !content) return; content.style.display = 'block'; link.classList.add('token-open'); } function init() { console.log('HERE SDK accordion init'); openHashTarget(); } document.removeEventListener('click', onTokenClick); document.addEventListener('click', onTokenClick); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } window.addEventListener('hashchange', openHashTarget); window.addEventListener('pageLoad', init); })();