Skip to content

Commit

Permalink
Updated Turf GeoJSON integration
Browse files Browse the repository at this point in the history
  • Loading branch information
1ec5 committed Sep 29, 2021
1 parent ca4bfff commit 11c3965
Show file tree
Hide file tree
Showing 35 changed files with 362 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public class AnimateGeoJSONLineExample: UIViewController, ExampleProtocol {
let updatedLine = Feature(geometry: .lineString(LineString(currentCoordinates)))
self.routeLineSource.data = .feature(updatedLine)
try! self.mapView.mapboxMap.style.updateGeoJSONSource(withId: self.sourceIdentifier,
geoJSON: updatedLine)
geoJSON: .feature(updatedLine))
}
}

Expand Down
6 changes: 3 additions & 3 deletions Apps/Examples/Examples/All Examples/AnimateLayerExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ public class AnimateLayerExample: UIViewController, ExampleProtocol {

// Identify the new coordinate to animate to, and calculate
// the bearing between the new coordinate and the following coordinate.
var geoJSON = Feature.init(geometry: Geometry.point(Point(coordinate)))
geoJSON.properties = ["bearing": coordinate.direction(to: nextCoordinate)]
var geoJSON = Feature(geometry: .point(Point(coordinate)))
geoJSON.properties = ["bearing": .number(coordinate.direction(to: nextCoordinate))]

// Update the airplane source layer with the new coordinate and bearing.
try! self.mapView.mapboxMap.style.updateGeoJSONSource(withId: self.airplaneSymbol.identifier,
geoJSON: geoJSON)
geoJSON: .feature(geoJSON))

runCount += 1

