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

ルートオプションを追加する

Routingアプリケーションの機能を高めるには、ユーザーのニーズに合わせてカスタマイズされた、さまざまなRouteOptionsを提供する必要があります。このセクションでは、利用可能なさまざまなルート検索機能について説明し、よりパーソナライズされた効率的なルート検索エクスペリエンスを構築できるようにします。

サポートされている移動モード

HERE SDK では次のルート タイプがサポートされています。

  • **乗用車のルート案内:**乗用車ルートではリアルタイムおよび過去の交通情報を使用します。乗用車のルートは車が進入できる道路に従い、歩行者ゾーンなどの車が通行できない場所を回避します。さらに、一方通行などの道路制限や冬季閉鎖などの時間に基づく道路へのアクセスも考慮されます。
  • **タクシーのルート案内:**乗用車ルートで使用できる機能に加え、タクシーの制限レーンと専用レーンも考慮されます。
  • トラックのルート案内:乗用車ルートで使用できる機能に加え、トラック関連の制約やその他のユーザー指定のトラックオプションも考慮されます。
  • **電気自動車 (EV) 用のルート:**EV ルートでは車両のエネルギー消費量を追跡できます。EV ルートを計算するときに充電スタンドをルートに追加することができ、ユーザーがエネルギーを使い果たすことなく目的地に到達できるようにします。同時に、全体的な移動時間と充電時間を最短にするためにルートが最適化されます。
  • バスのルート案内ではバス専用レーンとバス制限レーンがサポートされています。
  • 自家用バスのルート案内:都市部のバス専用道路は使用できないが、乗客の乗車場所および降車場所としてバス専用道路を使用する許可を得ている可能性がある、プライベートで運行しているバス会社用です。バス専用道路は、経由地がその道路上に設定されている場合にのみ使用されます。
  • 歩行者のルート案内
  • スクーターのルート案内:「スクーター」とは主に都市内の移動や輸送に使用される低出力の二輪車を指します。スクーター用のルートは高速道路や移動速度が 60km/時を超える道路を避けます。OptimizationMode.FASTESTのみがサポートされています。専用のスクーターレーンはまだサポートされていません。
  • **自転車のルート案内:**自転車のルートは、都市内を移動するカジュアルなサイクリストのために設計されたモードです。屋外のレーンや路面情報はサポートされていません。車属性と歩行者属性のみが使用されているため、たとえば自転車のレーンがある道路は優先されません。交通の方向に逆らって走行したり、公園外の歩行者専用区間を通行したりすることはできません。自転車のルート探索は、次のいずれかの条件に当てはまる場合に自転車で走行可能とされる歩行者用道路ネットワークを使用します。
    • 道路が車と歩行者の両方に開放されている。
    • 公園内の歩行者専用道路である。
    • 自転車での通行は禁止されているが、自転車から降りて運びながら通行できる。この移行により、SectionTransportMode が自転車から歩行者に変更されます。
  • 公共交通機関用ルート:WGS-84 に準拠した出発点と終点に基づき、特定の都市や都市圏で利用可能なすべての公共交通機関モードを使用します。公共交通機関のオプションは TransitRoutingEngine を使用して詳細にカスタマイズできます。
  • フェリーとシャトルバスはルートの一部にのみ使用され、これを使用する場合は最適な経路が確保されます。使用する移動モードを変更すると、表示されるSectionTransportModeが変更されます。

注 (HERE SDK for Android Navigate)

RoutingEngineでは、すべての移動モードをオンラインルート計算に使用できます。OfflineRoutingEngine では、キャッシュに保存されたマップ データまたはダウンロードされたオフライン マップでのオフラインルート計算にも一部の移動モードを使用できます。サポートされているオフライン モードの概要については、こちらを参照してください。

HERE SDKは、スクーターと自転車に対してのみ二輪車機能をサポートしています。オートバイの場合は、たとえば高速道路を回避するなどのカスタマイズされたAvoidanceOptionsを使用して、乗用車モードを使用することをお勧めします。

すべての移動モードでEVオプションを使用できるわけではありません。

各ルートタイプはRoutingOptionsクラスで決定され、このクラスはすべての移動モードのルート計算を共通の方法で設定できます。目的の移動モードは、routingOptions.transportSpecification.transportModeで設定します。これらのオプションはRoutingEnginecalculateRoute()メソッドに渡されます。

