Skip to content

Commit fcc7b22

Browse files
authored
Performance Enhancements (#10)
* Renderer for multi polygons if iOS 13 * Added grouped overlays which will group all geometries supplied by type and return only MultiPolygon and MultiPolyline overlays for rendering if iOS 13.
1 parent 83fa6b6 commit fcc7b22

55 files changed

Lines changed: 674 additions & 1417 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎Cartfile‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
github "MonsantoCo/GeospatialSwift" ~> 0.4.0
1+
github "MonsantoCo/TimberSwift" ~> 1.0.0
2+
github "MonsantoCo/GeospatialSwift" ~> 1.0.0

‎Cartfile.resolved‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
github "MonsantoCo/GeospatialSwift" "0.4.0"
2-
github "MonsantoCo/TimberSwift" "0.2.0"
1+
github "MonsantoCo/GeospatialSwift" "1.0.0"
2+
github "MonsantoCo/TimberSwift" "1.0.0"

‎GeospatialKit.xcodeproj/project.pbxproj‎

Lines changed: 18 additions & 199 deletions
Large diffs are not rendered by default.
Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,30 @@
1-
/**
2-
A protocol provided for unit testing.
3-
*/
4-
public protocol GeospatialCocoaProtocol: GeospatialProtocol {
5-
var image: ImageManagerProtocol! { get }
6-
var map: MapManagerProtocol! { get }
7-
8-
func drawing(context: CGContext, drawingRenderModel: DrawingRenderModel) -> GeometryProjectorProtocol
9-
}
1+
import GeospatialSwift
102

113
/**
124
Extends GeospatialSwift with Cocoa functionality. Create an image or render overlays and annotations for simple MapKit View interaction.
135
*/
14-
final public class GeospatialCocoa: Geospatial, GeospatialCocoaProtocol {
6+
final public class GeospatialCocoa: Geospatial {
157
/**
168
Everything Image
179
*/
18-
public private(set) var image: ImageManagerProtocol!
10+
public let image: ImageManager
1911

2012
/**
2113
Everything Map
2214
*/
23-
public private(set) var map: MapManagerProtocol!
15+
public let map: MapManager
2416

2517
/**
2618
Initialize the interface using a configuration to describe how the interface should react to requests.
2719
*/
2820
public override init() {
29-
super.init()
30-
3121
image = ImageManager()
3222
map = MapManager()
23+
24+
super.init()
3325
}
3426

35-
public func drawing(context: CGContext, drawingRenderModel: DrawingRenderModel) -> GeometryProjectorProtocol {
27+
public func drawing(context: CGContext, drawingRenderModel: DrawingRenderModel) -> GeometryProjector {
3628
return GeometryProjector(context: context, drawingRenderModel: drawingRenderModel, debug: false)
3729
}
3830
}
Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,6 @@
1-
public protocol ImageManagerProtocol {
2-
func image(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, debug: Bool) -> UIImage?
3-
4-
@discardableResult
5-
func snapshot(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, debug: Bool, completion: @escaping (UIImage?) -> Void) -> SnapshotRequest?
6-
}
7-
8-
extension ImageManagerProtocol {
9-
public func image(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double) -> UIImage? {
10-
return image(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false)
11-
}
12-
13-
@discardableResult
14-
public func snapshot(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, completion: @escaping (UIImage?) -> Void) -> SnapshotRequest? {
15-
return snapshot(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false, completion: completion)
16-
}
17-
18-
public func image(for geoJsonObjects: [GeoJsonObject], with drawingRenderModel: DrawingRenderModel, width: Double, height: Double) -> UIImage? {
19-
let geometries = geoJsonObjects.compactMap { $0.objectGeometries }.flatMap { $0 }
20-
let geoJsonObject = Geospatial().geoJson.geometryCollection(geometries: geometries)
21-
22-
return image(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false)
23-
}
24-
25-
@discardableResult
26-
public func snapshot(for geoJsonObjects: [GeoJsonObject], with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, completion: @escaping (UIImage?) -> Void) -> SnapshotRequest? {
27-
let geometries = geoJsonObjects.compactMap { $0.objectGeometries }.flatMap { $0 }
28-
let geoJsonObject = Geospatial().geoJson.geometryCollection(geometries: geometries)
29-
30-
return snapshot(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false, completion: completion)
31-
}
32-
}
1+
import GeospatialSwift
332

34-
public struct ImageManager: ImageManagerProtocol {
3+
public struct ImageManager {
354
internal let imageGenerator: ImageGeneratorProtocol
365

376
init() {
@@ -49,6 +18,15 @@ public struct ImageManager: ImageManagerProtocol {
4918
public func image(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, debug: Bool) -> UIImage? {
5019
return imageGenerator.image(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: debug)
5120
}
21+
public func image(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double) -> UIImage? {
22+
return image(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false)
23+
}
24+
public func image(for geoJsonObjects: [GeoJsonObject], with drawingRenderModel: DrawingRenderModel, width: Double, height: Double) -> UIImage? {
25+
let geometries = geoJsonObjects.compactMap { $0.objectGeometries }.flatMap { $0 }
26+
let geoJsonObject = Geospatial().geoJson.geometryCollection(geometries: geometries)
27+
28+
return image(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false)
29+
}
5230

5331
/**
5432
Same as create but with a Map background
@@ -58,4 +36,15 @@ public struct ImageManager: ImageManagerProtocol {
5836
public func snapshot(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, debug: Bool, completion: @escaping (UIImage?) -> Void) -> SnapshotRequest? {
5937
return imageGenerator.snapshot(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: debug, completion: completion)
6038
}
39+
@discardableResult
40+
public func snapshot(for geoJsonObject: GeoJsonObject, with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, completion: @escaping (UIImage?) -> Void) -> SnapshotRequest? {
41+
return snapshot(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false, completion: completion)
42+
}
43+
@discardableResult
44+
public func snapshot(for geoJsonObjects: [GeoJsonObject], with drawingRenderModel: DrawingRenderModel, width: Double, height: Double, completion: @escaping (UIImage?) -> Void) -> SnapshotRequest? {
45+
let geometries = geoJsonObjects.compactMap { $0.objectGeometries }.flatMap { $0 }
46+
let geoJsonObject = Geospatial().geoJson.geometryCollection(geometries: geometries)
47+
48+
return snapshot(for: geoJsonObject, with: drawingRenderModel, width: width, height: height, debug: false, completion: completion)
49+
}
6150
}

‎GeospatialKit/API/Map/MapManager.swift‎

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,8 @@
1-
public protocol MapManagerProtocol {
2-
func annotations(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any], debug: Bool) -> [GeospatialMapAnnotation]
3-
func annotationView(for annotation: MKAnnotation, with overlayRenderModel: OverlayRenderModel, from mapView: MKMapView, reuseId: String) -> MKAnnotationView
4-
func overlays(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any]) -> [GeospatialMapOverlay]
5-
func renderer(for overlay: MKOverlay, with overlayRenderModel: OverlayRenderModel) -> MKOverlayRenderer
6-
}
1+
import GeospatialSwift
72

8-
public extension MapManagerProtocol {
9-
func annotations(for geoJsonObject: GeoJsonObject) -> [GeospatialMapAnnotation] {
10-
return annotations(for: geoJsonObject, withProperties: [:], debug: false)
11-
}
12-
13-
func annotations(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any]) -> [GeospatialMapAnnotation] {
14-
return annotations(for: geoJsonObject, withProperties: properties, debug: false)
15-
}
16-
17-
func overlays(for geoJsonObject: GeoJsonObject) -> [GeospatialMapOverlay] {
18-
return overlays(for: geoJsonObject, withProperties: [:])
19-
}
20-
}
21-
22-
public struct MapManager: MapManagerProtocol {
23-
internal let overlayGenerator: OverlayGeneratorProtocol
24-
internal let annotationGenerator: AnnotationGeneratorProtocol
3+
public struct MapManager {
4+
internal let overlayGenerator: OverlayGenerator
5+
internal let annotationGenerator: AnnotationGenerator
256

267
init() {
278
overlayGenerator = OverlayGenerator()
@@ -36,7 +17,13 @@ public struct MapManager: MapManagerProtocol {
3617
- returns: annotations for qualifying components
3718
*/
3819
public func annotations(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any], debug: Bool) -> [GeospatialMapAnnotation] {
39-
return annotationGenerator.annotations(for: geoJsonObject, withProperties: properties, debug: debug)
20+
annotationGenerator.annotations(for: geoJsonObject, withProperties: properties, debug: debug)
21+
}
22+
public func annotations(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any]) -> [GeospatialMapAnnotation] {
23+
return annotations(for: geoJsonObject, withProperties: properties, debug: false)
24+
}
25+
public func annotations(for geoJsonObject: GeoJsonObject) -> [GeospatialMapAnnotation] {
26+
return annotations(for: geoJsonObject, withProperties: [:], debug: false)
4027
}
4128

4229
/**
@@ -57,10 +44,37 @@ public struct MapManager: MapManagerProtocol {
5744

5845
- returns: overlays for qualifying components
5946
*/
47+
public func overlays(for geoJsonObject: GeoJsonObject) -> [GeospatialMapOverlay] {
48+
return overlays(for: geoJsonObject, withProperties: [:])
49+
}
6050
public func overlays(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any]) -> [GeospatialMapOverlay] {
6151
return overlayGenerator.overlays(for: geoJsonObject, withProperties: properties)
6252
}
6353

54+
/**
55+
Returns overlays for the qualifying componenets of the geoJsonObject
56+
57+
- geoJsonObject: The GeoJsonObject used to create overlays
58+
59+
- returns: overlays for qualifying components
60+
*/
61+
@available(iOS 13.0, *)
62+
public func groupedOverlays(for geoJsonObjects: [GeoJsonObject]) -> [GeospatialMapOverlay] {
63+
return groupedOverlays(for: geoJsonObjects, withProperties: [:])
64+
}
65+
@available(iOS 13.0, *)
66+
public func groupedOverlays(for geoJsonCoordinatesGeometries: [GeoJsonCoordinatesGeometry]) -> [GeospatialMapOverlay] {
67+
return groupedOverlays(for: geoJsonCoordinatesGeometries, withProperties: [:])
68+
}
69+
@available(iOS 13.0, *)
70+
public func groupedOverlays(for geoJsonObjects: [GeoJsonObject], withProperties properties: [String: Any]) -> [GeospatialMapOverlay] {
71+
return overlayGenerator.groupedOverlays(for: geoJsonObjects, withProperties: properties)
72+
}
73+
@available(iOS 13.0, *)
74+
public func groupedOverlays(for geoJsonCoordinatesGeometries: [GeoJsonCoordinatesGeometry], withProperties properties: [String: Any]) -> [GeospatialMapOverlay] {
75+
return overlayGenerator.groupedOverlays(for: geoJsonCoordinatesGeometries, withProperties: properties)
76+
}
77+
6478
/**
6579
Returns a renderer for the overlay using the overlayRenderModel
6680

‎GeospatialKit/Annotation/AnnotationGenerator.swift‎

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
internal protocol AnnotationGeneratorProtocol {
2-
func annotations(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any], debug: Bool) -> [GeospatialMapAnnotation]
3-
func annotationView(for annotation: MKAnnotation, with overlayRenderModel: OverlayRenderModel, from mapView: MKMapView, reuseId: String) -> MKAnnotationView
4-
}
1+
import GeospatialSwift
52

6-
internal struct AnnotationGenerator: AnnotationGeneratorProtocol {
3+
internal struct AnnotationGenerator {
74
func annotations(for geoJsonObject: GeoJsonObject, withProperties properties: [String: Any], debug: Bool) -> [GeospatialMapAnnotation] {
8-
guard let geometries = geoJsonObject.objectGeometries else { Log.info("No geometry objects for: \(geoJsonObject.geoJson)."); return [] }
9-
10-
return geometries.flatMap { annotations(for: $0, withProperties: properties, debug: debug) }
5+
return geoJsonObject.objectGeometries.flatMap { annotations(for: $0, withProperties: properties, debug: debug) }
116
}
127

138
func annotationView(for annotation: MKAnnotation, with overlayRenderModel: OverlayRenderModel, from mapView: MKMapView, reuseId: String) -> MKAnnotationView {
@@ -26,23 +21,23 @@ internal struct AnnotationGenerator: AnnotationGeneratorProtocol {
2621
var annotations: [GeospatialMapAnnotation] = []
2722

2823
switch geometry {
29-
case let point as GeoJsonPoint:
24+
case let point as GeoJson.Point:
3025
annotations += [annotation(for: point, withProperties: properties)]
31-
case let multiPoint as GeoJsonMultiPoint:
26+
case let multiPoint as GeoJson.MultiPoint:
3227
annotations += multiPoint.points.map { annotation(for: $0, withProperties: properties) }
33-
case let polygon as GeoJsonPolygon:
28+
case let polygon as GeoJson.Polygon:
3429
if debug { annotations += [annotation(for: polygon.centroid, withProperties: properties)] }
35-
case let multiLine as GeoJsonMultiLineString:
30+
case let multiLine as GeoJson.MultiLineString:
3631
if debug { annotations += multiLine.points.map { annotation(for: $0, withProperties: properties) } }
37-
case let multiPolygon as GeoJsonMultiPolygon:
32+
case let multiPolygon as GeoJson.MultiPolygon:
3833
if debug { annotations += multiPolygon.polygons.map { annotation(for: $0.centroid, withProperties: properties) } }
39-
case let geometryCollection as GeoJsonGeometryCollection:
40-
annotations += geometryCollection.objectGeometries?.flatMap { self.annotations(for: $0, withProperties: properties, debug: debug) } ?? []
34+
case let geometryCollection as GeoJson.GeometryCollection:
35+
annotations += geometryCollection.objectGeometries.flatMap { self.annotations(for: $0, withProperties: properties, debug: debug) }
4136
default:
4237
()
4338
}
4439

45-
if debug, let coordinatesGeometry = geometry as? GeoJsonCoordinatesGeometry, !(coordinatesGeometry is GeoJsonPoint) {
40+
if debug, let coordinatesGeometry = geometry as? GeoJsonCoordinatesGeometry, !(coordinatesGeometry is GeoJson.Point) {
4641
return annotations + coordinatesGeometry.points.map { annotation(for: $0, withProperties: properties) }
4742
}
4843

‎GeospatialKit/Annotation/GeospatialMapAnnotation.swift‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,21 @@ public protocol GeospatialMapAnnotation: MKAnnotation {
55
public final class GeospatialPointAnnotation: MKPointAnnotation, GeospatialMapAnnotation {
66
public private(set) var properties: [String: Any] = [:]
77

8-
init(properties: [String: Any]) {
8+
public init(properties: [String: Any]) {
99
self.properties = properties
1010
}
11+
12+
public convenience init(coordinate: CLLocationCoordinate2D, properties: [String: Any]) {
13+
self.init(properties: properties)
14+
15+
self.coordinate = coordinate
16+
}
17+
18+
public convenience init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String?, properties: [String: Any]) {
19+
self.init(properties: properties)
20+
21+
self.title = title
22+
self.subtitle = subtitle
23+
self.coordinate = coordinate
24+
}
1125
}

‎GeospatialKit/Draw/GeometryProjector.swift‎

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import CoreGraphics
22

3-
public protocol GeometryProjectorProtocol {
4-
func draw(geoJsonObject: GeoJsonObject, width: Double, height: Double, zoom: Double, centerOffset: CGPoint?)
5-
}
3+
import GeospatialSwift
64

7-
class GeometryProjector: GeometryProjectorProtocol {
5+
public class GeometryProjector {
86
private let context: CGContext
97
private let drawingRenderModel: DrawingRenderModel
108
private let snapshotSettings: SnapshotSettings?
@@ -18,7 +16,7 @@ class GeometryProjector: GeometryProjectorProtocol {
1816
}
1917

2018
#warning("Zoom and centerOffset?")
21-
func draw(geoJsonObject: GeoJsonObject, width: Double, height: Double, zoom: Double = 1, centerOffset: CGPoint? = nil) {
19+
public func draw(geoJsonObject: GeoJsonObject, width: Double, height: Double, zoom: Double = 1, centerOffset: CGPoint? = nil) {
2220
let desiredImageRect = CGRect(x: 0, y: 0, width: width, height: height)
2321

2422
if let snapshotSettings = snapshotSettings {
@@ -28,36 +26,36 @@ class GeometryProjector: GeometryProjectorProtocol {
2826
context.fill(desiredImageRect)
2927
}
3028

31-
guard let geometries = geoJsonObject.objectGeometries, let insetBoundingBox = geoJsonObject.objectBoundingBox?.mappingBoundingBox(insetPercent: drawingRenderModel.inset) else {
32-
Log.info("No geometry objects or bounding box for: \(geoJsonObject.geoJson).")
29+
guard let insetBoundingBox = geoJsonObject.objectBoundingBox?.mappingBoundingBox(insetPercent: drawingRenderModel.inset) else {
30+
Log.info("No bounding box for: \(geoJsonObject.geoJson).")
3331
return
3432
}
3533

3634
let pointProjector = PointProjector(boundingBox: insetBoundingBox, width: width, height: height)
3735

38-
geometries.forEach {
36+
geoJsonObject.objectGeometries.forEach {
3937
drawGeometry(pointProjector: pointProjector, geometry: $0)
4038
}
4139
}
4240

4341
private func drawGeometry(pointProjector: PointProjector, geometry: GeoJsonGeometry) {
4442
switch geometry {
45-
case let point as GeoJsonPoint:
43+
case let point as GeoJson.Point:
4644
drawPin(pointProjector: pointProjector, point: point)
47-
case let multiPoint as GeoJsonMultiPoint:
45+
case let multiPoint as GeoJson.MultiPoint:
4846
multiPoint.points.forEach { drawPin(pointProjector: pointProjector, point: $0) }
49-
case let lineString as GeoJsonLineString:
47+
case let lineString as GeoJson.LineString:
5048
drawLine(pointProjector: pointProjector, line: lineString)
51-
case let multiLineString as GeoJsonMultiLineString:
52-
multiLineString.lineStrings.forEach { drawLine(pointProjector: pointProjector, line: $0) }
53-
case let polygon as GeoJsonPolygon:
49+
case let multiLineString as GeoJson.MultiLineString:
50+
multiLineString.lines.forEach { drawLine(pointProjector: pointProjector, line: $0) }
51+
case let polygon as GeoJson.Polygon:
5452
drawPolygon(pointProjector: pointProjector, polygon: polygon)
5553

5654
if debug { drawPin(pointProjector: pointProjector, point: polygon.centroid) }
57-
case let multiPolygon as GeoJsonMultiPolygon:
55+
case let multiPolygon as GeoJson.MultiPolygon:
5856
multiPolygon.polygons.forEach { drawPolygon(pointProjector: pointProjector, polygon: $0) }
59-
case let geometryCollection as GeoJsonGeometryCollection:
60-
geometryCollection.objectGeometries?.forEach {
57+
case let geometryCollection as GeoJson.GeometryCollection:
58+
geometryCollection.objectGeometries.forEach {
6159
drawGeometry(pointProjector: pointProjector, geometry: $0)
6260
}
6361
default: return
@@ -89,7 +87,7 @@ class GeometryProjector: GeometryProjectorProtocol {
8987
pinImage.draw(in: CGRect(origin: cgPoint, size: CGSize(width: width, height: height)))
9088
}
9189

92-
private func drawLine(pointProjector: PointProjector, line: GeoJsonLineString) {
90+
private func drawLine(pointProjector: PointProjector, line: GeodesicLine) {
9391
let points = line.points
9492

9593
let cgPoints: [CGPoint]
@@ -115,7 +113,7 @@ class GeometryProjector: GeometryProjectorProtocol {
115113
if debug { points.forEach { drawPin(pointProjector: pointProjector, point: $0) } }
116114
}
117115

118-
private func drawPolygon(pointProjector: PointProjector, polygon: GeoJsonPolygon) {
116+
private func drawPolygon(pointProjector: PointProjector, polygon: GeodesicPolygon) {
119117
context.setLineWidth(CGFloat(drawingRenderModel.lineWidth))
120118
context.setStrokeColor(drawingRenderModel.shapeLineColor.cgColor)
121119
context.setFillColor(drawingRenderModel.shapeFillColor.cgColor)

‎GeospatialKit/Draw/PointProjector.swift‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import GeospatialSwift
2+
13
internal struct PointProjector {
24
private let scale: Double
35
private let projectedOffset: (x: Double, y: Double)

0 commit comments

Comments
 (0)