ガイダンスを開始します

HERE SDK を使用すると、包括的なターン・バイ・ターンナビ (矢印ナビ)エクスペリエンスを構築できます。 このフィーチャーを使用すると、アプリは現在のデバイスの位置を計算されたルートと照合して確認し、ナビゲーションの指示をジャストインタイムで取得できます。

ナビゲーションは、publicTransitを除くすべての利用可能なトランスポートモードでサポートされています。 公共交通機関の利用は、ナビゲーションで不確かな、予期しない結果が生じる可能性があります。

bus ルートのナビゲーションサポートは現在制限されています : 今後リリースされる HERE SDK では、バス固有のレーンアシスタンスの改善や、バスナビゲーションのより正確なターンバイターンナビが期待されています。

トランスポートモードは、 Routeをまたいで変更される場合があります。たとえば、公園を歩いて観光地に到着した場合、車を降りる必要がある場合があります。 ルートが計算されると、トランスポート モードが Route オブジェクトの各 Section に添付されます。

車、トラック、タクシー、バス、スクーターのルートについては、道路と地図で車両の位置を合わせます。また、徒歩ルートなどの他のモードについては、舗装されていない舗装されていない舗装されていない舗装路やドライバーがアクセスできないその他の経路に位置を合わせることができます。 自転車ルートでは、利用可能なすべてのパスを利用できます。

HERE SDK では、トラッキングルートがなくても トラッキングモードをサポートしています。トラッキングモードでは、現在の道路、マップマッチングした場所、および制限速度などのその他のサポート情報が提供されます。

HERE SDK に は、 視覚的なフィードバックを示すための操作矢印のための UI アセットがありません。 代わりに、ルート上で利用できるすべての情報が単純なデータ型として提供され、必要に応じて独自のアセットを選択できます。

ヒント : ご自身の iOS アプリケーションで使用できる再利用可能なアセットは、 HERE の MSDKUI オープンソースプロジェクトにあり ます。このプロジェクトは、 GitHub のこのリンクから利用できます。 再利用可能なアイコンの数は、 HERE の公式アイコンライブラリ に記載されています。

カスタマイズされたナビゲーションマップ ビューは、オプションでVisualNavigatorとともにレンダリングされます。 startRendering() が呼び出されると、現在の方向を示す矢印の形式で事前設定されたインスタンス MapMarker3D が追加され、受信位置の更新がスムーズに補間されます。 さらに、マップの向きが最適なデフォルト値に変更されます。

事前設定されたインスタンスMapMarker3D は、独自のモデルを設定してカスタマイズすることも、無効にすることもできます。 内部的に、VisualNavigatorLocationIndicatorインスタンスを使用するため、VisualNavigatorLocationIndicatorカスタムを設定することもできます。 この操作が完了したら、インスタンスを手動で追加、削除、および更新する必要があります。 マップ ビューですでにLocationIndicatorインスタンスを使用している場合と同様 に、関連するマップアイテムのセクションを参照してください。

デフォルトでは、LocationIndicatorのスタイルは、VisualNavigatorに設定できるトランスポートモードによって決まります。 ルートが設定されている場合は、代わりにルートインスタンスから取得されます。 カスタムアセットを使用する場合は、クラスLocationIndicatorを介してスタイルを直接切り替える必要があります。

NavigationCustom Example アプリで は、ナビゲーションが停止したときにカスタムLocationIndicatorおよび別のタイプに切り替える方法を示します。 また、ナビゲーションパースペクティブのカスタマイズ方法も示します。

音声ガイダンスは、 任意 のプラットフォーム TTS (音声合成)ソリューションにStringとして送信できる操作通知を提供します。

オフラインガイダンスがサポートされています。 キャッシュ されているか、または事前にロードされているマップ データがないとルートがリージョンに到達しない限り、オフライン マップおよびトラッキングは、すでにキャッシュまたはダウンロードされているターン・バイ・ターンナビ (矢印ナビ)データでオフラインで完全に動作します。

ターン・バイ・ターンナビ (矢印ナビ)

ターン・バイ・ターンナビ (矢印ナビ)の基本原則は、速度や方位の値などの位置情報を頻繁に受信し、道路と照合して目的のルートと比較することです。 現在地 と 次の目的地を案内する操作指示が表示されます。

ルートを出るときに、メートル単位で偏差が通知されます。 この通知は、新しいルートを計算するかどうかを決定するのに役立ちます。 最後に、位置シミュレータを使用すると、開発フェーズでルートナビゲーションをテストできます。

注 : 重要

ターン・バイ・ターンナビ (矢印ナビ)を使用するアプリケーション開発者は、想定されるすべての使用シナリオでアプリケーションを徹底的にテストして、安全で正しい動作を保証する必要があります。 アプリケーション開発者は、アプリユーザーに以下を含む ( ただし、これらに限定されない ) 義務について警告する責任があります。

  • 安全でない、または違法な状況につながる可能性のある指示に従わないでください。
  • すべての地域の法律に従ってください。
  • 運転中に携帯電話またはそのフィーチャーの一部を使用することは禁止されている場合がありますので、ご了承ください。
  • 運転中は、常にハンドルから手を離さないでください。
  • 走行中は、道路の安全性を最優先にしてください。

以下のセクションのすべてのコードスニペットは 、ナビゲーションサンプルアプリの一部として GitHub でも利用できます。このアプリは、関連するコードを示し、指導中に画面をアクティブに保つなど、安定したドライビング体験とベストプラクティスを提供します。 ただし、本格的な量産対応アプリケーションのすべての側面をカバーするわけではありません。 たとえば、アプリ では、アプリ がバックグラウンドで動作している間に位置情報の更新を取得する方法は表示されません。

位置情報のバックグラウンド更新を取得する場合 は、『位置情報の取得』ガイドの関連セクションを参照してください。

さらに 、 GitHubNavigationQuickStart アプリを利用し て、数行のコードでガイダンスを開始する方法を確認することもできます。 次のセクションも参照してください。

利用開始

HERE SDK のナビゲーションフィーチャーについてより詳しく調べる前に、まず短いコードの例を参照して、音声で操作できる指示とガイダンスビューを使用してガイダンスを開始する方法を示します。

private func startGuidance(route: Route) {
    do {
        // Without a route set, this starts tracking mode.
        try visualNavigator = VisualNavigator()
    } catch let engineInstantiationError {
        fatalError("Failed to initialize VisualNavigator. Cause: \(engineInstantiationError)")
    }

    // This enables a navigation view including a rendered navigation arrow.
    visualNavigator!.startRendering(mapView: mapView)

    // Hook in one of the many delegates. Here we set up a delegate to get instructions on the maneuvers to take while driving.
    // For more details, please check the "Navigation" example app and the Developer's Guide.
    visualNavigator!.maneuverNotificationDelegate = self

    // Set a route to follow. This leaves tracking mode.
    visualNavigator!.route = route

    // VisualNavigator acts as LocationDelegate to receive location updates directly from a location provider.
    // Any progress along the route is a result of getting a new location fed into the VisualNavigator.
    setupLocationSource(locationDelegate: visualNavigator!, route: route)
}

// Conform to ManeuverNotificationDelegate.
func onManeuverNotification(_ text: String) {
    print("ManeuverNotifications: \(text)")
}

private func setupLocationSource(locationDelegate: LocationDelegate, route: Route) {
    do {
        // Provides fake GPS signals based on the route geometry.
        try locationSimulator = LocationSimulator(route: route,
                                                  options: LocationSimulatorOptions())
    } catch let instantiationError {
        fatalError("Failed to initialize LocationSimulator. Cause: \(instantiationError)")
    }

    locationSimulator!.delegate = locationDelegate
    locationSimulator!.start()
}

このコードの抜粋では、ガイダンスビューが開始 され、提供されたrouteで定義されている宛先に到達するまで、操作手順がコンソールに出力されます ( 宣言を含むすべてのコードについては、「 NavigationQuickStart Example アプリ 」を参照してください ) 。 操作の指示はドライバーに伝えられることを意図しており、「左折して 5,000 m 先の Invalidenstra ß e に入る」などの文字列が含まれている場合があります。 操作方法の詳細な説明も利用できます。詳細については、以下のセクションを参照してください。

上記では、 HERE SDK のシミュレーションフィーチャーを使用して位置情報の更新を取得しています。 もちろん、VisualNavigatorに実際の位置情報の更新をフィードすることもできます。

ナビゲーションアプリの基本原則は次のとおりです。

  1. Routeを作成します。 走行するルートがないと、ガイダンスを開始できません。
  2. インスタンスVisualNavigator を作成してレンダリングを開始します ( または、独自のガイダンスビューをレンダリングする場合はインスタンスNavigator を作成します ) 。
  3. RouteVisualNavigatorに設定します。
  4. 位置情報の更新がVisualNavigatorに送られました。 位置情報がないと、ルート沿いのルートの進行状況を検出できません。 これにより、上に示したようにシミュレートが可能です。また、実際の位置情報の更新ができます。

利用開始時は、 GitHubNavigationQuickStart サンプルアプリ を参照して、この仕組みを確認してください。 そこでは、 HERE SDK が提供する多くのナビゲーションフィーチャーの詳細を確認できます。

Waypointを設定する場合 、ドライバーが道路のどちら側に到着するかを、sideOfStreetHintに設定して調整できます。 ドライバーが動いている場合、ベアリング値を headingInDegrees に設定 Waypointすることで、初期の方向を決定できます。 これにより、次の目的地がドライバーの後ろにある場合に、不要な U ターンを避けることができます。 これは、不要な道路横断を避けるためなど、歩行者のルートを最適化するのにも役立ちます。

ナビゲーターを使用して、ガイダンスイベントを検知

前述のように、目的地へのナビゲーションを開始する前に、次の 2 つのことを行う必要があります。

  • 走行するRoute 。 ナビゲーションを開始するには、NavigatorまたはVisualNavigatorインスタンスにRouteを設定する必要があります。
  • Navigator または VisualNavigator インスタンスにユーザーがいる場所を定期的に通知する場所ソース。

ルートがすでに計算されていない場合は、次のように作成します。 Route インスタンスを取得中で あることがここに示されます。 アプリをトラッキングモードでのみ開始する場合は、この手順をスキップできます。

ターン・バイ・ターンナビ (矢印ナビ)中に、NavigatorまたはVisualNavigatorインスタンスから現在のLocationと同期されたすべてのManeuver情報を取得します。 移動中は 、Routeオブジェクトから直接Manueverデータを取得しないでください

ガイダンスを開始するには、 2 つの選択肢があります。 ヘッドレス Navigator を使用するか、またはVisualNavigatorのサポートを受け てください。 NavigatorVisualNavigator のサブセットを提供するため、どちらも同じインターフェイスを提供しますが、VisualNavigator は、個別の Location更新間のスムーズな補間などのフィーチャーを備えた視覚的なレンダリング支援を最上位に提供します。

別の要件は、Locationインスタンスを提供することです。現在の場所で頻繁に更新を行わないとナビゲーションを実行できないためです。 このため には、 GitHub にあるプロバイダの実装を使用できます。

プラットフォームポジショニングソリューションを実装するか、 HERE SDK ポジショニングフィーチャーを使用するか または ロケーションシミュレータを設定することで、新しい場所にフィードできます。

基本的な情報フローは次のとおりです。

ロケーションプロバイダ => ロケーション => (Visual ) ナビゲータ => イベント

Location 任意のソースを「ロケーションプロバイダ」として設定できます。 onLocationUpdated()Navigator またはVisualNavigatorでのみ呼び出す必要 があります。

開発者は、有効な場所でVisualNavigatorにフィードする責任があります。 VisualNavigatorは、受信した各場所について、ルート沿いの進行状況を示す適切なイベント(操作、予想されるルートからの逸脱など)を使用して応答します。 結果のイベントは、提供された位置信号の精度と周波数に依存します。

まず、参照実装の新しいインスタンスを作成して場所を取得します。

herePositioningProvider = HEREPositioningProvider()

次に、新しい VisualNavigator インスタンスを作成し HEREPositioningProvider 、上記のからへのデリゲートとして設定します。 この VisualNavigator クラスは、場所を受け取る onLocationUpdated(location:) メソッドを定義する LocationDelegate プロトコルに準拠しています。

do {
    try visualNavigator = VisualNavigator()
} catch let engineInstantiationError {
    fatalError("Failed to initialize VisualNavigator. Cause: \(engineInstantiationError)")
}

// Now visualNavigator will receive locations from the HEREPositioningProvider.
herePositioningProvider.startLocating(locationDelegate: visualNavigator,
                                      accuracy: .navigation)

さらに、トラッキングするルートを設定してください ( トラッキングモードにする予定がある場合のみ ) 。

visualNavigator.route = route

VisualNavigatorのレンダリング機能を使用しない場合は 、代わりにクラスNavigatorを使用することもできます。 このクラスは、フードの下の同じコードを使用 し、VisualNavigatorとまったく同じように動作しますが、特殊なナビゲーションビューのレンダリングはサポートしていません。

次のステップでは、ルートの進行状況、現在の場所、次のルート変更の進行状況について通知を受け取るように、いくつかの代理人を設定できます。

visualNavigator.navigableLocationDelegate = self
visualNavigator.routeDeviationDelegate = self
visualNavigator.routeProgressDelegate = self

HERE では、 RouteProgressDelegateNavigableLocationDelegate 、および RouteDeviationDelegate の各プロトコルを満たすための準拠メソッドを設定しています。