RoutingOptionsで設定できる移動モードは次のとおりです。

  • TransportMode.CAR:車両のルートを計算します。route.getRequestedTransportMode()TransportMode.CARを返します。これがデフォルトです。
  • TransportMode.TRUCK:トラックのルートを計算します。route.getRequestedTransportMode()TransportMode.TRUCKを返します。
  • TransportMode.PEDESTRIAN:歩行者のルートを計算します。route.getRequestedTransportMode()TransportMode.PEDESTRIANを返します。
  • TransportMode.CARまたはTransportMode.TRUCKを使用し、RoutingOptions.evOptionsElectricVehicleOptionsを設定することで、電気自動車のルートを計算できます。
  • TransportMode.SCOOTER:スクーターのルートを計算します。route.getRequestedTransportMode()TransportMode.SCOOTERを返します。
  • TransportMode.BICYCLE:自転車のルートを計算します。route.getRequestedTransportMode()TransportMode.BICYCLE を返します。
  • TransportMode.TAXI:タクシーのルートを計算します。route.getRequestedTransportMode()TransportMode.TAXI を返します。
  • TransportMode.BUS:バスのルートを計算します。route.getRequestedTransportMode()TransportMode.BUSを返します。
  • TransportMode.PRIVATE_BUSで民間バス用ルートを計算する場合、route.getRequestedTransportMode()TransportMode.PRIVATE_BUSを返します。
  • TransitRouteOptions:公共交通機関のルートを計算します (TransitRoutingEngineでのみ利用可能)。route.getRequestedTransportMode()TransportMode.PUBLIC_TRANSITを返します。

TransportMode は、ルート計算が完了した後にルート検索エンジンによって設定されます。getRequestedTransportMode() はルート オプションから移動モードを決定しますが、RouteSection ごとに異なる移動モードを設定できます。route.getSectionTransportMode() には、上記の移動モードに加え、特定のセクションに使用する必要がある実際の SectionTransportMode があり、ferrycarShuttleTrain などの移動モードも一覧表示されます。

デフォルトでは、出発地と目的地の経由地のみを通過する場合、最終的なルートには1つのルートSectionのみが含まれます。各 route オブジェクトには、設定されている経由地と移動モードの数に応じて、より多くのルート セクションを含めることができます。セクションは、ルートを複数の論理パーツに分割するルートレッグとして機能します。詳細についてはこちらを参照してください。

ルートを計算する前に、メインの移動モードがユーザーによって指定されますが、最終的な移動モードは Section ごとにルート検索エンジンによって設定されます。

Route には複数の SectionTransportMode を含めることができます。このような場合、移動モードの違いがわかるように、ルートは別の Section に分割されます。フェリーに乗るために車から出るときなど、移動モードを変更するには、基本的には移動の停止が必要です。ただし、マルチモーダル ルート検索 (またはインターモーダル ルート検索) はサポートされていません。乗用車のルートに目的地として公園内の観光スポットが含まれている場合、最後の経由地は乗用車で到達可能な公園の前の最後の場所にマップマッチングされ、ルートには歩行者セクションは含まれません。

このようなギャップは、RoutePlace オブジェクトの originalCoordinatesmapMatchedCoordinates を比較することで検出できます。フォールバックとして適切な移動モードを使用して、これら 2 つの座標間の距離を新しいルート計算で埋めることをアプリケーションで決定できます。徒歩ではなくタクシーや公共交通機関を利用することを好むユーザーもいるため、このようなモーダル ルートは多数の異なるオプションで構成できます。HERE SDK ではこのようなモーダル ルートを個別のリクエストとしてのみサポートしているため、アプリケーションではフォールバック ロジックを実装する必要があります。代替策として Intermodal Routing API の使用を検討してください。

ルートに沿ったすべての地理座標がマップマッチング (道路へのスナップとも呼ばれる) されます。Waypoints がさらに追加された場合、それらもマップマッチングされ、その元の座標は、Section の始まりと終わりを示す RoutePlace 内のマップ マッチングした場所と比較できます。

使用可能なすべてのルート オプションを使用すると、複数のパラメーターをさらに指定して、必要に応じてルート計算を最適化できます。

上記の各オプションには、共通 RouteOptions オブジェクトを格納するフィールドが含まれています。このオプションを使用すると、代替ルートの数などの一般的なオプションを指定できます。OptimizationMode で移動時間とルートの長さに基づいて最適なルートを検索することもできます。

デフォルトでは、ルートは FASTEST ルート モードを使用して計算されます。

