MapAmapGeneralProcessing.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. //
  2. // MapAmapGeneralProcessing.swift
  3. // map_amap_ios
  4. //
  5. // Created by 诺诺诺的言 on 2025/7/22.
  6. //
  7. import Foundation
  8. import MapKit
  9. import ObjectiveC
  10. extension Decodable {
  11. static func fromJson(json: Any) -> Self? {
  12. do {
  13. let data = try JSONSerialization.data(withJSONObject: json, options: [])
  14. return try JSONDecoder().decode(Self.self, from: data)
  15. } catch {
  16. print(error.localizedDescription)
  17. return nil
  18. }
  19. }
  20. }
  21. extension Encodable {
  22. func toJson() -> [String: Any] {
  23. guard let data = try? JSONEncoder().encode(self) else {
  24. return [:]
  25. }
  26. return try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
  27. }
  28. }
  29. struct ATMapCameraPosition: Codable {
  30. var latitude: CGFloat
  31. var longitude: CGFloat
  32. // 地图缩放比例,对应span
  33. var zoom: CGFloat
  34. }
  35. struct ATMapPadding: Codable {
  36. var top: CGFloat
  37. var left: CGFloat
  38. var bottom: CGFloat
  39. var right: CGFloat
  40. var padding: UIEdgeInsets {
  41. return UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
  42. }
  43. }
  44. // 定义关联对象的键
  45. private var associatedLineIdKey = "associatedLineIdKey"
  46. private var associatedLineTypeKey = "associatedLineTypeKey"
  47. private var associatedColorKey = "associatedColorKey"
  48. private var associatedWidthKey = "associatedWidthKey"
  49. extension MKPolyline {
  50. // 关联 lineId 属性
  51. var associatedLineId: String? {
  52. get {
  53. return objc_getAssociatedObject(self, &associatedLineIdKey) as? String
  54. }
  55. set {
  56. objc_setAssociatedObject(self, &associatedLineIdKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  57. }
  58. }
  59. // 关联 lineType 属性
  60. var associatedLineType: String? {
  61. get {
  62. return objc_getAssociatedObject(self, &associatedLineTypeKey) as? String
  63. }
  64. set {
  65. objc_setAssociatedObject(self, &associatedLineTypeKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  66. }
  67. }
  68. // 关联 color 属性
  69. var associatedColor: String? {
  70. get {
  71. return objc_getAssociatedObject(self, &associatedColorKey) as? String
  72. }
  73. set {
  74. objc_setAssociatedObject(self, &associatedColorKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  75. }
  76. }
  77. // 关联 width 属性
  78. var associatedWidth: Double? {
  79. get {
  80. return objc_getAssociatedObject(self, &associatedWidthKey) as? Double
  81. }
  82. set {
  83. objc_setAssociatedObject(self, &associatedWidthKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  84. }
  85. }
  86. }
  87. class ATMapPolyline: NSObject, Codable {
  88. var id: String = UUID().uuidString
  89. var lineId: String // 新增:用于记录的线ID
  90. var lineType: String // 新增:用于记录线的样式 normal error selected color
  91. var points: [CLLocationCoordinate2D]
  92. var mapPadding: ATMapPadding?
  93. var color : String ///轨迹的颜色
  94. var width: Double /// 轨迹的宽度
  95. var polyline: MKPolyline {
  96. return MKPolyline(coordinates: points, count: points.count)
  97. }
  98. enum CodingKeys: String, CodingKey {
  99. case lineId, lineType, points, mapPadding,color,width
  100. }
  101. required init(from decoder: Decoder) throws {
  102. let container = try decoder.container(keyedBy: CodingKeys.self)
  103. if container.contains(.lineId) {
  104. lineId = try container.decodeIfPresent(String.self, forKey: .lineId) ?? ""
  105. } else {
  106. lineId = ""
  107. }
  108. if container.contains(.lineType) {
  109. lineType = try container.decodeIfPresent(String.self, forKey: .lineType) ?? ""
  110. } else {
  111. lineType = "";
  112. }
  113. if container.contains(.points) {
  114. points = try container.decodeIfPresent([CLLocationCoordinate2D].self, forKey: .points) ?? [CLLocationCoordinate2D]()
  115. } else {
  116. points = [CLLocationCoordinate2D]()
  117. }
  118. if container.contains(.color) {
  119. color = try container.decodeIfPresent(String.self, forKey: .color) ?? ""
  120. } else {
  121. color = ""
  122. }
  123. if container.contains(.width) {
  124. width = try container.decodeIfPresent(Double.self, forKey: .width) ?? 0
  125. } else {
  126. width = 0
  127. }
  128. if container.contains(.mapPadding) {
  129. mapPadding = try container.decodeIfPresent(ATMapPadding.self, forKey: .mapPadding) ?? ATMapPadding(top: 0, left: 0, bottom: 0, right: 0)
  130. } else {
  131. mapPadding = ATMapPadding(top: 0, left: 0, bottom: 0, right: 0)
  132. }
  133. }
  134. func encode(to encoder: Encoder) throws {
  135. var container = encoder.container(keyedBy: CodingKeys.self)
  136. try container.encode(lineId, forKey: .lineId)
  137. try container.encode(lineType, forKey: .lineType)
  138. try container.encode(points, forKey: .points)
  139. try container.encodeIfPresent(mapPadding, forKey: .mapPadding)
  140. }
  141. // 初始化方法
  142. init(lineId: String, lineType: String, points: [CLLocationCoordinate2D], mapPadding: ATMapPadding? = nil,color : String,width : Double) {
  143. self.lineId = lineId
  144. self.lineType = lineType
  145. self.points = points
  146. self.mapPadding = mapPadding
  147. self.color = color
  148. self.width = width
  149. super.init()
  150. }
  151. }
  152. class ATMapMarker: NSObject, Codable {
  153. var id: String
  154. var markerId: String
  155. var markerName: String?
  156. var customAvatarUrl : String?
  157. var latitude: CGFloat
  158. var longitude: CGFloat
  159. var isSelected: Bool
  160. var markerType: any MapMarkerSupportType
  161. var tags: [String : String]?
  162. init(id: String, markerId: String,markerName: String?, customAvatarUrl: String?,location: CLLocationCoordinate2D, markerType: any MapMarkerSupportType, isSelected: Bool = false,tags: [String : String]?) {
  163. self.id = id
  164. self.markerId = markerId
  165. self.markerName = markerName
  166. self.customAvatarUrl = customAvatarUrl
  167. self.latitude = location.latitude
  168. self.longitude = location.longitude
  169. self.markerType = markerType
  170. self.isSelected = isSelected
  171. self.tags = tags
  172. }
  173. func update(coordinate: CLLocationCoordinate2D, name: String? = nil, isSelect: Bool) {
  174. self.latitude = coordinate.latitude
  175. self.longitude = coordinate.longitude
  176. self.markerName = name
  177. self.isSelected = isSelect
  178. }
  179. enum CodingKeys: String, CodingKey {
  180. case id,markerId,markerName,customAvatarUrl, latitude, longitude, isSelected, markerType,tags
  181. }
  182. required init(from decoder: Decoder) throws {
  183. let container = try decoder.container(keyedBy: CodingKeys.self)
  184. id = try container.decode(String.self, forKey: .id)
  185. if id.isEmpty {
  186. id = "user_location"
  187. }
  188. if container.contains(.markerName) {
  189. markerName = try container.decodeIfPresent(String.self, forKey: .markerName) ?? ""
  190. } else {
  191. markerName = ""
  192. }
  193. if container.contains(.customAvatarUrl) {
  194. customAvatarUrl = try container.decodeIfPresent(String.self, forKey: .customAvatarUrl) ?? ""
  195. } else {
  196. customAvatarUrl = ""
  197. }
  198. if container.contains(.latitude) {
  199. latitude = try container.decodeIfPresent(CGFloat.self, forKey: .latitude) ?? 0
  200. } else {
  201. latitude = 0
  202. }
  203. if container.contains(.longitude) {
  204. longitude = try container.decodeIfPresent(CGFloat.self, forKey: .longitude) ?? 0
  205. } else {
  206. longitude = 0
  207. }
  208. if container.contains(.isSelected) {
  209. isSelected = try container.decodeIfPresent(Bool.self, forKey: .isSelected) ?? false
  210. } else {
  211. isSelected = false
  212. }
  213. // 使用工厂方法创建正确类型的markerType
  214. if container.contains(.markerType) {
  215. let rawValue = try container.decodeIfPresent(Int.self, forKey: .markerType) ?? 1
  216. markerType = MarkerTypeFactory.markerType(from: rawValue)
  217. } else {
  218. markerType = MarkerTypeFactory.markerType(from: 1)
  219. }
  220. ///气泡内容
  221. // 处理tags为空的情况
  222. if container.contains(.tags) {
  223. tags = try container.decodeIfPresent([String: String].self, forKey: .tags) ?? [:]
  224. } else {
  225. tags = [:] // 默认为空字典
  226. }
  227. if container.contains(.markerId) {
  228. markerId = try container.decodeIfPresent(String.self, forKey: .markerId) ?? ""
  229. } else {
  230. markerId = ""
  231. }
  232. }
  233. func encode(to encoder: Encoder) throws {
  234. var container = encoder.container(keyedBy: CodingKeys.self)
  235. try container.encode(id, forKey: .id)
  236. try container.encode(markerName, forKey: .markerName)
  237. try container.encode(customAvatarUrl, forKey: .customAvatarUrl)
  238. try container.encode(latitude, forKey: .latitude)
  239. try container.encode(longitude, forKey: .longitude)
  240. try container.encode(isSelected, forKey: .isSelected)
  241. try container.encode(markerType.rawValue, forKey: .markerType)
  242. try container.encode(tags, forKey: .tags)
  243. try container.encode(markerId, forKey: .markerId)
  244. }
  245. }
  246. extension ATMapMarker: MKAnnotation {
  247. var coordinate: CLLocationCoordinate2D {
  248. return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
  249. }
  250. }
  251. extension CLLocationCoordinate2D: Codable {
  252. enum CodingKeys: String, CodingKey {
  253. case latitude
  254. case longitude
  255. }
  256. public init(from decoder: Decoder) throws {
  257. let container = try decoder.container(keyedBy: CodingKeys.self)
  258. let latitude = try container.decode(Double.self, forKey: .latitude)
  259. let longitude = try container.decode(Double.self, forKey: .longitude)
  260. self.init(latitude: latitude, longitude: longitude)
  261. }
  262. public func encode(to encoder: Encoder) throws {
  263. var container = encoder.container(keyedBy: CodingKeys.self)
  264. try container.encode(latitude, forKey: .latitude)
  265. try container.encode(longitude, forKey: .longitude)
  266. }
  267. }
  268. class ATMapLocation: NSObject, Codable {
  269. var latitude: CGFloat?
  270. var longitude: CGFloat?
  271. var address: String?
  272. var errorCode: Int = 0
  273. var time: Int?
  274. var bearing: CGFloat?
  275. var speed: CGFloat?
  276. init(latitude: CGFloat? = nil, longitude: CGFloat? = nil, address: String? = nil, time: Int? = nil, bearing: CGFloat? = nil, speed: CGFloat? = nil) {
  277. self.latitude = latitude
  278. self.longitude = longitude
  279. self.address = address
  280. self.time = time
  281. self.bearing = bearing
  282. self.speed = speed
  283. super.init()
  284. }
  285. static func fromLocation(location: CLLocation) -> ATMapLocation {
  286. return ATMapLocation(
  287. latitude: CGFloat(location.coordinate.latitude),
  288. longitude: CGFloat(location.coordinate.longitude),
  289. address: nil,
  290. time: Int(location.timestamp.timeIntervalSince1970 * 1000),
  291. bearing: CGFloat(location.course),
  292. speed: CGFloat(location.speed)
  293. )
  294. }
  295. }