// Conform to RouteProgressDelegate.
// Notifies on the progress along the route including maneuver instructions.
func onRouteProgressUpdated(_ routeProgress: RouteProgress) {
    // [SectionProgress] is guaranteed to be non-empty.
    let distanceToDestination = routeProgress.sectionProgress.last!.remainingDistanceInMeters
    print("Distance to destination in meters: \(distanceToDestination)")
    let trafficDelayAhead = routeProgress.sectionProgress.last!.trafficDelay
    print("Traffic delay ahead in seconds: \(trafficDelayAhead)")

    // Contains the progress for the next maneuver ahead and the next-next maneuvers, if any.
    let nextManeuverList = routeProgress.maneuverProgress
    guard let nextManeuverProgress = nextManeuverList.first else {
        print("No next maneuver available.")
        return
    }

    let nextManeuverIndex = nextManeuverProgress.maneuverIndex
    guard let nextManeuver = visualNavigator.getManeuver(index: nextManeuverIndex) else {
        // Should never happen as we retrieved the next maneuver progress above.
        return
    }

    let action = nextManeuver.action
    let roadName = getRoadName(maneuver: nextManeuver)
    let logMessage = "'\(String(describing: action))' on \(roadName) in \(nextManeuverProgress.remainingDistanceInMeters) meters."

    if previousManeuverIndex != nextManeuverIndex {
        // Log only new maneuvers and ignore changes in distance.
        showMessage("New maneuver: " + logMessage)
    } else {
        // A maneuver update contains a different distance to reach the next maneuver.
        showMessage("Maneuver update: " + logMessage)
    }

    previousManeuverIndex = nextManeuverIndex
}

// Conform to NavigableLocationDelegate.
// Notifies on the current map-matched location and other useful information while driving or walking.
func onNavigableLocationUpdated(_ navigableLocation: NavigableLocation) {
    guard navigableLocation.mapMatchedLocation != nil else {
        print("The currentNavigableLocation could not be map-matched. Are you off-road?")
        return
    }

    let speed = navigableLocation.originalLocation.speedInMetersPerSecond
    let accuracy = navigableLocation.originalLocation.speedAccuracyInMetersPerSecond
    print("Driving speed: \(String(describing: speed)) plus/minus accuracy of \(String(describing: accuracy)).")
}

// Conform to RouteDeviationDelegate.
// Notifies on a possible deviation from the route.
func onRouteDeviation(_ routeDeviation: RouteDeviation) {
    guard let route = visualNavigator.route else {
        // May happen in rare cases when route was set to nil inbetween.
        return
    }

    // Get current geographic coordinates.
    var currentGeoCoordinates = routeDeviation.currentLocation.originalLocation.coordinates
    if let currentMapMatchedLocation = routeDeviation.currentLocation.mapMatchedLocation {
        currentGeoCoordinates = currentMapMatchedLocation.coordinates
    }

    // Get last geographic coordinates on route.
    var lastGeoCoordinates: GeoCoordinates?
    if let lastLocationOnRoute = routeDeviation.lastLocationOnRoute {
        lastGeoCoordinates = lastLocationOnRoute.originalLocation.coordinates
        if let lastMapMatchedLocationOnRoute = lastLocationOnRoute.mapMatchedLocation {
            lastGeoCoordinates = lastMapMatchedLocationOnRoute.coordinates
        }
    } else {
        print("User was never following the route. So, we take the start of the route instead.")
        lastGeoCoordinates = route.sections.first?.departurePlace.originalCoordinates
    }

    guard let lastGeoCoordinatesOnRoute = lastGeoCoordinates else {
        print("No lastGeoCoordinatesOnRoute found. Should never happen.")
        return
    }

    let distanceInMeters = currentGeoCoordinates.distance(to: lastGeoCoordinatesOnRoute)
    print("RouteDeviation in meters is \(distanceInMeters)")

    // Now, an application needs to decide if the user has deviated far enough and
    // what should happen next: For example, you can notify the user or simply try to
    // calculate a new route. When you calculate a new route, you can, for example,
    // take the current location as new start and keep the destination - another
    // option could be to calculate a new route back to the lastMapMatchedLocationOnRoute.
    // At least, make sure to not calculate a new route every time you get a RouteDeviation
    // event as the route calculation happens asynchronously and takes also some time to
    // complete.
}

RouteProgressDelegateの内部では、渡されたRouteインスタンスのSectionごとの進行状況に関する詳細情報にアクセスできます。 ルートは、ウェイポイントおよびトランスポートモードの数に基づいて複数のセクションに分割できます。 remainingDistanceInMeters および trafficDelay はすでにセクションごとに累積されています。 SectionProgress 一覧表の最後の項目を確認して、目的地までの全体的な残り距離と全体的な推定交通遅延を取得します。

trafficDelayRoute データが計算された時刻に基づいているため 、ガイダンス中の交通障害による遅れは更新されません。 値は、初期データに基づいて進行中のセクションに沿ってのみ更新されます。 現在 のトラフィック状況に基づいて、最適化されたルートを定期的に要求するには、DynamicRoutingEngine を使用します。

内部 RouteProgressDelegate では、前方にある次の操作にアクセスすることもできます。 このために、次のものを使用します maneuverIndex

// Contains the progress for the next maneuver ahead and the next-next maneuvers, if any.
let nextManeuverList = routeProgress.maneuverProgress
guard let nextManeuverProgress = nextManeuverList.first else {
    print("No next maneuver available.")
    return
}

let nextManeuverIndex = nextManeuverProgress.maneuverIndex
guard let nextManeuver = visualNavigator.getManeuver(index: nextManeuverIndex) else {
    // Should never happen as we retrieved the next maneuver progress above.
    return
}

maneuver 取得した情報 visualNavigator を使用して、ドライバーが次のアクションや、このアクションが実行されるまでの距離などのその他の役立つ情報を表示するためのディスプレイを作成できます。 上記の例のようなデバッグ目的で使用されている場合を除き、テキスト表現には使用しないことをお勧めします。 代わりに音声ガイダンスを使用してください ( 以下を参照 ) 。

ただし、ローカライズされた道路名または番地 ( 高速道路番号など ) を表示すると便利です。これらの住所は、次のように取得できます。

func getRoadName(maneuver: Maneuver) -> String {
    let currentRoadTexts = maneuver.roadTexts
    let nextRoadTexts = maneuver.nextRoadTexts

    let currentRoadName = currentRoadTexts.names.defaultValue()
    let currentRoadNumber = currentRoadTexts.numbers.defaultValue()
    let nextRoadName = nextRoadTexts.names.defaultValue()
    let nextRoadNumber = nextRoadTexts.numbers.defaultValue()

    var roadName = nextRoadName == nil ? nextRoadNumber : nextRoadName

    // On highways, we want to show the highway number instead of a possible road name,
    // while for inner city and urban areas road names are preferred over road numbers.
    if maneuver.nextRoadType == RoadType.highway {
        roadName = nextRoadNumber == nil ? nextRoadName : nextRoadNumber
    }

    if maneuver.action == ManeuverAction.arrive {
        // We are approaching destination, so there's no next road.
        roadName = currentRoadName == nil ? currentRoadNumber : currentRoadName
    }

    // Nil happens only in rare cases, when also the fallback above is nil.
    return roadName ?? "unnamed road"
}

上に示すように、currentRoadTexts.names.defaultValue 経由でデフォルトの道路テキストを直接取得できます。 ほとんどの場合、この道路名はローカルの標識に示されている通りになります。

または、currentRoadTexts.names.preferredValue(for: [locale])経由で、優先言語のリストに基づいて道路名のローカライズされたテキストを取得 できます。 使用できる言語がない場合は、既定の言語が返されます。

RoadTextsDelegateを使用 して、現在運転中の状況RoadTexts(トラッキングモード中など)について通知を受け取ることができます。

デバイスの GPS センサーによって提供された位置が正確でない可能性があるため、 VisualNavigator は内部的に、 NavigableLocation 物体の一部として当社に提供されたマップマッチした場所を計算します。 この場所は、通りなどのナビゲーション可能な経路にあることが想定されています。 ただし、ユーザーが車を降りた場合や、 GPS 信号が弱すぎてマップマッチした場所を見つけることができない場合にも、軌道から外れてしまうことがあります。

マップマッチした場所を使用して、ユーザーに視覚的なフィードバックを提供することをお勧めします。 ユーザーがオフロードにいる場合など、位置情報を地図で照合できなかった場合にのみ、不一致にフォールバックすると便利 originalLocationです。 以下 VisualNavigator では、のレンダリング機能を使用して、マップ ビューを自動的に更新することを選択します。

Navigator または VisualNavigator から取得した場合、ナビゲーション中に Maneuver 説明テキスト(nextManeuver.text)はになります。 Route インスタンスから取得した場合にのみ、ローカライズされた命令が含まれます。 ManeuverAction 列挙型(enum)はナビゲーション中に視覚的なインジケータを表示するために使用され、テキストによる指示は、旅程を開始する前に操縦をプレビューするために、より多くのリストに入ることになっています。

反対に、nextManeuver.roadTextsnextManeuver.nextRoadTexts および nextManeuver.exitSignTexts は、ナビゲーション中のターンバイターン操作の一部として表示されることを意味します。したがって、これらの操作は、ManeuverNavigator または VisualNavigator から取得された場合にのみ空ではありません。 Route インスタンスから取得した場合、これらの属性は常に空になります。

高速道路などの一部の道路には名前がありません。 そのような場合は、道路番号の取得を試みることができます。 また、世界のどこかに名前のない道路がある可能性もあることにも注意してください。

次の表に、操作手順のプロパティの使用方法を示します。

操作手順のプロパティ
RoutingEngine Navigator / VisualNavigator
maneuver.text 空でない文字列を提供します。 空でない文字列を提供します。 出力例 text: "Detmolder Stra ß e を A100 方面に右折します。 "
maneuver.roadTexts 空の文字列を提供します。 空でない文字列を提供します。 出力例 roadTexts.names.defaultValue(): "Stadtring" 。
maneuver.nextRoadTexts 空の文字列を提供します。 空でない文字列を提供します。 出力例 nextRoadTexts.names.defaultValue(): "Halenseestra ß e"
Operation.exitSignTexts 空の文字列を提供します。 空でない文字列を提供します。 出力例 exitSignTexts.defaultValue(): " ハンブルク " 。

上記のイベントを自分でトリガーする必要はありません。 代わりに、 VisualNavigator は、ロケーションプロバイダの実装から取得されたものとして、提供された場所で反応します。

ルートの逸脱が検出された場合は、ユーザーを目的地にリルーティングするかどうかを distanceInMeters に基づいて決定できます。 フルルートの再計算では、同じルートパラメータを使用することがあります。 ルートに戻る方法の詳細については、次のセクションを参照してください。

上の例では、に含まれている座標に基づいて距離を計算します RouteDeviationdistanceInMeters。 この距離は、ルート上の予想される場所と実際の場所の間の直線距離です。 その距離が遠すぎると判断 visualNavigator された場合は、インスタンスへの新たに計算されたルートを設定できます。それ以降のすべてのイベントは、新しいルートに基づいて作成されます。

ドライブガイダンスのシナリオでは、 lastLocationOnRoutemapMatchedLocationnullの場合があることに注意してください。 routeDeviation.lastLocationOnRoutenullの場合 、ユーザーはルートを走行していませんでした。これは、開始位置が道路ネットワーク から離れている場合に発生することがあります。 通常、 Navigator/VisualNavigatorLocation の更新内容を道路と一致させようとします。 ドライバーが遠すぎると、その場所を見つけることができません。

イベントが非同期で配信されるため、古いルートについてはキュー内の以前のイベントが 1 回だけ配信されることがあります。 必要に応じて、新しいルートを設定した後で新しい代理を追加して、この問題を回避できます。

ナビゲーションサンプルアプリ に、偏差を検出する方法が示されています。

道路標識のイベントを聞きます

道に沿って多くの標識を見つけることができます。 運転中に、RoadSignWarningDelegateを設定することで、これらの標識に関する詳細な通知を受信できます。

結果の RoadSignWarning イベントには、RoadSignTypeRoadSignCategory などの情報を含むシールドに関する情報が含まれます。

デフォルトでは、イベントは他の警告と同じ距離のしきい値で開始されます。

  • 高速道路を利用する場合、約 2000 メートル先にイベントが発生します。
  • 田舎道では、約 1500 メートル先にイベントが発生します。
  • 都市部では、約 1000 メートル先にイベントが発生します。

RoadSignWarningOptions では、通知を受け取る標識のフィルタを設定できます。

優先道路標識の例をいくつか示します。

すべての道路標識が含まれているわけではありません。 RoadSignType はサポートされているすべてのタイプを一覧表示 たとえば 、制限速度 を示す道路標識は、専用のSpeedLimitDelegateで検知できるため、除外されます。

次のコード スニペット は、使用例を示しています。

private func setupRoadSignWarnings() {
    var roadSignWarningOptions = RoadSignWarningOptions()
    // Set a filter to get only shields relevant for trucks and heavyTrucks.
    roadSignWarningOptions.vehicleTypesFilter = [RoadSignVehicleType.trucks, RoadSignVehicleType.heavyTrucks]
    visualNavigator.roadSignWarningOptions = roadSignWarningOptions
}

...

// Conform to the RoadShieldsWarningDelegate.
// Notifies on road shields as they appear along the road.
func onRoadSignWarningUpdated(_ roadSignWarning: RoadSignWarning) {
    print("Road sign distance (m): \(roadSignWarning.distanceToRoadSignInMeters)")
    print("Road sign type: \(roadSignWarning.type.rawValue)")

    if let signValue = roadSignWarning.signValue {
        // Optional text as it is printed on the local road sign.
        print("Road sign text: " + signValue.text)
    }

    // For more road sign attributes, please check the API Reference.
}

RoadSignWarning イベントは次の 2 回正確に発行されます。

  • DistanceTypeAHEAD で、distanceToRoadSignInMeters が 0 より大きい場合。
  • DistanceTypePASSED 0 の場合 distanceToRoadSignInMeters