アルゴリズムを変更することもできます。たとえば、目的地に早く到達するときに、ルートの長さがそれほど重要ではない場合は、RouteOptionsFASTEST ルート モードを選択します。時間がそれほど重要ではなく、ルートを短くする場合は SHORTEST を選択します。

最適なルートを見つけるために、ルート検索アルゴリズムではさまざまなパラメーターが考慮されます。これは、アルゴリズムが常に絶対的に最短または最速のルートを提供することを意味するものではありません。たとえば、次の道路ネットワークを考えてみましょう。

Illustration: Which route would you choose?

A 地点から B 地点への移動を計画するときは、4 つの異なる道路からいずれかを選択できます。緑のルートが高速道路を表しているとしましょう。この道路は、目的の都市にたどり着くうえで他のどのルートよりも距離が長いですが、最速のルートである可能性があります。

最短ルートを希望する場合は、黄色と赤のルートは距離が短くても、アルゴリズムでは青色のルートが選択される場合があります。なぜそうなるのでしょうか。もちろん、黄色の道路は最短ルートですが、フェリーに乗る必要がある川を渡る必要があります。アルゴリズムではこれを時間がかかると見なす場合があります。その結果、両方ともわずかに長くなりますが、黄色のルートの代わりに赤または青のルートを選択する場合があります。

他の 2 つのオプションを見てみましょう。青と赤のルートを比較する場合、ルート検索アルゴリズムでは、青のルートが赤のルートよりもわずかに距離が長いにもかかわらず最短ルートとして推奨されることがあります。通常、複数の右左折があることはドライバーにとってデメリットになります。この場合、赤のルートには青のルートよりも多くの右左折が含まれていますが、青のルートはわずかに長いだけであるため、推奨ルートとなる場合があります。ルート検索アルゴリズムでは、右左折や他の多くの道路特性 (ドライバーの減速を引き起こす可能性のある信号機や踏切など) にペナルティが課されます。

一般的なルート検索オプションに加え、トラックのルーティングなど、サポートされているさまざまな移動モードに特化したオプションがHERE SDKには用意されています。たとえば、VehicleSpecificationでトラックの寸法を指定して、トラックが通過できる適切なルートのみを検索できます。この場合には、道路幅やトンネルの高さなどのパラメーターが考慮されます。すべての移動モードの車両固有の制限は、RoutingOptions.transportSpecificationVehicleSpecificationで設定できます。

最終的なルートは特定の条件に基づいて最適化されますが、信頼できない状況が生じることがあります。ベルリン市内を巡る旅を想像してみてください。ベルリンの観光名所を巡りたい場合、最速ルートや最短ルートは選択肢に入らないでしょう。このような場合は、追加の経由地を設定することをお勧めします。以下に例を示します。

複数の経由地を挿入する

デフォルトでは、出発地と目的地の経由地のみを設定する場合、最終的なルートには 1 つのルート Section のみが含まれます。各ルート オブジェクトには、設定する経由地の数に応じて、さらに多くのルート セクションを含めることができます。セクションは、ルートを複数の論理パーツに分割するルートレッグとして機能します。

経由地とは、より多くのセクションまたはルートの形状を決定するためにユーザーが設定できる座標です (フェリーで川を横断する場合などに便利です)。

オンライン RoutingEngine でサポートされている経由地の数は、最大で約 200 個に制限されています。

経由地には次の 2 つのタイプがあります。

  • STOPOVER:デフォルトの経由地タイプ。このポイントは必ず通過するため、運転指示のリストに表示され、ルートは複数のルート セクションに分割されます。
  • PASS_THROUGH:運転指示リストに表示されない場合があり、タッチ入力の結果など、ルートを形作るためのヒントとして扱われます。このタイプではルートは複数のセクションに分割されません。

新しい Waypoint オブジェクトを作成する場合、STOPOVER タイプはデフォルトで設定されます。このタイプは、最初と最後の経由地で使用されるタイプである必要があります。2 つの経由地のみが出発地と目的地として機能する場合、ルートは次のようになります。

One route section between starting point and destination.

RoutingEngine では複数の経由地を処理できます。ベースとなるアルゴリズムでは、指定された ListWaypointType の順序を考慮しながら、すべての経由地を通過する最適なパスを見つけようとします。各 STOPOVER 経由地は出発地と目的地の間で渡されます。これらはそれぞれ、経由地リストの最初と最後のアイテムです。

