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

トラフィック・エンジン

TrafficEngineを使用すると、事故、工事、通行止めなどの現在の交通事案に関する詳細かつローカライズ可能な情報をクエリできます。

1行のコードでマップレイヤーの状態trafficIncidentsを有効にすることで、地図上で交通事案を視覚化できます。HERE SDKは別のレイヤーもサポートしており、trafficFlowレイヤーを追加することで現在の交通状況を確認できます。

また、「ルート上の交通状況を視覚化する」セクションに示すように、Routeインスタンスに沿った交通状況を表示します。

TrafficEngineでクエリしたデータは、HERE Traffic API v7に基づいています。

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

トラフィック・エンジンを初期化する

TrafficEngine を使用すると、進行中の交通事案に関する詳細情報を取得できます。GeoBox または GeoCircle で、GeoCorridor を経由するルートに沿ってインシデントを検索できます。

たとえば、特定の種類のインシデントのみを検索するなど、複数のオプションを設定することもできます。その結果、影響を受ける車のタイプ、日付情報、位置情報、ローカライズ可能な説明、概要などに関する結果が得られます。

まず、TrafficEngine の新しいインスタンスを作成します。

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

トラフィック リクエストを開始する

以下では、GeoCircle 内で可能性のある TrafficIncidents を検索します。

private func queryForIncidents(centerCoords: GeoCoordinates) {
    let geoCircle = GeoCircle(center: centerCoords, radiusInMeters: 1000)
    let trafficIncidentsQueryOptions = TrafficIncidentsQueryOptions()
    // Optionally, specify a language:
    // If the language is not supported, then the default behavior is applied and
    // the language of the country where the incident occurs is used.
    // trafficIncidentsQueryOptions.languageCode = LanguageCode.enUs
    trafficEngine.queryForIncidents(inside: geoCircle,
                                    queryOptions: trafficIncidentsQueryOptions,
                                    completion: onTrafficIncidentsFound);
}

// TrafficIncidentQueryCompletionHandler to receive traffic items.
func onTrafficIncidentsFound(error: TrafficQueryError?,
                             trafficIncidentsList: [TrafficIncident]?) {
    if let trafficQueryError = error {
        print("TrafficQueryError: \(trafficQueryError)")
        return
    }

    // If error is nil, it is guaranteed that the list will not be nil.
    var trafficMessage = "Found \(trafficIncidentsList!.count) result(s). See log for details."
    let nearestIncident = getNearestTrafficIncident(currentGeoCoords: tappedGeoCoordinates,
                                                    trafficIncidentsList: trafficIncidentsList!)
    trafficMessage.append(contentsOf: " Nearest incident: \(nearestIncident?.description.text ?? \"nil\")")
    showDialog(title: "Nearby traffic incidents",
               message: trafficMessage)

    for trafficIncident in trafficIncidentsList! {
        print(trafficIncident.description.text)
    }
}

トラフィック レスポンスを処理する

アプリは検出された各 TrafficIncident の説明をログに記録します。ドイツで検索すると、デフォルトでは結果はドイツ語で表示されます。

たとえば、次のように設定することで、別の言語を指定することもできます。

trafficIncidentsQueryOptions.languageCode = LanguageCode.enUs

trafficIncidents は、インシデントの場所を示す交通アイコンと線をレンダリングするレイヤーであることに注意してください。

TrafficIncident には、その位置を示す GeoPolyline が含まれています。地図上のタップされた位置とポリラインに含まれる地理座標を比較することで、地図上のタップされた位置に最も近いインシデントを見つけることができます。

private func getNearestTrafficIncident(currentGeoCoords: GeoCoordinates,
                                       trafficIncidentsList: [TrafficIncident]) -> TrafficIncident? {
    if trafficIncidentsList.count == 0 {
        return nil
    }

    // By default, traffic incidents results are not sorted by distance.
    var nearestDistance: Double = Double.infinity
    var nearestTrafficIncident: TrafficIncident!
    for trafficIncident in trafficIncidentsList {
        var trafficIncidentPolylines: [GeoPolyline] = []

        // It is guaranteed that each incident has a valid polyline.
        trafficIncidentPolylines.append(trafficIncident.location.polyline)

        // If the polyline contains any gaps, they are available as additionalPolylines in TrafficLocation.
        trafficIncidentPolylines.append(contentsOf: trafficIncident.location.additionalPolylines)

        for polyline in trafficIncidentPolylines {
            for geoCoords in polyline.vertices {
                let currentDistance = currentGeoCoords.distance(to: geoCoords)
                if currentDistance < nearestDistance {
                    nearestDistance = currentDistance
                    nearestTrafficIncident = trafficIncident
                }
            }
        }
    }

    return nearestTrafficIncident
}

