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

ルート検索を開始する

HERE SDKでは、A地点からB地点までの最適なルートを計算するRoutingEngineが用意されており、複数の経由地設定やローカライズ可能な右左折ごとの運転指示などの機能が含まれています。

希望のルートタイプ (最速または最短) とさまざまなルートオプション (速度プロファイル、ルート制限、ビネットオプションなど) を設定して優先設定を指定することで、最もエネルギーを節約できる最適なルートを見つけることができます。HEREは、高度なルート検索技術と専用のEVルートプランニングサポートにより、地球をよりクリーンで安全なものにするお手伝いをします。

機能の概要:

  • ルートを計算する:さまざまな移動モードで複数の経由地を使用してルートを計算します。
  • Isoline Routing:時間、距離、または燃料消費量に基づいて、特定のポイントからの到達範囲を表す等値線ポリゴンを計算します。
  • ルートに沿って検索する:ルート全体に沿って場所を検索します (この機能については「検索」セクションで説明します)。
  • ルートインポート/ルートの照合:他のAPIからルートをインポートできます。
  • オフラインルーティング (Navigateでのみ使用可能):インターネット接続が利用できない場合は、専用のオフラインのルート検索エンジンに切り替えて、すでにキャッシュに保存されているマップデータまたは事前に読み込まれたオフラインマップデータでルートを計算できます。

ルート検索はHERE Routing API v8に基づいています。ルート検索に基づくトランザクションの例:RoutingEngineRoutingOptionsを使用してルートを計算します。RoutingOptions.transportSpecification.transportModeで移動モードをcartruckpedestrianbicyclebustaxiまたはscooterに設定できます。TrafficOptimizationMode.timeDependentは使用しないでください。時間を意識したルート検索では現在の交通量を含むよりよい結果を提供できるため、timeDependentがデフォルトで設定されています。 時間を意識したルート検索の例:RoutingEngineTrafficOptimizationMode.timeDependentを使用してルートを計算します。デフォルトでは、これは有効になっています。RouteOptions.arrivalTimeおよびRouteOptions.arrivalTimenullのままである場合、HERE SDKは現在のデバイス時刻を使用します。 通行料金を考慮したルート検索の例:RoutingEngineRouteOptions.enableTollstrueに設定してルートを計算します。

ルート検索にはHERE Public Transit APIも使用されます。HERE Public Transit APIの使用例:TransitRoutingEngineを使用してルートを計算します。

これらの機能の価格については、「HERE基本プランの価格表」を参照してください。Navigateライセンスを使用している場合、または価格についてご質問がある場合は、お問い合わせください。

RoutingEngineを初期化する

次の方法でルートエンジンを作成して移動を開始します。

do {
    try routingEngine = RoutingEngine()
} catch let engineInstantiationError {
    fatalError("Failed to initialize routing engine. Cause: \(engineInstantiationError)")
}

新しいRoutingEngineインスタンスを作成すると、前述のように処理する必要のあるエラーがスローされる場合があります。このようなエラーは、たとえば、HERE SDKの初期化が事前に失敗していた場合に発生する可能性があります。

ルートを計算する

次のステップとして、出発地と目的地 (どちらもGeoCoordinatesインスタンスを保持するWaypointタイプ) の2つの経由地に基づいてルートを計算できます。以下では、乗用車に合わせて最適化されたルートを計算するためにデフォルトの RoutingOptions を設定します。

let routingOptions = RoutingOptions()
routingEngine.calculateRoute(with: [Waypoint(coordinates: startGeoCoordinates!),
                                    Waypoint(coordinates: destinationGeoCoordinates!)],
                             options: routingOptions) { (routingError, routes) in

        if let error = routingError {
            self.showDialog(title: "Error while calculating a route:", message: "\(error)")
            return
        }

        let route = routes!.first
        self.showRouteDetails(route: route!)
        self.showRouteOnMap(route: route!)
        self.logRouteViolations(route: route!)
}

calculateRoute()は複数回呼び出すことができます。たとえば、さまざまなルート検索オプションを使用して複数のルートを並行して計算するために呼び出すことができます。