Waypoint waypoint1 = new Waypoint(createRandomGeoCoordinatesInViewport());
Waypoint waypoint2 = new Waypoint(createRandomGeoCoordinatesInViewport());
List<Waypoint> waypoints = new ArrayList<>(Arrays.asList(new Waypoint(startGeoCoordinates),
        waypoint1, waypoint2, new Waypoint(destinationGeoCoordinates)));

routingEngine.calculateRoute(
        waypoints,
        new RoutingOptions(),
        new CalculateRouteCallback() {
            @Override
            public void onRouteCalculated(@Nullable RoutingError routingError, @Nullable List<Route> routes) {
                if (routingError == null) {
                    // Handle the results.
                }
            }
        });
val waypoint1 = Waypoint(createRandomGeoCoordinatesAroundMapCenter())
val waypoint2 = Waypoint(createRandomGeoCoordinatesAroundMapCenter())
val waypoints = arrayListOf(Waypoint(startGeoCoordinates), waypoint1, waypoint2, Waypoint(destinationGeoCoordinates))

routingEngine?.calculateRoute(
    waypoints,
    RoutingOptions(),
    object : CalculateRouteCallback {
        override fun onRouteCalculated(routingError: RoutingError?, routes: List<Route>?) {
            if (routingError == null) {
                // Handle the results.
            }
        }
    })

以下の図に示すように、コード スニペットを使用してルートに 2 つの STOPOVER 経由地を追加することで、出発地と目的地の間に 3 つのルート セクションが作成されました。

経由地リストの順序では、ルートに沿って渡される順序を定義します。

Illustration: Adding two additional waypoints.

目的地までの移動にかかる推定時間やルートの全長 (メートル単位) など、ルートに関する追加情報は以下のように Route オブジェクトから取得できます。

// estimatedTravelTimeInSeconds includes traffic delay.
long estimatedTravelTimeInSeconds = route.getDuration().getSeconds();
long estimatedTrafficDelayInSeconds = route.getTrafficDelay().getSeconds();
int lengthInMeters = route.getLengthInMeters();
// estimatedTravelTimeInSeconds includes traffic delay.
val estimatedTravelTimeInSeconds: Long = route.duration.seconds
val estimatedTrafficDelayInSeconds: Long = route.trafficDelay.seconds
val lengthInMeters: Int = route.lengthInMeters

移動の時間と距離はSectionごとにも利用できます。

private void logRouteSectionDetails(Route route) {
    DateFormat dateFormat = new SimpleDateFormat("HH:mm");

    for (int i = 0; i < route.getSections().size(); i++) {
        Section section = route.getSections().get(i);

        Log.d(TAG, "Route Section : " + (i + 1));
        Log.d(TAG, "Route Section Departure Time : "
                + dateFormat.format(section.getDepartureLocationTime().localTime));
        Log.d(TAG, "Route Section Arrival Time : "
                + dateFormat.format(section.getArrivalLocationTime().localTime));
        Log.d(TAG, "Route Section length : " + section.getLengthInMeters() + " m");
        Log.d(TAG, "Route Section duration : " + section.getDuration().getSeconds() + " s");
    }
}
private fun logRouteSectionDetails(route: Route) {
    val dateFormat: DateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())

    for (i in route.sections.indices) {
        val section: Section = route.sections.get(i)

        Log.d(TAG, "Route Section : " + (i + 1))
        Log.d(TAG, "Route Section Departure Time : "
                    + dateFormat.format(section.departureLocationTime!!.localTime)
        )
        Log.d(TAG, "Route Section Arrival Time : "
                    + dateFormat.format(section.arrivalLocationTime!!.localTime)
        )
        Log.d(TAG, "Route Section length : " + section.lengthInMeters + " m")
        Log.d(TAG, "Route Section duration : " + section.duration.seconds + " s")
    }
}

追加の STOPOVER 経由地がない場合、ルートには 1 つの Section だけが含まれます。追加の STOPOVER 経由地が指定されている場合、ルートは各経由地間、出発地から最初の経由地まで、および最後の経由地から目的地まで、複数のルート セクションに分割されます。

stopover の追加の経由地を追加するとルートが複数のセクションに分割され、ルートはこのポイントを通過して、そのポイントの運転指示を生成するよう強制されます。

Section には GeoPolyline の形式でルートの形状が含まれており、最初の座標が出発点を示し、最後の座標が目的地を示す座標の配列として表されます。

