Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Placemark.properties #163

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions MapboxGeocoder.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
35506B8B200F856400629509 /* BridgingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35506B8A200F856400629509 /* BridgingTests.m */; };
35506B8C200F856400629509 /* BridgingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35506B8A200F856400629509 /* BridgingTests.m */; };
35506B8D200F856400629509 /* BridgingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35506B8A200F856400629509 /* BridgingTests.m */; };
355A7B7C21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355A7B7B21527B700001D2AD /* MBGeocodedPlacemark.swift */; };
355A7B7D21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355A7B7B21527B700001D2AD /* MBGeocodedPlacemark.swift */; };
355A7B7E21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355A7B7B21527B700001D2AD /* MBGeocodedPlacemark.swift */; };
355A7B7F21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355A7B7B21527B700001D2AD /* MBGeocodedPlacemark.swift */; };
355A7B8121527FAF0001D2AD /* forward_valid_hk.json in Resources */ = {isa = PBXBuildFile; fileRef = 355A7B8021527FAF0001D2AD /* forward_valid_hk.json */; };
355A7B8221527FAF0001D2AD /* forward_valid_hk.json in Resources */ = {isa = PBXBuildFile; fileRef = 355A7B8021527FAF0001D2AD /* forward_valid_hk.json */; };
355A7B8321527FAF0001D2AD /* forward_valid_hk.json in Resources */ = {isa = PBXBuildFile; fileRef = 355A7B8021527FAF0001D2AD /* forward_valid_hk.json */; };
357B4358202CC90A00735521 /* reverse_address.json in Resources */ = {isa = PBXBuildFile; fileRef = 357B4357202CC90A00735521 /* reverse_address.json */; };
357B4359202CC90A00735521 /* reverse_address.json in Resources */ = {isa = PBXBuildFile; fileRef = 357B4357202CC90A00735521 /* reverse_address.json */; };
357B435A202CC90A00735521 /* reverse_address.json in Resources */ = {isa = PBXBuildFile; fileRef = 357B4357202CC90A00735521 /* reverse_address.json */; };
Expand Down Expand Up @@ -223,6 +230,8 @@
07CF85C220F6DF93007B26B6 /* permanent_reverse_multiple_no_results.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = permanent_reverse_multiple_no_results.json; sourceTree = "<group>"; };
07CF85C620F6DFEB007B26B6 /* permanent_reverse_single_valid.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = permanent_reverse_single_valid.json; sourceTree = "<group>"; };
35506B8A200F856400629509 /* BridgingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BridgingTests.m; sourceTree = "<group>"; };
355A7B7B21527B700001D2AD /* MBGeocodedPlacemark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MBGeocodedPlacemark.swift; sourceTree = "<group>"; };
355A7B8021527FAF0001D2AD /* forward_valid_hk.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = forward_valid_hk.json; sourceTree = "<group>"; };
357B4357202CC90A00735521 /* reverse_address.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = reverse_address.json; sourceTree = "<group>"; };
35D3DE382112410A00B62912 /* CoreLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreLocation.swift; sourceTree = "<group>"; };
DA1AC0211E5C23B8006DF1D6 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; };
Expand Down Expand Up @@ -415,6 +424,7 @@
DA2EC05D1CED732F00D4BA5D /* MBGeocodeOptions.swift */,
DDC229591A36073B006BE405 /* MBGeocoder.swift */,
DA2E03EF1CB0FDB400D1269A /* MBPlacemark.swift */,
355A7B7B21527B700001D2AD /* MBGeocodedPlacemark.swift */,
DA29C8DE1CEBE90200E48A61 /* MBPlacemarkScope.h */,
DA2EC05B1CED72E900D4BA5D /* MBPlacemarkScope.swift */,
DA2E03F11CB0FE0200D1269A /* MBRectangularRegion.swift */,
Expand Down Expand Up @@ -488,6 +498,7 @@
DDF1E85B1BD70E4C00C40C78 /* reverse_valid.json */,
DDF1E85A1BD70E4C00C40C78 /* reverse_invalid.json */,
357B4357202CC90A00735521 /* reverse_address.json */,
355A7B8021527FAF0001D2AD /* forward_valid_hk.json */,
);
name = Fixtures;
path = fixtures;
Expand Down Expand Up @@ -793,6 +804,7 @@
buildActionMask = 2147483647;
files = (
07CF85B020F6DF2F007B26B6 /* permanent_forward_multiple_no_results.json in Resources */,
355A7B8221527FAF0001D2AD /* forward_valid_hk.json in Resources */,
07CF85A820F6DF0F007B26B6 /* permanent_invalid.json in Resources */,
07CF85C020F6DF86007B26B6 /* permanent_reverse_single_no_results.json in Resources */,
DA5170B81CF1B1F900CD6DCF /* forward_valid.json in Resources */,
Expand Down Expand Up @@ -824,6 +836,7 @@
buildActionMask = 2147483647;
files = (
07CF85B120F6DF2F007B26B6 /* permanent_forward_multiple_no_results.json in Resources */,
355A7B8321527FAF0001D2AD /* forward_valid_hk.json in Resources */,
07CF85A920F6DF0F007B26B6 /* permanent_invalid.json in Resources */,
07CF85C120F6DF86007B26B6 /* permanent_reverse_single_no_results.json in Resources */,
DA5170E21CF2542B00CD6DCF /* forward_valid.json in Resources */,
Expand Down Expand Up @@ -878,6 +891,7 @@
buildActionMask = 2147483647;
files = (
07CF85AF20F6DF2F007B26B6 /* permanent_forward_multiple_no_results.json in Resources */,
355A7B8121527FAF0001D2AD /* forward_valid_hk.json in Resources */,
07CF85A720F6DF0F007B26B6 /* permanent_invalid.json in Resources */,
07CF85BF20F6DF86007B26B6 /* permanent_reverse_single_no_results.json in Resources */,
DA210BAD1CB4BFF7008088FD /* forward_valid.json in Resources */,
Expand Down Expand Up @@ -970,6 +984,7 @@
files = (
DA5170B31CF1B1E000CD6DCF /* MBRectangularRegion.swift in Sources */,
DA5170B01CF1B1E000CD6DCF /* MBPlacemark.swift in Sources */,
355A7B7D21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */,
DA5170AF1CF1B1E000CD6DCF /* MBGeocoder.swift in Sources */,
DA5170B21CF1B1E000CD6DCF /* MBPlacemarkScope.swift in Sources */,
DA5170AE1CF1B1E000CD6DCF /* MBGeocodeOptions.swift in Sources */,
Expand All @@ -996,6 +1011,7 @@
files = (
DA5170DE1CF2541C00CD6DCF /* MBRectangularRegion.swift in Sources */,
DA5170DB1CF2541C00CD6DCF /* MBPlacemark.swift in Sources */,
355A7B7E21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */,
DA5170DA1CF2541C00CD6DCF /* MBGeocoder.swift in Sources */,
DA5170DD1CF2541C00CD6DCF /* MBPlacemarkScope.swift in Sources */,
DA5170D91CF2541C00CD6DCF /* MBGeocodeOptions.swift in Sources */,
Expand All @@ -1022,6 +1038,7 @@
files = (
DA5170F91CF2582F00CD6DCF /* MBRectangularRegion.swift in Sources */,
DA5170F61CF2582F00CD6DCF /* MBPlacemark.swift in Sources */,
355A7B7F21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */,
DA5170F51CF2582F00CD6DCF /* MBGeocoder.swift in Sources */,
DA5170F81CF2582F00CD6DCF /* MBPlacemarkScope.swift in Sources */,
DA5170F41CF2582F00CD6DCF /* MBGeocodeOptions.swift in Sources */,
Expand All @@ -1044,6 +1061,7 @@
files = (
DA2EC05E1CED732F00D4BA5D /* MBGeocodeOptions.swift in Sources */,
DA2E03F21CB0FE0200D1269A /* MBRectangularRegion.swift in Sources */,
355A7B7C21527B700001D2AD /* MBGeocodedPlacemark.swift in Sources */,
DDC2295E1A360843006BE405 /* MBGeocoder.swift in Sources */,
DA2EC05C1CED72E900D4BA5D /* MBPlacemarkScope.swift in Sources */,
DA2E03F01CB0FDB400D1269A /* MBPlacemark.swift in Sources */,
Expand Down
194 changes: 194 additions & 0 deletions MapboxGeocoder/MBGeocodedPlacemark.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import Foundation


/**
A concrete subclass of `Placemark` to represent results of geocoding requests.
*/
@objc(MBGeocodedPlacemark)
open class GeocodedPlacemark: Placemark {

private enum CodingKeys: String, CodingKey {
case routableLocations = "routable_points"
case relevance
}

private enum PointsCodingKeys: String, CodingKey {
case points
}

/**
An array of locations that serve as hints for navigating to the placemark.

If the `GeocodeOptions.includesRoutableLocations` property is set to `true`, this property contains locations that are suitable to use as a waypoint in a routing engine such as MapboxDirections.swift. Otherwise, if the `GeocodeOptions.includesRoutableLocations` property is set to `false`, this property is set to `nil`.

For the placemark’s geographic center, use the `location` property. The routable locations may differ from the geographic center. For example, if a house’s driveway leads to a street other than the nearest street (by straight-line distance), then this property may contain the location where the driveway meets the street. A route to the placemark’s geographic center may be impassable, but a route to the routable location would end on the correct street with access to the house.
*/
@objc open var routableLocations: [CLLocation]?

public required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

if let pointsContainer = try? container.nestedContainer(keyedBy: PointsCodingKeys.self, forKey: .routableLocations),
var coordinatesContainer = try? pointsContainer.nestedUnkeyedContainer(forKey: .points) {

if let routableLocation = try coordinatesContainer.decodeIfPresent(RoutableLocation.self),
let coordinate = routableLocation.coordinate {
routableLocations = [CLLocation(coordinate: coordinate)]
}
}

relevance = try container.decodeIfPresent(Double.self, forKey: .relevance) ?? -1

try super.init(from: decoder)
}

public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encodeIfPresent(relevance, forKey: .relevance)

if let routableLocations = routableLocations,
!routableLocations.isEmpty {
var pointsContainer = container.nestedContainer(keyedBy: PointsCodingKeys.self, forKey: .routableLocations)
var coordinatesContainer = pointsContainer.nestedUnkeyedContainer(forKey: .points)
let routableLocation = RoutableLocation(coordinates: [routableLocations[0].coordinate.longitude,
routableLocations[0].coordinate.latitude])
try coordinatesContainer.encode(routableLocation)
}

try super.encode(to: encoder)
}

@objc open override var debugDescription: String {
return qualifiedName!
}

internal var qualifiedNameComponents: [String] {
if qualifiedName!.contains(", ") {
return qualifiedName!.components(separatedBy: ", ")
}
// Chinese addresses have no commas and are reversed.
return (superiorPlacemarks?.map { $0.name } ?? []).reversed() + [name]
}

@objc open var formattedName: String {
let text = super.name
// For address features, `text` is just the street name. Look through the fully-qualified address to determine whether to put the house number before or after the street name.
if let houseNumber = address, scope == .address {
let streetName = text
let reversedAddress = "\(streetName) \(houseNumber)"
if qualifiedNameComponents.contains(reversedAddress) {
return reversedAddress
} else {
return "\(houseNumber) \(streetName)"
}
} else {
return text
}
}

@objc open override var genres: [String]? {
return properties?.category?.components(separatedBy: ", ")
}

@objc open override var imageName: String? {
return properties?.maki
}

/**
A numerical score from 0 (least relevant) to 0.99 (most relevant) measuring
how well each returned feature matches the query. Use this property to
remove results that don’t fully match the query.
*/
@objc open var relevance: Double

private var clippedAddressLines: [String] {
let lines = qualifiedNameComponents
if scope == .address {
return lines
}

guard let qualifiedName = qualifiedName,
qualifiedName.contains(", ") else {
// Chinese addresses have no commas and are reversed.
return Array(lines.prefix(lines.count))
}

return Array(lines.suffix(from: 1))
}

/**
The placemark’s full address in the customary local format, with each line in a separate string in the array.

If you need to fit the same address on a single line, use the `qualifiedName` property, in which each line is separated by a comma instead of a line break.
*/
var formattedAddressLines: [String]? {
return clippedAddressLines
}

#if !os(tvOS)
@available(iOS 9.0, OSX 10.11, *)
@objc open override var postalAddress: CNPostalAddress? {
let postalAddress = CNMutablePostalAddress()

if scope == .address {
postalAddress.street = name
} else if let address = address {
postalAddress.street = address.replacingOccurrences(of: ", ", with: "\n")
}

if let placeName = place?.name {
postalAddress.city = placeName
}
if let regionName = administrativeRegion?.name {
postalAddress.state = regionName
}
if let postalCode = postalCode?.name {
postalAddress.postalCode = postalCode
}
if let countryName = country?.name {
postalAddress.country = countryName
}
if let ISOCountryCode = country?.code {
postalAddress.isoCountryCode = ISOCountryCode
}

return postalAddress
}
#endif

open override var code: String? {
get { return country?.code }
set { country?.code = code }
}

@objc open override var addressDictionary: [AnyHashable: Any]? {
var addressDictionary: [String: Any] = [:]
if scope == .address {
addressDictionary[MBPostalAddressStreetKey] = name
} else if let address = properties?.address {
addressDictionary[MBPostalAddressStreetKey] = address
} else if let address = address {
addressDictionary[MBPostalAddressStreetKey] = address
}
addressDictionary[MBPostalAddressCityKey] = place?.name
addressDictionary[MBPostalAddressStateKey] = administrativeRegion?.name
addressDictionary[MBPostalAddressPostalCodeKey] = postalCode?.name
addressDictionary[MBPostalAddressCountryKey] = country?.name
addressDictionary[MBPostalAddressISOCountryCodeKey] = country?.code
addressDictionary["formattedAddressLines"] = clippedAddressLines
addressDictionary["name"] = name
addressDictionary["subAdministrativeArea"] = district?.name ?? place?.name
addressDictionary["subLocality"] = neighborhood?.name
addressDictionary["subThoroughfare"] = subThoroughfare
addressDictionary["thoroughfare"] = thoroughfare
return addressDictionary
}

/**
The phone number to contact a business at this location.
*/
@objc open override var phoneNumber: String? {
return properties?.phoneNumber
}
}
Loading