越南地图方向库.swift 2.0.1

越南地图方向库.swift 2.0.1

nhatpv维护。



  • 在CocoaPods.org上的页面

变更日志

Mapbox方向

MapboxDirections.swift使得连接iOS、macOS、tvOS或watchOS应用程序到Mapbox方向APIMapbox匹配API变得容易。快速获取驾驶、骑行或步行路线,无论是单向还是多个停靠点,都可以通过简单易用的接口实现,这类似于MapKit的MKDirections API。将GPX轨迹拟合到OpenStreetMap道路网络上。Mapbox方向和匹配API是由OSRM路由引擎驱动的。

尽管其名称如此,MapboxDirections.swift不仅可以用于Swift 4,也适用于Objective-C和Cocoa-AppleScript代码。

MapboxDirections.swift与MapboxGeocoder.swiftMapboxStatic.swift、iOS的Mapbox导航SDK,以及iOS的Mapbox Maps SDK或macOS SDK具有良好的兼容性。

入门

在您的Carthage Cartfile中指定以下依赖项

github "mapbox/MapboxDirections.swift" ~> 0.23

或您的CocoaPods Podfile中

pod 'MapboxDirections.swift', '~> 0.23'

然后导入MapboxDirections@import MapboxDirections;

v0.12.1 是使用 Swift 3 编写的 MapboxDirections.swift 的最后一个版本。所有后续版本都将基于以 Swift 4 编写的 master 分支。下面的 Swift 示例都是使用 Swift 4 编写的。

此仓库包含使用 Swift 和 Objective-C 编写的示例应用程序,展示了如何使用此框架。要运行它们,您需要使用 0.19 版本或更高版本的 Carthage 安装依赖项。更多示例和详细文档可以在Mapbox API 文档中找到。

用法

API 参考

要使用此 API,您需要一个Mapbox 访问令牌。如果您已经在使用Mapbox Maps SDK for iOSmacOS SDK,只要您已在应用的 Info.plist 文件中将其置于 MGLMapboxAccessToken 键,MapboxDirections.swift 会自动识别您的访问令牌。

下面的示例提供了 Swift(标记为 main.swift)、Objective-C(标记为 main.m)和 AppleScript(标记为 AppDelegate.applescript)。有关更多详细信息,请参阅MapboxDirections.swift API 参考

计算两个位置之间的路线

主要的路线类是 Directions(在 Swift 中)或 MBDirections(在 Objective-C 或 AppleScript 中)。使用您的访问令牌创建一个路线对象

// main.swift
import MapboxDirections

let directions = Directions(accessToken: "<#your access token#>")
// main.m
@import MapboxDirections;

MBDirections *directions = [[MBDirections alloc] initWithAccessToken:@"<#your access token#>"];
-- AppDelegate.applescript
set theDirections to alloc of MBDirections of the current application
tell theDirections to initWithAccessToken:"<#your access token#>"

或者,您可以将访问令牌置于应用的 Info.plist 文件中的 MGLMapboxAccessToken 键,然后使用共享的路线对象

// main.swift
let directions = Directions.shared
// main.m
MBDirections *directions = [MBDirections sharedDirections];
-- AppDelegate.applescript
set theDirections to sharedDirections of MBDirections of the current application

拥有路线对象后,构造一个 RouteOptions 或 MBRouteOptions 对象,并将其传递到 Directions.calculate(_:completionHandler:) 方法中。

// main.swift

let waypoints = [
    Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox"),
    Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House"),
]
let options = RouteOptions(waypoints: waypoints, profileIdentifier: .automobileAvoidingTraffic)
options.includesSteps = true

let task = directions.calculate(options) { (waypoints, routes, error) in
    guard error == nil else {
        print("Error calculating directions: \(error!)")
        return
    }

    if let route = routes?.first, let leg = route.legs.first {
        print("Route via \(leg):")

        let distanceFormatter = LengthFormatter()
        let formattedDistance = distanceFormatter.string(fromMeters: route.distance)

        let travelTimeFormatter = DateComponentsFormatter()
        travelTimeFormatter.unitsStyle = .short
        let formattedTravelTime = travelTimeFormatter.string(from: route.expectedTravelTime)

        print("Distance: \(formattedDistance); ETA: \(formattedTravelTime!)")

        for step in leg.steps {
            print("\(step.instructions)")
            let formattedDistance = distanceFormatter.string(fromMeters: step.distance)
            print("\(formattedDistance)")
        }
    }
}
// main.m

NSArray<MBWaypoint *> *waypoints = @[
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(38.9131752, -77.0324047) coordinateAccuracy:-1 name:@"Mapbox"],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(38.8977, -77.0365) coordinateAccuracy:-1 name:@"White House"],
];
MBRouteOptions *options = [[MBRouteOptions alloc] initWithWaypoints:waypoints
                                                  profileIdentifier:MBDirectionsProfileIdentifierAutomobileAvoidingTraffic];