これは、たとえば、Section ごとに異なる色の地図ポリラインを使用して、地図上でルートを視覚化するのに役立ちます。ただし、全体のポリラインを Route オブジェクトから直接取得することもできます。

マップ マッチングされた経由地を取得する

ルートを計算する場合、オフロードであっても、任意の場所を出発地、目的地、または中間の STOPOVERPASS_THROUGH 経由地として使用できます。ただし、結果として得られるルートは、指定された経由地を正確に通過しない場合があります。ルート検索アルゴリズムでは、指定された座標にできる限り近づけようとします。これを実現するために、指定された移動モードなどのさまざまなパラメーターを考慮して、座標セットごとに最も近いルート セグメントを見つける高度な技術が HERE SDK には組み込まれています。このプロセスはマップ マッチングと呼ばれています。

ただし、ルートの形状はマップマッチングされた経由地のみで構成されます。

Route の各 Section について、セクションの先頭 (出発地) と最後 (到着地) で RoutePlace にアクセスできます。Routeplace には、パラメーターとして渡された mapMatchedCoordinatesoriginalCoordinates が含まれます。両方とも等しい場合もあれば、異なる場合もあります。異なる場合は、originalCoordinates が道路上にないことを意味します。

RoutePlace には、移動中に役立つ可能性のある詳細情報が含まれています。たとえば、電気自動車では役に立つ chargeInKilowattHours (以下を参照) や元の経由地の sideOfDestination とともに、chargingStation 情報にアクセスできます。

Illustration: Original and map-matched waypoints.

ルートに沿って移動しており、ストップオーバーとして道路から外れた観光スポットを指定したと想像してください。道路を走行しながらルートに沿って目的地に向かっているときにマップマッチングされた対応する経由地に到着すると、sideOfDestination フィールドには、観光スポット (または上図のレストラン) が現在移動している通りの左側と右側のどちらにあるかが表示されます。

場合によっては、指定されたストップオーバーが目の前、現在地の上または下にある場合もあります。このような場合、sideOfDestinationフィールドにはその場所がUNDEFINEDとして示されます。たとえば、湖に行こうとしていて道路が湖の目の前で終わる場合などです。

場所を経由地として設定する

SearchEngine から取得された Place には、1 つ以上のアクセス ポイントが含まれる場合があります。たとえば、大きな倉庫には複数の入口がある場合がありますが、倉庫の中心には直接には到達できない場合があります。アクセス ポイントは車で到達できることを想定していることに注意してください。

ルートの場合は、利用可能なアクセス ポイント (存在する場合) の 1 つに移動することをお勧めしますが、sideOfStreetHint はその場所の地理座標に設定します。アクセス ポイントが不明な場合、またはその場所に直接到達可能な場合、リストは空になります。

List<GeoCoordinates> accessPoints = place.getAccessPoints();
Waypoint destinationWaypoint = new Waypoint(place.getGeoCoordinates());
if (!accessPoints.isEmpty()) {
    // Set the first access point of a place as route destination.
    destinationWaypoint.coordinates = accessPoints.get(0);
    // When reaching destination provide a hint on the actual location of the place.
    destinationWaypoint.sideOfStreetHint = place.getGeoCoordinates();
}

結果として得られる Route オブジェクトの RoutePlace には、経由地がアクセス ポイントに設定されたときに ACCESS_POINT に設定される RoutePlaceType が含まれます。

上の図を見て、sideOfStreetHintRoutePlaceSideOfDestination にどのような影響を与えるかを確認してください。

場所に複数のアクセス ポイントがある場合、適切なアクセス ポイントの選択はユーザーが行います。

経由地を出発地として設定する

移動を開始するとき、適切な開始方向を選択するための RoutingEngine に追加のヒントを提供すると便利です。たとえば、必要な U ターンを強制する場合などです。

たとえば、次のように最初の進行方向を指定できます。

startWaypoint.headingInDegrees = location.bearingInDegrees;

ユーザーが動いている場合には方位値がルート計算の改善に役立ちます。Location オブジェクトが測位ソースから取得され、ユーザーがすでに移動していた場合、このオブジェクトには方位値が含まれることに注意してください。そうでない場合、設定されない可能性があります。このようなシナリオは、たとえば、ユーザーが提案されたルートから逸脱した後でルートを再計算する必要がある場合など、案内中により一般的に発生する可能性があります。

