LocationView.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // Copyright (C) 2016 Inigo Valentin
  2. //
  3. // This file is part of the Gasteizko Margolariak IOS app.
  4. //
  5. // The Gasteizko Margolariak IOS app is free software: you can
  6. // redistribute it and/or modify it under the terms of the
  7. // GNU General Public License as published by the Free Software
  8. // Foundation, either version 3 of the License, or (at your
  9. // option) any later version.
  10. //
  11. // The Gasteizko Margolariak IOS app is distributed in the
  12. // hope that it will be useful, but WITHOUT ANY WARRANTY;
  13. // without even the implied warranty of MERCHANTABILITY or
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
  15. // Public License for more details.
  16. //
  17. // You should have received a copy of the GNU General Public
  18. // License along with the Gasteizko Margolariak IOS app.
  19. // If not, see <http://www.gnu.org/licenses/>.
  20. import Foundation
  21. import CoreData
  22. import MapKit
  23. import UIKit
  24. /**
  25. Class to handle the location view.
  26. */
  27. class LocationView: UIView {
  28. @IBOutlet var container: UIView!
  29. @IBOutlet weak var map: MKMapView!
  30. @IBOutlet weak var lbTitle: UILabel!
  31. @IBOutlet weak var lbDistance: UILabel!
  32. @IBOutlet weak var lbNo: UILabel!
  33. var controller: ViewController
  34. var storyboard: UIStoryboard
  35. var didFindMyLocation = false
  36. var locationTimer: Timer? = nil
  37. var mapRenderer: MKTileOverlayRenderer!
  38. /**
  39. Default constructor for the interface builder.
  40. :param: frame View frame.
  41. */
  42. override init(frame: CGRect){
  43. // Set controller
  44. self.storyboard = UIStoryboard(name: "Main", bundle: nil)
  45. self.controller = storyboard.instantiateViewController(withIdentifier: "GMViewController") as! ViewController
  46. super.init(frame: frame)
  47. }
  48. /**
  49. Run when the view is started.
  50. */
  51. required init?(coder aDecoder: NSCoder) {
  52. // Set controller
  53. self.storyboard = UIStoryboard(name: "Main", bundle: nil)
  54. self.controller = storyboard.instantiateViewController(withIdentifier: "GMViewController") as! ViewController
  55. super.init(coder: aDecoder)
  56. // Load the contents of the HomeView.xib file.
  57. Bundle.main.loadNibNamed("LocationView", owner: self, options: nil)
  58. self.addSubview(self.container)
  59. self.container.frame = self.bounds
  60. // Set map up
  61. //map.isMyLocationEnabled = true
  62. //map.addObserver(self, forKeyPath: "myLocation", options: NSKeyValueObservingOptions.new, context: nil)
  63. //let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: 42.846399, longitude: -2.673365, zoom: 12.0)
  64. //map.camera = camera
  65. // Schedule location fetches
  66. getNewLocation()
  67. Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(getNewLocation), userInfo: nil, repeats: true)
  68. }
  69. /**
  70. Get new user location and recalculates distance to GM .
  71. */
  72. @objc func getNewLocation(){
  73. let defaults = UserDefaults.standard
  74. if (defaults.value(forKey: "GMLocLat") != nil && defaults.value(forKey: "GMLocLon") != nil){
  75. let lat = defaults.value(forKey: "GMLocLat") as! Double
  76. let lon = defaults.value(forKey: "GMLocLon") as! Double
  77. let time = defaults.value(forKey: "GMLocTime") as! Date
  78. let cTime = Date()
  79. let minutes = Calendar.current.dateComponents([.minute], from: time, to: cTime).minute
  80. if (minutes! < 30){
  81. self.map.isHidden = false
  82. self.lbTitle.isHidden = false
  83. self.lbDistance.isHidden = false
  84. self.lbNo.isHidden = true
  85. // Set up map
  86. setupMapRenderer()
  87. self.map.showsUserLocation = true
  88. self.map.delegate = self;
  89. // Set marker
  90. let annotation = MKPointAnnotation()
  91. annotation.coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lon)
  92. self.map.addAnnotation(annotation)
  93. // Center map
  94. let center = CLLocation(latitude: lat, longitude: lon)
  95. let radius: CLLocationDistance = 1000
  96. let coordinateRegion = MKCoordinateRegionMakeWithDistance(center.coordinate,
  97. radius, radius)
  98. self.map.setRegion(coordinateRegion, animated: true)
  99. let location = self.controller.getLocation()
  100. if location != nil {
  101. let d: Int = calculateDistance(lat1: location.latitude, lon1: location.longitude, lat2: lat, lon2: lon)
  102. if d <= 1000 {
  103. self.lbDistance.text = "A \(d) metros de ti."
  104. }
  105. else{
  106. self.lbDistance.text = "A \(Int(d/1000)) kilómetros de ti."
  107. }
  108. }
  109. }
  110. else{
  111. self.map.isHidden = true
  112. self.lbTitle.isHidden = true
  113. self.lbDistance.isHidden = true
  114. self.lbNo.isHidden = false
  115. }
  116. }
  117. }
  118. /**
  119. Converts degrees to radians.
  120. :param: degrees Angle in degrees.
  121. :return: Angle in radiands.
  122. */
  123. func degreesToRadians(degrees: Double) -> Double {
  124. return degrees * Double.pi / 180;
  125. }
  126. /**
  127. Calculates the distance, in integer meters, between two coordinates.
  128. :param: lat1 Latitude component of the first point.
  129. :param: lon1 Longitude component of the first point.
  130. :param: lat2 Latitude component of the second point.
  131. :param: lon2 Longitude component of the second point.
  132. :return: Distance, in integer meters, between the points.
  133. */
  134. func calculateDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Int {
  135. let eRadius: Double = 6371
  136. let dLat: Double = degreesToRadians(degrees: lat2-lat1)
  137. let dLon: Double = degreesToRadians(degrees: lon2-lon1)
  138. let l1: Double = degreesToRadians(degrees: lat1)
  139. let l2: Double = degreesToRadians(degrees: lat2)
  140. let a: Double = sin(dLat/2) * sin(dLat/2) + sin(dLon/2) * sin(dLon/2) * cos(l1) * cos(l2)
  141. let c: Double = 2 * atan2(sqrt(a), sqrt(1-a))
  142. let m: Double = eRadius * c * 1000
  143. return Int(m)
  144. }
  145. /**
  146. Selects the renderer for the map.
  147. :return: The map renderer.
  148. */
  149. func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
  150. return mapRenderer
  151. }
  152. /**
  153. Sets up the map renderer using OpenStreet Maps tiles.
  154. */
  155. func setupMapRenderer() {
  156. let osmTemplate = "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
  157. let osmOverlay = MKTileOverlay(urlTemplate: osmTemplate)
  158. osmOverlay.canReplaceMapContent = true
  159. self.map.add(osmOverlay, level: .aboveLabels)
  160. self.mapRenderer = MKTileOverlayRenderer(tileOverlay: osmOverlay)
  161. }
  162. }
  163. /**
  164. Extension to make the class comply with MKMapViewDelegate.
  165. */
  166. extension LocationView: MKMapViewDelegate {
  167. func map(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
  168. return mapRenderer
  169. }
  170. }