Waypointを設定するときにsideOfStreetHintを設定することで、歩行者またはドライバーが停車地に到着するときに道路のどちら側になるか調整できます。

歩行者またはドライバーが移動している場合、startingWaypoint?.headingInDegrees = location.bearingInDegrees を設定することで、方位値によって最初の進行方向が決定されます。これにより、次の目的地がドライバーの後方にある場合に不要なUターンを回避できます。歩行者は、これにより道路を横断する必要がなくなるので、よりよいルートを確保することができます。

各ルート計算は非同期で実行されます。完了するとRouteリストか、エラーがあったときにエラーを示すRoutingErrorを取得します。すべてうまくいくと nil になります。エラーが発生した場合、ルート リストは nil になります。たとえば、指定された移動モードでルートが実行可能でない場合、エンジンでルートを計算できません。

エラーがなければ、ルートリストには結果が1つだけ含まれます。ルートオプションを使用して代替ルートの数を指定すると、追加のルートバリエーションをリクエストできます。デフォルトでは、代替ルートなしでルートが計算されます。

上記のコード スニペットのshowRouteDetails()メソッドを使用して、運転指示を含むルートの詳細を表示します。完全なソースコードは付属のサンプルアプリで確認できます。運転指示については以下でも詳しく説明します。showRouteOnMap()メソッドには、マップ上でルートをレンダリングする方法の例が含まれています。この点については、後述のセクションで簡単に説明します。

ETAおよび交通情報を取得する

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

// estimatedTravelTimeInSeconds includes traffic delay.
let estimatedTravelTimeInSeconds = route.duration
// Get predictive traffic delay data.
let estimatedTrafficDelayInSeconds = route.trafficDelay
let lengthInMeters = route.lengthInMeters

交通情報に関する詳細については、「リアルタイムおよび予測交通データソースの違い」のセクションを参照してください。

到着予測時刻 (ETA) は、デバイスの地理座標によって異なるタイムゾーンで表示できます。たとえば、ルートを計算するとき、デバイスの現在のタイムゾーンが目的地のタイムゾーンと異なる場合があります。ベルリンからロンドンまでのルートを計算するシナリオを考えてみましょう。各都市は異なるタイムゾーンに従っています。これに対処するため、ETAを複数のタイムゾーンで表示できます。デバイスの現在のタイムゾーン (ベルリン)、目的地のタイムゾーン (ロンドン)、またグローバルリファレンスとしてUTC (協定世界時) を設定します。

同じETAが異なるタイムゾーン間でどのように変化するかの例は次のとおりです。

デバイスの現在のタイムゾーン (ベルリン) に基づくETA デバイスの目的地のタイムゾーン (ロンドン) に基づくETA UTCでのETA
8:30 AM 7:30 AM 6:30 AM

デバイスのタイムゾーンでETAを計算するには、次の方法を使用します。この方法では、Routeオブジェクトから推定移動時間を取得し、現在の日付と時刻を初期化して、移動時間を追加し、結果の形式を設定します。

/**
 * Returns the ETA (as a string in ‘HH:mm’ format) in the current device’s timezone, derived from the estimatedTravelTimeInSeconds, which is sourced from the Route object.
 *
 * - Parameter route: Original route object from RoutingEngine.
 * - Returns: A string representing the ETA in "HH:mm" format.
 */
 func getETAinDeviceTimeZone(route: Route) -> String {
    let estimatedTravelTimeInSeconds = route.duration

    // Get an instance of the Calendar class initialized with the current date and time
    let calendar = Calendar.current
    var dateComponents = DateComponents()
    dateComponents.second = Int(estimatedTravelTimeInSeconds)

    // Add the estimated travel time (in seconds) to the current time
    if let etaDate = calendar.date(byAdding: dateComponents, to: Date()) {
        return getFormattedDate(etaDate)
    } else {
        return ""
    }
}

目的地のタイムゾーンのETAを計算するには、次の方法を使用します。この方法では、到着地の現地時間と、目的地の現地時間と協定世界時 (UTC) の差を取得します。