スピードカメラ、道路標識、現実的なビューなど、道路沿いの単一のオブジェクトについて通知する位置警告の場合、一度に発生するアクティブな警告は常に1つだけです。 これは、各 ahead イベントの後に常に passed イベントが続くことを意味し、1つのオブジェクトに対する2つの先行警告が同時にアクティブになることを回避します。

ルート偏差を処理します

上記のセクションで見たように、このイベント RouteDeviation を使用して、ドライバーが元ルートを離れたときに検出できます。 これは、たとえばドライバーが運転中に代替ルートやルート オプションについて以前に選択した内容を無視して、目的地まで別のルートを選択した場合など、偶然または意図的に発生する可能性があることに注意してください。

上記のように 、ドライバーの現在の位置からルート上の最後の既知の位置までの距離を検出できます。 その距離に基づいて、アプリケーションは、新しいルート全体を計算する時か、ルート代替およびルートオプションの選択を維持するためにユーザーを元のルートに誘導する時かを決定できます。

HERE SDKは ルートを自動的に再計算することはなく、偏差距離のみを記録するため、ルートに戻る方法に関するロジックはアプリ側で実装する必要があります。

ヒント: このイベントRouteDeviation は、新しいロケーションが更新されるたびに起動されます。 イベントの不必要な処理を避けるために、ドライバーがまだ逸脱しているかどうかを確認するために数秒待つことをお勧めします。 イベントが発生しなくなった場合は、ドライバーがルートに戻っていることを意味します。 ルート計算は非同期的に行われ、新しいルート計算を開始するタイミングと方法がアプリケーションによって決定されることに注意してください。 ただし、 Navigator または VisualNavigator インスタンスへのナビゲーション中にいつでも新しいルートを設定でき、今後のイベントは新しく設定された Route インスタンスに基づいて更新されます。

ユーザーがオフロードである場合もあることを言及する必要があります。 新しいルートを設定した後も、ユーザはまだオフロードにいる可能性があります。そのため、ユーザはまだルートをたどることができません。 このような場合でも、新しく設定されたルートの偏差イベントを受信し、 routeDeviation.lastLocationOnRoute は、nullになります。 ユーザーの現在の位置が変更されていない場合は、新しいルート計算を再開しないことをお勧めします。

HERE SDK には、ルートの逸脱を処理するための複数の API があります。

  1. 新しい、または更新した RouteOptions を使用して新しい代替ルートを提供するために、RoutingEngine を使用してルート全体を再計算します。 ユーザーの現在の位置を新しい開始点として使用する場合は、最初のWaypointの進行方向も指定してください 。
  2. このメソッドreturnToRoute() を使用して、最初に選択した代替ルートに到達するための新しいルートを計算します。 オンライン RoutingEngine およびOfflineRouteEngineで利用できます。 OfflineRouteEngine を使用して計算されたルート には、交通情報が含まれなくなっていることに注意してください。
  3. 元のルート上にある新しい出発地を使用して routingEngine.refreshRoute()で古いルートを更新し、必要に応じてルート オプションを更新します。RouteHandle は元のルートを識別する必要があります。 このオプションでは、逸脱した場所からルートに戻るパスは提供されないため、それ自体では、逸脱のユースケースには適していません。
  4. さらに、HERE SDKは、現在のトラフィック状況に基づいて最適化されたルートを定期的に要求できるDynamicRoutingEngineを提供します。 RouteHandleを必要とするため、オンラインで計算されたルートが必要です。 これは、ユーザーがまだルートをたどっている間に、より良いルートを見つけることを目的としています。 したがって、入力として現在の位置を必要としますが、偏差のユースケースには最適な選択ではない場合があります。

1 番めと 3 番めのオプションについては 、「ルーティング 」セクションで説明します。 元のルートを更新する 3 番目のオプションでは、逸脱した場所からルートに戻るパスは提供されません。 このため、以下では説明しません。 ただし、アプリケーションは、ルートから移動された部分を削除して、ユーザーが自分で新しい出発地点に到達できるようにするために使用できます。

逸脱した場所の距離や位置などのパラメータに基づいて、アプリケーションはドライバーに提供するオプションを決定する必要があります。

逸脱後のルートに戻る

RoutingEngine またはOfflineRoutingEngineを使用して、元のルートに戻るルートをオンラインまたはオフラインで計算 します。 この方法returnToRoute() は、最初に選択したルートを維持しながら、ドライバーができるだけ早くルートに戻るのを支援する場合に使用します。

returnToRoute() は、ルート逸脱を処理するための選択肢の1つにすぎません。 代替オプションについては、上記を参照してください。 たとえば、場合によっては、ユーザーの目的地までの新しいルート全体を計算することをお勧めします。

現在 、このフィーチャーreturnToRoute()はエンジンと同じトランスポートモードをサポート しています。、OfflineRoutingEngineおよびRoutingEngineの両方を使用できます。 RoutingEngineでメソッドを実行する場合 、パブリックトランジットルートのみがサポートされません。RoutingEngine の他のすべての利用可能なトランスポートモードがサポートされます。

このOfflineRoutingEngineメソッドのreturnToRoute()には、キャッシュ、またはすでにダウンロードされたマップ データが必要です。 ほとんどの場合、ドライバーがルートから逸脱している間に、元のルートに戻るパスがすでにキャッシュされている可能性があります。 ただし、逸脱が大きすぎる場合は、代わりに新しいルートを計算することを検討してください。

ルートの計算には、次のパラメータが必要です。

  • オリジナルのRouteNavigator / VisualNavigatorから入手できます。
  • で使用するに OfflineRoutingEngineは、ルートにすでに沿って移動したルートの正規化された割合も設定する必要があります。この割合は RouteDeviation 、次のイベントから利用できます。routeDeviation.fractionTraveled。 オンラインの RoutingEngine 場合、このパラメータは無視されます。 fractionTraveled このパラメータは、ルート上のドライバーの最後の既知の位置に基づいています。 ユーザーがルートを出発すると、「いいえ RouteProgress 」が配達されます。 この値は、 0 (進行状況なし) ~ 1 (宛先に到達)の値に正規化されます。 すでに走行したルートの一部は、ルート計算によって無視されます。
  • 新しい開始地点の Waypoint。ドライバーの現在のマップと一致する場所である可能性があります。

新しい出発地点は 、次のイベントRouteDeviation から取得できます。

// Get current geographic coordinates.
var currentGeoCoordinates = routeDeviation.currentLocation.originalLocation.coordinates
if let currentMapMatchedLocation = routeDeviation.currentLocation.mapMatchedLocation {
    currentGeoCoordinates = currentMapMatchedLocation.coordinates
}

// If too far away, consider to calculate a new route instead.
Waypoint newStartingPoint = Waypoint(currentGeoCoordinates)

オンラインRoutingEngine では 、完全に新しいルートが計算されることがあります。たとえば、ユーザーが以前に選択したルートの代替ルートよりも早く目的地に到達できる場合です。 OfflineRoutingEngine は 、ルートの非移動部分を誤って再利用します。

一般に、アルゴリズムは元のルートに戻る最速の方法を探しますが、宛先までの距離も考慮します。 新しいルートは、可能であれば元のルートの形状を保持しようとします。

まだ走行していないストップオーバー はスキップされません。 パススルーウェイポイントの場合、新しいルートでそれらのルートがまったく考慮される保証はありません。

任意で、ドライバーの見出し方向を設定することで、ルート計算を改善できます。

if currentMapMatchedLocation.bearingInDegrees != nil {
    newStartingPoint.headingInDegrees = currentMapMatchedLocation.bearingInDegrees
}

最後に、新しいルートを計算します。

routingEngine.returnToRoute(originalRoute,
                            startingPoint: newStartingPoint,
                            routeFractionTraveled: routeFractionTravelled) { (routingError, routes) in
        if (routingError == nil) {
            let newRoute = routes?.first
            // ...
        } else {
            // Handle error.
        }
}

CalculateRouteCompletionHandler が再利用されるため、ルートのリストが提供されます。 ただし、リストに含まれるルートは 1 つだけです。 エラー処理は、  RoutingEngineと同じロジックに従います。

オンラインおよびオフラインでの使用に関する一般的なガイドラインとして 、このフィーチャーreturnToRoute()は、その先にある originalRoute のすでに計算された部分を再利用しようとします。 トラフィックデータは、RoutingEngineが、オンラインで使用された場合にのみ更新され、反映されます。

作成された新しいルートも 、originalRouteで検出されたものと同じものOptimizationModeを使用します。

ただし、最良の結果を得る RoutingEngine には、オンラインを使用してトラフィックを最適化したルートを取得することをお勧めします。

より適切なルートを動的に検索

現在のトラフィック状況に基づいて、最適化されたルートを定期的に要求するには、DynamicRoutingEngine を使用します。 このエンジンは、走行中の現在のルートよりも速い( ETA に基づいて)新しいルートを検索します。

DynamicRoutingEngine には、オンライン接続と RouteHandleが必要です。 オフラインでより適切なルートを検索しようとした場合、または RouteHandleが有効になっていない 場合、ルーティングエラーが伝播されます。

// Enable route handle.
var carOptions = CarOptions()
carOptions.routeOptions.enableRouteHandle = true

DynamicRoutingEngineOptionsを設定すると 、より適切なルートで通知を受け取る前にminTimeDifferenceを定義できます。 は minTimeDifference 、現在設定されているルートの残りの ETA と比較されます。 で DynamicRoutingEngineOptions は、 pollInterval エンジンがより適切なルートを検索する頻度を決定するようにを設定することもできます。

private void createDynamicRoutingEngine() {
    DynamicRoutingEngineOptions dynamicRoutingOptions = new DynamicRoutingEngineOptions();
    // We want an update for each poll iteration, so we specify 0 difference.
    dynamicRoutingOptions.minTimeDifference = Duration.ofSeconds(0);
    dynamicRoutingOptions.minTimeDifferencePercentage = 0.0;
    dynamicRoutingOptions.pollInterval = Duration.ofMinutes(5);

    try {
        // With the dynamic routing engine you can poll the HERE backend services to search for routes with less traffic.
        // This can happen during guidance - or you can periodically update a route that is shown in a route planner.
        dynamicRoutingEngine = new DynamicRoutingEngine(dynamicRoutingOptions);
    } catch (InstantiationErrorException e) {
        throw new RuntimeException("Initialization of DynamicRoutingEngine failed: " + e.error.name());
    }
}

A を minTimeDifference 0 に設定すると、ルートが同じであってもイベントが取得されます。

より適切なルートを受信すると、元のルートとの差 route がメートルと秒で表示されます。

// Conform to the DynamicRoutingDelegate.
// Notifies on traffic-optimized routes that are considered better than the current route.
func onBetterRouteFound(newRoute: Route,
                        etaDifferenceInSeconds: Int32,
                        distanceDifferenceInMeters: Int32) {
    print("DynamicRoutingEngine: Calculated a new route.")
    print("DynamicRoutingEngine: etaDifferenceInSeconds: \(etaDifferenceInSeconds).")
    print("DynamicRoutingEngine: distanceDifferenceInMeters: \(distanceDifferenceInMeters).")

    // An implementation can decide to switch to the new route:
    // visualNavigator.route = newRoute
}

// Conform to the DynamicRoutingDelegate.
func onRoutingError(routingError: RoutingError) {
    print("Error while dynamically searching for a better route: \(routingError).")
}

提供され たetaDifferenceInSecondsdistanceDifferenceInMetersに基づい て、現在のルートと比較して、newRouteを使用するかどうかをアプリケーションが決定できます。 その場合は、いつでもVisualNavigator またはNavigatorに設定できます。

DynamicRoutingEngineは 交通情報および ETA を定期的に更新するために使用できますが 、新しいルートが異なるとは限りません。 さらに、 DynamicRoutingEngine はインフォームをオン distanceDifferenceInMeters にしますが、ルートの長さが変更されていない場合、ルートのシェイプが同じであるとは限りません。 ただし、 ETA のみが変更され、長さが同じ場合、交通状況の更新により ETA のみが更新された可能性があります。 元のルートにとどまることが重要な場合 routingEngine.refreshRoute()は、ルートシェイプの座標を比較するか、または独自のルートを計算することを検討する必要があります。 呼び出し refreshRoute()ても ルートの形状は変更されません。 反対 DynamicRoutingEngine に、の用途はより適切なルートを見つけることであり、そのためには新しいルート形状をたどり、交通の障害物を回避することが最も望ましいことに注意してください。 また、より適切なルートは、前方のルートに交通障害物が存在する(または存在しなくなった)場合にのみ発見できます。

ドライバーの最後のマップマッチングした場所 を更新し、 取得後すぐにDynamicRoutingEngine ( RouteProgress またはNavigableLocation更新の一部として ) に設定してください。 これは、より適切なルートが常にドライバーの現在の位置に近い位置から開始されるようにするために重要です。

dynamicRoutingEngine!.updateCurrentLocation(mapMatchedLocation: lastMapMatchedLocation,
                                           sectionIndex: routeProgress.sectionIndex)

lastMapMatchedLocationNavigableLocationListener および sectionIndexRouteProgressListener から取得できます 。 updateCurrentLocation() からイベントを受信する場合は、RouteProgressListenerを呼び出すことをお勧めします。

これの実装例について は、対応するナビゲーションの例アプリを参照してください。

ビジュアルナビゲータを使用してマップ ビューを更新

位置の更新に自分で対応するか、またはこの目的で VisualNavigator を使用できます。

通常、ナビゲーション中に次の操作を行います。

  • マップ上の現在の位置をトラッキングします。
  • 現在の方向を示す位置矢印を表示します。
  • マップを現在の方向に回転させます。
  • 操作矢印など、他の視覚的なアセットを追加します。

新しい位置情報イベントが発生するたびに、 VisualNavigator に送られた元の GPS 信号から計算されたマップマッチした場所を保持する新しい NavigableLocation が発生します。 このマップマッチした場所を使用してマップ ビューを更新できます。