経由地の順序を最適化する (HERE SDK for Android Navigate)

OfflineEngine (上記を参照) では、オフラインでの経由地の順序の決定によって巡回セールスマンのユースケースをサポートすることもできます。この機能はオンライン RoutingEngine ではまだサポートされていません。

RouteOptions.optimizeWaypointsOrderを設定すると、Route沿いにある複数のストップオーバーのWaypointアイテムの順序を自動的に指定できます。trueに設定すると、OfflineRoutingEngineは経由地の順序を最適化して、stopoverタイプが設定されたすべての経由地を確実に経由しながら目的地に早く到着できるようにするか、ルートを短縮します。

指定された OptimizationMode によって、並べ替えの結果、より速いルートが得られるか、より短いルートが得られるかが決まります。

ルート計算への影響を確認するには、少なくとも 5 つ以上の経由地 (出発地と目的地を含む) を設定する必要があります。必要に応じて、各RoutePlaceoriginalCoordinatesをユーザー定義の座標と比較することで、再シャッフルされた経由地を識別できます。ストップオーバーごとにルートが複数のセクションに分割されるため、RoutePlaceオブジェクトはRouteオブジェクトの各Sectionに提供されます。ナビゲーション中に、MilestoneStatus イベントはユーザー定義の経由地に到達したかどうかを通知します。

Illustration: A route with and without waypoint sequencing.

道路の特徴を除外する

トンネル、高速道路、低排気ガス規制ゾーン (LEZ)、地域、フェリー、通行料金、その他の道路フィーチャー (急な曲がり角など) を除外するには AvoidanceOptions を使用します。RoadFeaturesZoneCategoryGeoBoxCountryCode 要素などのリストを渡すことができます。

RoadFeatures には、トンネルや有料道路などの道路固有のフィーチャーが含まれます。たとえば、すべての高速道路を旅程から除外するには、機能のリストにCONTROLLED_ACCESS_HIGHWAYを追加します。

AvoidanceOptionsは、ローカライズや単位に関するオプションを含む他のルートオプションとともに、RoutingOptions.avoidanceOptionsで設定できます。これらのオプションはルートの計算時に読み込まれ、エンジンは指定された機能を回避するように動作します。

Screenshot: Two routes without and with an avoidance area.

設定されたオプションを回避できない場合、たとえば、閉鎖されたエリアからルートが始まる場合、提供された SectionNotice 要素でそのような違反を検査できます。これらが設定されている場合、そのようなルートを拒否することを決定できます。

道路セグメントを回避する

ルートの特定のセグメントを回避するには、AvoidanceOptionsを使用します。セグメントを回避するには、SegmentReferenceを使用します。Routeの各Spanには、それぞれのSpanに対するSegmentReferenceが含まれます。

次の例は、AvoidanceOptionsを使用してルートのセグメントを回避する方法を示しています。

SegmentReference segmentReference = new SegmentReference();

// The segmentId and tilePartitionId can be obtained from each span of the Route object.
// For example, the segmentId and tilePartitionId used below is part of the route created by above start and destination coordinates.
String segmentId = "here:cm:segment:807958890";
long tilePartitionId = 377894441;
segmentReference.segmentId = segmentId;
segmentReference.tilePartitionId = tilePartitionId;

AvoidanceOptions avoidanceOptions = new AvoidanceOptions();
avoidanceOptions.segments = Arrays.asList(segmentReference);
routingOptions.avoidanceOptions = avoidanceOptions;

SegmentReferenceを取得する (Navigateでのみ使用可能)

SegmentReferenceは、SegmentDataLoaderを使用して取得することもできます。実装の詳細については、「RoutingWithAvoidanceOptions」サンプルアプリを参照してください。

通行料金を取得する

ルートの個々のセクションに沿って考えられる通行料金を取得できます。

これには、窓に張るステッカーや道路税などのビネットの支払いの詳細に関する情報も含まれます。

OfflineRoutingEngineユーザーの場合、これはこの機能のベータリリースであるため、いくつかのバグや予期しない動作が発生する可能性があります。OfflineRoutingEngineはNavigateなどのライセンスで使用できます。RoutingEngineのユーザーの場合、この機能は安定しています。

通行料金を取得するには、routeOptions.enableTolls フラグを設定する必要があります。デフォルトでは false に設定されています。このフラグが有効な場合、「API リファレンス」で定義されているように、料金適用可能な移動モードの料金データがリクエストされます。