Expand Down
8 changes: 4 additions & 4 deletions Apps/Examples/Examples/All Examples/FeatureStateExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,11 @@ public class FeatureStateExample: UIViewController, ExampleProtocol {

// Extract the earthquake feature from the queried features
if let earthquakeFeature = queriedfeatures.first?.feature,
case .number(.double(let earthquakeIdDouble)) = earthquakeFeature.identifier,
case .number(let earthquakeIdDouble) = earthquakeFeature.identifier,
case .point(let point) = earthquakeFeature.geometry,
let magnitude = earthquakeFeature.properties?["mag"] as? Double,
let place = earthquakeFeature.properties?["place"] as? String,
let timestamp = earthquakeFeature.properties?["time"] as? Double {
case let .number(magnitude) = earthquakeFeature.properties?["mag"],
case let .string(place) = earthquakeFeature.properties?["place"],
case let .number(timestamp) = earthquakeFeature.properties?["time"] {

let earthquakeId = Int(earthquakeIdDouble).description

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public class FeaturesAtPointExample: UIViewController, ExampleProtocol {
switch result {
case .success(let queriedfeatures):
if let firstFeature = queriedfeatures.first?.feature?.properties,
let stateName = firstFeature["STATE_NAME"] as? String {
case let .string(stateName) = firstFeature["STATE_NAME"] {
self?.showAlert(with: "You selected \(stateName)")
}
case .failure(let error):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class LineGradientExample: UIViewController, ExampleProtocol {
var featureCollection: FeatureCollection?
do {
let data = try Data(contentsOf: filePath)
featureCollection = try GeoJSON.parse(FeatureCollection.self, from: data)
featureCollection = try JSONDecoder().decode(FeatureCollection.self, from: data)
} catch {
print("Error parsing data: \(error)")
}
Expand Down
2 changes: 1 addition & 1 deletion Apps/Examples/Examples/All Examples/LiveDataExample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ final class LiveDataExample: UIViewController, ExampleProtocol {
self.parseGeoJSON { result in
switch result {
case .success(let feature):
try! self.mapView.mapboxMap.style.updateGeoJSONSource(withId: self.sourceId, geoJSON: feature)
try! self.mapView.mapboxMap.style.updateGeoJSONSource(withId: self.sourceId, geoJSON: .feature(feature))
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class MultipleGeometriesExample: UIViewController, ExampleProtocol {

do {
let data = try Data(contentsOf: filePath)
featureCollection = try GeoJSON.parse(FeatureCollection.self, from: data)
featureCollection = try JSONDecoder().decode(FeatureCollection.self, from: data)
} catch {
print("Error parsing data: \(error)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,16 @@ class SymbolClusteringExample: UIViewController, ExampleProtocol {
// Check whether the feature has values for `ASSETNUM` and `LOCATIONDETAIL`. These properties
// come from the fire hydrant dataset and indicate that the selected feature is not clustered.
if let selectedFeatureProperties = queriedFeatures.first?.feature?.properties,
let featureInformation = selectedFeatureProperties["ASSETNUM"] as? String,
let location = selectedFeatureProperties["LOCATIONDETAIL"] as? String {
case let .string(featureInformation) = selectedFeatureProperties["ASSETNUM"],
case let .string(location) = selectedFeatureProperties["LOCATIONDETAIL"] {
self?.showAlert(withTitle: "Hydrant \(featureInformation)", and: "\(location)")
// If the feature is a cluster, it will have `point_count` and `cluster_id` properties. These are assigned
// when the cluster is created.
} else if let selectedFeatureProperties = queriedFeatures.first?.feature?.properties,
let pointCount = selectedFeatureProperties["point_count"] as? Int,
let clusterId = selectedFeatureProperties["cluster_id"] as? Int {
case let .number(pointCount) = selectedFeatureProperties["point_count"],
case let .number(clusterId) = selectedFeatureProperties["cluster_id"] {
// If the tap landed on a cluster, pass the cluster ID and point count to the alert.
self?.showAlert(withTitle: "Cluster ID \(clusterId)", and: "There are \(pointCount) points in this cluster")
self?.showAlert(withTitle: "Cluster ID \(Int(clusterId))", and: "There are \(Int(pointCount)) points in this cluster")
}
case .failure(let error):
self?.showAlert(withTitle: "An error occurred: \(error.localizedDescription)", and: "Please try another hydrant")
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Mapbox welcomes participation and contributions from everyone.
* `CameraAnimationsManager.options` has been removed. Use `MapboxMap.cameraBounds` and `MapboxMap.setCameraBounds(with:)` instead. ([#712](https://github.com/mapbox/mapbox-maps-ios/pull/712))
* `MapboxMap.setCameraBounds(for:)` has been renamed to `.setCameraBounds(with:)` ([#712](https://github.com/mapbox/mapbox-maps-ios/pull/712))
* Requires [Turf v2.0.0-rc.2](https://github.com/mapbox/turf-swift/releases/tag/v2.0.0-rc.2). ([#715](https://github.com/mapbox/mapbox-maps-ios/pull/715))
* Renames `Style.updateGeoJSONSource<T: GeoJSONObject>(withId:geoJSON:)` to `Style.updateGeoJSONSource(withId:geoJSON:)`. Instead of passing in the expected GeoJSON object type, you perform pattern matching on the return value using `case let`. ([#715](https://github.com/mapbox/mapbox-maps-ios/pull/715))

### Features ✨ and improvements 🏁

Expand Down
8 changes: 8 additions & 0 deletions MapboxMaps.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public struct CircleAnnotation: Annotation {
internal var feature: Turf.Feature {
var feature = Turf.Feature(geometry: geometry)
feature.identifier = .string(id)
var properties = [String: Any?]()
properties["layerProperties"] = layerProperties
properties["userInfo"] = userInfo
var properties = JSONObject()
properties["layerProperties"] = JSONValue(rawValue: layerProperties)
properties["userInfo"] = userInfo.flatMap(JSONValue.init(rawValue:))
feature.properties = properties
return feature
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public struct PointAnnotation: Annotation {
internal var feature: Turf.Feature {
var feature = Turf.Feature(geometry: geometry)
feature.identifier = .string(id)
var properties = [String: Any?]()
properties["layerProperties"] = layerProperties
properties["userInfo"] = userInfo
var properties = JSONObject()
properties["layerProperties"] = JSONValue(rawValue: layerProperties)
properties["userInfo"] = userInfo.flatMap(JSONValue.init(rawValue:))
feature.properties = properties
return feature
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public struct PolygonAnnotation: Annotation {
internal var feature: Turf.Feature {
var feature = Turf.Feature(geometry: geometry)
feature.identifier = .string(id)
var properties = [String: Any?]()
properties["layerProperties"] = layerProperties
properties["userInfo"] = userInfo
var properties = JSONObject()
properties["layerProperties"] = JSONValue(rawValue: layerProperties)
properties["userInfo"] = userInfo.flatMap(JSONValue.init(rawValue:))
feature.properties = properties
return feature
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public struct PolylineAnnotation: Annotation {
internal var feature: Turf.Feature {
var feature = Turf.Feature(geometry: geometry)
feature.identifier = .string(id)
var properties = [String: Any?]()
properties["layerProperties"] = layerProperties
properties["userInfo"] = userInfo
var properties = JSONObject()
properties["layerProperties"] = JSONValue(rawValue: layerProperties)
properties["userInfo"] = userInfo.flatMap(JSONValue.init(rawValue:))
feature.properties = properties
return feature
}
Expand Down
21 changes: 9 additions & 12 deletions Sources/MapboxMaps/Foundation/Extensions/Turf/Feature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,14 @@ extension Turf.Feature {
*/
switch feature.identifier {
case let identifier as NSNumber:
if String(cString: identifier.objCType) == "q" {
self.identifier = .number(.int(identifier.intValue))
} else {
self.identifier = .number(.double(identifier.doubleValue))
}
self.identifier = .number(identifier.doubleValue)
case let identifier as String:
self.identifier = FeatureIdentifier.string(identifier)
self.identifier = .string(identifier)
default:
break
}

properties = feature.properties
properties = JSONObject(rawValue: feature.properties)
}

/// Initialize a `Turf.Feature` with a `Point`.
Expand Down Expand Up @@ -84,9 +80,7 @@ extension MapboxCommon.Feature {
// Features may or may not have an identifier. If they have one,
// it is either a number or string value.
switch feature.identifier {
case let .number(.int(intId)):
identifier = NSNumber(value: intId)
case let .number(.double(doubleId)):
case let .number(doubleId):
identifier = NSNumber(value: doubleId)
case let .string(stringId):
identifier = NSString(string: stringId)
Expand All @@ -98,10 +92,13 @@ extension MapboxCommon.Feature {
#endif
}

let geometry = MapboxCommon.Geometry(geometry: feature.geometry)
// A null geometry is valid GeoJSON but not supported by MapboxCommon.
// The closest thing would be an empty GeometryCollection.
let nonNullGeometry = feature.geometry ?? .geometryCollection(.init(geometries: []))
let geometry = MapboxCommon.Geometry(geometry: nonNullGeometry)

self.init(identifier: identifier,
geometry: geometry,
properties: (feature.properties as? [String: NSObject]) ?? [:])
properties: (feature.properties?.rawValue as? [String: NSObject]) ?? [:])
}
}
2 changes: 1 addition & 1 deletion Sources/MapboxMaps/Style/Style.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public class Style {
///
/// - Attention: This method is only effective with sources of `GeoJSONSource`
/// type, and cannot be used to update other source types.
public func updateGeoJSONSource<T: GeoJSONObject>(withId id: String, geoJSON: T) throws {
public func updateGeoJSONSource(withId id: String, geoJSON: GeoJSONObject) throws {
guard let sourceInfo = allSourceIdentifiers.first(where: { $0.id == id }),
sourceInfo.type == .geoJson else {
fatalError("updateGeoJSONSource: Source with id '\(id)' is not a GeoJSONSource.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-sort-key"] as? Double, annotation.circleSortKey)
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .number(circleSortKey) = layerProperties["circle-sort-key"] else {
return XCTFail()
}
XCTAssertEqual(circleSortKey, annotation.circleSortKey)
}

func testCircleBlur() {
Expand All @@ -21,7 +25,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-blur"] as? Double, annotation.circleBlur)
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .number(circleBlur) = layerProperties["circle-blur"] else {
return XCTFail()
}
XCTAssertEqual(circleBlur, annotation.circleBlur)
}

func testCircleColor() {
Expand All @@ -31,7 +39,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-color"] as? String, annotation.circleColor.flatMap { $0.rgbaString })
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .string(circleColor) = layerProperties["circle-color"] else {
return XCTFail()
}
XCTAssertEqual(circleColor, annotation.circleColor.flatMap { $0.rgbaString })
}

func testCircleOpacity() {
Expand All @@ -41,7 +53,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-opacity"] as? Double, annotation.circleOpacity)
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .number(circleOpacity) = layerProperties["circle-opacity"] else {
return XCTFail()
}
XCTAssertEqual(circleOpacity, annotation.circleOpacity)
}

func testCircleRadius() {
Expand All @@ -51,7 +67,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-radius"] as? Double, annotation.circleRadius)
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .number(circleRadius) = layerProperties["circle-radius"] else {
return XCTFail()
}
XCTAssertEqual(circleRadius, annotation.circleRadius)
}

func testCircleStrokeColor() {
Expand All @@ -61,7 +81,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-stroke-color"] as? String, annotation.circleStrokeColor.flatMap { $0.rgbaString })
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .string(circleStrokeColor) = layerProperties["circle-stroke-color"] else {
return XCTFail()
}
XCTAssertEqual(circleStrokeColor, annotation.circleStrokeColor.flatMap { $0.rgbaString })
}

func testCircleStrokeOpacity() {
Expand All @@ -71,7 +95,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-stroke-opacity"] as? Double, annotation.circleStrokeOpacity)
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .number(circleStrokeOpacity) = layerProperties["circle-stroke-opacity"] else {
return XCTFail()
}
XCTAssertEqual(circleStrokeOpacity, annotation.circleStrokeOpacity)
}

func testCircleStrokeWidth() {
Expand All @@ -81,7 +109,11 @@ final class CircleAnnotationTests: XCTestCase {
guard let featureProperties = try? XCTUnwrap(annotation.feature.properties) else {
return
}
XCTAssertEqual((featureProperties["layerProperties"] as! [String: Any])["circle-stroke-width"] as? Double, annotation.circleStrokeWidth)
guard case let .object(layerProperties) = featureProperties["layerProperties"],
case let .number(circleStrokeWidth) = layerProperties["circle-stroke-width"] else {
return XCTFail()
}
XCTAssertEqual(circleStrokeWidth, annotation.circleStrokeWidth)
}
}

Expand Down
Loading

0 comments on commit 11c3965

Please sign in to comment.