ほとんどの場合、位置情報の更新は頻繁に行われますが、個別の手順で行われることに注意してください。つまり、各場所の間に数百メートルの距離がある可能性があります。 カメラを新しい場所に更新すると、少しジャンプすることがあります。

一方、VisualNavigatorのレンダリングフィーチャーを使用すると 、スムーズに補間された移動を利用できます。 ドライバーの速度に応じて、 2 つの位置更新の間の不足している座標が補間され、ターゲットマップの位置が自動的に更新されます。

さらに、は VisualNavigator マップを傾斜させ、マップを見出し方向に回転させて、 3D 位置の矢印とを表示 LocationIndicatorします。 これらはすべて、次の 1 行のコードでアクティブ化できます。

visualNavigator.startRendering(mapView: mapView)

スクリーンショット: デバイスで実行されているターン・バイ・ターンナビ (矢印ナビ)の例。

さらに、次のものを使用して、現在の場所のトラッキングを停止できます。

visualNavigator.cameraBehavior = nil

次のコマンドを使用して再度有効にします。

// Alternatively, use DynamicCameraBehavior to auto-zoom the camera during guidance.
visualNavigator.cameraBehavior = FixedCameraBehavior()

デフォルトでは、カメラトラッキングが有効になっています。 したがって、マップは常に現在の位置を中心に配置されます。 これを一時的に無効にすると、ユーザーが手動でパニングしたり、ナビゲーションまたは追従中にマップを操作したりできます。 3D の位置を示す矢印が移動し続けますが、マップは移動しません。 カメラトラッキングモードが再び有効になると、マップが現在の位置にジャンプし、位置情報の更新内容をスムーズにトラッキングできます。

進行中のナビゲーションを停止するには、 visualNavigator.route = nil 電話をかけ、上記の代理人を nil にリセットするか、または単に位置情報プロバイダ stop() を呼び出します。 詳細については 、以下のストップナビゲーションセクションを参照してください。

ソースコードの全文について は、対応するナビゲーションのサンプルアプリを確認してください。

ナビゲーションエクスペリエンスをカスタマイズします

NavigationCustom Example アプリで は、ナビゲーションが停止したときにカスタムLocationIndicatorおよび別のタイプに切り替える方法を示します。 また、ナビゲーションパースペクティブのカスタマイズ方法も示します。 GitHubでサンプルアプリを探します。

  • CameraBehavior は、ガイダンス中のマップ ビュー の外観をカスタマイズできます。 を使用して自動ズームの動作 DynamicCameraBehavior を設定でき FixedCameraBehavior ます。または、を使用して静的なチルトおよびズームの方向を設定できます。この方向は、プログラムで更新できます。 また、主点の変更などの他のオプションも使用できます。
  • ManeuverNotificationOptions では、 TTS 音声コマンドをいつ転送するかを指定できます。

マップ ビュー のカスタマイズオプションがさらに必要な場合 は、VisualNavigator の代わりに Navigator を使用することを検討してください。 ヘッドレスNavigatorであれば、同じ機能を利用できます。 ただし、デフォルトまたはカスタマイズ可能なレンダリングオプションはありません。その代わりに、マップ ビュー 全体を独自にレンダリングできます。たとえば、より大きなルートラインやその他の視覚的なカスタマイズを使用する場合は、 HERE SDK の一般的なレンダリング機能を使用できます。

Navigatorを使用している場合、スムーズなマップエクスペリエンスをレンダリングするには、マップビューの現在のターゲット位置を自分で更新する必要があります。 ロケーションプロバイダは、新しい位置情報の更新を個別の手順でのみ送信します。これは、高頻度で配達された場合でも、「ジャンプ」マップ ビュー につながります。 そのため、 InterpolatedLocationDelegate を使用して、VisualNavigatorと同じスムーズな位置更新を取得することをお勧めします。

ルートの飲食

デフォルト では、VisualNavigatorは異なる色でRouteをレンダリングし、現在の位置の背後にある移動パーツをユーザーののパーツから視覚的に分離します。 これは無効化またはカスタマイズできます。 既定では、 HERE Wego モバイルアプリケーションと同じ色が使用されます。

通過済みのルートの視覚化を無効にする場合は、次を呼び出してください。

visualNavigator.isRouteProgressVisible = false

デフォルト VisualNavigatorColors では、昼間モードと夜間モードが使用できます。 たとえば、日中に応じて色を切り替えることができます。 デフォルトの色は、次のようにカスタマイズできます。

private func customizeVisualNavigatorColors() {
    let routeAheadColor = UIColor.blue
    let routeBehindColor = UIColor.red
    let routeAheadOutlineColor = UIColor.yellow
    let routeBehindOutlineColor = UIColor.gray
    let maneuverArrowColor = UIColor.green

    let visualNavigatorColors = VisualNavigatorColors.dayColors()
    let routeProgressColors = RouteProgressColors(
        ahead: routeAheadColor,
        behind: routeBehindColor,
        outlineAhead: routeAheadOutlineColor,
        outlineBehind: routeBehindOutlineColor
    )

    // Sets the color used to draw maneuver arrows.
    visualNavigatorColors.maneuverArrowColor = maneuverArrowColor
    // Sets route color for a single transport mode. Other modes are kept using defaults.
    visualNavigatorColors.setRouteProgressColors(sectionTransportMode: SectionTransportMode.car, routeProgressColors: routeProgressColors)
    // Sets the adjusted colors for route progress and maneuver arrows based on the day color scheme.
    visualNavigator?.colors = visualNavigatorColors
}

これ により、パスに沿ってレンダリングされる操作矢印の色を変更して、次のターンを示すこともできます。

経由地イベントを受信します

VisualNavigator / Navigator classes は、より便利な通知を提供します。 次に、渡されたウェイポイントで通知を受け取る方法の例を示します。 目的地のウェイポイントでは、次の 2 つの方法で通知を受け取ることができます。

  • 以下の最初の代理人が目的地に到着したことを通知します。そのため、ナビゲーションを停止できます。
  • 一方、次の 2 番目のデリゲートは 、宛先経由地 を含むすべてのタイプの経由地 について通知を受け取る方法を示し ていますが、パススルー経由地 は含まれていません
// Conform to DestinationReachedDelegate.
// Notifies when the destination of the route is reached.
func onDestinationReached() {
    showMessage("Destination reached. Stopping turn-by-turn navigation.")
    stopNavigation()
}

// Conform to MilestoneStatusDelegate.
// Notifies when a waypoint on the route is reached or missed.
func onMilestoneStatusUpdated(milestone: Milestone, status: MilestoneStatus) {
    if milestone.waypointIndex != nil && status == MilestoneStatus.reached {
        print("A user-defined waypoint was reached, index of waypoint: \(String(describing: milestone.waypointIndex))")
        print("Original coordinates: \(String(describing: milestone.originalCoordinates))")
    } else if milestone.waypointIndex != nil && status == MilestoneStatus.missed {
        print("A user-defined waypoint was missed, index of waypoint: \(String(describing: milestone.waypointIndex))")
        print("Original coordinates: \(String(describing: milestone.originalCoordinates))")
    } else if milestone.waypointIndex == nil && status == MilestoneStatus.reached {
        // For example, when transport mode changes due to a ferry a system-defined waypoint may have been added.
        print("A system-defined waypoint was reached, index of waypoint: \(String(describing: milestone.mapMatchedCoordinates))")
    } else if milestone.waypointIndex == nil && status == MilestoneStatus.missed {
        // For example, when transport mode changes due to a ferry a system-defined waypoint may have been added.
        print("A system-defined waypoint was missed, index of waypoint: \(String(describing: milestone.mapMatchedCoordinates))")
    }
}

このメソッド onMilestoneStatusUpdated()は 、ルートに沿って渡された、または失われたウェイポイントに関する情報を含むインスタンスMilestoneを提供します。 ストップオーバー のウェイポイントのみが含まれています。 また、目的地のウェイポイントと、ユーザーが追加したその他のすべてのストップオーバーウェイポイントが含まれます。 さらに、 HERE SDK が追加したウェイポイントも含まれています。たとえば、フェリーを利用する必要がある場合などです。 ただし、旅程の出発地点である最初のウェイポイントは除外されます。 パス スルータイプのウェイポイント も除外されます。

Milestone には、ルートの計算時にユーザーが設定したウェイポイントリストを参照するインデックスが含まれています。 利用できない場合、 Milestoneは ルートの計算中に設定されたウェイポイントを参照します。たとえば、フェリーを利用する必要があることを示すために、ルーティングアルゴリズムによって追加のストップオーバーが含まれていた場合などです。

MilestoneStatus 列挙型 (enum) は、対応する Milestoneに達したか、または不在であったかを示します。

制限速度のイベントを受信します

SpeedLimitDelegate を実装すると 、道路で利用できる制限速度でイベントを受信できます。 これらは、ローカルの標識に示されている制限速度、および特定の気象条件にのみ有効な制限速度などの特殊な速度状況に関する警告になります。

条件付きとしてマークされている制限速度は、時間によって異なる場合があります。 たとえば、学校区の制限速度は、特定の時間帯にのみ有効です。 この場合、 HERE SDK はデバイスの時間を制限速度の時間範囲と比較します。 制限速度が現在有効な場合、イベントとして伝播されます。有効でない場合は、イベントとして伝播されません。

実装例については 、 GitHub にあるナビゲーションの例アプリ を参照してください。

// Conform to SpeedLimitDelegate.
// Notifies on the current speed limit valid on the current road.
func onSpeedLimitUpdated(_ speedLimit: SpeedLimit) {
    let speedLimit = getCurrentSpeedLimit(speedLimit)

    if speedLimit == nil {
        print("Warning: Speed limits unknown, data could not be retrieved.")
    } else if speedLimit == 0 {
        print("No speed limits on this road! Drive as fast as you feel safe ...")
    } else {
        print("Current speed limit (m/s): \(String(describing: speedLimit))")
    }
}

private func getCurrentSpeedLimit(_ speedLimit: SpeedLimit) -> Double? {
    // Note that all values can be nil if no data is available.

    // The regular speed limit if available. In case of unbounded speed limit, the value is zero.
    print("speedLimitInMetersPerSecond: \(String(describing: speedLimit.speedLimitInMetersPerSecond))")

    // A conditional school zone speed limit as indicated on the local road signs.
    print("schoolZoneSpeedLimitInMetersPerSecond: \(String(describing: speedLimit.schoolZoneSpeedLimitInMetersPerSecond))")

    // A conditional time-dependent speed limit as indicated on the local road signs.
    // It is in effect considering the current local time provided by the device's clock.
    print("timeDependentSpeedLimitInMetersPerSecond: \(String(describing: speedLimit.timeDependentSpeedLimitInMetersPerSecond))")

    // A conditional non-legal speed limit that recommends a lower speed,
    // for example, due to bad road conditions.
    print("advisorySpeedLimitInMetersPerSecond: \(String(describing: speedLimit.advisorySpeedLimitInMetersPerSecond))")

    // A weather-dependent speed limit as indicated on the local road signs.
    // The HERE SDK cannot detect the current weather condition, so a driver must decide
    // based on the situation if this speed limit applies.
    print("fogSpeedLimitInMetersPerSecond: \(String(describing: speedLimit.fogSpeedLimitInMetersPerSecond))")
    print("rainSpeedLimitInMetersPerSecond: \(String(describing: speedLimit.rainSpeedLimitInMetersPerSecond))")
    print("snowSpeedLimitInMetersPerSecond: \(String(describing: speedLimit.snowSpeedLimitInMetersPerSecond))")

    // For convenience, this returns the effective (lowest) speed limit between
    // - speedLimitInMetersPerSecond
    // - schoolZoneSpeedLimitInMetersPerSecond
    // - timeDependentSpeedLimitInMetersPerSecond
    return speedLimit.effectiveSpeedLimitInMetersPerSecond()
}

制限速度は、指定した転送モードによって異なります。 現在、HERE SDK では、各国の正規顧客車両規制(CVR)に基づいて、車両トラックの差別化を図っています。 つまり、上記 SpeedLimit のイベントはトラックの制限速度の低下を示している可能性があります。 たとえば、高速道路で は、制限速度はドイツで最大 80 km/時 になります。一方、車では、制限速度が 130 km/時 以上であることが示されている場合があります。 CVR の制限速度を取得するには、地図バージョン 32 以降を使用してください。 より低い地図バージョンでは、トラックは車と同じ制限速度を受け取ります。 MapUpdater 地図のバージョンは、ダウンロードされた地域がない場合でもで更新できます。ナビゲーションは、現在地図キャッシュに保存されているのと同じバージョンのマップ データ のみを要求するためです。 したがって、これはオンラインとオフラインでの使用の両方に適用されることに注意してください。

情報

トラックの場合は TruckSpecifications 、の内側も指定することをお勧め RouteOptionsします。 プロパティ grossWeightInKilograms および weightInKilograms は、トラックの制限速度に影響を与える可能性があります。 これらの値はルート計算に使用されるだけでなく、トラックの重量が 3.5 t を下回るか、または超えるかを判断するためにルートから内部的に取得されます ほとんどの国では、法的に許可されている制限速度に影響があります。 重量が設定されていない場合、法的に許容されているトラックの最高速度制限のみが転送されます。 HERE SDK は、トラックの重量が非常に少ないと想定します。

速度警告イベントを受信します

新しい制限速度イベント ( 上記を参照 ) を受信したときに、自分で制限速度を超過したことを検出できますが、アプリに速度警告フィーチャーを実装するのに役立つ、より便利なソリューションがあります。

これは、天候に応じた制限速度などの一時的な制限速度を超過した場合には警告しません。