/**
 * Calculates the estimated time of arrival (ETA) in the destination timezone for a given route.
 * It is possible that the destination can be in a different timezone compared to the source.
 * Therefore, we are also calculating the ETA in the destination timezone. For example, the source can be in Berlin and the destination can be in Dubai.
 *
 * - Parameter route: Original route object from RoutingEngine.
 * - Returns: A string representing the estimated time of arrival in the destination timezone, formatted as "hh:mm".
 */
func getETAinDestinationTimeZone(route: Route) -> String {
    let arrivalLocationTime = getArrivalLocationTime(route:route)
    let destinationDate = arrivalLocationTime.localTime

    // The timeOffset represents the difference between the local time at destination and Coordinated Universal Time (UTC) in minutes.
    let timeOffset = Int(arrivalLocationTime.utcOffset/60)

    return getFormattedDate(destinationDate,timeOffset: timeOffset)
}

特定のルートでのETAを協定世界時 (UTC) で計算するには、次の方法を使用します。この方法では、世界時間として規定される一時標準時でETAが表されます。

/**
 * Calculates the estimated time of arrival (ETA) in Coordinated Universal Time (UTC) for a given route.
 * UTC (Coordinated Universal Time) is the primary time standard by which the world regulates clocks and time.
 *
 * @param route Original route object from RoutingEngine.
 * @return A string representing the estimated time of arrival in UTC, formatted as "HH:mm".
 */
func getEstimatedTimeOfArrivalInUTC(route: Route) -> String {
    let utcDate = getArrivalLocationTime(route: route).utcTime

    // The UTC offset represents the difference in hours and minutes between a specific time zone and Coordinated Universal Time (UTC).
    // It indicates whether the local time is ahead (+) or behind (-) UTC.
    // By using an offset of 0, we ensure that the time being represented is in Coordinated Universal Time (UTC).
    let utcTimeOffset = 0
    return getFormattedDate(utcDate, timeOffset: utcTimeOffset)
}

getArrivalLocationTime(route: Route) メソッドは、ルートの最終セクションから特定のルートの到着時刻を取得します。ルート内の各セクションの所要時間を順番に累算します。たとえば、5分かかるセクションが2つある場合、最初のセクションの所要時間は5分、2つ目のセクションの合計所要時間は 10分 (各セクションで5分) です。

// Returns the arrival time at the final location of the route.
private func getArrivalLocationTime(route: Route) -> LocationTime {
    let lastSectionIndex = route.sections.count - 1

    // The lastSection contains cumulative duration values that increase sequentially.
    // For instance, if there are two sections, each with a duration of 5 minutes, the first section will reflect a total duration of 5 minutes,
    // while the second section will show a total duration of 10 minutes.
    // This is because the total time includes the initial 5 minutes for the first section, followed by an additional 5 minutes to complete the second section, resulting in a cumulative travel time.
    let lastSection = route.sections[lastSectionIndex]
    return lastSection.arrivalLocationTime!
}

上記のETAを特定のタイムゾーンでフォーマットする方法は次のとおりです:

/**
 * Formats the given date to a string representation using the device's default timezone.
 *
 * - Parameter date: The Date object to be formatted.
 * - Returns: A string representing the formatted time in the default timezone.
 */
private func getFormattedDate(_ date: Date) -> String {
    // Create a DateFormatter instance that formats the time in a short format (e.g., "HH:mm a").
    let dateFormatter = DateFormatter()
    dateFormatter.timeStyle = .short

    // Format the date using the configured DateFormatter and return the result as a string.
    return dateFormatter.string(from: date)
}

既存のルートの交通情報を更新するには、「交通情報を更新する」を参照してください。これにより、交通データと到着予測時刻 (ETA) を更新できます。

交通が最適化されたルート計算

HERE SDKは交通データを自動的に統合し、最も速く正確なルートを計算します。

デフォルトでは、ルートは現在の交通状況と予測交通状況の両方を考慮して最適化されます。RoutingEngineは予測型位置情報サービスを使用してルート走行中の交通状況を先読みし、計算されるルートが遭遇する可能性の高い交通状況を考慮します。

  • 最速ルートの計算時には、現在の交通状況が自動的に考慮されます。
  • RoutingEngineは、履歴パターンとリアルタイムデータに基づいて将来の交通状況を予測します。
  • 到着予測時刻 (ETA) には、交通渋滞による遅延が含まれます。
  • ルートの各Spanには、渋滞係数を含む詳細な交通速度情報が含まれます。
  • 必要に応じて、TrafficEngineを使用してルートに沿った交通データをクエリします。

