### Setup and Lifecycle of GMUClusterManager Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Demonstrates the complete setup of `GMUClusterManager`, including defining a custom cluster item, configuring the algorithm, icon generator, and renderer, adding a large number of items, and triggering the initial clustering. It also includes delegate methods for handling taps on clusters and individual items. ```swift import GoogleMaps import GoogleMapsUtils // Custom cluster item class POIItem: NSObject, GMUClusterItem { var position: CLLocationCoordinate2D var name: String init(position: CLLocationCoordinate2D, name: String) { self.position = position self.name = name } } class ClusteringViewController: UIViewController, GMUClusterManagerDelegate, GMSMapViewDelegate { private var mapView: GMSMapView! private var clusterManager: GMUClusterManager! override func viewDidLoad() { super.viewDidLoad() let camera = GMSCameraPosition.camera(withLatitude: 37.7749, longitude: -122.4194, zoom: 10) mapView = GMSMapView(frame: view.bounds, camera: camera) view.addSubview(mapView) // 1. Build the cluster pipeline let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm() let iconGen = GMUDefaultClusterIconGenerator() let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGen) renderer.animatesClusters = true renderer.minimumClusterSize = 4 renderer.maximumClusterZoom = 20 renderer.animationDuration = 0.5 clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer) clusterManager.setDelegate(self, mapDelegate: self) // 2. Add 1 000 items var items = [POIItem]() for i in 0..<1000 { let lat = 37.0 + Double.random(in: 0..<2) let lng = -122.0 + Double.random(in: 0..<2) items.append(POIItem(position: CLLocationCoordinate2D(latitude: lat, longitude: lng), name: "Point \(i)")) } clusterManager.addItems(items) // 3. Trigger initial clustering clusterManager.cluster() } // Tap on a cluster → zoom in func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool { let update = GMSCameraUpdate.setTarget(cluster.position, zoom: mapView.camera.zoom + 1) mapView.animate(with: update) return true } // Tap on an individual item func clusterManager(_ clusterManager: GMUClusterManager, didTapClusterItem clusterItem: GMUClusterItem) -> Bool { if let poi = clusterItem as? POIItem { print("Tapped: \(poi.name) at \(poi.position)") } return true } } ``` -------------------------------- ### Navigate to Objective-C Demo App Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/samples/README.md Use these commands to navigate to the Objective-C demo application directory, install dependencies, and open the workspace. ```bash cd ObjCDemoApp pod install open ObjCDemoApp.xcworkspace ``` -------------------------------- ### Navigate to Swift Demo App Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/samples/README.md Use these commands to navigate to the Swift demo application directory, install dependencies, and open the workspace. ```bash cd SwiftDemoApp pod install open SwiftDemoApp.xcworkspace ``` -------------------------------- ### Install Google Maps iOS Utils via Carthage Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Add the Google Maps iOS Utils library to your Cartfile for Carthage installation. This method is only supported for Maps SDK v7.1.0 or earlier. ```text github "googlemaps/google-maps-ios-utils" ~> 7.1.0 ``` -------------------------------- ### Install Google Maps iOS Utils via CocoaPods Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Add the Google Maps and Google-Maps-iOS-Utils pods to your Podfile for CocoaPods installation. Ensure you use the correct versions compatible with your project. ```ruby use_frameworks! target 'TARGET_NAME' do pod 'GoogleMaps', '10.0.0' pod 'Google-Maps-iOS-Utils', '7.1.0' # x-release-please-version end ``` -------------------------------- ### Import GoogleMapsUtils in Swift Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Import the GoogleMapsUtils module in your Swift project after installing the library. ```swift import GoogleMapsUtils ``` -------------------------------- ### Install Google Maps iOS Utils via Swift Package Manager Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Add the Google Maps iOS Utils library to your Xcode project using Swift Package Manager by providing the GitHub repository URL. ```text https://github.com/googlemaps/google-maps-ios-utils ``` -------------------------------- ### Using GQTPointQuadTree for Spatial Indexing Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Demonstrates how to create a custom item, build a quadtree, add items, perform range queries, remove items, and clear the tree. Ensure items conform to GQTPointQuadTreeItem. The tree is not thread-safe. ```objc #import // 1. Custom item @interface LocationItem : NSObject @property (nonatomic) CLLocationCoordinate2D coordinate; @property (nonatomic, copy) NSString *name; - (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coord name:(NSString *)name; @end @implementation LocationItem - (GQTPoint)point { return (GQTPoint){ self.coordinate.longitude, self.coordinate.latitude }; } @end // 2. Build tree covering the whole globe GQTBounds worldBounds = { -180, -90, 180, 90 }; GQTPointQuadTree *tree = [[GQTPointQuadTree alloc] initWithBounds:worldBounds]; // 3. Add 10 000 items for (NSInteger i = 0; i < 10000; i++) { double lat = -90.0 + arc4random_uniform(180); double lng = -180.0 + arc4random_uniform(360); LocationItem *item = [[LocationItem alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, lng) name:[NSString stringWithFormat:@"POI %ld", i]]; [tree add:item]; } NSLog(@"Tree size: %lu", (unsigned long)[tree count]); // 10000 // 4. Query a bounding box (San Francisco Bay Area) GQTBounds sfBounds = { -122.55, 37.65, -122.30, 37.90 }; NSArray *results = [tree searchWithBounds:sfBounds]; NSLog(@"Items in SF: %lu", (unsigned long)results.count); // 5. Remove an item LocationItem *toRemove = results.firstObject; if (toRemove) { BOOL removed = [tree remove:toRemove]; NSLog(@"Removed: %@", removed ? @"YES" : @"NO"); } // 6. Clear all [tree clear]; NSLog(@"After clear: %lu", (unsigned long)[tree count]); // 0 ``` -------------------------------- ### Import Google Maps SDK and Utilities Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Import the necessary frameworks in your Swift or Objective-C files. ```swift // Swift import GoogleMaps import GoogleMapsUtils ``` ```objc // Objective-C @import GoogleMaps; @import GoogleMapsUtils; ``` -------------------------------- ### Creating Geometry Objects in Swift Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Demonstrates the creation of GMUPoint, GMULineString, GMUPolygon (with a hole), and GMUGeometryCollection objects. Ensure Google Maps and Google Maps Utils are imported. ```swift import GoogleMaps import GoogleMapsUtils // Point let point = GMUPoint(coordinate: CLLocationCoordinate2D(latitude: 51.5, longitude: -0.12)) print(point.coordinate) // (51.5, -0.12) // LineString let path = GMSMutablePath() path.add(CLLocationCoordinate2D(latitude: 51.50, longitude: -0.12)) path.add(CLLocationCoordinate2D(latitude: 51.52, longitude: -0.10)) path.add(CLLocationCoordinate2D(latitude: 51.54, longitude: -0.08)) let line = GMULineString(path: path) print(line.path.count()) // 3 // Polygon with a hole let outer = GMSMutablePath() outer.add(CLLocationCoordinate2D(latitude: 0, longitude: 0)) outer.add(CLLocationCoordinate2D(latitude: 0, longitude: 1)) outer.add(CLLocationCoordinate2D(latitude: 1, longitude: 1)) outer.add(CLLocationCoordinate2D(latitude: 1, longitude: 0)) let hole = GMSMutablePath() hole.add(CLLocationCoordinate2D(latitude: 0.2, longitude: 0.2)) hole.add(CLLocationCoordinate2D(latitude: 0.2, longitude: 0.8)) hole.add(CLLocationCoordinate2D(latitude: 0.8, longitude: 0.8)) hole.add(CLLocationCoordinate2D(latitude: 0.8, longitude: 0.2)) let polygon = GMUPolygon(paths: [outer, hole]) // outer ring + 1 hole // GeometryCollection let collection = GMUGeometryCollection(geometries: [point, line, polygon]) print(collection.geometries.count) // 3 ``` -------------------------------- ### GMUHeatmapTileLayer: Data-Density Heatmap Rendering Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Renders a smooth color-gradient overlay where warmer colors indicate higher concentrations of weighted data points. Requires GMUHeatmapTileLayer, GMUGradient, and GMUWeightedLatLng. Configure radius (≤ 50), opacity, gradient, and zoom intensities. ```swift import GoogleMaps import GoogleMapsUtils class HeatmapViewController: UIViewController { private var mapView: GMSMapView! private var heatmapLayer: GMUHeatmapTileLayer! override func viewDidLoad() { super.viewDidLoad() let camera = GMSCameraPosition.camera(withLatitude: 37.7, longitude: -122.4, zoom: 10) mapView = GMSMapView(frame: view.bounds, camera: camera) view.addSubview(mapView) // Gradient: green (low) → yellow (mid) → red (high) let gradient = GMUGradient( colors: [.green, .yellow, .red], startPoints: [0.1, 0.5, 1.0] as [NSNumber], colorMapSize: 256 ) // Build weighted data from a JSON file guard let url = Bundle.main.url(forResource: "heatmap_data", withExtension: "json"), let data = try? Data(contentsOf: url), let json = try? JSONSerialization.jsonObject(with: data) as? [[String: Double]] else { return } let points: [GMUWeightedLatLng] = json.compactMap { dict in guard let lat = dict["lat"], let lng = dict["lng"] else { return nil } return GMUWeightedLatLng( coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lng), intensity: Float(dict["weight"] ?? 1.0) ) } // Configure and show heatmap heatmapLayer = GMUHeatmapTileLayer() heatmapLayer.radius = 40 heatmapLayer.opacity = 0.8 heatmapLayer.gradient = gradient heatmapLayer.minimumZoomIntensity = 5 heatmapLayer.maximumZoomIntensity = 10 heatmapLayer.weightedData = points heatmapLayer.map = mapView } @IBAction func toggleHeatmap(_ sender: UISwitch) { heatmapLayer.map = sender.isOn ? mapView : nil } } ``` -------------------------------- ### Add CocoaPods Dependency Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Specify the Google Maps SDK and the utility library in your Podfile. ```ruby # Podfile use_frameworks! target 'MyApp' do pod 'GoogleMaps', '~> 10.0' pod 'Google-Maps-iOS-Utils', '7.1.0' end ``` -------------------------------- ### Add Swift Package Manager Dependency Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Add the library as a dependency in your Package.swift file and require the target in any module that needs it. ```swift // Package.swift let package = Package( name: "MyApp", platforms: [.iOS(.v16)], dependencies: [ .package( url: "https://github.com/googlemaps/google-maps-ios-utils", from: "7.1.0" ) ], targets: [ .target( name: "MyApp", dependencies: [ .product(name: "GoogleMapsUtils", package: "google-maps-ios-utils") ] ) ] ) ``` -------------------------------- ### Import GoogleMapsUtils in Objective-C Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Import the GoogleMapsUtils module in your Objective-C project using the @import syntax. ```objective-c @import GoogleMapsUtils; ``` -------------------------------- ### Render KML Data with GMUKmlParser Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Parse and render KML data onto a GMSMapView using GMUKmlParser and GMUGeometryRenderer. Ensure the KML file path is correctly specified. ```swift import GoogleMaps import GoogleMapsUtils func renderKml() { // Parse KML let path: String = // Path to your KML file... let kmlUrl = URL(fileURLWithPath: path) let kmlParser = GMUKmlParser(url: kmlUrl) kmlParser.parse() // Render parsed KML let renderer = GMUGeometryRenderer( map: mapView, geometries: kmlParser.placemarks, styles: kmlParser.styles, styleMaps: kmlParser.styleMaps ) renderer.render() } ``` -------------------------------- ### Generate Dense Heatmap from Sparse Data with Interpolation Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Use HeatmapInterpolationPoints to synthesize additional GMUWeightedLatLng points when the source dataset is too sparse. The influence parameter controls intensity fall-off with distance, and granularity sets search coarseness. Ensure the influence parameter is within the range of [2.0, 2.5]. ```swift import GoogleMapsUtils class HeatmapInterpolationViewController: UIViewController { private var heatmapLayer: GMUHeatmapTileLayer! func loadInterpolatedHeatmap(sparseCoordinates: [(lat: Double, lng: Double, w: Float)]) { let interpolator = HeatmapInterpolationPoints(givenClusterIterations: 25) // Seed with sparse observations let seedPoints = sparseCoordinates.map { GMUWeightedLatLng( coordinate: CLLocationCoordinate2D(latitude: $0.lat, longitude: $0.lng), intensity: $0.w ) } interpolator.addWeightedLatLngs(latlngs: seedPoints) // Generate dense synthetic points do { let densePoints = try interpolator.generatePoints( influence: 2.2, granularity: 0.1 ) print("Generated \(densePoints.count) interpolated points from \(seedPoints.count) seeds") heatmapLayer = GMUHeatmapTileLayer() heatmapLayer.radius = 50 heatmapLayer.weightedData = densePoints heatmapLayer.map = mapView } catch { // influence must be in [2.0, 2.5] print("Interpolation error: \(error)") } } } ``` -------------------------------- ### Render KML Files with GMUKMLParser and GMUGeometryRenderer Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Use GMUKMLParser to parse KML data from a URL and GMUGeometryRenderer to draw the parsed placemarks, styles, and style maps onto the GMSMapView. Call clear() to remove only the KML geometries. ```swift import GoogleMaps import GoogleMapsUtils class KMLViewController: UIViewController { private var mapView: GMSMapView! private var renderer: GMUGeometryRenderer? override func viewDidLoad() { super.viewDidLoad() mapView = GMSMapView(frame: view.bounds) view.addSubview(mapView) renderKML() } func renderKML() { guard let path = Bundle.main.path(forResource: "SampleRoute", ofType: "kml"), let url = URL(string: "file://\(path)") else { return } // Parse let parser = GMUKMLParser(url: url) parser.parse() print("Placemarks : \(parser.placemarks.count)") print("Styles : \(parser.styles.count)") print("Style maps : \(parser.styleMaps.count)") // Render renderer = GMUGeometryRenderer( map: mapView, geometries: parser.placemarks, styles: parser.styles, styleMaps: parser.styleMaps ) renderer?.render() // Zoom to first placemark if let first = parser.placemarks.first, let point = first.geometry as? GMUPoint { mapView.animate(toLocation: point.coordinate) } } func clearKML() { renderer?.clear() // Removes only KML geometry; other markers remain } } ``` -------------------------------- ### Cluster Markers with GMUClusterManager Source: https://github.com/googlemaps/google-maps-ios-utils/blob/main/README.md Set up and use GMUClusterManager to group nearby markers on a GMSMapView. Requires GMSMapViewDelegate conformance and initialization of icon generator, algorithm, and renderer. ```swift import GoogleMaps import GoogleMapsUtils class MarkerClustering: UIViewController, GMSMapViewDelegate { private var mapView: GMSMapView! private var clusterManager: GMUClusterManager! override func viewDidLoad() { super.viewDidLoad() // Set up the cluster manager with the supplied icon generator and // renderer. let iconGenerator = GMUDefaultClusterIconGenerator() let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm() let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGenerator) clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer) // Register self to listen to GMSMapViewDelegate events. clusterManager.setMapDelegate(self) // ... } // ... } let markerArray = [marker1, marker2, marker3, marker4] // define your own markers clusterManager.add(markerArray) clusterManager.cluster() ``` -------------------------------- ### CLLocationCoordinate2D Extensions for Geographic Calculations Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Utilizes extensions on CLLocationCoordinate2D for distance, heading, interpolation, and offset calculations. Requires CoreLocation, GoogleMaps, and GoogleMapsUtils imports. Calculations are based on the WGS-84 Earth model. ```swift import CoreLocation import GoogleMaps import GoogleMapsUtils let london = CLLocationCoordinate2D(latitude: 51.5074, longitude: -0.1278) let newYork = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) // Great-circle distance in metres let distM = london.distance(to: newYork) print(String(format: "%.0f km", distM / 1000)) // ~5 570 km // Initial bearing (degrees) let bear = london.heading(to: newYork) print(String(format: "%.1f°", bear)) // ~288.5° // Midpoint along the arc let midpoint = london.interpolate(to: newYork, fraction: 0.5) print(midpoint) // approx (55.79, -44.48) // Move 500 km due East from London let east500 = london.offset(distance: 500_000, heading: 90) print(east500) // approx (51.29, 7.26) ``` -------------------------------- ### GMSPath Extensions for Geographic Analysis Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Adds area calculation, point containment testing, path snapping, and multi-colour polyline styling to GMSPath. Requires GoogleMaps and GoogleMapsUtils imports. Ensure a mapView is available for polyline rendering. ```swift import GoogleMaps import GoogleMapsUtils // Build a closed path (square ~111 km aside) let square = GMSMutablePath() square.add(CLLocationCoordinate2D(latitude: 0, longitude: 0)) square.add(CLLocationCoordinate2D(latitude: 0, longitude: 1)) square.add(CLLocationCoordinate2D(latitude: 1, longitude: 1)) square.add(CLLocationCoordinate2D(latitude: 1, longitude: 0)) // Area let areaM2 = square.area() print(String(format: "%.0f km²", areaM2 / 1e6)) // ≈ 12 308 km² // Point containment (geodesic) let inside = CLLocationCoordinate2D(latitude: 0.5, longitude: 0.5) let outside = CLLocationCoordinate2D(latitude: 2.0, longitude: 2.0) print(square.contains(coordinate: inside, geodesic: true)) // true print(square.contains(coordinate: outside, geodesic: true)) // false // Snap tolerance — is a point within 10 m of the path edge? let edgeNear = CLLocationCoordinate2D(latitude: 0.0, longitude: 0.5) print(square.isOnPath(coordinate: edgeNear, geodesic: true, tolerance: 10)) // true // Multi-colour polyline spans let red = GMSStrokeStyle.solidColor(.red) let blue = GMSStrokeStyle.solidColor(.blue) let spans = square.styleSpans( styles: [red, blue], lengths: [0.5, 0.5], // 50 % red, 50 % blue lengthKind: .rhumb ) let polyline = GMSPolyline(path: square) polyline.spans = spans polyline.map = mapView ``` -------------------------------- ### Render GeoJSON Files with GMUGeoJSONParser and GMUGeometryRenderer Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Use GMUGeoJSONParser to parse GeoJSON data from a URL and GMUGeometryRenderer to draw the parsed features onto the GMSMapView. Custom styles can be provided if the GeoJSON lacks embedded styling. ```swift class GeoJSONViewController: UIViewController { private var mapView: GMSMapView! private var renderer: GMUGeometryRenderer? override func viewDidLoad() { super.viewDidLoad() mapView = GMSMapView(frame: view.bounds) view.addSubview(mapView) renderGeoJSON() } func renderGeoJSON() { guard let path = Bundle.main.path(forResource: "boundaries", ofType: "geojson"), let url = URL(string: "file://\(path)") else { return } let parser = GMUGeoJSONParser(url: url) parser.parse() // Inspect features for feature in parser.features { if let f = feature as? GMUFeature { print("id=\(f.identifier ?? \"none\") props=\(f.properties ?? [:])") } } // Build a custom style for polygons let style = GMUStyle( styleID: "#custom", strokeColor: UIColor.blue, fillColor: UIColor.blue.withAlphaComponent(0.2), width: 2, scale: 1, heading: 0, anchor: CGPoint(x: 0.5, y: 0.5), iconUrl: nil, title: nil, hasFill: true, hasStroke: true ) renderer = GMUGeometryRenderer( map: mapView, geometries: parser.features, styles: [style] ) renderer?.render() } } ``` -------------------------------- ### Create Custom Color Ramps with GMUGradient Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt GMUGradient maps intensity values in [0, 1] to a color by interpolating between specified (startPoint, color) pairs. It generates a color-lookup table for efficient rendering. Ensure startPoints are non-descending floats in [0, 1] and that the colors and startPoints arrays have the same length. ```swift import UIKit import GoogleMapsUtils // Two-stop gradient: transparent cyan → opaque magenta let simple = GMUGradient( colors: [UIColor.cyan.withAlphaComponent(0), UIColor.magenta], startPoints: [0.0, 1.0] as [NSNumber], colorMapSize: 256 ) // Five-stop rainbow (low → high) let rainbow = GMUGradient( colors: [ UIColor(red: 0, green: 0, blue: 1, alpha: 0.3), // blue UIColor(red: 0, green: 1, blue: 0.6, alpha: 0.6), // cyan UIColor(red: 0.2, green: 0.8, blue: 0, alpha: 0.8), // green UIColor(red: 1, green: 0.6, blue: 0, alpha: 0.9), // orange UIColor(red: 1, green: 0, blue: 0, alpha: 1.0), // red ], startPoints: [0.1, 0.3, 0.5, 0.7, 1.0] as [NSNumber], colorMapSize: 512 ) let colorMap = rainbow.generateColorMap() // [UIColor] of 512 entries let layer = GMUHeatmapTileLayer() layer.gradient = rainbow ``` -------------------------------- ### Configure Clustering Algorithm Distance Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Adjust the cluster-distance threshold for GMUNonHierarchicalDistanceBasedAlgorithm to control cluster tightness. A smaller value results in tighter clusters. ```objc // Objective-C — tighter clusters (50 pt distance) GMUNonHierarchicalDistanceBasedAlgorithm *algo = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] initWithClusterDistancePoints:50]; // Wider clusters (150 pt distance) GMUNonHierarchicalDistanceBasedAlgorithm *algoWide = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] initWithClusterDistancePoints:150]; // Grid-based alternative (simpler, faster for very large sets) GMUGridBasedClusterAlgorithm *gridAlgo = [[GMUGridBasedClusterAlgorithm alloc] init]; id iconGen = [[GMUDefaultClusterIconGenerator alloc] init]; GMUDefaultClusterRenderer *renderer = [[GMUDefaultClusterRenderer alloc] initWithMapView:_mapView clusterIconGenerator:iconGen]; _clusterManager = [[GMUClusterManager alloc] initWithMap:_mapView algorithm:algo renderer:renderer]; ``` -------------------------------- ### HeatmapInterpolationPoints Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Synthesizes additional GMUWeightedLatLng points using k-means clustering and inverse-distance weighting (IDW) to fill gaps in sparse datasets for continuous heatmaps. The 'influence' parameter controls intensity falloff with distance, and 'granularity' sets search coarseness. ```APIDOC ## HeatmapInterpolationPoints ### Description Uses k-means clustering combined with inverse-distance weighting (IDW) to synthesise additional `GMUWeightedLatLng` points when the source dataset is too sparse to produce a continuous heatmap. ### Parameters - `givenClusterIterations` (Int): The number of iterations for k-means clustering. - `influence` (Double): Controls how quickly intensity falls with distance. Must be in the range [2.0, 2.5]. - `granularity` (Float): Sets the search coarseness. Recommended value is 0.1, range is [0, 1]. ### Methods - `addWeightedLatLngs(latlngs: [GMUWeightedLatLng])`: Seeds the interpolator with initial data points. - `generatePoints(influence: Float, granularity: Float) throws -> [GMUWeightedLatLng]`: Generates dense synthetic points based on the provided influence and granularity. ### Example Usage ```swift import GoogleMapsUtils class HeatmapInterpolationViewController: UIViewController { private var heatmapLayer: GMUHeatmapTileLayer! func loadInterpolatedHeatmap(sparseCoordinates: [(lat: Double, lng: Double, w: Float)]) { let interpolator = HeatmapInterpolationPoints(givenClusterIterations: 25) // Seed with sparse observations let seedPoints = sparseCoordinates.map { GMUWeightedLatLng( coordinate: CLLocationCoordinate2D(latitude: $0.lat, longitude: $0.lng), intensity: $0.w ) } interpolator.addWeightedLatLngs(latlngs: seedPoints) // Generate dense synthetic points do { let densePoints = try interpolator.generatePoints( influence: 2.2, granularity: 0.1 ) print("Generated \(densePoints.count) interpolated points from \(seedPoints.count) seeds") heatmapLayer = GMUHeatmapTileLayer() heatmapLayer.radius = 50 heatmapLayer.weightedData = densePoints heatmapLayer.map = mapView } catch { // influence must be in [2.0, 2.5] print("Interpolation error: \(error)") } } } ``` ``` -------------------------------- ### Customize Marker Appearance with GMUDefaultClusterRenderer Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Implement GMUClusterRendererDelegate to modify markers before they are displayed. This allows for custom icons, titles, and snippets based on the underlying data. ```swift class CustomRendererViewController: UIViewController, GMUClusterRendererDelegate { private var clusterManager: GMUClusterManager! override func viewDidLoad() { super.viewDidLoad() let mapView = GMSMapView(frame: view.bounds) let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm() // Custom buckets with brand colours let buckets = [10, 50, 100, 200, 1000] as [NSNumber] let colors = [ UIColor(red: 0.2, green: 0.6, blue: 1.0, alpha: 1), UIColor(red: 0.1, green: 0.8, blue: 0.4, alpha: 1), UIColor(red: 1.0, green: 0.8, blue: 0.0, alpha: 1), UIColor(red: 1.0, green: 0.5, blue: 0.0, alpha: 1), UIColor(red: 0.9, green: 0.1, blue: 0.1, alpha: 1), ] let iconGen = GMUDefaultClusterIconGenerator(buckets: buckets, backgroundColors: colors) let renderer = GMUDefaultClusterRenderer(mapView: mapView, clusterIconGenerator: iconGen) renderer.delegate = self clusterManager = GMUClusterManager(map: mapView, algorithm: algorithm, renderer: renderer) } // Called before a marker is shown — customise freely func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) { if let item = marker.userData as? POIItem { marker.title = item.name marker.snippet = "Lat: \(item.position.latitude)" marker.icon = UIImage(named: "custom_pin") } } // Called after the marker has been animated onto the map func renderer(_ renderer: GMUClusterRenderer, didRenderMarker marker: GMSMarker) { print("Marker rendered: \(marker.title ?? "cluster")") } } ``` -------------------------------- ### MapPoint: Projected Coordinate Utilities Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt MapPoint represents coordinates in the mercator-projected space. Use it for fast Euclidean approximations, such as within custom clustering algorithms, avoiding repeated projection/unprojection. Ensure GoogleMapsUtils is imported. ```swift import CoreLocation import GoogleMapsUtils let coord = CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194) // Project to map space let mp = coord.mapPoint print(mp.x, mp.y) // projected x/y // Unproject back let back = mp.location print(back.latitude, back.longitude) // ≈ 37.7749, -122.4194 // Distance in projected space (dimensionless, relative units) let mp2 = CLLocationCoordinate2D(latitude: 37.8, longitude: -122.4).mapPoint let dist = mp.distance(to: mp2) print(dist) // Linear interpolation at 30 % between two points let midPt = MapPoint.interpolate(from: mp, to: mp2, fraction: 0.3) print(midPt.location) ``` -------------------------------- ### GMUGradient Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Defines custom color ramps for heatmaps by mapping intensity values in the range [0, 1] to colors through linear interpolation between specified (startPoint, color) pairs. It generates a color-lookup table for efficient rendering. ```APIDOC ## GMUGradient ### Description Maps intensity values in [0, 1] to a color by linearly interpolating between a set of (startPoint, color) pairs. Generates a color-lookup table of `colorMapSize` entries for efficient per-pixel lookup during tile rendering. ### Parameters - `colors` ([UIColor]): An array of `UIColor` objects representing the colors in the gradient. - `startPoints` ([NSNumber]): An array of non-descending `NSNumber` floats in the range [0, 1], indicating the position of each color stop. Must be the same length as the `colors` array. - `colorMapSize` (Int): The number of entries in the generated color lookup table. ### Methods - `generateColorMap() -> [UIColor]`: Generates and returns an array of `UIColor` objects representing the color lookup table. ### Example Usage ```swift import UIKit import GoogleMapsUtils // Two-stop gradient: transparent cyan → opaque magenta let simple = GMUGradient( colors: [UIColor.cyan.withAlphaComponent(0), UIColor.magenta], startPoints: [0.0, 1.0] as [NSNumber], colorMapSize: 256 ) // Five-stop rainbow (low → high) let rainbow = GMUGradient( colors: [ UIColor(red: 0, green: 0, blue: 1, alpha: 0.3), // blue UIColor(red: 0, green: 1, blue: 0.6, alpha: 0.6), // cyan UIColor(red: 0.2, green: 0.8, blue: 0, alpha: 0.8), // green UIColor(red: 1, green: 0.6, blue: 0, alpha: 0.9), // orange UIColor(red: 1, green: 0, blue: 0, alpha: 1.0), // red ], startPoints: [0.1, 0.3, 0.5, 0.7, 1.0] as [NSNumber], colorMapSize: 512 ) let colorMap = rainbow.generateColorMap() // [UIColor] of 512 entries let layer = GMUHeatmapTileLayer() layer.gradient = rainbow ``` ``` -------------------------------- ### GMSPolygon Extensions: contains and area Source: https://context7.com/googlemaps/google-maps-ios-utils/llms.txt Use these convenience wrappers to perform point-in-polygon tests and area calculations directly on a GMSPolygon object. Ensure the polygon is added to the map before use. ```swift import GoogleMaps import GoogleMapsUtils // Create polygon on the map let poly = GMSPolygon() let p = GMSMutablePath() p.add(CLLocationCoordinate2D(latitude: 37.7, longitude: -122.5)) p.add(CLLocationCoordinate2D(latitude: 37.7, longitude: -122.3)) p.add(CLLocationCoordinate2D(latitude: 37.9, longitude: -122.3)) p.add(CLLocationCoordinate2D(latitude: 37.9, longitude: -122.5)) poly.path = p poly.fillColor = UIColor.cyan.withAlphaComponent(0.3) poly.map = mapView // Test containment let sfCenter = CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194) print(poly.contains(coordinate: sfCenter)) // true // Area if let areaM2 = poly.area() { print(String(format: "Area: %.0f km²", areaM2 / 1e6)) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.