onSpeedWarningStatusChanged() ドライバーが現在許可されている制限速度を超えるとただちに通知されます。 また、制限速度を超過した後、ドライバーが再び低速で走行しているときにも通知されます。

// Conform to SpeedWarningDelegate.
// Notifies when the current speed limit is exceeded.
func onSpeedWarningStatusChanged(_ status: SpeedWarningStatus) {
    if status == SpeedWarningStatus.speedLimitExceeded {
        // Driver is faster than current speed limit (plus an optional offset).
        // Play a notification sound to alert the driver.
        // Note that this may not include temporary special speed limits, see SpeedLimitDelegate.
        AudioServicesPlaySystemSound(SystemSoundID(1016))
    }

    if status == SpeedWarningStatus.speedLimitRestored {
        print("Driver is again slower than current speed limit (plus an optional offset).")
    }
}

onSpeedWarningStatusChanged() では、制限速度データが利用できない場合は通知されません。 この情報は NavigableLocation 、インスタンスの一部としてのみ使用できます。

SpeedWarningStatus が 通知されるのは、現在の速度を超過した場合、または再び復元された場合のみです。たとえば、ドライバーが頻繁に運転する速度が速すぎた場合、 1 つのイベントのみが通知されます。

onSpeedWarningStatusChanged() 現在の道路の制限速度およびドライバーの速度に応じて通知します。 つまり、ルートから独立して、速度警告イベントを追跡モードでも取得できます。 その結果 speedLimitRestored 、ルートが変更されたときに、再び低速走行した後でイベントを受け取ることができます。

オプションで、制限速度の値に追加されるオフセットを定義できます。 オフセットを含む制限速度を超過した場合にのみ、通知が送られます。 以下では、 2 つのオフセットを定義します。 1 つは、より低い方のオフセット、もう 1 つはより高速な制限のためのオフセットです。 境界は highSpeedBoundaryInMetersPerSecond次の要素で定義されます。

private func setupSpeedWarnings() {
    let speedLimitOffset = SpeedLimitOffset(lowSpeedOffsetInMetersPerSecond: 2,
                                            highSpeedOffsetInMetersPerSecond: 4,
                                            highSpeedBoundaryInMetersPerSecond: 25)
    visualNavigator.speedWarningOptions = SpeedWarningOptions(speedLimitOffset: speedLimitOffset)
}

ここでは、highSpeedBoundaryInMetersPerSecond を 25 m/s に設定しています。 制限速度の標識に 25 m/s を超える値が表示 されている場合、使用されているオフセットはhighSpeedOffsetInMetersPerSecondです。 25 m/s 未満の場合、使用されているオフセットは lowSpeedOffsetInMetersPerSecondです。

上で使用した値の例では、

  • 道路の制限速度が 27 m/s の場合、使用される(高速)オフセットは 4 m/s です これは、 31 m/s = 27 m/s + 4 m/s を超える速度で走行している場合にのみ警告通知を受け取ることを意味します highSpeedOffsetInMetersPerSecond 現在の制限速度がより大きいため、 highSpeedBoundaryInMetersPerSecondが使用されます。

  • 道路の制限速度が 20 m/s の場合、使用されている(低速)オフセットは 2 m/s です つまり、 22 m/s = 20 m/s + 2 m/s を超える速度で走行している場合にのみ、警告通知が送られます lowSpeedOffsetInMetersPerSecond 現在の制限速度がよりも小さいため、 highSpeedBoundaryInMetersPerSecondが使用されます。

負のオフセット値も設定できます。 これは、制限に達する前にバッファを用意して制限速度を超過しないようにする場合に役立ちます。 走行 速度が遅すぎる場合、例えば定義されているオフセットよりも遅い場合などは、前の速度警告が復元されない限り、通知を受け取ることはありません。

トラック 運転者の場合、トラッキングモードの場合は、navigator.trackingTransportProfile(vehicleProfile: vehicleProfile)を呼び出してtruck輸送モードなどを使用してVehicleProfile設定します。 デフォルト car では、が想定され、車両に有効な制限速度のみを受信します。車両に応じて重量などの他の車両プロパティを指定してください。 トラックドライバー は、ルートを計算する際に、RouteOptions内側TruckSpecificationsを指定することも考慮する必要があります。 ガイダンス中にルートをフォローすると、制限速度に影響が出ることがあります。 トラックの制限速度は、地域の顧客車両規制( CVR )に基づいて決定されます。 たとえば、日本では、トラックの重量が 8T を超える場合、または積載量が 5T を超える場合、または積載量が 11 名を超える場合にのみ、トラックと見なされます。 それ以外の場合、これらは「軽量トラック」と見なされ、同じ制限速度が車両に適用されます。

スピードカメライベントを受信します

NavigatorまたはVisualNavigatorSafetyCameraWarningDelegateを接続すると、ドライバーの速度を検知するカメラに通知するSafetyCameraWarningイベントについて通知を受け取ることができます。

ほとんどの国では、カメラは固定的にインストールされています。 HERE SDK は、カメラが現在アクティブかどうかを通知しません。

「スピードカメラ」とも呼ばれるセイフティカメラに関する通知を受け取ることは、国によっては利用できない場合があります。地域の法律および規制によります。 フランスなどの国では、スピードカメラの正確な位置情報は法律で禁止されています。 代わりに、政府のガイドラインを満たすためには、 ここでの通知の精度を下げることのみができます。 ただし、ほとんどの国では、正確な位置情報が許可されています。

現在、以下の国々がサポートされています。

スピードカメラのカバレッジ

  • アメリカ合衆国
  • イギリスのイギリスと北アイルランド
  • アラブ首長国連邦
  • トルコ
  • タイ
  • 台湾
  • スウェーデン
  • スペイン
  • 南アフリカ
  • スロベニア
  • スロバキア
  • シンガポール
  • セルビア
  • サウジアラビア
  • ロシア連邦
  • ルーマニア
  • カタール
  • ポルトガル
  • ポーランド
  • オマーン
  • ノルウェー
  • オランダ
  • メキシコ
  • マレーシア
  • マカオ
  • ルクセンブルグ
  • リトアニア
  • ラトビア
  • クウェート
  • カザフスタン
  • イタリア
  • イスラエル
  • マン島
  • アイスランド
  • ハンガリー
  • 香港
  • ギリシャ
  • フランス
  • フィンランド
  • エストニア
  • デンマーク
  • チェコ
  • キプロス
  • クロアチア
  • チリ
  • カナダ
  • ブルガリア
  • ブラジル
  • ボスニア・ヘルツェゴビナ
  • ベルギー
  • ベラルーシ
  • バーレーン
  • アゼルバイジャン
  • オーストリア
  • アルゼンチン
  • アンドラ

道路の属性を取得します

RoadAttributesDelegateを実装すると、道路属性でイベントを受信できます。 道路を走行中に属性が変更されると、イベントが開始されます。

// Conform to the RoadAttributesDelegate.
// Notifies on the attributes of the current road including usage and physical characteristics.
func onRoadAttributesUpdated(_ roadAttributes: RoadAttributes) {
    // This is called whenever any road attribute has changed.
    // If all attributes are unchanged, no new event is fired.
    // Note that a road can have more than one attribute at the same time.
    print("Received road attributes update.")

    if (roadAttributes.isBridge) {
      // Identifies a structure that allows a road, railway, or walkway to pass over another road, railway,
      // waterway, or valley serving map display and route guidance functionalities.
        print("Road attributes: This is a bridge.")
    }
    if (roadAttributes.isControlledAccess) {
      // Controlled access roads are roads with limited entrances and exits that allow uninterrupted
      // high-speed traffic flow.
        print("Road attributes: This is a controlled access road.")
    }
    if (roadAttributes.isDirtRoad) {
      // Indicates whether the navigable segment is paved.
        print("Road attributes: This is a dirt road.")
    }
    if (roadAttributes.isDividedRoad) {
      // Indicates if there is a physical structure or painted road marking intended to legally prohibit
      // left turns in right-side driving countries, right turns in left-side driving countries,
      // and U-turns at divided intersections or in the middle of divided segments.
        print("Road attributes: This is a divided road.")
    }
    if (roadAttributes.isNoThrough) {
      // Identifies a no through road.
        print("Road attributes: This is a no through road.")
    }
    if (roadAttributes.isPrivate) {
      // Private identifies roads that are not maintained by an organization responsible for maintenance of
      // public roads.
        print("Road attributes: This is a private road.")
    }
    if (roadAttributes.isRamp) {
      // Range is a ramp: connects roads that do not intersect at grade.
        print("Road attributes: This is a ramp.")
    }
    if (roadAttributes.isRightDrivingSide) {
      // Indicates if vehicles have to drive on the right-hand side of the road or the left-hand side.
      // For example, in New York it is always true and in London always false as the United Kingdom is
      // a left-hand driving country.
        print("Road attributes: isRightDrivingSide = \(roadAttributes.isRightDrivingSide)")
    }
    if (roadAttributes.isRoundabout) {
      // Indicates the presence of a roundabout.
        print("Road attributes: This is a roundabout.")
    }
    if (roadAttributes.isTollway) {
      // Identifies a road for which a fee must be paid to use the road.
        print("Road attributes change: This is a road with toll costs.")
    }
    if (roadAttributes.isTunnel) {
      // Identifies an enclosed (on all sides) passageway through or under an obstruction.
        print("Road attributes: This is a tunnel.")
    }
}

実装例について は、 GitHub にあるナビゲーションの例アプリを参照してください。

HERE SDK 自体は、このようなイベントには反応しませ roadAttributes.isTunnelん。 アプリケーションは isTunnel 、 true である限り夜間マップ スキーム に切り替えることを決定できます。 内部的には、 HERE SDK はトンネル補間アルゴリズムを使用してこの検出を提供しています。通常、 GPS 信号は非常に弱いか、トンネルにいる間に失われる可能性があります。

レーンアシスタンスを利用できます

HERE SDK は、ドライバーがルートの走行を助けるために車線変更を提供します。 「いいえ Route 」に設定されている場合、車線支援は提供されません。

ジャンクションに達する前に、 2 人の独立した受講者を設定して、次のイベントを取得できます ( 交差点およびロータリーを含む ) 。

  • ManeuverViewLaneAssistance: Lane ジャンクションが複雑と見なされているかどうかにかかわらず、ジャンクションで次のルート操作が行われた場合の推奨事項のリストを提供します。
  • JunctionViewLaneAssistance: Lane ジャンクションで操作が行われたかどうかにかかわらず、複雑なジャンクションでのみ推奨事項のリストを提供します。 このイベントは、非複合ジャンクションには配信されません

複合ジャンクションは次のように定義されます。

  • ジャンクションには少なくとも分岐があります。
  • ジャンクションには、現在のルートに沿っていない方向のレーンが少なくとも 2 つあります。

両方のイベントを同じジャンクションまたは異なるジャンクションに送信できます。 Lane インスタンスには、現在の道路で利用可能な車線、その方向のカテゴリ、車線が推奨されるかどうかなどの情報が含まれています。

どちらのイベントも、高速道路以外のジャンクションより 300 メートル先、高速道路のジャンクションより 1300 メートル先に発生します。 ただし、現在のところ、次の複合ジャンクションまでの距離は JunctionViewLaneAssistance イベントの一部として公開されていません。 ManeuverViewLaneAssistanceでは、 この距離は、RouteProgressイベント経由で利用できる次の操作までの距離の一部として利用できます。

各車線は、以下 LaneDirectionCategoryに保存されている複数の方向に進むことができます。

  • straight: 直進する車線。
  • slightlyLeft: 45 度前後にわずかに左に出る車線。
  • slightlyRight: 45 度前後にわずかに右に曲がる車線。
  • quiteLeft: 90 度前後にかなり左に出る車線。
  • quiteRight: 90 度前後の車線。
  • hardLeft: 135 度ほど左に曲がる車線。
  • hardRight: 135 度前後に急に曲がる車線。
  • uTurnLeft: 左に U ターンして 180 度曲がる車線。
  • uTurnRight: 右に U ターンして 180 度曲がる車線。

すべてのメンバーが 同時にtrue または false にできることに注意してください。 理論 的には、すべてのメンバーが車線がすべての複数の方向に導かれる場合にtrue になることがあります。 ただし、ほとんどの車線は 1 つまたは 2 つの方向につながっており、たとえば、車線が 2 つの別々の車線に分かれた場合、quiteLeftquiteRighttrue になります。

ドライバーに視覚的なフィードバックを提供するには、 9 つの方向ごとに 1 つの透明なイメージアセットを作成することをお勧めします。 各画像をオーバーレイとして使用し、複数の画像を 1 つの車線のピクトグラムに混合して、道路上の車線ごとに可能な道順を示すことができます。

最も重要なのは、車両がルートを走行している間に、どの車線を走行するかドライバーに知らせることができることです。 この情報はLane.recommendationStateに保存 され、推奨レーンの絵文字を強調表示することをお勧めします。

図 : 3 つのレーンがある道路で、左端の 2 つの道路が次の操作につながる可能性のある視覚化の例。

レーンアシスタンス情報 には、逆方向のレーンは含まれていません。代わりに、現在の走行方向のレーンのみが記述されています。 レーンのリストは、常に左端のレーン(インデックス 0 )から道路の右端のレーン(最後のインデックス)まで並べ替えられます。

このように、レーンアシスタンスは、左側および右側の両方の運転国で同じように機能します。

左側の運転国にいるかをroadAttributes.isRightDrivingSide で確認してください。 操縦指示およびその他の通知は、自動的に国に合わせて調整されます。 レーンアシスタンスの場合、国に関係なくコードは同じように機能します。レーンのリストは常に左からインデックス 0 から右に並べ替えられます。

ManeuverViewLaneAssistance イベントを受信した直後にイベントを表示することをお勧めします。 音声 ManeuverNotificationDelegate ガイダンスイベントを受信するために、イベントがと同期されます。