交通の最適化は自動的に行われるため、明示的に有効にする必要はありませんが、無効にすることもできます。

交通の最適化を無効にする

RoutingEngineは_予測型位置情報サービス_を使用して今後の交通状況を予測します。つまり、生成されるルートはリアルタイムの交通データに応じて動的に変化し、ルート形状が変化していきます。

通常は交通の最適化が求められますが、たとえば、バスの運転手は事前に定義されたバスルートに従わなければならないため、より適切なルートを選択することはできません。

これを管理するため、HERE SDKにはTrafficOptimizationModeと呼ばれる機能があります。交通状況を気にせずに決められたルートを走行する場合は、TrafficOptimizationMode.disabledを選択して交通の最適化を完全に無効にします。

routeOptions.trafficOptimizationMode = .disabled

TrafficOptimizationModeを無効にするとRouteからの交通情報もすべて無効になり、到着予測時刻には遅延の可能性が考慮されません。

ルートからインシデントの概要を取得する

ルート沿いの基本的な交通事案情報を取得するには、section.getTrafficIncidents()を呼び出して、SectionごとにRouteインスタンスから交通状況の概要を直接取得できます。結果として得られるTrafficIncidentOnRouteオブジェクトには、TrafficEngineから取得可能なデータの一部が含まれており、全体像を把握できます。

Routeオブジェクトに含まれるインシデントカテゴリーは次のとおりです。

  • accident:交通事故。
  • congestion:交通渋滞。
  • construction:建設工事。
  • disableVehicle:道路で転倒または故障した車。
  • laneRestriction:レーンごとの規制。
  • massTransit:鉄道や地下鉄などの公共交通機関に関するインシデント。
  • plannedEvent:スポーツイベントやフェスティバルなどの活動に関連するインシデント。
  • roadClosure:道路の閉鎖。
  • roadHazard:倒木や信号故障などの道路上の危険な障害物。
  • weather:悪天候。
  • other:他のどのカテゴリーにも当てはまらない既知のインシデント。
  • unknown:特定のタイプに分類されないインシデント。

HERE SDKはこれらのインシデントタイプに対応するアイコンアセットを提供していませんが、trafficIncidentsマップフィーチャーレイヤーを有効にすることで、地図上にすべてのインシデントをアイコンで表示できます。同様に、trafficFlowレイヤーを有効にして、道路の一般的な交通流を表示することもできます。詳細については、「交通情報の使用を開始する」セクションを参照してください。

今後の制限速度などを確認する

Route オブジェクトは、Route に沿った詳細情報を公開して、今後の制限速度、踏切、道路の属性と道路名、動的な交通情報などを把握します。

次の属性を見てみましょう:Span.sectionPolylineOffsetSpan.dynamicSpeedInfoSpan.streetAttributesSpan.carAttributesSpan.truckAttributesSpan.scooterAttributesSpan.walkAttributesSpan.durationInSecondsSpan.streetNamesSpan.routeNumbersSpan.speedLimitInMetersPerSecondSpan.consumptionInKilowattHoursSpan.functionalRoadClassSpan.durationSpan.baseDuration。属性の完全なリストについては、「APIリファレンス」を参照してください。

各属性はスパンごとに指定され、スパン全体の長さに対して有効です。場合によっては、2つの交差点間の道路ネットワークの一部を示すセグメントIDが見つかることもあります。Spanはルート関連の概念で、同じ属性を持つルートの一部です。同じセグメント上に複数のスパンが存在する場合があり、通常、各セグメントには開始オフセットと終了オフセットがあります。

Spanはルートセグメントの最小部分を定義し、そのカーブはGeoCoordinatesのリストとして公開されます。

踏切情報を取得する