options.includesSteps = YES;

NSURLSessionDataTask *task = [directions calculateDirectionsWithOptions:options
                                                      completionHandler:^(NSArray<MBWaypoint *> * _Nullable waypoints,
                                                                          NSArray<MBRoute *> * _Nullable routes,
                                                                          NSError * _Nullable error) {
    if (error) {
        NSLog(@"Error calculating directions: %@", error);
        return;
    }

    MBRoute *route = routes.firstObject;
    MBRouteLeg *leg = route.legs.firstObject;
    if (leg) {
        NSLog(@"Route via %@:", leg);

        NSLengthFormatter *distanceFormatter = [[NSLengthFormatter alloc] init];
        NSString *formattedDistance = [distanceFormatter stringFromMeters:leg.distance];

        NSDateComponentsFormatter *travelTimeFormatter = [[NSDateComponentsFormatter alloc] init];
        travelTimeFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyleShort;
        NSString *formattedTravelTime = [travelTimeFormatter stringFromTimeInterval:route.expectedTravelTime];

        NSLog(@"Distance: %@; ETA: %@", formattedDistance, formattedTravelTime);

        for (MBRouteStep *step in leg.steps) {
            NSLog(@"%@", step.instructions);
            NSString *formattedDistance = [distanceFormatter stringFromMeters:step.distance];
            NSLog(@"%@", formattedDistance);
        }
    }
}];
-- AppDelegate.applescript

set mapbox to alloc of MBWaypoint of the current application
tell mapbox to initWithCoordinate:{38.9131752, -77.0324047} coordinateAccuracy:-1 |name|:"Mapbox"
set theWhiteHouse to alloc of MBWaypoint of the current application
tell theWhiteHouse to initWithCoordinate:{38.8977, -77.0365} coordinateAccuracy:-1 |name|:"White House"
set theWaypoints to {mapbox, theWhiteHouse}

set theOptions to alloc of MBRouteOptions of the current application
tell theOptions to initWithWaypoints:theWaypoints profileIdentifier:"mapbox/driving-traffic"
set theOptions's includesSteps to true

set theURL to theDirections's URLForCalculatingDirectionsWithOptions:theOptions
set theData to the current application's NSData's dataWithContentsOfURL:theURL
set theJSON to the current application's NSJSONSerialization's JSONObjectWithData:theData options:0 |error|:(missing value)

set theRoute to alloc of MBRoute of the current application
tell theRoute to initWithJson:(the first item of theJSON's routes) waypoints:theWaypoints profileIdentifier:"mapbox/driving"
set theLeg to the first item of theRoute's legs

log "Route via " & theLeg's |name| & ":"

set theDistanceFormatter to alloc of NSLengthFormatter of the current application
tell theDistanceFormatter to init()
set theDistance to theDistanceFormatter's stringFromMeters:(theLeg's distance)

log "Distance: " & theDistance

repeat with theStep in theLeg's steps
    log theStep's instructions
    set theDistance to theDistanceFormatter's stringFromMeters:(theStep's distance)
    log "" & theDistance & ""
end repeat

此库默认使用 Mapbox Directions API 的第 5 版。要使用第 4 版,将 RouteOptions 替换为 RouteOptionsV4(或将 MBRouteOptions 替换为 MBRouteOptionsV4)。

将路径点匹配到道路网络

如果您有一个 GPX 跟踪或其他 GPS 导出的位置数据,您可以使用 Map Matching API 清理数据并使其适应道路网络

// main.swift

let coordinates = [
    CLLocationCoordinate2D(latitude: 32.712041, longitude: -117.172836),
    CLLocationCoordinate2D(latitude: 32.712256, longitude: -117.17291),
    CLLocationCoordinate2D(latitude: 32.712444, longitude: -117.17292),
    CLLocationCoordinate2D(latitude: 32.71257,  longitude: -117.172922),
    CLLocationCoordinate2D(latitude: 32.7126,   longitude: -117.172985),
    CLLocationCoordinate2D(latitude: 32.712597, longitude: -117.173143),
    CLLocationCoordinate2D(latitude: 32.712546, longitude: -117.173345)
]

let options = MatchOptions(coordinates: coordinates)
options.includesSteps = true