JunctionViewLaneAssistance イベントによって提供された車線情報は、別の UI エリアに表示することをお勧めします。これは、今後注意が必要な複雑な交差点があることを示しています。

ManeuverViewLaneAssistance を利用して、ジャンクションでの操縦について推奨される車線を取得できます

このイベントManeuverViewLaneAssistance では、操作が行われるジャンクションで推奨レーンが提供されます。 この操作は、 VisualNavigatorMapViewをレンダリングしているときに、マップ上で操作矢印によって表示されます。ジャンクションの場所は、RouteProgressイベントの一部として利用できる次のManeuverジャンクションから取得できます。

ManeuverViewLaneAssistance イベントは、ManeuverNotificationDelegateによって送信された対応する操作音声通知と同期されます。 これは、ほとんどの道路で、交差点までの距離で次の操作を説明する操作音声通知テキストと同じ頻度で、イベントが同時に到着することを意味します。 以下で説明するように、このイベントは、 TTS エンジンが操作メッセージをドライバーに伝えるために使用できます。

上記の他のイベントと同様に、NavigatorまたはVisualNavigatorManeuverViewLaneAssistanceDelegateを添付できます。 結果 ManeuverViewLaneAssistance のオブジェクトには、現在の道路で利用可能な車線に関する情報と、その道順などの情報が含まれます。

次のコード スニペットは、どのレーンを取得するかについての情報を取得する方法を示しています。

// Conform to the ManeuverViewLaneAssistanceDelegate.
// Notifies which lane(s) lead to the next (next) maneuvers.
func onLaneAssistanceUpdated(_ laneAssistance: ManeuverViewLaneAssistance) {
    // This lane list is guaranteed to be non-empty.
    let lanes = laneAssistance.lanesForNextManeuver
    logLaneRecommendations(lanes)

    let nextLanes = laneAssistance.lanesForNextNextManeuver
    if !nextLanes.isEmpty {
        print("Attention, the next next maneuver is very close.")
        print("Please take the following lane(s) after the next maneuver: ")
        logLaneRecommendations(nextLanes)
    }
}

private func logLaneRecommendations(_ lanes: [Lane]) {
    // The lane at index 0 is the leftmost lane adjacent to the middle of the road.
    // The lane at the last index is the rightmost lane.
    var laneNumber = 0
    for lane in lanes {
        // This state is only possible if laneAssistance.lanesForNextNextManeuver is not empty.
        // For example, when two lanes go left, this lanes leads only to the next maneuver,
        // but not to the maneuver after the next maneuver, while the highly recommended lane also leads
        // to this next next maneuver.
        if lane.recommendationState == .recommended {
            print("Lane \(laneNumber) leads to next maneuver, but not to the next next maneuver.")
        }

        // If laneAssistance.lanesForNextNextManeuver is not empty, this lane leads also to the
        // maneuver after the next maneuver.
        if lane.recommendationState == .highlyRecommended {
            print("Lane \(laneNumber) leads to next maneuver and eventually to the next next maneuver.")
        }

        if lane.recommendationState == .notRecommended {
            print("Do not take lane \(laneNumber) to follow the route.")
        }

        laneNumber += 1
    }
}

laneAssistance.lanesForNextNextManeuverは、通常空のリストですが、 2 つの操作が非常に近い場合があります。 このような場合、このリストには、現在の操作状況に達した直後に車線が取得する情報が保持されます。

次の操作に達するまで、車線に関する情報が有効になります。 次の操作に到達するか、または新しい ManeuverViewLaneAssistance イベントに含まれている情報に置き換えられたら、非表示にする必要があります。

// See above code snippet for the RouteProgressDelegate.
if previousManeuverIndex != nextManeuverIndex {
    // A new maneuver: Remove stale lane assistance info.
}

上記のコードRouteProgressDelegate を参照 すると、nextManeuverIndexの入手方法を確認できます。この方法では、新しい操作を行う必要があることが示されます。

JunctionViewLaneAssistance で、複合ジャンクションのレーンに関する推奨事項を入手できます

HERE SDK は、ManeuverViewLaneAssistance(上記を参照)に加えて、ジャンクションで実際に操作が行われていない場合でも、複雑なジャンクションで利用可能なレーンについて通知するイベント JunctionViewLaneAssistance を提供します。 これらの通知は ManeuverViewLaneAssistanceと並行して動作しますが 複雑 なジャンクションに達する前にのみ発生します ( 上記を参照 ) 。

ManeuverViewLaneAssistanceと比較して、このJunctionViewLaneAssistanceイベントでは、複雑なジャンクションを安全に通過するためにより多くのレーンを推奨できますが、ジャンクションを通過した後、これらのレーンのすべてが次の操作につながるわけではありません。

ManeuverViewLaneAssistanceとは異なり 、ジャンクションが渡されたタイミングを検出するには、リストが空かどうかを確認します。

// Conform to the JunctionViewLaneAssistanceDelegate.
// Notfies which lane(s) lead to the next maneuvers at complex junctions.
func onLaneAssistanceUpdated(_ laneAssistance: JunctionViewLaneAssistance) {
    let lanes = laneAssistance.lanesForNextJunction        
    if (lanes.isEmpty) {
      print("You have passed the complex junction.")
    } else {
      print("Attention, a complex junction is ahead.")
      logLaneRecommendations(lanes)
    }
}

複合ジャンクションを通過したら、アプリ の UI を更新して車線情報を削除することをお勧めします。 JunctionViewLaneAssistance イベントは、複雑な交差点でどの車線を走行するかを示す追加のヒントと見なすことができます。特に、このような交差点で操縦が行われない場合は、この情報は ManeuverViewLaneAssistanceイベントに含まれていないためです。

ルートがない場合、車線変更に関連するイベントは発生しませんので、ご注意ください。

標識や交差点表示のリアルなビューを取得できます

RealisticViewWarningDelegate では、道路標識および複合交差点ビューの SVG 文字列データを 3D で受信できます。このイベントRealisticViewWarning には、標識と交差点のビュー、両方の SVG データが含まれています。 この警告は 、複雑 なジャンクションにのみ表示されます(上記を参照)。

private func setupRealisticViewWarnings() {
    let realisticViewWarningOptions = RealisticViewWarningOptions(aspectRatio: AspectRatio.aspectRatio3X4, darkTheme: false)
    visualNavigator.realisticViewWarningOptions = realisticViewWarningOptions

    visualNavigator.realisticViewWarningDelegate = self
}

// Notifies on signposts together with complex junction views.
// Signposts are shown as they appear along a road on a shield to indicate the upcoming directions and
// destinations, such as cities or road names.
// Junction views appear as a 3D visualization (as a static image) to help the driver to orientate.
//
// Optionally, you can use a feature-configuration to preload the assets as part of a Region.
//
// The event matches the notification for complex junctions, see JunctionViewLaneAssistance.
// Note that the SVG data for junction view is composed out of several 3D elements,
// a horizon and the actual junction geometry.
func onRealisticViewWarningUpdated(_ realisticViewWarning: RealisticViewWarning) {
    let distance = realisticViewWarning.distanceToRealisticViewInMeters
    let distanceType: DistanceType = realisticViewWarning.distanceType

    // Note that DistanceType.reached is not used for Signposts and junction views
    // as a junction is identified through a location instead of an area.
    if distanceType == DistanceType.ahead {
        print("A RealisticView ahead in: " + String(distance) + " meters.")
    } else if distanceType == DistanceType.passed {
        print("A RealisticView just passed.")
    }

    let realisticView = realisticViewWarning.realisticView
    let signpostSvgImageContent = realisticView.signpostSvgImageContent
    let junctionViewSvgImageContent = realisticView.junctionViewSvgImageContent
    // The resolution-independent SVG data can now be used in an application to visualize the image.
    // Use a SVG library of your choice to create an SVG image out of the SVG string.
    // Both SVGs contain the same dimension and the signpostSvgImageContent should be shown on top of
    // the junctionViewSvgImageContent.
    // The images can be quite detailed, therefore it is recommended to show them on a secondary display
    // in full size.
    print("signpostSvgImage: \(signpostSvgImageContent)")
    print("junctionViewSvgImage: \(junctionViewSvgImageContent)")
}

realisticView.signpostSvgImageContentは 、realisticView.junctionViewSvgImageContentの上にオーバーレイすることを目的 としています。 両方の画像を同じ縦横比でリクエストできます。 このようにすると、両方の画像のサイズが同じになり、左上の同じ位置にレンダリングできます。

スクリーンショット : 標識の画像でオーバーレイされた交差点表示。

HERE SDK は SVG を文字列としてのみ提供 するので、サードパーティのライブラリ を使用して、 SvgView などの SVG 文字列の内容をレンダリングする必要があります。

ジャンクションビューのデータは約 2 MB のみを占有するように最適化され、署名後のデータはわずか数 KB しか占有しません。 ただし、利用可能 なフィーチャー設定 を使用して、事前にイメージデータをプリロードすることをお勧め します。詳細については、最適化ガイドを参照してください。

16:9の解像度は横向きの形式で使用できますが、縦向きモードでも使用して、全画面表示ができないようにすることができます。 ただし、SVGアセットは非常に詳細なので、セカンダリディスプレイでフルスクリーンで表示することをお勧めします。

スピードカメラ、道路標識、現実的なビューなど、道路沿いの単一のオブジェクトについて通知する位置警告の場合、一度に発生するアクティブな警告は常に1つだけです。 これは、各 ahead イベントの後に常に passed イベントが続くことを意味し、1つのオブジェクトに対する2つの先行警告が同時にアクティブになることを回避します。

ナビゲーションの例GitHub のアプリ を参照して、使用例を確認してください。

このフィーチャーRealisticView はベータリリースとしてリリースされているため、いくつかのバグや予期しない動作が発生する可能性があります。 非推奨プロセスなしで新しいリリースでは、関連するAPIが変更される可能性があります。

トラック案内

HERE SDK は、さまざまな機能を備えたプレミアムトラックの取り回しおよびガイダンスをサポートしています。 たとえば、ナビゲーション中にデリゲートを添付して、狭いトンネルなど、トラックの前方の制限について通知を受け取ることができます。 他にも、大型トラックや、トラックの重量が道路の許容重量を超える道路を通過するのに十分な高さではない橋が制限されることがあります。

次のコード スニペットを参照してください。

// Conform to the TruckRestrictionsWarningDelegate.
// Notifies truck drivers on road restrictions ahead.
func onTruckRestrictionsWarningUpdated(_ restrictions: [TruckRestrictionWarning]) {
    // The list is guaranteed to be non-empty.
    for truckRestrictionWarning in restrictions {
        if truckRestrictionWarning.distanceType == DistanceType.ahead {
            print("TruckRestrictionWarning ahead in \(truckRestrictionWarning.distanceInMeters) meters.")
        } else if truckRestrictionWarning.distanceType == DistanceType.reached {
            print("A restriction has been reached.")
        } else if truckRestrictionWarning.distanceType == DistanceType.passed {
            // If not preceded by a "reached"-notification, this restriction was valid only for the passed location.
            print("A restriction was just passed.")
        }

        // One of the following restrictions applies, if more restrictions apply at the same time,
        // they are part of another TruckRestrictionWarning element contained in the list.
        if truckRestrictionWarning.weightRestriction != nil {
            let type = truckRestrictionWarning.weightRestriction!.type
            let value = truckRestrictionWarning.weightRestriction!.valueInKilograms
            print("TruckRestriction for weight (kg): \(type): \(value)")
        } else if truckRestrictionWarning.dimensionRestriction != nil {
            // Can be either a length, width or height restriction of the truck. For example, a height
            // restriction can apply for a tunnel. Other possible restrictions are delivered in
            // separate TruckRestrictionWarning objects contained in the list, if any.
            let type = truckRestrictionWarning.dimensionRestriction!.type
            let value = truckRestrictionWarning.dimensionRestriction!.valueInCentimeters
            print("TruckRestriction for dimension: \(type): \(value)")
        } else {
            print("TruckRestriction: General restriction - no trucks allowed.")
        }
    }
}

DistanceType.reachedは 、トラックの制限に達したことを通知します。 制限が渡されると、イベントの後にpassedが渡されます。 制限に長さがない場合、 reached はスキップ され、イベントreached のみが送信されます。 ahead イベントは常に最初に送信されます。

すべての制限がない場合は、一般的なトラックの制限が適用されます。 制限のタイプは、TruckRestrictionWarningTypeからも参照 できます。

一部の制限事項は 、道路の一方の方向にのみ有効であることに注意してください。

nullルート または 新しいルートを設定してガイダンスを停止すると 、ahead通知で発行された制限は、保留中の制限警告をクリアするための passedイベントが即座に発生します。ルートを追従中 - ルートにないすべての制限がフィルタリングされますが、ドライバーがルートから十分に離れた( 15 メートルを超える)とただちに、現在の道路で前方にサポートされている制限が適用され、再び制限警告が表示されます。

トラックの制限に関する通知しきい値は、他のバーナーとは若干異なります。

  • 都市部 ahead では、イベントは 1000 m 先ではなく、 500 m 先に送信されます。
  • 田舎道では、イベントは 750 m 先に送られます ( 先に 1500 m 進むのではなく ) 。
  • 高速道路では、イベントは 1500 m 先に送られます ( 前方は 2000 m ではありません ) 。

このイベントTruckRestrictionWarning は、前方の道路網のマップ データに基づいています。 現在設定されている内容にかかわらず、制限が適用 TransportModeされます。

ルートを計算するとき に、次TruckSpecificationsを含むTruckOptions を指定でき ます。 これは結果Routeに影響を与える可能性があります。 ただし 、TruckRestrictionWarningイベントには影響しません。 先方のマップ データで検出されたほとんどの制限事項が転送されます。 そのため、現在の車両に関連しない制限警告をアプリケーションがフィルタリングすることは理にかなっている場合があります。 このイベントでは、トラッキングするルートがない場合にもトラッキングモードでイベントが配信されます。