もちろん、MapPolyline を追加して、地図上にインシデントのポリラインを自分自身でレンダリングすることもできます。独自のアイコンを MapMarker として追加することもできます。インシデントのタイプに応じて、別の画像を選択することもできます。

交通量情報をクエリする

TrafficEngineを使用すると、trafficEngine.queryForFlow(...)を呼び出して非同期リクエストを実行することで、リアルタイムの交通渋滞に関する情報をクエリすることもできます。なお、リクエストが発生した時刻が異なる可能性があり、アプリ側での表示方法も異なる場合があるため、データがtrafficFlowレイヤーに表示されているものとは異なる可能性があります。

private func requestRealtimeTrafficOnRoute(route: Route) {
    // We are interested to see traffic also for side paths.
    let halfWidthInMeters = 500
    let geoCorridor = GeoCorridor(polyline: route.geometry.vertices,
                                  halfWidthInMeters: Int32(halfWidthInMeters))
    let trafficFlowQueryOptions = TrafficFlowQueryOptions()

    trafficEngine.queryForFlow(inside: geoCorridor,
                               queryOptions: trafficFlowQueryOptions) { (trafficQueryError, trafficFlowList) in
        if let error = trafficQueryError {
            self.showDialog(title: "Error while fetching traffic flow", message: "\(error)")
            return
        }

        if let trafficFlows = trafficFlowList {
            for trafficFlow in trafficFlows {
                guard let confidence = trafficFlow.confidence, confidence > 0.5 else {
                    // Exclude speed-limit data and include only real-time and historical
                    // flow information.
                    continue
                }

                // Visualize all polylines unfiltered as we get them from the TrafficEngine.
                let trafficGeoPolyline = trafficFlow.location.polyline
                self.addTrafficPolylines(jamFactor: trafficFlow.jamFactor,
                                         geoPolyline: trafficGeoPolyline)
            }
        }
    }
}

次の手順では、独自のカラーエンコーディングを使用して交通流ポリラインをレンダリングできます。

private func addTrafficPolylines(jamFactor: Double, geoPolyline: GeoPolyline) {
    guard let lineColor = getTrafficColor(jamFactor: jamFactor) else {
        // We skip rendering low traffic.
        return
    }

    let widthInPixels: Float = 10
    do {
        let trafficSpanMapPolyline =  try MapPolyline(geometry: geoPolyline,
                                                      representation: MapPolyline.SolidRepresentation(
                                                            lineWidth: MapMeasureDependentRenderSize(
                                                                sizeUnit: RenderSize.Unit.pixels,
                                                                size: Double(widthInPixels)),
                                                            color: lineColor,
                                                            capShape: LineCap.round))
        mapView.mapScene.addMapPolyline(trafficSpanMapPolyline)
        mapPolylines.append(trafficSpanMapPolyline)
    } catch let error {
        print("Failed to create MapPolyline: \(error.localizedDescription)")
    }
}

// Define a traffic color scheme based on the traffic jam factor.
// 0 <= jamFactor < 4: No or light traffic.
// 4 <= jamFactor < 8: Moderate or slow traffic.
// 8 <= jamFactor < 10: Severe traffic.
// jamFactor = 10: No traffic, ie. the road is blocked.
// Returns null in case of no or light traffic.
private func getTrafficColor(jamFactor: Double) -> UIColor? {
    if jamFactor < 4 {
        return nil
    } else if jamFactor < 8 {
        return UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 0.63) // Yellow
    } else if jamFactor < 10 {
        return UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.63) // Red
    }
    return UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.63) // Black
}

Trafficサンプルアプリを試す

使用例は、GitHubから「Traffic」サンプルアプリの一部として入手できます。