let task = directions.calculate(options) { (matches, error) in
    guard error == nil else {
        print("Error matching coordinates: \(error!)")
        return
    }

    if let match = matches?.first, let leg = match.legs.first {
        print("Match via \(leg):")

        let distanceFormatter = LengthFormatter()
        let formattedDistance = distanceFormatter.string(fromMeters: match.distance)

        let travelTimeFormatter = DateComponentsFormatter()
        travelTimeFormatter.unitsStyle = .short
        let formattedTravelTime = travelTimeFormatter.string(from: match.expectedTravelTime)

        print("Distance: \(formattedDistance); ETA: \(formattedTravelTime!)")

        for step in leg.steps {
            print("\(step.instructions)")
            let formattedDistance = distanceFormatter.string(fromMeters: step.distance)
            print("\(formattedDistance)")
        }
    }
}
// main.m
NSArray<MBWaypoint *> *waypoints = @[
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.712041, -117.172836) coordinateAccuracy:-1 name:nil],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.712256, -117.17291) coordinateAccuracy:-1 name:nil],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.712444, -117.17292) coordinateAccuracy:-1 name:nil],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.71257, -117.172922) coordinateAccuracy:-1 name:nil],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.7126, -117.172985) coordinateAccuracy:-1 name:nil],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.712597, -117.173143) coordinateAccuracy:-1 name:nil],
    [[MBWaypoint alloc] initWithCoordinate:CLLocationCoordinate2DMake(32.712546, -117.173345) coordinateAccuracy:-1 name:nil],
];

MBMatchOptions *matchOptions = [[MBMatchOptions alloc] initWithWaypoints:waypoints profileIdentifier:MBDirectionsProfileIdentifierAutomobile];
NSURLSessionDataTask *task = [[[MBDirections alloc] initWithAccessToken:MapboxAccessToken] calculateMatchesWithOptions:matchOptions completionHandler:^(NSArray<MBMatch *> * _Nullable matches, NSError * _Nullable error) {
    if (error) {
        NSLog(@"Error matching waypoints: %@", error);
        return;
    }
    
    MBMatch *match = matches.firstObject;
    MBRouteLeg *leg = match.legs.firstObject;
    if (leg) {
        NSLog(@"Match via %@:", leg);
        
        NSLengthFormatter *distanceFormatter = [[NSLengthFormatter alloc] init];
        NSString *formattedDistance = [distanceFormatter stringFromMeters:leg.distance];
        
        NSDateComponentsFormatter *travelTimeFormatter = [[NSDateComponentsFormatter alloc] init];
        travelTimeFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyleShort;
        NSString *formattedTravelTime = [travelTimeFormatter stringFromTimeInterval:match.expectedTravelTime];
        
        NSLog(@"Distance: %@; ETA: %@", formattedDistance, formattedTravelTime);
        
        for (MBRouteStep *step in leg.steps) {
            NSLog(@"%@", step.instructions);
            NSString *formattedDistance = [distanceFormatter stringFromMeters:step.distance];
            NSLog(@"%@", formattedDistance);
        }
    }
}];

您还可以使用 Swift 中的 Directions.calculateRoutes(matching:completionHandler:) 方法或 Objective-C 中的 -[MBDirections calculateRoutesMatchingOptions:completionHandler:] 方法来获取适用于标准 Directions API 响应的任何位置的 Route 对象。

与其他 Mapbox 库一起使用

在地图上绘制路线

使用Mapbox Maps SDK for iOSmacOS SDK,您可以在 Swift 或 Objective-C 中轻松地将路线绘制到地图上

// main.swift

if route.coordinateCount > 0 {
    // Convert the route’s coordinates into a polyline.
    var routeCoordinates = route.coordinates!
    let routeLine = MGLPolyline(coordinates: &routeCoordinates, count: route.coordinateCount)

    // Add the polyline to the map and fit the viewport to the polyline.
    mapView.addAnnotation(routeLine)
    mapView.setVisibleCoordinates(&routeCoordinates, count: route.coordinateCount, edgePadding: .zero, animated: true)
}
// main.m

if (route.coordinateCount) {
    // Convert the route’s coordinates into a polyline.
    CLLocationCoordinate2D *routeCoordinates = malloc(route.coordinateCount * sizeof(CLLocationCoordinate2D));
    [route getCoordinates:routeCoordinates];
    MGLPolyline *routeLine = [MGLPolyline polylineWithCoordinates:routeCoordinates count:route.coordinateCount];

    // Add the polyline to the map and fit the viewport to the polyline.
    [mapView addAnnotation:routeLine];
    [mapView setVisibleCoordinates:routeCoordinates count:route.coordinateCount edgePadding:UIEdgeInsetsZero animated:YES];

    // Make sure to free this array to avoid leaking memory.
    free(routeCoordinates);
}

显示逐段导航界面

请参阅Mapbox Navigation SDK for iOS文档中的用法示例。

测试

要运行包含的单元测试,您需要使用 0.19 版本或更高版本的Carthage安装依赖项。

  1. carthage build --platform iOS
  2. 打开 MapboxDirections.xcodeproj
  3. 转到 Product ‣ Test。