トラックルートの詳細については 、「ルーティング 」セクションを参照してください。 たとえば、トラック専用のルートの計算方法を見つけることができます。 一般に、ルートに Truck 輸送タイプが含まれている場合、トラック用に最適化されます。

さらに、いくつかの回避オプションを指定して、たとえば特定の都市部を除外できます。 これはすべて、ルートが計算され てNavigatorまたは、VisualNavigatorに渡される前に指定できます。

以下のフィーチャーについても説明します。

  • トラックの寸法などの車両の制限を指定したり、トラックが危険物を運搬している場合に、TruckSpecificationsおよびHazardousGoodリストを含むことができるように指定できます。 TruckOptionsこの情報を使用して、トラックルートを形成できます。 トラックの制限事項について通知を受け取るに TruckRestrictionWarning は、上記のようにイベントを聴いてください。
  • RoadAttributes前述のように特定の音声を聞くことができます。
  • 輸送モードがtruckに設定 されている場合、SpeedLimitイベントは顧客車両の規制( CVR )制限速度が車両よりも低くなっている可能性があることを示します。 ルートを計算するときは、RouteOptions内部TruckSpecificationsも指定することを検討してください。 トラッキングモードの場合 は、navigator.trackingTransportProfile(vehicleProfile: vehicleProfile)を呼び出して、truck転送モードでVehicleProfileを設定します。 デフォルトでは、トラッキングの car 場合、次のことが想定されます。 あなたのトラックに従って重量のような他の車の特性を指定することを確かめなさい。
  • 特に grossWeightInKilogramsweightInKilograms は、ルートの制限、到着予定時刻に影響があるだけでなく、CVR の制限速度にも影響があります。 適切に設定しないと TruckSpecifications、ルートおよび通知が適切でない可能性があります。
  • AvoidanceOptionsを使用して、排出ゾーンを除外して、良識ある都心部の空気を汚染しないようにすることができます。この機能を使用 すると、特定の類似RoadFeaturesのトンネルを回避することもできます。 これらはTruckOptions経由で設定でき、ルート計算から除外されます。
  • マップにスピードカメラのアイコンを表示するマップ レイヤースキームを有効にできます:MapScene.Layers.safetyCameras。注 : このレイヤーは車にも適しています。
  • トラック固有の情報をマップに表示するように最適化されたマップ レイヤー スキームを有効にできます:MapScene.Layers.vehicleRestrictions。 たとえば、 影響を受ける道路上でアクティブおよび 非アクティブな制限を紫色の線で強調表示するための いくつかのMapFeatureModesが提供されます。灰色の線または灰色のアイコンは、制限が非アクティブであることを示します。 道路がこのような紫の線を横切っており、その道路自体が紫で示されていない場合、この制限は現在の道路には適用されません。 アイコンが正確な場所を示すとは限りません。 たとえば、制限された道路の場合、アイコンが制限された道路の中央に配置されます。または、制限がより長い場合は、 1 つ以上の道路に沿って同じ制限についてアイコンを複数回繰り返すことができます。 アイコン自体は国ごとにローカライズされ、制限のタイプを表します。 ほとんどの制限では、制限の場所と種類も TruckRestrictionWarning イベントによって示されます ( 上図を参照 ) 。

MapScene.Layers.vehicleRestrictions

位置情報プロバイダを実装します

Location インスタンスを提供するには、ロケーションプロバイダが必要 VisualNavigatorです。 任意のソースから位置データをフィードできます。 HERE では、デバイスからのネイティブの位置データ テストドライブのシミュレートされた位置データを切り替えることができる実装を使用する予定です。

すでに説明したように、 VisualNavigatorLocationDelegate プロトコルに準拠しているため、呼び出した onLocationUpdated(location:) クラスのデリゲートとして使用できます。

位置情報データのソースとして、「 位置情報を検索 」セクションに示されているコードに基づいたHEREPositioningProviderを使用します。

ナビゲーションでは LocationAccuracy.navigationLocationEngine ターン・バイ・ターンナビ (矢印ナビ)中に最良の結果が保証されるように、の開始時にを使用することをお勧めします。

イベントを配信するには、herePositioningProviderを開始する必要があります 。

herePositioningProvider.startLocating(locationDelegate: visualNavigator,
                                      accuracy: .navigation)

必要な HERE SDKの Location タイプには、ベアリングおよび速度情報、現在の地理座標、 VisualNavigatorによって消費されるその他の情報が含まれます。 提供されたデータの正確性と完全性が高いほど、ナビゲーション全体の操作性がより正確になります。

Locationオブジェクトから取得されたbearing値によって 移動の方向が決まり 、 その方向に回転するLocationIndicatorアセットによって示されます。 ユーザーが移動していない場合、新しいベアリング値が設定されるまで最後のローテーション値が保持されます。 Location データのソースに応じて、この値の精度を増減できます。

内部的には 、Locationtimestamp が使用され、ユーザーがトンネルを通過しているか、または信号が単に失われたかなどを評価します。

GitHub で、ロケーションプロバイダのリファレンス実装を見つける ことができます。

位置シミュレータを設定します

開発中に、テスト目的でルート上で予想される進行状況を再生すると便利な場合があります。 は LocationSimulator 、元のルート座標から取得された連続的な位置情報を提供します。

以下では、 LocationSimulator を代替プロバイダとして統合し、実際の位置情報の更新とシミュレートされた位置情報の切り替えを可能にしています。

import heresdk

// A class that provides simulated location updates along a given route.
// The frequency of the provided updates can be set via LocationSimulatorOptions.
class HEREPositioningSimulator {

    private var locationSimulator: LocationSimulator?

    func startLocating(locationDelegate: LocationDelegate, route: Route) {
        if let locationSimulator = locationSimulator {
            locationSimulator.stop()
        }

        locationSimulator = createLocationSimulator(locationDelegate: locationDelegate, route: route)
        locationSimulator!.start()
    }

    func stopLocating() {
        if locationSimulator != nil {
            locationSimulator!.stop()
            locationSimulator = nil
        }
    }

    // Provides fake GPS signals based on the route geometry.
    private func createLocationSimulator(locationDelegate: LocationDelegate,
                                         route: Route) -> LocationSimulator {
        let notificationIntervalInSeconds: TimeInterval = 0.5
        let locationSimulatorOptions = LocationSimulatorOptions(speedFactor: 2,
                                                                notificationInterval: notificationIntervalInSeconds)
        let locationSimulator: LocationSimulator

        do {
            try locationSimulator = LocationSimulator(route: route,
                                                      options: locationSimulatorOptions)
        } catch let instantiationError {
            fatalError("Failed to initialize LocationSimulator. Cause: \(instantiationError)")
        }

        locationSimulator.delegate = locationDelegate
        locationSimulator.start()

        return locationSimulator
    }
}

また、LocationSimulatorOptionsを設定することで 、現在のシミュレート位置の移動速度を指定することができます。 デフォルトでは 、notificationInterval は1で、speedFactorは 1.0です。これは、トラフィック関連の制約を考慮せずに、ユーザが通常運転または各ルートセグメントを歩く平均速度に等しくなります。 デフォルトの速度は、道路形状、道路状況、その他の統計データによって異なる場合がありますが、現在の制限速度を超えることはありません。 値が1.0を超えると、速度が比例して増加します。 ルートに指定した時間間隔で十分な座標が含まれていない場合は、によって追加のロケーションイベントが補間 VisualNavigatorされます。

LocationSimulatorによって放出される位置は 補間されず、ソースに基づいて提供されます。 の場合 Route、ルート形状の座標が使用されます(互いに非常に近い)。 の場合 GPXTrack、座標はGPXデータに基づいて出力されます。 たとえば、2つの座標の間に100メートルのメートルがある場合、それらの2つの座標だけが時間設定に基づいて放出されます。 ただし、に入力すると VisualNavigator、レンダリングされたマップアニメーションはによって補間 VisualNavigatorされます。

VisualNavigator 連続 Location する更新間の距離が 100 m を超える場合、はアニメーションをスキップします が speedFactor 増加すると、ロケーションの更新間隔も変化します。通知間隔が適切に調整されていない場合は、次のようになります。 たとえば、速度係数を 8 に変更する場合は、 Location 通知間隔を 125 ms (1000 ms/8) に変更して、更新間の距離を一貫したものにする必要があります。 notificationInterval および speedFactor は反比例します。 したがって、 A speedFactor が 3 の場合、 330 notificationInterval ms を推奨します。

次のコードは 、 enableRoutePlayback(route:)enableDevicePositioning()を呼び出して、シミュレートされた場所実際の場所をシームレスに切り替える方法を示し ています。

// Provides location updates based on the given route.
func enableRoutePlayback(route: Route) {
    herePositioningProvider.stopLocating()
    herePositioningSimulator.startLocating(locationDelegate: visualNavigator, route: route)
}

// Provides location updates based on the device's GPS sensor.
func enableDevicePositioning() {
    herePositioningSimulator.stopLocating()
    herePositioningProvider.startLocating(locationDelegate: visualNavigator,
                                          accuracy: .navigation)
}

新しいシミュレーションまたは実ロケーションソースを開始する前に、進行中のシミュレーションまたは実ロケーションソースを必ず停止する必要があります。

GitHub のナビゲーションサンプルアプリに含ま れている上記のコードを確認できます。

音声ガイダンス

運転中は、ユーザーの注意をルートに集中させる必要があります。 提供されている操作データから視覚的な表現を作成できますが ( 上記を参照 ) 、ターンバイターンガイダンス中に話すことを目的としたローカライズされたテキスト表現を取得することもできます。 これらの操作手順の通知Stringとして提供されるため 、任意の TTS ソリューションと一緒に使用できます。

操作の通知はドライバーを対象としています。 歩行者の案内には使用しないことをお勧めします。

通知の例を次に示します。

Voice message: After 1 kilometer turn left onto North Blaney Avenue.
Voice message: Now turn left.
Voice message: After 1 kilometer turn right onto Forest Avenue.
Voice message: Now turn right.
Voice message: After 400 meters turn right onto Park Avenue.
Voice message: Now turn right.

これらの通知を取得するには ManeuverNotificationDelegate、を設定します。

visualNavigator.maneuverNotificationDelegate = self

...

// Conform to ManeuverNotificationDelegate.
// Notifies on voice maneuver messages.
func onManeuverNotification(_ text: String) {
    voiceAssistant.speak(message: text)
}

HERE では、 VoiceAssistant 音声合成エンジンをラップして操作の通知を読み上げるというヘルパークラスを使用しています。 このエンジンはアップル AVSpeechSynthesizer のクラスを使用しています。 必要に 応じて、このクラスを GitHubナビゲーションサンプルアプリの一部として見つけることができます。

オプションで 、ナチュラルガイダンスを有効にすることもできます。 ManeuverNotification テキストは、ルートに沿って重要なオブジェクト(信号機や停止標識など)を含めるように拡張して、操作をより理解しやすくすることができます。 例: "次 の信号で 左折してウォールストリートに入ります。" デフォルトでは、このフィーチャーは無効になっています。 これを有効にするには、 includedNaturalGuidanceTypesのリストを介して ManeuverNotificationOptionstrafficLightなどの NaturalGuidanceType を少なくとも 1 つ追加します。

LanguageCode 通知テキストをローカライズするようにを設定し、 UnitSystemメートル法 または ヤードポンド法 の長さの単位を決定するようにを設定できます。 ルートを設定する前に、必ずこの番号を呼び出してください。そうしないと、デフォルトの設定 (en-US,metric) が使用されます。 詳細については ManeuverNotificationOptions、 API リファレンス を参照してください。

private func setupVoiceGuidance() {
    let ttsLanguageCode = getLanguageCodeForDevice(supportedVoiceSkins: VisualNavigator.availableLanguagesForManeuverNotifications())
    visualNavigator.maneuverNotificationOptions = ManeuverNotificationOptions(language: ttsLanguageCode,
                                                                              unitSystem: UnitSystem.metric)

    // Set language to our TextToSpeech engine.
    let locale = LanguageCodeConverter.getLocale(languageCode: ttsLanguageCode)
    if voiceAssistant.setLanguage(locale: locale) {
        print("TextToSpeech engine uses this language: \(locale)")
    } else {
        print("TextToSpeech engine does not support this language: \(locale)")
    }
}

この例では、デバイスの希望する言語設定を使用します。 以下に、これらの情報を取得する 1 つの方法を示します。

private func getLanguageCodeForDevice(supportedVoiceSkins: [heresdk.LanguageCode]) -> LanguageCode {

    // 1. Determine if preferred device language is supported by our TextToSpeech engine.
    let identifierForCurrenDevice = Locale.preferredLanguages.first!
    var localeForCurrenDevice = Locale(identifier: identifierForCurrenDevice)
    if !voiceAssistant.isLanguageAvailable(identifier: identifierForCurrenDevice) {
        print("TextToSpeech engine does not support: \(identifierForCurrenDevice), falling back to en-US.")
        localeForCurrenDevice = Locale(identifier: "en-US")
    }

    // 2. Determine supported voice skins from HERE SDK.
    var languageCodeForCurrenDevice = LanguageCodeConverter.getLanguageCode(locale: localeForCurrenDevice)
    if !supportedVoiceSkins.contains(languageCodeForCurrenDevice) {
        print("No voice skins available for \(languageCodeForCurrenDevice), falling back to enUs.")
        languageCodeForCurrenDevice = LanguageCode.enUs
    }

    return languageCodeForCurrenDevice
}