RouteRailwayCrossingのリストはRouteオブジェクトから取得できます。このオブジェクトには、踏切のGeoCoordinatesRouteOffset、ルートを横断する鉄道路線または路面電車路線のRouteRailwayCrossingTypeの情報が含まれます。

RouteOffsetとはセクションインデックスによって定義されるルート上の位置であり、そのセクションの始点からルート上の指定された位置までの距離 (メートル単位) のことです。 RouteOffset の詳細については、「APIリファレンス」を参照してください。

RouteRailwayCrossing を使用した簡単な実装は以下のとおりです。

for routeRailwayCrossing in route.railwayCrossings {
    // Coordinates of the route offset
    let routeOffsetCoordinates = routeRailwayCrossing.coordinates
    // Index of the corresponding route section. The start of the section indicates the start of the offset.
    let routeOffsetSectionIndex = routeRailwayCrossing.routeOffset.sectionIndex
    // Offset from the start of the specified section to the specified location along the route.
    let routeOffsetInMeters = routeRailwayCrossing.routeOffset.offsetInMeters

    print("A railway crossing of type \(routeRailwayCrossing.type) is situated \(routeOffsetInMeters) meters away from start of section: \(routeOffsetSectionIndex)")
}

ルート違反を検出する

ルートには、ルートの計算後に発生する可能性のある問題を説明するNoticeCode値のリストが含まれている場合があります。たとえば、ルートでトンネルを回避しなければならず、唯一のルート候補でトンネルを通過する必要がある場合、Routeには、リクエストされたトンネル回避の違反があったことを示す通知が含まれます。

  • 計算済みのRouteに違反の可能性がないか必ず確認することをお勧めします。
  • NoticeCodeNoticeオブジェクトの一部です。使用可能なNoticeオブジェクトのリストにはRouteSectionに従ってアクセスできます。
  • 違反が発生していない場合、リストは空になります。
  • 違反の可能性を排除する場合は、違反を1つでも含むルートをスキップすることをお勧めします。

ただし、リクエストされたルートオプションおよび実際のNoticeCode値のリストに応じて、実装はケースバイケースで判断します。ルートオプションの詳細については、次のセクションを参照してください。重要:説明をわかりやすくするため、このガイドのコードスニペットでは通知の列挙型 (enum) 値を評価しません。

次の方法でルート通知を検出できます。

// A route may contain several warnings, for example, when a certain route option could not be fulfilled.
// An implementation may decide to reject a route if one or more violations are detected.
private func logRouteViolations(route: Route) {
    let sections = route.sections
    for section in sections {
        for span in section.spans {
            let spanGeometryVertices = span.geometry.vertices;
            // This route violation spreads across the whole span geometry.
            guard let violationStartPoint: GeoCoordinates  = spanGeometryVertices.first else {
                print("Error: violation start geocoordinate is empty.")
                return
            };
            guard let violationEndPoint : GeoCoordinates = spanGeometryVertices.last else {
                print("Error: violation end geocoordinate is empty.")
                return
            };
            for index in span.noticeIndexes{
                let spanSectionNotice : SectionNotice = section.sectionNotices[Int(index)];
                // The violation code such as "violatedVehicleRestriction".
                let violationCode = spanSectionNotice.code;
                print("The violation \(violationCode)  starts at \(toString(geoCoordinates: violationStartPoint))  and ends at  \(toString(geoCoordinates: violationEndPoint)) .");

            }
        }
    }
}

すべてのルートにはルートに沿って高度値が含まれています。たとえば、計画された自転車旅行の標高プロファイルを作成する目的で高度値を使用します。

Routingサンプルアプリを試す

GitHubには、上記のすべてのコードスニペットに加え、その他のコードが含まれる「Routing」サンプルアプリがあります。

GitHubには「PublicTransit」サンプルアプリもあります。TransitRoutingEngineを使用して、A地点からB地点までの公共交通機関のルートを計算する方法を示します。A地点とB地点の間には複数の経由地があります。

GitHubにあるReroutingサンプルアプリも参照してください。これにはHERE SDK (Navigate) が必要ですが、UIビルディングブロックとIconProviderのコードは他のライセンスでも使用でき、たとえば、ルートプレビューパネルの一部として道路標識アイコンを表示できます。