PaymentMethodTollFare、一般的なToll情報を提供するsection.getTolls()経由で通行料金を取得します。

private void logTollDetails(Route route) {
    for (Section section : route.getSections()) {
        // The spans that make up the polyline along which tolls are required or
        // where toll booths are located.
        List<Span> spans = section.getSpans();
        List<Toll> tolls = section.getTolls();
        if (!tolls.isEmpty()) {
            Log.d(TAG, "Attention: This route may require tolls to be paid.");
        }
        for (Toll toll : tolls) {
            Log.d(TAG, "Toll information valid for this list of spans:");
            Log.d(TAG, "Toll systems: " + toll.tollSystems);
            Log.d(TAG, "Toll country code (ISO-3166-1 alpha-3): " + toll.countryCode);
            Log.d(TAG, "Toll fare information: ");
            for (TollFare tollFare : toll.fares) {
                // A list of possible toll fares which may depend on time of day, payment method and
                // vehicle characteristics. For further details please consult the local
                // authorities.
                Log.d(TAG, "Toll price: " + tollFare.price + " " + tollFare.currency);
                for (PaymentMethod paymentMethod : tollFare.paymentMethods) {
                    Log.d(TAG, "Accepted payment methods for this price: " + paymentMethod.name());
                }
            }
        }
    }
}
private fun logTollDetails(route: Route) {
    for (section in route.sections) {
        // The spans that make up the polyline along which tolls are required or
        // where toll booths are located.
        val tolls: List<Toll> = section.tolls
        if (tolls.isNotEmpty()) {
            Log.d(TAG, "Attention: This route may require tolls to be paid.")
        }
        for (toll in tolls) {
            Log.d(TAG, "Toll information valid for this list of spans:")
            Log.d(TAG, "Toll systems: " + toll.tollSystems)
            Log.d(TAG, "Toll country code (ISO-3166-1 alpha-3): " + toll.countryCode)
            Log.d(TAG, "Toll fare information: ")
            for (tollFare in toll.fares) {
                // A list of possible toll fares which may depend on time of day, payment method and
                // vehicle characteristics. For further details please consult the local
                // authorities.
                Log.d(TAG, "Toll price: " + tollFare.price + " " + tollFare.currency)
                for (paymentMethod in tollFare.paymentMethods) {
                    Log.d(TAG, "Accepted payment methods for this price: " + paymentMethod.name)
                }
            }
        }
    }
}

注 (HERE SDK for Android Navigate)

ナビゲーション中、つまりルートに従っている間、isTollwayなどの新しい道路属性を通知するRoadAttributesListenerを使用して、現在の道路で料金を支払う必要があるかどうかを知ることができます。さらに、TollStopWarningListener は、今後の料金所に関するイベントを提供します。

公共交通機関ルートを取得する

TransitRoutingEngineを使用して、A地点からB地点までの公共交通機関のルートを計算します。A地点とB地点の間には複数の経由地があります。この方法を説明する「PublicTransit」サンプルアプリ (Java版およびKotlin版) は、GitHubでご確認いただけます。

トラックルートを取得する

HERE SDK では、ルート計算のためにさまざまな移動モード (上記参照) がサポートされています。乗用車に合わせて最適化されたルートの計算方法を示した上記の例と同様に、トラックなどの他の移動タイプのルートも計算できます。

デフォルトオプションを設定することで、トラックに合わせて最適化されたルートを取得できますが、トラックに最適なルートを見つけるために利用できるオプションは他にも数多くあります。

たとえば、RoutingOptionsでは、transportSpecificationVehicleSpecificationを設定することでトラックの寸法などを指定でき、任意で車両重量やその他のパラメーターを考慮する設定も適用できます。

トラックのターン・バイ・ターンナビの詳細 (Navigateのみ) については、「トラックガイダンス」セクションを参照してください。

ルートラベルを取得する

ルートラベルは、計算されたルートが通過する主要な道路名またはルート番号 (高速道路の識別子など) に関する情報を提供します。ルートラベルは、ユーザーが各ルートを識別する際の手がかりとなるため、複数のルート候補を計算する場合に特に便利です。

各代替ルートは、主要道路と高速道路によって特徴付けられており、route.getRouteLabels()がそれぞれを一意にする最も重要な名称やルート番号を自動的に抽出します。これにより、各ルートが通過する主要な道路に関する情報を即座に得られ、ユーザーの土地勘に基づいたより適切な意思決定を行うことができます。