HERE SDK は 37 言語をサポートしています。 VisualNavigator を使用して、から言語を照会でき VisualNavigator.availableLanguagesForManeuverNotifications()ます。 HERE SDK 内のすべての言語が LanguageCode 列挙型 (enum) として指定されます。 これを Locale インスタンスに変換するには、LanguageCodeConverterを使用します。 これは、 GitHubナビゲーションサンプルアプリの一部として検索されるオープンソースのユーティリティクラスです。

操作の通知を生成するためにサポートされている各言語は HERE SDK フレームワーク内で音声スキンとして保存されます。 フレームワークを展開し 、 VOICE_ASSETS フォルダを探します。 関心のないアセットを手動で削除して、 HERE SDK パッケージのサイズを縮小できます。

ただし、操作の通知を TTS エンジンに送信するには、使用する言語が TTS エンジンでサポートされていることを確認する必要があります。 通常、各デバイスには一部の言語がプリインストールされていますが、最初はすべての言語が表示されているわけではありません。

音声ガイダンスでサポートされている言語

以下に 、サポートされているすべての音声言語のリストと、 HERE SDK フレームワーク内に保存されている関連する音声スキンの名前を示します。

  • アラビア語(サウジアラビア): voice_package_ar-sa
  • チェコ語 : voice_package_cs-cz
  • デンマーク語 : voice_package_da-dk
  • ドイツ語 : voice_package_de-de
  • ギリシャ語 : VOICE_PACKAGE_EL-GR
  • 英語 ( イギリス ) : voice_package_en-gb
  • 英語(米国 ): voice_package_en-US
  • スペイン語(スペイン): VOICE_PACKAGE_ES-ES
  • スペイン語(メキシコ): VOICE_PACKAGE_ES-MX
  • ペルシャ語(イラン料理): voice_package_fa-ir
  • フィンランド語: VOICE_PACKAGE_FI
  • フランス語(カナダ): voice_package_fr-CA
  • フランス語 : voice_package_fr-FR
  • ヘブライ語 : VOICE_PACKAGE_HE-IL
  • ヒンディー語 : voice_package_hi-in
  • クロアチア語 : VOICE_PACKAGE_hr-HR
  • ハンガリー語 : VOICE_PACKAGE_HU-HU
  • インドネシア語 : バハサ語 voice_package_id - ID
  • イタリア語: voice_package_it-it
  • 日本語: voice_package_ja-JP
  • 韓国語 : voice_package_ko-KR
  • ノルウェー語 : ブークモール語 voice_package_nb -no
  • オランダ語 : voice_package_nl-nl-nl
  • ポルトガル語(ポルトガル) VOICE_PACKAGE_pt
  • ポルトガル語(ブラジル): VOICE_PACKAGE_pt -BR
  • ポーランド語 : voice_package_pt -pt
  • ルーマニア語 : voice_package_ro-R
  • ロシア語 : voice_package_ru-ru
  • スロバキア語 : voice_package_sk-sk
  • セルビア語 : voice_package_sr-CS
  • スウェーデン語 : voice_package_sv -se
  • タイ語 : voice_package_th-th
  • トルコ語 : VOICE_PACKAGE_tr - TR
  • ウクライナ語 : VOICE_PACKAGE_UK-UA
  • ベトナム語 : voice_package_vi -vn
  • 中国語 ( 簡体字 ) : voice_package_zh-CN
  • 中国語 ( 繁体字香港 ): voice_package_zh-HK
  • 中華語(台湾語): voice_package_zh-TW

HERE SDK フレームワークを開き voice_assets 、フォルダーを検索します。 フレームワークのサイズを縮小する場合は、不要な音声パッケージを削除できます。

空間音声操作の通知

ManeuverNotificationDelegate で提供されているものvoiceTextと同様に、空間オーディオ情報を使用して拡張することもできます ( 上記を参照 ) 。

空間オーディオの操作の通知を使用すると、音声読み上げ文字列のステレオパノラマをリアルタイムで調整できます。 これは、車両に座っているドライバーに対する操作位置に基づいています。

このため には、ManeuverNotificationDelegateの代わりに(または並行して)SpatialManeuverNotificationDelegateを使用します。 空間的な操作が可能になると通知をトリガーします。 さらに、 SpatialManeuverAzimuthDelegate を追加して、 HERE SDK によって定義された空間オーディオ操作の通知軌跡の 1 つを構成する方位角エレメントをトリガーします。 結果 SpatialTrajectoryData には、使用する次の方位角が含まれ、空間オーディオ操作の通知の軌跡が終了したかどうかが示されます。

パンニングを開始し、 SpatialManeuverestimatedAudioCueDurationを更新するためにCustomPanningDataを渡し、 およびinitialAzimuthInDegrees プロパティと sweepAzimuthInDegrees プロパティをカスタマイズするためにSpatialManeuverAudioCuePanningを使用します。

ナビゲーションを停止します

route が 設定されかつLocationPrivider が開始されると、ターン・バイ・ターンナビ (矢印ナビ)が自動的に開始されますが、ナビゲーションの停止は可能なシナリオによって異なります。

ナビゲーションを停止してトラッキングモードに切り替え ( 以下を参照 ) 、パスをトラッキングしたままマップと一致する位置を受信するか、 またはトラッキングモードに戻らずにナビゲーションを停止します。 最初のケースでは、現在の routenilに設定するだけで済みます。 これにより、ターン・バイ・ターンナビ (矢印ナビ)関連のすべてのイベントの伝播のみが停止されますが、マップマッチングした場所アップデートおよび速度警告情報などを受信できるように、イベントは存続します。 ターン・バイ・ターンナビ (矢印ナビ)イベントの伝播は、目的の宛先に到達すると自動的に停止されます。 route を再度設定すると、ターン・バイ・ターンナビ (矢印ナビ)関連のすべてのイベントが再度伝播されます。

トラッキングモードに戻らずにナビゲーションを停止 する場合( たとえば、マップに一致しない位置の更新のみをロケーションプロバイダから直接取得する場合) は、VisualNavigatorからすべてのイベントを取得しないことをお勧めします。 このためには、すべての代理人をに個別に設定する必要 nilがあります。

アプリで位置情報の更新を利用するために、ロケーションプロバイダの実装を再利用できます。 HERE Positioning では、複数のインスタンスLocationDelegateを 設定できます。

VisualNavigatorを使用する場合は、stopRendering()を呼び出します。 MapViewが呼び出されると、VisualNavigatorによって制御されなくなります。

  • マップの向き、カメラの距離、傾きなどの設定は、レンダリング中に変更された可能性がありますが、更新されなくなりました。 コール前の最後の状態stopRendering() が保持 されます。 たとえば、ガイダンス中にマップが傾いていた場合、マップは傾斜したままになります。 このため、stopRendering() を呼び出した後で、目的のカメラ設定を適用することをお勧めします。
  • 新しい場所をVisualNavigatorに送り続けても、マップは現在の場所に移動されなくなり ます。
  • VisualNavigator によって所有されている既定またはカスタムの位置情報インジケータが再度非表示になります。
  • RouteProgress nil デリゲートを設定してサブスクライブを解除しない限り、などの位置情報に基づくすべてのイベントが配信されます ( 上記を参照 ) 。

VisualNavigator MapView インスタンス上で動作するため、 stopRendering() を初期化解除する前にを呼び出すことをお勧め MapViewします。 さらに、停止 LocationSimulator することをお勧めします DynamicRoutingEngine 。 ただし、が MapView 一時停止している場合は、も停止する必要は VisualNavigatorありません。 VisualNavigatorMapView 一時停止すると、は自動的にレンダリングを停止し、 MapView が再開されるとレンダリングを開始します(が VisualNavigator 以前にレンダリングされていたとき)。

トラッキング

VisualNavigator このクラスを使用してターン・バイ・ターンナビ (矢印ナビ) を開始および停止できますが、追跡モードに切り替えて、追跡するルートを必要としないようにすることもできます。 このモードは 、しばしば運転者アシスタンスモードとも呼ばれます。 公共交通機関を除く、すべての交通手段で利用できます。 公共交通機関を利用すると、追跡に安全でない予期しない結果が生じる可能性があります。 他のすべての輸送モードがサポートされていますが、追跡はおよびトラックの輸送モードに最も適しています。

追跡を有効にするには、次の電話番号に連絡する必要があります。

visualNavigator.route = nil
herePositioningProvider.startLocating(locationDelegate: visualNavigator,
                                              accuracy: .navigation)

ここでは、実際の GPS 位置情報を取得できますが 、LocationSimulatorを使用して任意のルートから位置情報を再生することもできます ( 上図を参照 ) 。

もちろん、 route インスタンスを設定せずに VisualNavigator を初期化できます。追跡モードにのみ関心がある場合は、ルートを明示的に nil に設定する必要はありません。

追跡モードでは、 NavigableLocationDelegate ルート SpeedWarningDelegate を追跡することなく発生する可能性のある、やなどの代理人のイベントのみを取得できます。 RouteProgressDelegate ルートが設定されていない場合、などの他のデリゲートはイベントを配信しません。

これにより、受講者をアクティブな状態に保ち、無料の追跡とターンバイターンのナビゲーションをその場で切り替えることができます。

概要 については、 API リファレンス に問い合わせて、どの受講者が追跡モードで作業しているかを確認してください。

ドライバーが道順をすでに知っているが、現在の道路名や旅程中の制限速度などの追加情報を取得したい場合は、トラッキングが便利です。

旅程を準備します

HERE SDK は、マップ データ のルートプリフェッチをサポートしています。 これにより、ターン・バイ・ターンナビ (矢印ナビ) 中などのユーザー体験を改善して、一時的なネットワークの損失を適切に処理できます。

旅程が発生した地域にオフラインのマップがすでにダウンロードされている場合は、この操作は不要です。 この場合、すべてのマップ データ がすでに存在し、ネットワーク接続は必要ありません。 たとえば、専用の OfflineRoutingEngine とは異なり 、Navigatorまたは VisualNavigator は、キャッシュされたデータまたはオフライン マップ データにフォールバックする必要があるタイミングを自動的に決定します。 一般に、ナビゲーションにはマップ データ が必要です。マップ ビュー を表示せずにヘッドレスで実行された場合でも同様です。 この理由は、マップマッチングのためのナビゲーション中にマップ データ にアクセスし、たとえば制限速度などの特定の道路属性について通知する必要があるためです。 このデータは、デバイスで利用可能なデータから取得されます。または、利用できない場合は、ナビゲーション中にダウンロードする必要があります。 そのため、今後の道路を見越してより多くのデータをプリフェッチすることが有益です。 プリフェッチを使用しない場合、一時的な接続の損失はあまり適切に処理されません。

これはこのフィーチャーのベータリリースであるため、バグがいくつか発生したり、予期しない動作が発生する可能性があります。 関連する API は、非推奨プロセスなしで新しいリリースで変更されることがあります。

コンストラクタRoutePrefetcherには、パラメータとしてインスタンスSDKNativeEngineのみが必要です。 HERE SDK の初期化後、SDKNativeEngine.sharedInstance 経由で取得できます。

RoutePrefetcher では、マップ データ を事前にダウンロードできます。 マップ データ が マップキャッシュにロードされます。 マップキャッシュには独自のサイズ制約があり、すでにデータが含まれている可能性があります。 RoutePrefetcher は、新しいマップ データ を保存するために、古いキャッシュデータを削除する必要がある場合があります。

  • 旅程を開始する前にroutePrefetcher.prefetchAroundLocation(currentGeoCoordinates)を1 回コールすることをお勧めします。 このコールは、半径が 2 km の指定された場所をマップ データ が事前にマップキャッシュにプリフェッチし、ユーザーがルートのトラッキングを開始したときに十分なマップ データ が存在することを保証します。ただし、ルートがユーザーの現在の場所から開始されていることが前提です。

  • ナビゲーションが開始したら、次 routePrefetcher.prefetchAroundRouteOnIntervals​(navigator)を 1 回コールしてください。 現在指定されているインスタンスNavigator に設定されているルートに沿って、経路内のマップ データ をプリフェッチします。 ルートが設定されていない場合、データはプリフェッチされません。 ルートコリドーのデフォルトの長さは 10 km 、幅は 5 km です マップ データ は、不連続の間隔でのみプリフェッチされます。 現在の経路の終点に達する 1 km 前にプリフェッチが開始されます。 プリフェッチは、 RouteProgress イベントによって示される現在のマップマッチングした場所 に基づいて行われます。 最初のプリフェッチは、ルート沿いに 9 km の距離を走行した後に開始されます。 新しいルートがnavigatorに設定されている場合、このメソッドを再度呼び出す必要はありませんが、このメソッドが 2 回以上呼び出されても、悪影響はありません。

ナビゲーション 例のアプリ に、RoutePrefetcherの使用例を示します。

RoutePrefetcher がルートの開始時に正常に使用され、その後接続が失われた場合、キャッシュされたデータは、マップキャッシュが削除されるまで、今後のパワーサイクルであっても保持されます。 マップキャッシュの削除ポリシーの詳細について は、 ここ を参照してください。

  • ナビゲーション を開始するに、両方のメソッドを同時に呼び出すこともできます。 ただし、トレードオフのために、トリップ開始直後に必要なすべてのデータをプリフェッチするのに十分な時間がない場合があります。
  • prefetchAroundRouteOnIntervals() ガイダンス中にネットワークトラフィックが継続的に増加することに注意してください。

もちろん、プリフェッチされたデータがない場合でもガイダンスを利用できますが、エクスペリエンスの最適化はあまり行われない場合があります。

どちらの呼び出しも、キャッシュされたマップ データ を利用する一時的なオフラインの使用例を最適化するのに役立ちます。 prefetchAroundLocation() はナビゲーションユースケース の外部でも使用できますが 、prefetchAroundRouteOnIntervals() には進行中のナビゲーションシナリオが必要です。

」に一致する結果は 件です

    」に一致する結果はありません