Creative crypter
Creative crypter

Reputation: 1516

iOS - swift 3 - heatmap

i am using this project to generate my heatmap:

https://github.com/dataminr/DTMHeatmap

I integrated the code as stated in:

https://github.com/dataminr/DTMHeatmap/issues/1

from @johndpope:

https://github.com/johndpope/TranSafe

First, it is compiled successfully, but when i use the "readData" like this:

readData([[52.517138, 13.401489], [52.517137, 13.401488], [52.517136, 13.401487]])

i get the

Thread 1: EXC_BAD_ACCESS(code=2, address=blabla) error

here is the method:

func readData(_ array: [[Double]]){
    self.heatmap = DTMHeatmap()
    var dict = Dictionary<NSObject, AnyObject>();
    for entry in array{

        let coordinate = CLLocationCoordinate2D(latitude: entry[1], longitude: entry[0]);

        let mapPoint = MKMapPointForCoordinate(coordinate)

        let type = NSValue(mkCoordinate: coordinate).objCType // <- THIS IS IT

        let value = NSValue(bytes: Unmanaged.passUnretained(mapPoint as AnyObject).toOpaque(), objCType: type);
        dict[value] = 1 as AnyObject?;

    }
    self.heatmap.setData(dict as [AnyHashable: Any]);
    self.mapView.add(self.heatmap)
}

func MKMapPointForCoordinate(_ coordinate: CLLocationCoordinate2D) -> MKMapPoint {

    return MKMapPointForCoordinate(coordinate);

}

// etc ...

I have really no idea what i have done wrong, anybody could help me with this issue?

Upvotes: 3

Views: 2479

Answers (2)

ruralcoder
ruralcoder

Reputation: 1020

Very performant heatmap library. I managed to get this working and it renders nicely. I am adding this answer because it also includes the rendererFor overlay delegate function needed to work.

class HeatmapViewController: UIViewController, MKMapViewDelegate {

var heatmap: DTMHeatmap? = nil
var diffHeatmap: DTMDiffHeatmap? = nil
@IBOutlet weak var mapView: MKMapView!

override func viewDidLoad() {
    super.viewDidLoad()
    var ret: [AnyHashable: Any] = [:]

    for location in locations {
        var mapPoint = MKMapPointForCoordinate(location.coordinate)
        let mapPointValue = NSValue(bytes: &mapPoint, objCType: "{MKMapPoint=dd}")

        ret[mapPointValue] = 10.0 // weight
     }

     self.heatmap = DTMHeatmap()
     self.heatmap?.setData(ret)

     self.mapView.delegate = self; // Important
     self.mapView.add(self.heatmap!)   
  }
}

This part is very important and for this to work you need to set the mapView's delegate to self.

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    return DTMHeatmapRenderer(overlay: overlay)
}

Upvotes: 0

OOPer
OOPer

Reputation: 47896

As far as I can read from the original code of DTMHeatmap, the keys for the dictionary passed for setData need to be NSValues containing MKMapPoint. And the code you have shown is not a proper code to make such NSValues. (I really doubt the original Swift 2 code you have found would actually work..., MKMapView cannot be bridged to Objective-C object in Swift 2, so mapPoint as! AnyObject should always fail.)

The readData method should be something like this:

func readData(_ array: [[Double]]){
    self.heatmap = DTMHeatmap()
    var dict: [AnyHashable: Any] = [:]
    for entry in array{

        let coordinate = CLLocationCoordinate2D(latitude: entry[1], longitude: entry[0]);

        var mapPoint = MKMapPointForCoordinate(coordinate)

        //Creating `objCType` manually is not recommended, but Swift does not have `@encoding()`...
        let type = "{MKMapPoint=dd}"

        let value = NSValue(bytes: &mapPoint, objCType: type)
        dict[value] = 1

    }
    self.heatmap.setData(dict)
    self.mapView.add(self.heatmap)
}

(I haven't checked with the actual DTMHeatmap, so you may need some more fixes.)

Upvotes: 3

Related Questions