ルートラベルをルート応答に含めるには、ルート計算の前にrouteOptions.enableRouteLabelstrueに設定して機能を有効にしてください。デフォルトでは、このオプションはfalseに設定されています。

RoutingOptions routingOptions = new RoutingOptions();
routingOptions.routeOptions.enableRouteLabels = true;

ルートラベルを有効にすると、計算されたルートからroute.getRouteLabels()を使用して取得できます。各RouteLabelには、次の2つの重要な情報が含まれています。

  • nameLocalizedTextオブジェクトには、道路名またはルート番号が含まれています。
  • typeRouteLabelTypeは、ラベルが道路名を表すか、ルート番号を表すかを示します。

以下は、ルートラベルを取得してログを記録する例を示したものです。

private void logRouteLabels(Route route) {
    // Get the list of the street names or route numbers through which the route is going to pass.
    // Make sure to enable this feature via routeOptions.enableRouteLabels.
    List<RouteLabel> routeLabels = route.getRouteLabels();

    if (routeLabels.isEmpty()) {
        Log.d(TAG, "No route labels found for this route.");
        return;
    }

    for (RouteLabel routeLabel : routeLabels) {
        LocalizedText name = routeLabel.name;
        RouteLabelType routeLabelType = routeLabel.type;
        Log.d(TAG, "Route label: " + name.text + ", Type: " + routeLabelType.name());
    }
}

出力例:

Route label: Schönhauser Allee, Type: STREET_NAME
Route label: Torstraße, Type: STREET_NAME

ルートラベルがrouteOptions.enableRouteLabelsによって有効化されていない場合、getRouteLabels()メソッドは空のリストを返します。

RoutingOptionsを使用する

統一されたRoutingOptionsクラスは、すべての移動モードで使用されます。以下は、車両のルートのRoutingOptionsを設定する方法の例です。

    public void calculateVehicleRoute() {
        List<Waypoint> waypoints = new ArrayList<>(Arrays.asList(new Waypoint(startGeoCoordinates), new Waypoint(destinationGeoCoordinates)));
        routingEngine.calculateRoute(waypoints, getCarVehicleOptions(), new CalculateRouteCallback() {
            @Override
            public void onRouteCalculated(@Nullable RoutingError routingError, @Nullable List<Route> routes) {
                if (routingError == null && routes != null && !routes.isEmpty()) {
                    Route route = routes.get(0);
                    ...
                } else {
                    showDialog("Error while calculating route:", String.valueOf(routingError));
                }
            }
        });
    }

    private RoutingOptions getCarVehicleOptions() {
        RoutingOptions routingOptions = new RoutingOptions();
        routingOptions.routeOptions.optimizationMode = OptimizationMode.FASTEST;

        // Default transportMode is CAR; we are setting it here explicitly for clarity.
        // Optionally, you can set VehicleSpecification, for example, if your car is having unusual dimensions.
        routingOptions.transportSpecification.transportMode = TransportMode.CAR;

        return routingOptions;
    }

RoutingOptionsは、車両の仕様や、たとえば輸送する貨物などを定義するための特定の車両に依存しない方法を提供します。 以下は、トラックの特性を定義する車両仕様の使用例です。

// Builds a vehicle specification for truck, which would be used during route calculation for specific vehicle types.
private VehicleSpecification buildTruckSpecification() {
    WeightPerAxleGroup axleGroup = new WeightPerAxleGroup();
    axleGroup.singleAxleGroupInKilograms = 9000;
    axleGroup.tandemAxleGroupInKilograms = 17000;
    axleGroup.tripleAxleGroupInKilograms = 23000;

    return new VehicleSpecification.TruckBuilder()
            .withHeightInCentimeters(400)
            .withWidthInCentimeters(255)
            .withLengthInCentimeters(1800)
            .withAxleCount(6)
            .withTruckCategory(TruckCategory.TRACTOR)
            .withTrailerCount(1)
            .withTrailerAxleCount(3)
            .withGrossWeightInKilograms(44000)
            .withCurrentWeightInKilograms(40000)
            .withWeightPerAxleGroup(axleGroup)
            .withIsCommercial(true)
            .build();
}

...

RoutingOptions routingOptions = new RoutingOptions();
routingOptions.transportSpecification.transportMode = TransportMode.TRUCK;
routingOptions.transportSpecification.vehicleSpecification = buildTruckSpecification();

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); })();