├── FinishPlacemarkHint
├── FinishPlacemarkHelper
│ ├── art.scnassets
│ │ ├── ship.scn
│ │ └── texture.png
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── VectorMath
│ │ ├── VectorMath+SceneKit.swift
│ │ └── VectorMath+QuartzCore.swift
│ ├── Utils
│ │ └── Utils.swift
│ └── ViewController.swift
└── FinishPlacemarkHelper.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── project.pbxproj
├── PedestrianARNavigation
├── PedestrianARNavigation
│ ├── art.scnassets
│ │ ├── ship.scn
│ │ └── texture.png
│ ├── ARKit+CoreLocation
│ │ ├── LocationEstimatesHolder
│ │ │ ├── LocationEstimatesHolder.swift
│ │ │ ├── AdvancedLocationEstimatesHolder.swift
│ │ │ ├── BasicLocationEstimatesHolder.swift
│ │ │ └── SceneLocationEstimate+Extensions.swift
│ │ ├── TrueNorthCorrector
│ │ │ └── TrueNorthCorrector.swift
│ │ ├── LocationManager
│ │ │ ├── LocationManager.swift
│ │ │ └── NativeLocationManager.swift
│ │ ├── ARKitCoreLocationEngine.swift
│ │ └── GeoExtensions
│ │ │ └── GeoExtensions.swift
│ ├── Constants.swift
│ ├── RouteArrowAnimation.swift
│ ├── Utils
│ │ ├── Utils.swift
│ │ └── Utilities
│ │ │ ├── TimerAction.swift
│ │ │ ├── ArrayExtensions.swift
│ │ │ ├── Notifier.swift
│ │ │ ├── Geometry.swift
│ │ │ ├── SCNVector3Extensions.swift
│ │ │ └── AutoLayout.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── AppDelegate.swift
│ ├── VectorMath
│ │ ├── VectorMath+SceneKit.swift
│ │ └── VectorMath+QuartzCore.swift
│ ├── MapViewController.swift
│ ├── RouteAnimationUtils.swift
│ └── RouteNodes.swift
├── PedestrianARNavigation.xcodeproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── PedestrianARNavigationTests
│ ├── Info.plist
│ └── PedestrianARNavigationTests.swift
├── RoutePolyline
├── RoutePolyline.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
└── RoutePolyline
│ ├── RouteArrowAnimation.swift
│ ├── Info.plist
│ ├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── VectorMath
│ ├── VectorMath+SceneKit.swift
│ └── VectorMath+QuartzCore.swift
│ ├── RouteNodes.swift
│ ├── ViewController.swift
│ ├── Utils
│ └── Utils.swift
│ └── RouteAnimationUtils.swift
├── README.md
├── .gitignore
└── Links
/FinishPlacemarkHint/FinishPlacemarkHelper/art.scnassets/ship.scn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trimonovds/mobius-samples/HEAD/FinishPlacemarkHint/FinishPlacemarkHelper/art.scnassets/ship.scn
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/art.scnassets/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trimonovds/mobius-samples/HEAD/FinishPlacemarkHint/FinishPlacemarkHelper/art.scnassets/texture.png
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/art.scnassets/ship.scn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trimonovds/mobius-samples/HEAD/PedestrianARNavigation/PedestrianARNavigation/art.scnassets/ship.scn
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/art.scnassets/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trimonovds/mobius-samples/HEAD/PedestrianARNavigation/PedestrianARNavigation/art.scnassets/texture.png
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mobius-samples
2 |
3 | ### FinishPlacemarkHint
4 | Реализация вспомогательной метку в ARKit
5 | ### RoutePolyline
6 | Реализация полилинии маршрута
7 | ### PedestrianARNavigation
8 | Проект, в котором скомбинированы получение маршрута и отрисовка элементов маршрута (вспомогательная метка, метка финиша, полилиния маршрута). Метка конечной точки рендериться через UIKit. Коррекция направления осей не прикручена
9 | * Для выбора конечной точки маршрута нажми Destination, затем сделай longPress на карте и нажми Done =)
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/LocationEstimatesHolder/LocationEstimatesHolder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocationEstimatesHolder.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreLocation
11 |
12 | protocol LocationEstimatesHolder {
13 | var bestLocationEstimate: SceneLocationEstimate? { get }
14 | var estimates: [SceneLocationEstimate] { get }
15 |
16 | func add(_ locationEstimate: SceneLocationEstimate)
17 | func filter(_ isIncluded: (SceneLocationEstimate) -> Bool)
18 | }
19 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/TrueNorthCorrector/TrueNorthCorrector.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TrueNorthCorrector.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 09/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public func correctionAngleByBearing(_ e1: SceneLocationEstimate, _ e2: SceneLocationEstimate) -> Double {
12 | let calculatedE2Location = e1.translatedLocation(to: e2.position)
13 | return bearingBetween(e1.location.coordinate, calculatedE2Location.coordinate) - bearingBetween(e1.location.coordinate, e2.location.coordinate)
14 | }
15 |
--------------------------------------------------------------------------------
/Links:
--------------------------------------------------------------------------------
1 | сэмпл - https://github.com/trimonovds/mobius-samples
2 | бложик - https://medium.com/yandex-maps-ios
3 | формулы конвертации - https://www.movable-type.co.uk/scripts/latlong.html
4 | ARKit+CoreLocation - проект (https://github.com/ProjectDent/ARKit-CoreLocation), туторы (https://medium.com/journey-of-one-thousand-apps/arkit-and-corelocation-part-one-fc7cb2fa0150)
5 | много интересного про ARKit - https://medium.com/super-ventures-blog/why-is-arkit-better-than-the-alternatives-af8871889d6a
6 | другие тоже крутят оси =) - https://github.com/mapbox/mapbox-ar-unity
7 | история AR в одной картинке - https://blog.maugry.ru/blog/technologies/history-of-augmented-reality/
8 | esquire AR - https://www.youtube.com/watch?v=LGwHQwgBzSI
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/LocationEstimatesHolder/AdvancedLocationEstimatesHolder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AdvancedLocationEstimatesHolder.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 04/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class AdvancedLocationEstimatesHolder: BasicLocationEstimatesHolder {
12 |
13 | override func add(_ locationEstimate: SceneLocationEstimate) {
14 | for estimate in estimates {
15 | guard !estimate.canReplace(locationEstimate) else { return }
16 | }
17 | super.add(locationEstimate)
18 | filter { !locationEstimate.canReplace($0) }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigationTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 04/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import SceneKit
11 |
12 | struct Constants {
13 |
14 | static let sceneRadiusLimit: CGFloat = 100
15 |
16 | static let distanceBetweenArrows: Float = 5.0
17 |
18 | static let sampleRoute: [CGPoint] = [
19 | CGPoint.zero,
20 | CGPoint(x: 2, y: 0),
21 | CGPoint(x: 7, y: 0),
22 | CGPoint(x: 10, y: 0),
23 | CGPoint(x: 10, y: 5),
24 | CGPoint(x: 7, y: 7),
25 | CGPoint(x: 5, y: 5),
26 | CGPoint(x: 5, y: 10),
27 | CGPoint(x: 0, y: 10),
28 | CGPoint(x: -6, y: 4),
29 | CGPoint(x: 0, y: 0)
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/RouteArrowAnimation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouteArrowAnimation.swift
3 | // RoutePolyline
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct Step {
12 | let start: CGPoint
13 | let end: CGPoint
14 | let length: CGFloat
15 |
16 | init(start: CGPoint, end: CGPoint) {
17 | assert(start != end)
18 | self.start = start
19 | self.end = end
20 | self.length = start.distance(to: end)
21 | }
22 | }
23 |
24 | struct Animation {
25 | var steps: [Step]
26 | }
27 |
28 | extension Step {
29 | var vec: Vector2 {
30 | return Vector2(end) - Vector2(start)
31 | }
32 | }
33 |
34 | extension Animation {
35 | var points: [CGPoint] {
36 | return steps.map { [$0.start, $0.end] }.flatMap { $0 }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/RouteArrowAnimation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouteArrowAnimation.swift
3 | // RoutePolyline
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct Step {
12 | let start: CGPoint
13 | let end: CGPoint
14 | let length: CGFloat
15 |
16 | init(start: CGPoint, end: CGPoint) {
17 | assert(start != end)
18 | self.start = start
19 | self.end = end
20 | self.length = start.distance(to: end)
21 | }
22 | }
23 |
24 | struct Animation {
25 | var steps: [Step]
26 | }
27 |
28 | extension Step {
29 | var vec: Vector2 {
30 | return Vector2(end) - Vector2(start)
31 | }
32 | }
33 |
34 | extension Animation {
35 | var points: [CGPoint] {
36 | return steps.map { [$0.start, $0.end] }.flatMap { $0 }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // FinishPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import SceneKit
12 |
13 | extension UIImage {
14 | class func image(from view: UIView) -> UIImage? {
15 | UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
16 | guard let context = UIGraphicsGetCurrentContext() else { return nil }
17 |
18 | view.layer.render(in: context)
19 | let img = UIGraphicsGetImageFromCurrentImageContext()
20 | UIGraphicsEndImageContext()
21 | return img
22 | }
23 | }
24 |
25 | public extension NSAttributedString {
26 |
27 | public func boundingRect(size: CGSize) -> CGRect {
28 | let rect = self.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
29 | return rect.integral
30 | }
31 |
32 | public func boundingRect(width: CGFloat) -> CGRect {
33 | return boundingRect(size: CGSize(width: width, height: .infinity))
34 | }
35 |
36 | public func boundingSize(width: CGFloat) -> CGSize {
37 | return boundingRect(width: width).size
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utilities/TimerAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimerAction.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TimerAction {
12 |
13 | // MARK: Public Nested Types
14 |
15 | typealias Block = () -> Void
16 |
17 | // MARK: Public
18 |
19 | init(timeInterval: TimeInterval, repeats: Bool, onTick: @escaping Block) {
20 | let timerTarget = TimerTarget(onTick: onTick)
21 | self.timer = Timer.scheduledTimer(timeInterval: timeInterval, target: timerTarget,
22 | selector: #selector(TimerTarget.timerTickHandler),
23 | userInfo: nil, repeats: repeats)
24 | }
25 |
26 | deinit {
27 | invalidate()
28 | }
29 |
30 | // MARK: -
31 |
32 | func invalidate() {
33 | timer.invalidate()
34 | }
35 |
36 | // MARK: Private Properties
37 |
38 | private let timer: Timer
39 |
40 | // MARK: Private Nested Types
41 |
42 | private class TimerTarget {
43 |
44 | var onTick: Block
45 |
46 | init(onTick: @escaping Block) {
47 | self.onTick = onTick
48 | }
49 |
50 | @objc fileprivate func timerTickHandler() {
51 | onTick()
52 | }
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/LocationEstimatesHolder/BasicLocationEstimatesHolder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BasicLocationEstimatesHolder.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BasicLocationEstimatesHolder: LocationEstimatesHolder {
12 |
13 | private(set) var bestLocationEstimate: SceneLocationEstimate? = nil
14 | private(set) var estimates: [SceneLocationEstimate] = []
15 |
16 | func add(_ locationEstimate: SceneLocationEstimate) {
17 | estimates.append(locationEstimate)
18 | if let bestEstimate = bestLocationEstimate, bestEstimate < locationEstimate { return }
19 | bestLocationEstimate = locationEstimate
20 | }
21 |
22 | func filter(_ isIncluded: (SceneLocationEstimate) -> Bool) {
23 | let (passed, removed) = estimates.reduce(([SceneLocationEstimate](),[SceneLocationEstimate]())) { passedRemovedPair, estimate in
24 | let passed = isIncluded(estimate)
25 | return (passedRemovedPair.0 + (passed ? [estimate] : []),
26 | passedRemovedPair.1 + (passed ? [] : [estimate]))
27 | }
28 |
29 | assert(passed.count + removed.count == estimates.count)
30 |
31 | estimates = passed
32 | if let bestEstimate = bestLocationEstimate, !removed.contains(bestEstimate) { return }
33 | bestLocationEstimate = estimates.sorted{ $0 < $1 }.first
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utilities/ArrayExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ArrayExtensions.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 22/03/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Array {
12 |
13 | public func skip(_ n: Int) -> Array {
14 | let result: [Element] = []
15 | return n > count ? result : Array(self[Int(n).. Bool) -> Bool {
19 | return self.filter(condition).count == self.count
20 | }
21 |
22 | public func any(condition: (Element) -> Bool) -> Bool {
23 | return self.filter(condition).count > 0
24 | }
25 | }
26 |
27 | public extension Swift.Collection {
28 |
29 | /// Returns the element at the specified index iff it is within bounds, otherwise nil.
30 | public subscript (safe index: Index) -> Element? {
31 | return indices.contains(index) ? self[index] : nil
32 | }
33 | }
34 |
35 | extension Sequence {
36 |
37 | /// Returns single element that sutisfies predicate
38 | /// or nil if no elements found or more than one element found
39 | /// - Parameter condition: predicate
40 | /// - Returns: the only element that sutisfies predicate or nil otherwise
41 | public func single(condition: (Element) -> Bool) -> Element? {
42 | let sutisfiableElements = self.filter(condition)
43 | if sutisfiableElements.count > 1 {
44 | return nil
45 | } else {
46 | return sutisfiableElements.first
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/LocationManager/LocationManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocationManager.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreLocation
11 |
12 | public protocol LocationManager {
13 | var location: CLLocation? { get }
14 | var configuration: LocationManagerConfiguration { get set }
15 |
16 | func addListener(_ listener: LocationManagerListener)
17 | func removeListener(_ listener: LocationManagerListener)
18 |
19 | func suspend()
20 | func resume()
21 | }
22 |
23 | public enum DesiredAccuracy {
24 | case bestForNavigation
25 | case best
26 | case distance(Double)
27 | }
28 |
29 | public struct LocationManagerConfiguration {
30 | public var desiredAccuracy: DesiredAccuracy
31 | public var distanceFilter: Double
32 | public var updateFrequencyFilter: TimeInterval?
33 | public var allowsUseInBackground: Bool
34 |
35 | public init(desiredAccuracy: DesiredAccuracy, distanceFilter: Double,
36 | updateFrequencyFilter: TimeInterval? = nil, allowsUseInBackground: Bool = false)
37 | {
38 | self.desiredAccuracy = desiredAccuracy
39 | self.distanceFilter = distanceFilter
40 | self.updateFrequencyFilter = updateFrequencyFilter
41 | self.allowsUseInBackground = allowsUseInBackground
42 | }
43 | }
44 |
45 | public protocol LocationManagerListener: class {
46 | func onLocationUpdate(_ location: CLLocation)
47 | func onAuthorizationStatusUpdate(_ authorizationStatus: CLAuthorizationStatus)
48 | }
49 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 | This application will use the camera for Augmented Reality.
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 | arkit
33 |
34 | UIStatusBarHidden
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // RoutePolyline
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // FinishPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDocumentTypes
8 |
9 |
10 | CFBundleTypeName
11 | MKDirectionsRequest
12 | LSItemContentTypes
13 |
14 | com.apple.maps.directionsrequest
15 |
16 |
17 |
18 | CFBundleExecutable
19 | $(EXECUTABLE_NAME)
20 | CFBundleIdentifier
21 | $(PRODUCT_BUNDLE_IDENTIFIER)
22 | CFBundleInfoDictionaryVersion
23 | 6.0
24 | CFBundleName
25 | $(PRODUCT_NAME)
26 | CFBundlePackageType
27 | APPL
28 | CFBundleShortVersionString
29 | 1.0
30 | CFBundleVersion
31 | 1
32 | LSRequiresIPhoneOS
33 |
34 | MKDirectionsApplicationSupportedModes
35 |
36 | MKDirectionsModePedestrian
37 |
38 | NSCameraUsageDescription
39 | This application will use the camera for Augmented Reality.
40 | NSLocationAlwaysUsageDescription
41 |
42 | NSLocationWhenInUseUsageDescription
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 | arkit
52 |
53 | UIStatusBarHidden
54 |
55 | UISupportedInterfaceOrientations
56 |
57 | UIInterfaceOrientationPortrait
58 | UIInterfaceOrientationLandscapeLeft
59 | UIInterfaceOrientationLandscapeRight
60 |
61 | UISupportedInterfaceOrientations~ipad
62 |
63 | UIInterfaceOrientationPortrait
64 | UIInterfaceOrientationPortraitUpsideDown
65 | UIInterfaceOrientationLandscapeLeft
66 | UIInterfaceOrientationLandscapeRight
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/LocationEstimatesHolder/SceneLocationEstimate+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneLocationEstimate+Extensions.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import SceneKit
11 | import CoreLocation
12 |
13 | extension SceneLocationEstimate: Comparable {
14 |
15 | public static func < (lhs: SceneLocationEstimate, rhs: SceneLocationEstimate) -> Bool {
16 | if lhs.location.horizontalAccuracy == rhs.location.horizontalAccuracy {
17 | return lhs.location.timestamp > rhs.location.timestamp
18 | } else {
19 | return lhs.location.horizontalAccuracy < rhs.location.horizontalAccuracy
20 | }
21 | }
22 |
23 | public static func == (lhs: SceneLocationEstimate, rhs: SceneLocationEstimate) -> Bool {
24 | guard lhs.position.distance(vector: rhs.position) < Float.ulpOfOne else { return false }
25 | return lhs.location.coordinate.latitude == rhs.location.coordinate.latitude &&
26 | lhs.location.coordinate.longitude == rhs.location.coordinate.longitude &&
27 | lhs.location.horizontalAccuracy == rhs.location.horizontalAccuracy &&
28 | lhs.location.timestamp == rhs.location.timestamp
29 | }
30 | }
31 |
32 | extension CLLocation {
33 | public func isInsideAccuracyCircle(of location: CLLocation) -> Bool {
34 | return metersBetween(self.coordinate, location.coordinate) + self.horizontalAccuracy + .ulpOfOne < location.horizontalAccuracy
35 | }
36 | }
37 |
38 | extension CGPoint {
39 | func radiusContainsPoint(radius: CGFloat, point: CGPoint) -> Bool {
40 | let x = pow(point.x - self.x, 2)
41 | let y = pow(point.y - self.y, 2)
42 | let radiusSquared = pow(radius, 2)
43 | return x + y <= radiusSquared
44 | }
45 | }
46 |
47 | extension SceneLocationEstimate {
48 | public func canReplace(_ estimate: SceneLocationEstimate) -> Bool {
49 | guard !self.location.isInsideAccuracyCircle(of: estimate.location) else { return true }
50 | guard !estimate.location.isInsideAccuracyCircle(of: self.location) else { return false }
51 | guard metersBetween(self.location.coordinate, estimate.location.coordinate) < Double(self.location.horizontalAccuracy / 4) else { return false }
52 | return self < estimate
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // PedestrianARNavigation
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 |
20 | NativeLocationManager.sharedInstance.resume()
21 |
22 | return true
23 | }
24 |
25 | func applicationWillResignActive(_ application: UIApplication) {
26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
28 | }
29 |
30 | func applicationDidEnterBackground(_ application: UIApplication) {
31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 |
34 | NativeLocationManager.sharedInstance.suspend()
35 | }
36 |
37 | func applicationWillEnterForeground(_ application: UIApplication) {
38 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
39 |
40 | NativeLocationManager.sharedInstance.resume()
41 | }
42 |
43 | func applicationDidBecomeActive(_ application: UIApplication) {
44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
45 | }
46 |
47 | func applicationWillTerminate(_ application: UIApplication) {
48 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utilities/Notifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notifier.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class WeakObject: Hashable {
12 |
13 | public weak var obj: AnyObject?
14 |
15 | public var hashValue: Int {
16 | guard let obj = obj else { return 0 }
17 | return unsafeBitCast(obj, to: Int.self)
18 | }
19 |
20 | public init(_ obj: AnyObject) {
21 | self.obj = obj
22 | }
23 |
24 | public static func ==(lhs: WeakObject, rhs: WeakObject) -> Bool {
25 | guard lhs.obj != nil && rhs.obj != nil else { return false }
26 | return lhs.hashValue == rhs.hashValue
27 | }
28 |
29 | }
30 |
31 | public class WeakObjectCollection {
32 |
33 | // MARK: Public methods
34 |
35 | public init(){}
36 |
37 | public func array() -> [T] {
38 | filter()
39 | return collection.map { x in x.obj as! T}
40 | }
41 |
42 | public func insert(_ element: T) {
43 | filter()
44 | remove(element)
45 | collection.append(WeakObject(element as AnyObject))
46 | }
47 |
48 | public func remove(_ element: T) {
49 | filter()
50 | collection = collection.filter { return !(($0.obj! as AnyObject) === (element as AnyObject)) }
51 | }
52 |
53 | public func count() -> Int {
54 | filter()
55 | return collection.count
56 | }
57 |
58 | public func clear() {
59 | collection = []
60 | }
61 |
62 | public func contains(_ member: T) -> Bool {
63 | for obj in collection {
64 | if (obj.obj as AnyObject) === (member as AnyObject) {
65 | return true
66 | }
67 | }
68 |
69 | return false
70 | }
71 |
72 | // MARK: Private properties
73 |
74 | fileprivate var collection = [WeakObject]()
75 | }
76 |
77 | fileprivate extension WeakObjectCollection {
78 |
79 | // MARK: Private methods
80 |
81 | func filter() {
82 | collection = collection.filter { return $0.obj != nil }
83 | }
84 |
85 | }
86 |
87 | public class Notifier {
88 |
89 | //MARK: Public
90 |
91 | public typealias Listener = T
92 |
93 | public init() {}
94 |
95 | public func notify(_ call: ((Listener) -> Void)) {
96 | for l in listeners.array() {
97 | call(l)
98 | }
99 | }
100 |
101 | public func addListener(_ listener: Listener) {
102 | if !listeners.contains(listener) {
103 | listeners.insert(listener)
104 | }
105 | }
106 |
107 | public func removeListener(_ listener: Listener) {
108 | listeners.remove(listener)
109 | }
110 |
111 | public var hasListeners: Bool { return listenersCount != 0 }
112 | public var listenersCount: Int { return listeners.count() }
113 |
114 | // MARK: Private
115 |
116 | fileprivate var listeners = WeakObjectCollection()
117 | }
118 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/ARKitCoreLocationEngine.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocationTranslationEngine.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreLocation
11 | import SceneKit
12 | import ARKit
13 |
14 | protocol ARKitCoreLocationEngine {
15 | /// Converts geo coordinate to 3D position
16 | ///
17 | /// - Parameter coordinate: position on earth
18 | /// - Returns: position on 3D scene with y = 0
19 | func convert(coordinate: CLLocationCoordinate2D) -> SCNVector3?
20 | func userLocationEstimate() -> SceneLocationEstimate?
21 | }
22 |
23 | class ARKitCoreLocationEngineImpl: NSObject, ARKitCoreLocationEngine {
24 |
25 | init(view: SCNView, locationManager: LocationManager, locationEstimatesHolder: LocationEstimatesHolder) {
26 | self.scnView = view
27 | self.locationManager = locationManager
28 | self.locationEstimatesHolder = locationEstimatesHolder
29 | super.init()
30 |
31 | filterLocationEstimatesAction = TimerAction(timeInterval: 3.0, repeats: true) { [weak self] in
32 | self?.filterLocationEstimates()
33 | }
34 | locationManager.addListener(self)
35 | }
36 |
37 | func userLocationEstimate() -> SceneLocationEstimate? {
38 | guard let bestEstimate = locationEstimatesHolder.bestLocationEstimate else { return nil }
39 | guard let position = currentScenePosition() else { return nil }
40 | let correctLocation = bestEstimate.translatedLocation(to: position)
41 | return SceneLocationEstimate(location: correctLocation, position: position)
42 | }
43 |
44 | func convert(coordinate: CLLocationCoordinate2D) -> SCNVector3? {
45 | guard let anchorEstimate = locationEstimatesHolder.bestLocationEstimate else { return nil }
46 | let location = anchorEstimate.location
47 | let position = anchorEstimate.position
48 | let translation = location.coordinate.translation(toCoordinate: coordinate)
49 | return SCNVector3(
50 | x: position.x + Float(translation.longitudeTranslation),
51 | y: 0.0,
52 | z: position.z - Float(translation.latitudeTranslation)
53 | )
54 | }
55 |
56 | private let scnView: SCNView
57 | private let locationManager: LocationManager
58 | private let locationEstimatesHolder: LocationEstimatesHolder
59 | private var filterLocationEstimatesAction: TimerAction? = nil
60 | }
61 |
62 | extension ARKitCoreLocationEngineImpl {
63 | private func currentScenePosition() -> SCNVector3? {
64 | return scnView.pointOfView?.worldPosition
65 | }
66 |
67 | private func currentEulerAngles() -> SCNVector3? {
68 | return scnView.pointOfView?.eulerAngles
69 | }
70 |
71 | /// Filters locationEstimates
72 | func filterLocationEstimates() {
73 | guard let positionOnScene = currentScenePosition() else { return }
74 | let currentPoint = CGPoint(position: positionOnScene)
75 | locationEstimatesHolder.filter {
76 | let point = CGPoint(position: $0.position)
77 | return currentPoint.radiusContainsPoint(radius: Constants.sceneRadiusLimit, point: point)
78 | }
79 | }
80 | }
81 |
82 | extension ARKitCoreLocationEngineImpl: LocationManagerListener {
83 | func onAuthorizationStatusUpdate(_ authorizationStatus: CLAuthorizationStatus) {
84 |
85 | }
86 |
87 | func onLocationUpdate(_ location: CLLocation) {
88 | guard let positionOnScene = currentScenePosition() else { return }
89 | let newLocationEstimate = SceneLocationEstimate(location: location, position: positionOnScene)
90 | locationEstimatesHolder.add(newLocationEstimate)
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/VectorMath/VectorMath+SceneKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorMath+SceneKit.swift
3 | // VectorMath
4 | //
5 | // Version 0.3.2
6 | //
7 | // Created by Nick Lockwood on 24/11/2014.
8 | // Copyright (c) 2014 Nick Lockwood. All rights reserved.
9 | //
10 | // Distributed under the permissive zlib License
11 | // Get the latest version from here:
12 | //
13 | // https://github.com/nicklockwood/VectorMath
14 | //
15 | // This software is provided 'as-is', without any express or implied
16 | // warranty. In no event will the authors be held liable for any damages
17 | // arising from the use of this software.
18 | //
19 | // Permission is granted to anyone to use this software for any purpose,
20 | // including commercial applications, and to alter it and redistribute it
21 | // freely, subject to the following restrictions:
22 | //
23 | // 1. The origin of this software must not be misrepresented; you must not
24 | // claim that you wrote the original software. If you use this software
25 | // in a product, an acknowledgment in the product documentation would be
26 | // appreciated but is not required.
27 | //
28 | // 2. Altered source versions must be plainly marked as such, and must not be
29 | // misrepresented as being the original software.
30 | //
31 | // 3. This notice may not be removed or altered from any source distribution.
32 | //
33 | import SceneKit
34 |
35 | #if os(iOS) || os(tvOS)
36 | typealias SCNFloat = Float
37 | #else
38 | typealias SCNFloat = CGFloat
39 | #endif
40 |
41 | // MARK: SceneKit extensions
42 | public extension SCNVector3 {
43 | init(_ v: Vector3) {
44 | self.init(x: SCNFloat(v.x), y: SCNFloat(v.y), z: SCNFloat(v.z))
45 | }
46 | }
47 |
48 | public extension SCNVector4 {
49 | init(_ v: Vector4) {
50 | self.init(x: SCNFloat(v.x), y: SCNFloat(v.y), z: SCNFloat(v.z), w: SCNFloat(v.w))
51 | }
52 | }
53 |
54 | #if os(iOS) // SCNWMatrix4 = CATransform3D on Mac
55 | public extension SCNMatrix4 {
56 | init(_ m: Matrix4) {
57 | self.init(
58 | m11: SCNFloat(m.m11), m12: SCNFloat(m.m12), m13: SCNFloat(m.m13), m14: SCNFloat(m.m14),
59 | m21: SCNFloat(m.m21), m22: SCNFloat(m.m22), m23: SCNFloat(m.m23), m24: SCNFloat(m.m24),
60 | m31: SCNFloat(m.m31), m32: SCNFloat(m.m32), m33: SCNFloat(m.m33), m34: SCNFloat(m.m34),
61 | m41: SCNFloat(m.m41), m42: SCNFloat(m.m42), m43: SCNFloat(m.m43), m44: SCNFloat(m.m44)
62 | )
63 | }
64 | }
65 |
66 | #endif
67 |
68 | public extension SCNQuaternion {
69 | init(_ q: Quaternion) {
70 | self.init(x: SCNFloat(q.x), y: SCNFloat(q.y), z: SCNFloat(q.z), w: SCNFloat(q.w))
71 | }
72 | }
73 |
74 | // MARK: VectorMath extensions
75 | public extension Vector3 {
76 | init(_ v: SCNVector3) {
77 | self.init(x: Scalar(v.x), y: Scalar(v.y), z: Scalar(v.z))
78 | }
79 | }
80 |
81 | public extension Vector4 {
82 | init(_ v: SCNVector4) {
83 | self.init(x: Scalar(v.x), y: Scalar(v.y), z: Scalar(v.z), w: Scalar(v.w))
84 | }
85 | }
86 |
87 | #if os(iOS) // SCNWMatrix4 = CATransform3D on Mac
88 | public extension Matrix4 {
89 | init(_ m: SCNMatrix4) {
90 | self.init(
91 | m11: Scalar(m.m11), m12: Scalar(m.m12), m13: Scalar(m.m13), m14: Scalar(m.m14),
92 | m21: Scalar(m.m21), m22: Scalar(m.m22), m23: Scalar(m.m23), m24: Scalar(m.m24),
93 | m31: Scalar(m.m31), m32: Scalar(m.m32), m33: Scalar(m.m33), m34: Scalar(m.m34),
94 | m41: Scalar(m.m41), m42: Scalar(m.m42), m43: Scalar(m.m43), m44: Scalar(m.m44)
95 | )
96 | }
97 | }
98 |
99 | #endif
100 |
101 | public extension Quaternion {
102 | init(_ q: SCNQuaternion) {
103 | self.init(x: Scalar(q.x), y: Scalar(q.y), z: Scalar(q.z), w: Scalar(q.w))
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/VectorMath/VectorMath+SceneKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorMath+SceneKit.swift
3 | // VectorMath
4 | //
5 | // Version 0.3.2
6 | //
7 | // Created by Nick Lockwood on 24/11/2014.
8 | // Copyright (c) 2014 Nick Lockwood. All rights reserved.
9 | //
10 | // Distributed under the permissive zlib License
11 | // Get the latest version from here:
12 | //
13 | // https://github.com/nicklockwood/VectorMath
14 | //
15 | // This software is provided 'as-is', without any express or implied
16 | // warranty. In no event will the authors be held liable for any damages
17 | // arising from the use of this software.
18 | //
19 | // Permission is granted to anyone to use this software for any purpose,
20 | // including commercial applications, and to alter it and redistribute it
21 | // freely, subject to the following restrictions:
22 | //
23 | // 1. The origin of this software must not be misrepresented; you must not
24 | // claim that you wrote the original software. If you use this software
25 | // in a product, an acknowledgment in the product documentation would be
26 | // appreciated but is not required.
27 | //
28 | // 2. Altered source versions must be plainly marked as such, and must not be
29 | // misrepresented as being the original software.
30 | //
31 | // 3. This notice may not be removed or altered from any source distribution.
32 | //
33 | import SceneKit
34 |
35 | #if os(iOS) || os(tvOS)
36 | typealias SCNFloat = Float
37 | #else
38 | typealias SCNFloat = CGFloat
39 | #endif
40 |
41 | // MARK: SceneKit extensions
42 | public extension SCNVector3 {
43 | init(_ v: Vector3) {
44 | self.init(x: SCNFloat(v.x), y: SCNFloat(v.y), z: SCNFloat(v.z))
45 | }
46 | }
47 |
48 | public extension SCNVector4 {
49 | init(_ v: Vector4) {
50 | self.init(x: SCNFloat(v.x), y: SCNFloat(v.y), z: SCNFloat(v.z), w: SCNFloat(v.w))
51 | }
52 | }
53 |
54 | #if os(iOS) // SCNWMatrix4 = CATransform3D on Mac
55 | public extension SCNMatrix4 {
56 | init(_ m: Matrix4) {
57 | self.init(
58 | m11: SCNFloat(m.m11), m12: SCNFloat(m.m12), m13: SCNFloat(m.m13), m14: SCNFloat(m.m14),
59 | m21: SCNFloat(m.m21), m22: SCNFloat(m.m22), m23: SCNFloat(m.m23), m24: SCNFloat(m.m24),
60 | m31: SCNFloat(m.m31), m32: SCNFloat(m.m32), m33: SCNFloat(m.m33), m34: SCNFloat(m.m34),
61 | m41: SCNFloat(m.m41), m42: SCNFloat(m.m42), m43: SCNFloat(m.m43), m44: SCNFloat(m.m44)
62 | )
63 | }
64 | }
65 |
66 | #endif
67 |
68 | public extension SCNQuaternion {
69 | init(_ q: Quaternion) {
70 | self.init(x: SCNFloat(q.x), y: SCNFloat(q.y), z: SCNFloat(q.z), w: SCNFloat(q.w))
71 | }
72 | }
73 |
74 | // MARK: VectorMath extensions
75 | public extension Vector3 {
76 | init(_ v: SCNVector3) {
77 | self.init(x: Scalar(v.x), y: Scalar(v.y), z: Scalar(v.z))
78 | }
79 | }
80 |
81 | public extension Vector4 {
82 | init(_ v: SCNVector4) {
83 | self.init(x: Scalar(v.x), y: Scalar(v.y), z: Scalar(v.z), w: Scalar(v.w))
84 | }
85 | }
86 |
87 | #if os(iOS) // SCNWMatrix4 = CATransform3D on Mac
88 | public extension Matrix4 {
89 | init(_ m: SCNMatrix4) {
90 | self.init(
91 | m11: Scalar(m.m11), m12: Scalar(m.m12), m13: Scalar(m.m13), m14: Scalar(m.m14),
92 | m21: Scalar(m.m21), m22: Scalar(m.m22), m23: Scalar(m.m23), m24: Scalar(m.m24),
93 | m31: Scalar(m.m31), m32: Scalar(m.m32), m33: Scalar(m.m33), m34: Scalar(m.m34),
94 | m41: Scalar(m.m41), m42: Scalar(m.m42), m43: Scalar(m.m43), m44: Scalar(m.m44)
95 | )
96 | }
97 | }
98 |
99 | #endif
100 |
101 | public extension Quaternion {
102 | init(_ q: SCNQuaternion) {
103 | self.init(x: Scalar(q.x), y: Scalar(q.y), z: Scalar(q.z), w: Scalar(q.w))
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/VectorMath/VectorMath+SceneKit.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorMath+SceneKit.swift
3 | // VectorMath
4 | //
5 | // Version 0.3.2
6 | //
7 | // Created by Nick Lockwood on 24/11/2014.
8 | // Copyright (c) 2014 Nick Lockwood. All rights reserved.
9 | //
10 | // Distributed under the permissive zlib License
11 | // Get the latest version from here:
12 | //
13 | // https://github.com/nicklockwood/VectorMath
14 | //
15 | // This software is provided 'as-is', without any express or implied
16 | // warranty. In no event will the authors be held liable for any damages
17 | // arising from the use of this software.
18 | //
19 | // Permission is granted to anyone to use this software for any purpose,
20 | // including commercial applications, and to alter it and redistribute it
21 | // freely, subject to the following restrictions:
22 | //
23 | // 1. The origin of this software must not be misrepresented; you must not
24 | // claim that you wrote the original software. If you use this software
25 | // in a product, an acknowledgment in the product documentation would be
26 | // appreciated but is not required.
27 | //
28 | // 2. Altered source versions must be plainly marked as such, and must not be
29 | // misrepresented as being the original software.
30 | //
31 | // 3. This notice may not be removed or altered from any source distribution.
32 | //
33 | import SceneKit
34 |
35 | #if os(iOS) || os(tvOS)
36 | typealias SCNFloat = Float
37 | #else
38 | typealias SCNFloat = CGFloat
39 | #endif
40 |
41 | // MARK: SceneKit extensions
42 | public extension SCNVector3 {
43 | init(_ v: Vector3) {
44 | self.init(x: SCNFloat(v.x), y: SCNFloat(v.y), z: SCNFloat(v.z))
45 | }
46 | }
47 |
48 | public extension SCNVector4 {
49 | init(_ v: Vector4) {
50 | self.init(x: SCNFloat(v.x), y: SCNFloat(v.y), z: SCNFloat(v.z), w: SCNFloat(v.w))
51 | }
52 | }
53 |
54 | #if os(iOS) // SCNWMatrix4 = CATransform3D on Mac
55 | public extension SCNMatrix4 {
56 | init(_ m: Matrix4) {
57 | self.init(
58 | m11: SCNFloat(m.m11), m12: SCNFloat(m.m12), m13: SCNFloat(m.m13), m14: SCNFloat(m.m14),
59 | m21: SCNFloat(m.m21), m22: SCNFloat(m.m22), m23: SCNFloat(m.m23), m24: SCNFloat(m.m24),
60 | m31: SCNFloat(m.m31), m32: SCNFloat(m.m32), m33: SCNFloat(m.m33), m34: SCNFloat(m.m34),
61 | m41: SCNFloat(m.m41), m42: SCNFloat(m.m42), m43: SCNFloat(m.m43), m44: SCNFloat(m.m44)
62 | )
63 | }
64 | }
65 |
66 | #endif
67 |
68 | public extension SCNQuaternion {
69 | init(_ q: Quaternion) {
70 | self.init(x: SCNFloat(q.x), y: SCNFloat(q.y), z: SCNFloat(q.z), w: SCNFloat(q.w))
71 | }
72 | }
73 |
74 | // MARK: VectorMath extensions
75 | public extension Vector3 {
76 | init(_ v: SCNVector3) {
77 | self.init(x: Scalar(v.x), y: Scalar(v.y), z: Scalar(v.z))
78 | }
79 | }
80 |
81 | public extension Vector4 {
82 | init(_ v: SCNVector4) {
83 | self.init(x: Scalar(v.x), y: Scalar(v.y), z: Scalar(v.z), w: Scalar(v.w))
84 | }
85 | }
86 |
87 | #if os(iOS) // SCNWMatrix4 = CATransform3D on Mac
88 | public extension Matrix4 {
89 | init(_ m: SCNMatrix4) {
90 | self.init(
91 | m11: Scalar(m.m11), m12: Scalar(m.m12), m13: Scalar(m.m13), m14: Scalar(m.m14),
92 | m21: Scalar(m.m21), m22: Scalar(m.m22), m23: Scalar(m.m23), m24: Scalar(m.m24),
93 | m31: Scalar(m.m31), m32: Scalar(m.m32), m33: Scalar(m.m33), m34: Scalar(m.m34),
94 | m41: Scalar(m.m41), m42: Scalar(m.m42), m43: Scalar(m.m43), m44: Scalar(m.m44)
95 | )
96 | }
97 | }
98 |
99 | #endif
100 |
101 | public extension Quaternion {
102 | init(_ q: SCNQuaternion) {
103 | self.init(x: Scalar(q.x), y: Scalar(q.y), z: Scalar(q.z), w: Scalar(q.w))
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/VectorMath/VectorMath+QuartzCore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorMath+Quartz.swift
3 | // VectorMath
4 | //
5 | // Version 0.3.2
6 | //
7 | // Created by Nick Lockwood on 24/11/2014.
8 | // Copyright (c) 2014 Nick Lockwood. All rights reserved.
9 | //
10 | // Distributed under the permissive zlib License
11 | // Get the latest version from here:
12 | //
13 | // https://github.com/nicklockwood/VectorMath
14 | //
15 | // This software is provided 'as-is', without any express or implied
16 | // warranty. In no event will the authors be held liable for any damages
17 | // arising from the use of this software.
18 | //
19 | // Permission is granted to anyone to use this software for any purpose,
20 | // including commercial applications, and to alter it and redistribute it
21 | // freely, subject to the following restrictions:
22 | //
23 | // 1. The origin of this software must not be misrepresented; you must not
24 | // claim that you wrote the original software. If you use this software
25 | // in a product, an acknowledgment in the product documentation would be
26 | // appreciated but is not required.
27 | //
28 | // 2. Altered source versions must be plainly marked as such, and must not be
29 | // misrepresented as being the original software.
30 | //
31 | // 3. This notice may not be removed or altered from any source distribution.
32 | //
33 | import QuartzCore
34 |
35 | // MARK: SceneKit extensions
36 | public extension CGPoint {
37 | init(_ v: Vector2) {
38 | self.init(x: CGFloat(v.x), y: CGFloat(v.y))
39 | }
40 | }
41 |
42 | public extension CGSize {
43 | init(_ v: Vector2) {
44 | self.init(width: CGFloat(v.x), height: CGFloat(v.y))
45 | }
46 | }
47 |
48 | public extension CGVector {
49 | init(_ v: Vector2) {
50 | self.init(dx: CGFloat(v.x), dy: CGFloat(v.y))
51 | }
52 | }
53 |
54 | public extension CGAffineTransform {
55 | init(_ m: Matrix3) {
56 | self.init(
57 | a: CGFloat(m.m11), b: CGFloat(m.m12),
58 | c: CGFloat(m.m21), d: CGFloat(m.m22),
59 | tx: CGFloat(m.m31), ty: CGFloat(m.m32)
60 | )
61 | }
62 | }
63 |
64 | public extension CATransform3D {
65 | init(_ m: Matrix4) {
66 | self.init(
67 | m11: CGFloat(m.m11), m12: CGFloat(m.m12), m13: CGFloat(m.m13), m14: CGFloat(m.m14),
68 | m21: CGFloat(m.m21), m22: CGFloat(m.m22), m23: CGFloat(m.m23), m24: CGFloat(m.m24),
69 | m31: CGFloat(m.m31), m32: CGFloat(m.m32), m33: CGFloat(m.m33), m34: CGFloat(m.m34),
70 | m41: CGFloat(m.m41), m42: CGFloat(m.m42), m43: CGFloat(m.m43), m44: CGFloat(m.m44)
71 | )
72 | }
73 | }
74 |
75 | // MARK: VectorMath extensions
76 | public extension Vector2 {
77 | init(_ v: CGPoint) {
78 | self.init(x: Scalar(v.x), y: Scalar(v.y))
79 | }
80 |
81 | init(_ v: CGSize) {
82 | self.init(x: Scalar(v.width), y: Scalar(v.height))
83 | }
84 |
85 | init(_ v: CGVector) {
86 | self.init(x: Scalar(v.dx), y: Scalar(v.dy))
87 | }
88 |
89 | public func toCGPoint() -> CGPoint {
90 | return CGPoint(self)
91 | }
92 | }
93 |
94 | public extension Matrix3 {
95 | init(_ m: CGAffineTransform) {
96 | self.init(
97 | m11: Scalar(m.a), m12: Scalar(m.b), m13: 0,
98 | m21: Scalar(m.c), m22: Scalar(m.d), m23: 0,
99 | m31: Scalar(m.tx), m32: Scalar(m.ty), m33: 1
100 | )
101 | }
102 | }
103 |
104 | public extension Matrix4 {
105 | init(_ m: CATransform3D) {
106 | self.init(
107 | m11: Scalar(m.m11), m12: Scalar(m.m12), m13: Scalar(m.m13), m14: Scalar(m.m14),
108 | m21: Scalar(m.m21), m22: Scalar(m.m22), m23: Scalar(m.m23), m24: Scalar(m.m24),
109 | m31: Scalar(m.m31), m32: Scalar(m.m32), m33: Scalar(m.m33), m34: Scalar(m.m34),
110 | m41: Scalar(m.m41), m42: Scalar(m.m42), m43: Scalar(m.m43), m44: Scalar(m.m44)
111 | )
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/RouteNodes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouteNodes.swift
3 | // RoutePolyline
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import SceneKit
11 |
12 | class ARSCNPathArrow: SCNGeometry {
13 |
14 | convenience init(material: SCNMaterial) {
15 | let vertices: [SCNVector3] = [
16 | SCNVector3Make(-0.02, 0.00, 0.00), // 0
17 | SCNVector3Make(-0.02, 0.50, -0.33), // 1
18 | SCNVector3Make(-0.10, 0.44, -0.50), // 2
19 | SCNVector3Make(-0.22, 0.00, -0.39), // 3
20 | SCNVector3Make(-0.10, -0.44, -0.50), // 4
21 | SCNVector3Make(-0.02, -0.50, -0.33), // 5
22 |
23 | SCNVector3Make( 0.02, 0.00, 0.00), // 6
24 | SCNVector3Make( 0.02, 0.50, -0.33), // 7
25 | SCNVector3Make( 0.10, 0.44, -0.50), // 8
26 | SCNVector3Make( 0.22, 0.00, -0.39), // 9
27 | SCNVector3Make( 0.10, -0.44, -0.50), // 10
28 | SCNVector3Make( 0.02, -0.50, -0.33), // 11
29 | ]
30 |
31 | let sources: [SCNGeometrySource] = [SCNGeometrySource(vertices: vertices)]
32 | let indices: [Int32] = [0,3,5, 3,4,5, 1,2,3, 0,1,3, 10,9,11, 6,11,9, 6,9,7, 9,8,7,
33 | 6,5,11, 6,0,5, 6,1,0, 6,7,1, 11,5,4, 11,4,10, 9,4,3, 9,10,4, 9,3,2, 9,2,8, 8,2,1, 8,1,7]
34 | let geometryElements = [SCNGeometryElement(indices: indices, primitiveType: .triangles)]
35 | self.init(sources: sources, elements: geometryElements)
36 | self.materials = [material]
37 | }
38 |
39 | }
40 |
41 | class RoutePointNode: SCNNode {
42 |
43 | public init(radius: CGFloat = 0.2, color: UIColor = UIColor.blue, transparency: CGFloat = 0.3, height: CGFloat = 0.01) {
44 | let cylinder = SCNCylinder(radius: radius, height: height)
45 |
46 | cylinder.firstMaterial?.diffuse.contents = color
47 | cylinder.firstMaterial?.transparency = transparency
48 | cylinder.firstMaterial?.lightingModel = .constant
49 |
50 | super.init()
51 | self.geometry = cylinder
52 | }
53 |
54 | required public init?(coder aDecoder: NSCoder) {
55 | fatalError("init(coder:) has not been implemented")
56 | }
57 | }
58 |
59 | struct RouteGeometryFactory {
60 | static func arrowBlue() -> SCNGeometry {
61 | let blue = SCNMaterial()
62 | blue.diffuse.contents = UIColor.blue
63 | blue.lightingModel = .constant
64 | return ARSCNPathArrow(material: blue)
65 | }
66 |
67 | static func axesNode(quiverLength: CGFloat, quiverThickness: CGFloat) -> SCNNode {
68 | let quiverThickness = (quiverLength / 50.0) * quiverThickness
69 | let chamferRadius = quiverThickness / 2.0
70 |
71 | let xQuiverBox = SCNBox(width: quiverLength, height: quiverThickness, length: quiverThickness, chamferRadius: chamferRadius)
72 | xQuiverBox.firstMaterial?.diffuse.contents = UIColor.red
73 | let xQuiverNode = SCNNode(geometry: xQuiverBox)
74 | xQuiverNode.position = SCNVector3Make(Float(quiverLength / 2.0), 0.0, 0.0)
75 |
76 | let yQuiverBox = SCNBox(width: quiverThickness, height: quiverLength, length: quiverThickness, chamferRadius: chamferRadius)
77 | yQuiverBox.firstMaterial?.diffuse.contents = UIColor.green
78 | let yQuiverNode = SCNNode(geometry: yQuiverBox)
79 | yQuiverNode.position = SCNVector3Make(0.0, Float(quiverLength / 2.0), 0.0)
80 |
81 | let zQuiverBox = SCNBox(width: quiverThickness, height: quiverThickness, length: quiverLength, chamferRadius: chamferRadius)
82 | zQuiverBox.firstMaterial?.diffuse.contents = UIColor.blue
83 | let zQuiverNode = SCNNode(geometry: zQuiverBox)
84 | zQuiverNode.position = SCNVector3Make(0.0, 0.0, Float(quiverLength / 2.0))
85 |
86 | let quiverNode = SCNNode()
87 | quiverNode.addChildNode(xQuiverNode)
88 | quiverNode.addChildNode(yQuiverNode)
89 | quiverNode.addChildNode(zQuiverNode)
90 | quiverNode.name = "Axes"
91 | return quiverNode
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/VectorMath/VectorMath+QuartzCore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorMath+Quartz.swift
3 | // VectorMath
4 | //
5 | // Version 0.3.2
6 | //
7 | // Created by Nick Lockwood on 24/11/2014.
8 | // Copyright (c) 2014 Nick Lockwood. All rights reserved.
9 | //
10 | // Distributed under the permissive zlib License
11 | // Get the latest version from here:
12 | //
13 | // https://github.com/nicklockwood/VectorMath
14 | //
15 | // This software is provided 'as-is', without any express or implied
16 | // warranty. In no event will the authors be held liable for any damages
17 | // arising from the use of this software.
18 | //
19 | // Permission is granted to anyone to use this software for any purpose,
20 | // including commercial applications, and to alter it and redistribute it
21 | // freely, subject to the following restrictions:
22 | //
23 | // 1. The origin of this software must not be misrepresented; you must not
24 | // claim that you wrote the original software. If you use this software
25 | // in a product, an acknowledgment in the product documentation would be
26 | // appreciated but is not required.
27 | //
28 | // 2. Altered source versions must be plainly marked as such, and must not be
29 | // misrepresented as being the original software.
30 | //
31 | // 3. This notice may not be removed or altered from any source distribution.
32 | //
33 | import QuartzCore
34 |
35 | // MARK: SceneKit extensions
36 | public extension CGPoint {
37 | init(_ v: Vector2) {
38 | self.init(x: CGFloat(v.x), y: CGFloat(v.y))
39 | }
40 | }
41 |
42 | public extension CGSize {
43 | init(_ v: Vector2) {
44 | self.init(width: CGFloat(v.x), height: CGFloat(v.y))
45 | }
46 | }
47 |
48 | public extension CGVector {
49 | init(_ v: Vector2) {
50 | self.init(dx: CGFloat(v.x), dy: CGFloat(v.y))
51 | }
52 | }
53 |
54 | public extension CGAffineTransform {
55 | init(_ m: Matrix3) {
56 | self.init(
57 | a: CGFloat(m.m11), b: CGFloat(m.m12),
58 | c: CGFloat(m.m21), d: CGFloat(m.m22),
59 | tx: CGFloat(m.m31), ty: CGFloat(m.m32)
60 | )
61 | }
62 | }
63 |
64 | public extension CATransform3D {
65 | init(_ m: Matrix4) {
66 | self.init(
67 | m11: CGFloat(m.m11), m12: CGFloat(m.m12), m13: CGFloat(m.m13), m14: CGFloat(m.m14),
68 | m21: CGFloat(m.m21), m22: CGFloat(m.m22), m23: CGFloat(m.m23), m24: CGFloat(m.m24),
69 | m31: CGFloat(m.m31), m32: CGFloat(m.m32), m33: CGFloat(m.m33), m34: CGFloat(m.m34),
70 | m41: CGFloat(m.m41), m42: CGFloat(m.m42), m43: CGFloat(m.m43), m44: CGFloat(m.m44)
71 | )
72 | }
73 | }
74 |
75 | // MARK: VectorMath extensions
76 | public extension Vector2 {
77 | init(_ v: CGPoint) {
78 | self.init(x: Scalar(v.x), y: Scalar(v.y))
79 | }
80 |
81 | init(_ v: CGSize) {
82 | self.init(x: Scalar(v.width), y: Scalar(v.height))
83 | }
84 |
85 | init(_ v: CGVector) {
86 | self.init(x: Scalar(v.dx), y: Scalar(v.dy))
87 | }
88 |
89 | public func toCGPoint() -> CGPoint {
90 | return CGPoint(self)
91 | }
92 | }
93 |
94 | public extension Matrix3 {
95 | init(_ m: CGAffineTransform) {
96 | self.init(
97 | m11: Scalar(m.a), m12: Scalar(m.b), m13: 0,
98 | m21: Scalar(m.c), m22: Scalar(m.d), m23: 0,
99 | m31: Scalar(m.tx), m32: Scalar(m.ty), m33: 1
100 | )
101 | }
102 | }
103 |
104 | public extension Matrix4 {
105 | init(_ m: CATransform3D) {
106 | self.init(
107 | m11: Scalar(m.m11), m12: Scalar(m.m12), m13: Scalar(m.m13), m14: Scalar(m.m14),
108 | m21: Scalar(m.m21), m22: Scalar(m.m22), m23: Scalar(m.m23), m24: Scalar(m.m24),
109 | m31: Scalar(m.m31), m32: Scalar(m.m32), m33: Scalar(m.m33), m34: Scalar(m.m34),
110 | m41: Scalar(m.m41), m42: Scalar(m.m42), m43: Scalar(m.m43), m44: Scalar(m.m44)
111 | )
112 | }
113 | }
114 |
115 | public extension LineSegment {
116 | init(_ p1: CGPoint, _ p2: CGPoint) {
117 | self.init(Vector2(p1), Vector2(p2))
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/VectorMath/VectorMath+QuartzCore.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorMath+Quartz.swift
3 | // VectorMath
4 | //
5 | // Version 0.3.2
6 | //
7 | // Created by Nick Lockwood on 24/11/2014.
8 | // Copyright (c) 2014 Nick Lockwood. All rights reserved.
9 | //
10 | // Distributed under the permissive zlib License
11 | // Get the latest version from here:
12 | //
13 | // https://github.com/nicklockwood/VectorMath
14 | //
15 | // This software is provided 'as-is', without any express or implied
16 | // warranty. In no event will the authors be held liable for any damages
17 | // arising from the use of this software.
18 | //
19 | // Permission is granted to anyone to use this software for any purpose,
20 | // including commercial applications, and to alter it and redistribute it
21 | // freely, subject to the following restrictions:
22 | //
23 | // 1. The origin of this software must not be misrepresented; you must not
24 | // claim that you wrote the original software. If you use this software
25 | // in a product, an acknowledgment in the product documentation would be
26 | // appreciated but is not required.
27 | //
28 | // 2. Altered source versions must be plainly marked as such, and must not be
29 | // misrepresented as being the original software.
30 | //
31 | // 3. This notice may not be removed or altered from any source distribution.
32 | //
33 | import QuartzCore
34 |
35 | // MARK: SceneKit extensions
36 | public extension CGPoint {
37 | init(_ v: Vector2) {
38 | self.init(x: CGFloat(v.x), y: CGFloat(v.y))
39 | }
40 | }
41 |
42 | public extension CGSize {
43 | init(_ v: Vector2) {
44 | self.init(width: CGFloat(v.x), height: CGFloat(v.y))
45 | }
46 | }
47 |
48 | public extension CGVector {
49 | init(_ v: Vector2) {
50 | self.init(dx: CGFloat(v.x), dy: CGFloat(v.y))
51 | }
52 | }
53 |
54 | public extension CGAffineTransform {
55 | init(_ m: Matrix3) {
56 | self.init(
57 | a: CGFloat(m.m11), b: CGFloat(m.m12),
58 | c: CGFloat(m.m21), d: CGFloat(m.m22),
59 | tx: CGFloat(m.m31), ty: CGFloat(m.m32)
60 | )
61 | }
62 | }
63 |
64 | public extension CATransform3D {
65 | init(_ m: Matrix4) {
66 | self.init(
67 | m11: CGFloat(m.m11), m12: CGFloat(m.m12), m13: CGFloat(m.m13), m14: CGFloat(m.m14),
68 | m21: CGFloat(m.m21), m22: CGFloat(m.m22), m23: CGFloat(m.m23), m24: CGFloat(m.m24),
69 | m31: CGFloat(m.m31), m32: CGFloat(m.m32), m33: CGFloat(m.m33), m34: CGFloat(m.m34),
70 | m41: CGFloat(m.m41), m42: CGFloat(m.m42), m43: CGFloat(m.m43), m44: CGFloat(m.m44)
71 | )
72 | }
73 | }
74 |
75 | // MARK: VectorMath extensions
76 | public extension Vector2 {
77 | init(_ v: CGPoint) {
78 | self.init(x: Scalar(v.x), y: Scalar(v.y))
79 | }
80 |
81 | init(_ v: CGSize) {
82 | self.init(x: Scalar(v.width), y: Scalar(v.height))
83 | }
84 |
85 | init(_ v: CGVector) {
86 | self.init(x: Scalar(v.dx), y: Scalar(v.dy))
87 | }
88 |
89 | public func toCGPoint() -> CGPoint {
90 | return CGPoint(self)
91 | }
92 | }
93 |
94 | public extension Matrix3 {
95 | init(_ m: CGAffineTransform) {
96 | self.init(
97 | m11: Scalar(m.a), m12: Scalar(m.b), m13: 0,
98 | m21: Scalar(m.c), m22: Scalar(m.d), m23: 0,
99 | m31: Scalar(m.tx), m32: Scalar(m.ty), m33: 1
100 | )
101 | }
102 | }
103 |
104 | public extension Matrix4 {
105 | init(_ m: CATransform3D) {
106 | self.init(
107 | m11: Scalar(m.m11), m12: Scalar(m.m12), m13: Scalar(m.m13), m14: Scalar(m.m14),
108 | m21: Scalar(m.m21), m22: Scalar(m.m22), m23: Scalar(m.m23), m24: Scalar(m.m24),
109 | m31: Scalar(m.m31), m32: Scalar(m.m32), m33: Scalar(m.m33), m34: Scalar(m.m34),
110 | m41: Scalar(m.m41), m42: Scalar(m.m42), m43: Scalar(m.m43), m44: Scalar(m.m44)
111 | )
112 | }
113 | }
114 |
115 | public extension LineSegment {
116 | init(_ p1: CGPoint, _ p2: CGPoint) {
117 | self.init(Vector2(p1), Vector2(p2))
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/Utils/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // FinishPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import SceneKit
12 |
13 | public func reflect(_ value: T, of reflectionPoint: T) -> T {
14 | let diff = value - reflectionPoint
15 | return reflectionPoint - diff
16 | }
17 |
18 | extension CGRect {
19 | var mid: CGPoint {
20 | return CGPoint(x: midX, y: midY)
21 | }
22 |
23 | var topLeft: CGPoint{
24 | return origin
25 | }
26 |
27 | var topRight: CGPoint{
28 | return CGPoint(x: origin.x + width, y: origin.y)
29 | }
30 |
31 | var bottomLeft: CGPoint{
32 | return CGPoint(x: origin.x, y: origin.y + height)
33 | }
34 |
35 | var bottomRight: CGPoint{
36 | return CGPoint(x: origin.x + width, y: origin.y + height)
37 | }
38 | }
39 |
40 | struct CGLine {
41 | let point1: CGPoint
42 | let point2: CGPoint
43 | }
44 |
45 | extension CGPoint {
46 | func distance(to point: CGPoint) -> CGFloat {
47 | let dx = self.x - point.x
48 | let dy = self.y - point.y
49 | let dist = sqrt(pow(dx, 2) + pow(dy, 2))
50 | return dist
51 | }
52 | }
53 |
54 | let MT_EPS: CGFloat = 1e-4
55 |
56 | typealias CGDelta = CGPoint
57 |
58 | extension CGLine {
59 |
60 | func point(atDistance distance: CGFloat) -> CGPoint {
61 | let start = Vector2(self.point1)
62 | let end = Vector2(self.point2)
63 | let vec = start + (end - start).normalized() * Scalar(distance)
64 | return CGPoint(vec)
65 | }
66 |
67 | func contains(point: CGPoint) -> Bool {
68 | let end: CGPoint = self.point2
69 | let start: CGPoint = self.point1
70 | let startToEnd = Vector2(end) - Vector2(start)
71 | let startToPoint = Vector2(point) - Vector2(start)
72 | return (startToPoint.angle(with: startToEnd).truncatingRemainder(dividingBy: .twoPi) ~= 0.0)
73 | && (startToPoint.length <= startToEnd.length)
74 | }
75 |
76 | var length: CGFloat {
77 | return point1.distance(to: point2)
78 | }
79 |
80 | func intersection(withRect rect: CGRect) -> CGPoint? {
81 | let top = CGLine(point1: rect.topLeft, point2: rect.topRight)
82 | let right = CGLine(point1: rect.topRight, point2: rect.bottomRight)
83 | let bottom = CGLine(point1: rect.bottomLeft, point2: rect.bottomRight)
84 | let left = CGLine(point1: rect.topLeft, point2: rect.bottomLeft)
85 |
86 |
87 | let points: [CGPoint?] = [ top.intersection(withLine: self),
88 | right.intersection(withLine: self),
89 | left.intersection(withLine: self),
90 | bottom.intersection(withLine: self)]
91 |
92 | for p in points {
93 | if p != nil {
94 | return p!
95 | }
96 | }
97 |
98 | return nil;
99 | }
100 |
101 | func intersection(withLine line: CGLine) -> CGPoint? {
102 | let line1 = self
103 | let line2 = line
104 |
105 | let x1 = line1.point1.x
106 | let y1 = line1.point1.y
107 | let x2 = line1.point2.x
108 | let y2 = line1.point2.y
109 | let x3 = line2.point1.x
110 | let y3 = line2.point1.y
111 | let x4 = line2.point2.x
112 | let y4 = line2.point2.y
113 |
114 | let denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1)
115 | let numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3)
116 | let numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3)
117 |
118 | /* Are the lines coincident? */
119 | if (fabs(numera) < MT_EPS && fabs(numerb) < MT_EPS && fabs(denom) < MT_EPS) {
120 | return CGPoint(x: (x1 + x2) / 2.0, y: (y1 + y2) / 2.0)
121 | }
122 |
123 | /* Are the line parallel */
124 | if (fabs(denom) < MT_EPS) {
125 | return nil
126 | }
127 |
128 | /* Is the intersection along the the segments */
129 | let mua = numera / denom
130 | let mub = numerb / denom
131 | if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
132 | return nil
133 | }
134 | return CGPoint(x: x1 + mua * (x2 - x1), y: y1 + mua * (y2 - y1))
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigationTests/PedestrianARNavigationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PedestrianARNavigationTests.swift
3 | // PedestrianARNavigationTests
4 | //
5 | // Created by Dmitry Trimonov on 18/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import CoreLocation
11 | @testable import PedestrianARNavigation
12 |
13 | class PedestrianARNavigationTests: XCTestCase {
14 |
15 | override func setUp() {
16 | super.setUp()
17 | // Put setup code here. This method is called before the invocation of each test method in the class.
18 | }
19 |
20 | override func tearDown() {
21 | // Put teardown code here. This method is called after the invocation of each test method in the class.
22 | super.tearDown()
23 | }
24 |
25 | func testExample() {
26 | // This is an example of a functional test case.
27 | // Use XCTAssert and related functions to verify your tests produce the correct results.
28 |
29 | let size = ViewController.finishPlacemarkSize(
30 | forDistance: 50.0,
31 | closeDistance: 0.0,
32 | farDistance: 100.0,
33 | closeDistanceSize: 100.0,
34 | farDistanceSize: 50.0
35 | )
36 | XCTAssert(size == 75.0)
37 | }
38 |
39 | func testTranslationToPosition() {
40 |
41 | let coreLocationE1 = CLLocationCoordinate2D(latitude: 55.768382, longitude: 37.617810)
42 | let coreLocationActualLocation2 = coreLocationE1.transform(using: -162.0, longitudinalMeters: 240.0)
43 | let expectedLocation = CLLocationCoordinate2D(latitude: 55.766986, longitude: 37.621629)
44 |
45 | let distance = metersBetween(coreLocationActualLocation2, expectedLocation)
46 | XCTAssert(distance < 7.0)
47 | }
48 |
49 | func testCLLocationCoordinate2DTransformLon() {
50 | let center = CLLocationCoordinate2DMake(0, 0)
51 | let lonMeters: CLLocationDistance = 111000
52 | let result = center.transform(using: 0, longitudinalMeters: lonMeters)
53 | XCTAssert(fabs(result.lat - 0.0) <= 1e-6)
54 | XCTAssert(fabs(result.lon - 0.997130) <= 1e-6)
55 | }
56 |
57 | func testCLLocationCoordinate2DTransformLat() {
58 | let center = CLLocationCoordinate2DMake(0, 0)
59 | let latMeters: CLLocationDistance = 2 * .pi * GeometryConstants.EarthRadius / 4
60 | let result = center.transform(using: latMeters, longitudinalMeters: 0.0)
61 | XCTAssert(fabs(result.lat - 90.505170) <= 1e-6)
62 | XCTAssert(fabs(result.lon - 0.0) <= 1e-6)
63 | }
64 |
65 | func testSizeIsEqualToCloseDistanceSizeWhenDistanceIsLessThenCloseDistance() {
66 | // This is an example of a functional test case.
67 | // Use XCTAssert and related functions to verify your tests produce the correct results.
68 |
69 | let distance: CGFloat = 10.0
70 | let size = ViewController.finishPlacemarkSize(
71 | forDistance: distance,
72 | closeDistance: 30.0,
73 | farDistance: 100.0,
74 | closeDistanceSize: 100.0,
75 | farDistanceSize: 23.0
76 | )
77 | XCTAssert(size == 100.0)
78 | }
79 |
80 | func testSizeIsEqualToFarDistanceSizeWhenDistanceIsMoreThenFarDistance() {
81 | // This is an example of a functional test case.
82 | // Use XCTAssert and related functions to verify your tests produce the correct results.
83 |
84 | let distance: CGFloat = 120.0
85 | let size = ViewController.finishPlacemarkSize(
86 | forDistance: distance,
87 | closeDistance: 30.0,
88 | farDistance: 100.0,
89 | closeDistanceSize: 120.0,
90 | farDistanceSize: 50.0
91 | )
92 | XCTAssert(size == 50.0)
93 | }
94 |
95 | func testSize() {
96 | let distance: CGFloat = 20.0
97 | let size = ViewController.finishPlacemarkSize(
98 | forDistance: distance,
99 | closeDistance: 10.0,
100 | farDistance: 50.0,
101 | closeDistanceSize: 100.0,
102 | farDistanceSize: 60.0
103 | )
104 | XCTAssert(size == 90.0)
105 | }
106 |
107 | func testPerformanceExample() {
108 | // This is an example of a performance test case.
109 | self.measure {
110 | // Put the code you want to measure the time of here.
111 | }
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/MapViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MapViewController.swift
3 | // PedestrianARNavigation
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MapKit
11 |
12 | protocol MapViewControllerDelegate: class {
13 | func viewController(_ mapVc: MapViewController, didSetDestination destination: CLLocationCoordinate2D)
14 | }
15 |
16 | class MapViewController: UIViewController, MKMapViewDelegate {
17 |
18 | weak var delegate: MapViewControllerDelegate? = nil
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 |
23 | map = MKMapView()
24 | map.delegate = self
25 | let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(setDestination))
26 | map.addGestureRecognizer(longPressGestureRecognizer)
27 | view.addSubview(map)
28 |
29 | doneButton = UIButton(type: .system)
30 | doneButton.translatesAutoresizingMaskIntoConstraints = false
31 | view.addSubview(doneButton)
32 |
33 | doneButton.setTitle("Done", for: .normal)
34 | doneButton.addTarget(self, action: #selector(onDoneTapped), for: .touchUpInside)
35 | [doneButton].forEach {
36 | $0?.backgroundColor = UIColor.black.withAlphaComponent(0.8)
37 | $0?.setTitleColor(UIColor.white, for: .normal)
38 | }
39 | doneButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8.0).isActive = true
40 | doneButton.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -8.0).isActive = true
41 | doneButton.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
42 | doneButton.heightAnchor.constraint(equalToConstant: 75.0).isActive = true
43 |
44 | NativeLocationManager.sharedInstance.addListener(self)
45 |
46 | userLocationAnnotation.title = "My Location"
47 | map.addAnnotation(userLocationAnnotation)
48 | }
49 |
50 | @objc func setDestination(_ gestureRecognizer: UIGestureRecognizer) {
51 | if gestureRecognizer.state == UIGestureRecognizerState.began {
52 | let touchPoint = gestureRecognizer.location(in: map)
53 | let touchLocation = map.convert(touchPoint, toCoordinateFrom: map)
54 | lastDestination = touchLocation
55 |
56 | if let prevAnnotation = destinationAnnotation {
57 | map.removeAnnotation(prevAnnotation)
58 | }
59 |
60 | let annotation = MKPointAnnotation()
61 | annotation.coordinate = touchLocation
62 | annotation.title = "Destination"
63 | map.addAnnotation(annotation)
64 | destinationAnnotation = annotation
65 | }
66 | }
67 |
68 | @objc func onDoneTapped(_ sender: UIButton) {
69 | if let coordinate = lastDestination {
70 | self.delegate?.viewController(self, didSetDestination: coordinate)
71 | }
72 |
73 | self.dismiss(animated: true, completion: nil)
74 | }
75 |
76 | override func viewDidLayoutSubviews() {
77 | super.viewDidLayoutSubviews()
78 | map.frame = self.view.bounds
79 | }
80 |
81 | override func viewDidAppear(_ animated: Bool) {
82 | super.viewDidAppear(animated)
83 |
84 | if let userCoordinate = NativeLocationManager.sharedInstance.location?.coordinate {
85 | updateUserLocationAnnotation(withCoordinate: userCoordinate)
86 | let region = MKCoordinateRegion(center: userCoordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
87 | self.map.setRegion(region, animated: true)
88 | }
89 | }
90 |
91 | private var map: MKMapView!
92 | private var doneButton: UIButton!
93 | private var lastDestination: CLLocationCoordinate2D? = nil
94 | private var userLocationAnnotation: MKPointAnnotation = MKPointAnnotation()
95 | private var destinationAnnotation: MKPointAnnotation? = nil
96 | }
97 |
98 | extension MapViewController: LocationManagerListener {
99 |
100 | func onLocationUpdate(_ location: CLLocation) {
101 | updateUserLocationAnnotation(withCoordinate: location.coordinate)
102 |
103 | }
104 |
105 | func onAuthorizationStatusUpdate(_ authorizationStatus: CLAuthorizationStatus) {
106 | }
107 |
108 | func updateUserLocationAnnotation(withCoordinate coordinate: CLLocationCoordinate2D) {
109 | userLocationAnnotation.coordinate = coordinate
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/LocationManager/NativeLocationManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NativeLocationManager.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 03/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreLocation
11 |
12 | public class NativeLocationManager: NSObject {
13 |
14 | public class var sharedInstance: NativeLocationManager { return Static.instance }
15 |
16 | // MARK: Initialization
17 |
18 | public override init() {
19 | self.locationManager = CLLocationManager()
20 |
21 | super.init()
22 |
23 | locationManager.requestWhenInUseAuthorization()
24 | if let location = locationManager.location, isLocationViable(location) {
25 | self.lastLocation = location
26 | }
27 | locationManager.delegate = self
28 | locationManager.startUpdatingLocation()
29 | }
30 |
31 | deinit {
32 | locationManager.delegate = nil
33 | locationManager.stopUpdatingLocation()
34 | }
35 |
36 | // MARK: Private
37 |
38 | fileprivate let locationManager: CLLocationManager
39 | fileprivate let listeners = WeakObjectCollection()
40 | fileprivate var lastLocation: CLLocation? = nil
41 |
42 | }
43 |
44 | extension NativeLocationManager: LocationManager {
45 |
46 | public var location: CLLocation? {
47 | return lastLocation
48 | }
49 |
50 | public var authorizationStatus: CLAuthorizationStatus {
51 | return CLLocationManager.authorizationStatus()
52 | }
53 |
54 | public var configuration: LocationManagerConfiguration {
55 | get {
56 | let accuracy = convert(locationManager.desiredAccuracy)
57 | let distance = locationManager.distanceFilter
58 | return LocationManagerConfiguration(desiredAccuracy: accuracy, distanceFilter: distance)
59 | }
60 | set {
61 | locationManager.desiredAccuracy = convert(newValue.desiredAccuracy)
62 | locationManager.distanceFilter = newValue.distanceFilter
63 | }
64 | }
65 |
66 | public func addListener(_ listener: LocationManagerListener) {
67 | assert(Thread.isMainThread)
68 | listeners.insert(listener)
69 | }
70 |
71 | public func removeListener(_ listener: LocationManagerListener) {
72 | assert(Thread.isMainThread)
73 | listeners.remove(listener)
74 | }
75 |
76 | public func suspend() {
77 | locationManager.stopUpdatingLocation()
78 | }
79 |
80 | public func resume() {
81 | locationManager.startUpdatingLocation()
82 | }
83 | }
84 |
85 | extension NativeLocationManager: CLLocationManagerDelegate {
86 |
87 | @objc public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
88 | guard let location = locations.last, isLocationViable(location) else { return }
89 |
90 | for l in listeners.array() {
91 | l.onLocationUpdate(location)
92 | }
93 | }
94 |
95 | @objc public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
96 | for l in listeners.array() {
97 | l.onAuthorizationStatusUpdate(status)
98 | }
99 | }
100 | }
101 |
102 | fileprivate extension NativeLocationManager {
103 |
104 | struct Static {
105 | static let instance = NativeLocationManager()
106 | static let maxTimeSinceLastUpdate: TimeInterval = 30.0
107 | }
108 |
109 | func isLocationViable(_ location: CLLocation?) -> Bool {
110 | guard let location = location else { return false }
111 | guard Date().timeIntervalSince(location.timestamp) < Static.maxTimeSinceLastUpdate else { return false }
112 | if let lastLocation = self.lastLocation, lastLocation.timestamp > location.timestamp {
113 | return false
114 | }
115 | self.lastLocation = location
116 | return true
117 | }
118 |
119 | func convert(_ from: DesiredAccuracy) -> Double {
120 | switch configuration.desiredAccuracy {
121 | case .best:
122 | return kCLLocationAccuracyBest
123 | case .bestForNavigation:
124 | return kCLLocationAccuracyBestForNavigation
125 | case .distance(let distance):
126 | return distance
127 | }
128 | }
129 |
130 | func convert(_ from: Double) -> DesiredAccuracy {
131 | switch from {
132 | case kCLLocationAccuracyBest:
133 | return .best
134 | case kCLLocationAccuracyBestForNavigation:
135 | return .bestForNavigation
136 | default:
137 | return .distance(from)
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utilities/Geometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // UserLocationPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 24/03/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SceneKit
11 |
12 | public func reflect(_ value: T, of reflectionPoint: T) -> T {
13 | let diff = value - reflectionPoint
14 | return reflectionPoint - diff
15 | }
16 |
17 | public extension FloatingPoint {
18 | public var degreesToRadians: Self { return self * .pi / 180 }
19 | public var radiansToDegrees: Self { return self * 180 / .pi }
20 | }
21 |
22 | extension CGRect {
23 | var mid: CGPoint {
24 | return CGPoint(x: midX, y: midY)
25 | }
26 |
27 | var topLeft: CGPoint{
28 | return origin
29 | }
30 |
31 | var topRight: CGPoint{
32 | return CGPoint(x: origin.x + width, y: origin.y)
33 | }
34 |
35 | var bottomLeft: CGPoint{
36 | return CGPoint(x: origin.x, y: origin.y + height)
37 | }
38 |
39 | var bottomRight: CGPoint{
40 | return CGPoint(x: origin.x + width, y: origin.y + height)
41 | }
42 | }
43 |
44 | struct CGLine {
45 | let point1: CGPoint
46 | let point2: CGPoint
47 | }
48 |
49 | extension CGPoint {
50 | func distance(to point: CGPoint) -> CGFloat {
51 | let dx = self.x - point.x
52 | let dy = self.y - point.y
53 | let dist = sqrt(pow(dx, 2) + pow(dy, 2))
54 | return dist
55 | }
56 | }
57 |
58 | let MT_EPS: CGFloat = 1e-4
59 |
60 | typealias CGDelta = CGPoint
61 |
62 | extension CGLine {
63 |
64 | func point(atDistance distance: CGFloat) -> CGPoint {
65 | let start = Vector2(self.point1)
66 | let end = Vector2(self.point2)
67 | let vec = start + (end - start).normalized() * Scalar(distance)
68 | return CGPoint(vec)
69 | }
70 |
71 | func contains(point: CGPoint) -> Bool {
72 | let end: CGPoint = self.point2
73 | let start: CGPoint = self.point1
74 | let startToEnd = Vector2(end) - Vector2(start)
75 | let startToPoint = Vector2(point) - Vector2(start)
76 | let pointToEnd = Vector2(end) - Vector2(point)
77 | if fabs(CGFloat(startToPoint.length)) < MT_EPS || fabs(CGFloat(pointToEnd.length)) < MT_EPS {
78 | return true
79 | } else {
80 | return (startToPoint.angle(with: startToEnd).truncatingRemainder(dividingBy: .twoPi) ~= 0.0)
81 | && (startToPoint.length <= startToEnd.length)
82 | }
83 | }
84 |
85 | var length: CGFloat {
86 | return point1.distance(to: point2)
87 | }
88 |
89 | func intersection(withRect rect: CGRect) -> CGPoint? {
90 | let top = CGLine(point1: rect.topLeft, point2: rect.topRight)
91 | let right = CGLine(point1: rect.topRight, point2: rect.bottomRight)
92 | let bottom = CGLine(point1: rect.bottomLeft, point2: rect.bottomRight)
93 | let left = CGLine(point1: rect.topLeft, point2: rect.bottomLeft)
94 |
95 |
96 | let points: [CGPoint?] = [ top.intersection(withLine: self),
97 | right.intersection(withLine: self),
98 | left.intersection(withLine: self),
99 | bottom.intersection(withLine: self)]
100 |
101 | for p in points {
102 | if p != nil {
103 | return p!
104 | }
105 | }
106 |
107 | return nil;
108 | }
109 |
110 | func intersection(withLine line: CGLine) -> CGPoint? {
111 | let line1 = self
112 | let line2 = line
113 |
114 | let x1 = line1.point1.x
115 | let y1 = line1.point1.y
116 | let x2 = line1.point2.x
117 | let y2 = line1.point2.y
118 | let x3 = line2.point1.x
119 | let y3 = line2.point1.y
120 | let x4 = line2.point2.x
121 | let y4 = line2.point2.y
122 |
123 | let denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1)
124 | let numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3)
125 | let numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3)
126 |
127 | /* Are the lines coincident? */
128 | if (fabs(numera) < MT_EPS && fabs(numerb) < MT_EPS && fabs(denom) < MT_EPS) {
129 | return CGPoint(x: (x1 + x2) / 2.0, y: (y1 + y2) / 2.0)
130 | }
131 |
132 | /* Are the line parallel */
133 | if (fabs(denom) < MT_EPS) {
134 | return nil
135 | }
136 |
137 | /* Is the intersection along the the segments */
138 | let mua = numera / denom
139 | let mub = numerb / denom
140 | if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
141 | return nil
142 | }
143 | return CGPoint(x: x1 + mua * (x2 - x1), y: y1 + mua * (y2 - y1))
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // FinishPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SceneKit
11 | import ARKit
12 |
13 | class ViewController: UIViewController, ARSCNViewDelegate {
14 |
15 | @IBOutlet var sceneView: ARSCNView!
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | // Set the view's delegate
21 | sceneView.delegate = self
22 |
23 | // Show statistics such as fps and timing information
24 | sceneView.showsStatistics = true
25 |
26 | // Create a new scene
27 | let scene = SCNScene()
28 |
29 | // Set the scene to the view
30 | sceneView.scene = scene
31 |
32 | // Add node for route finish point
33 |
34 | routeFinishNode = createSphereNode(withRadius: 0.5, color: UIColor.green)
35 | routeFinishNode.position = SCNVector3Make(10.0, 0.0, 0.0)
36 | scene.rootNode.addChildNode(routeFinishNode)
37 |
38 | // Draw route finish placemark hint
39 |
40 | routeFinishHint = UIView()
41 | routeFinishHint.isHidden = true
42 | routeFinishHint.frame = CGRect(x: 0.0, y: 0.0, width: 50, height: 50)
43 | routeFinishHint.layer.cornerRadius = 25.0
44 | routeFinishHint.backgroundColor = UIColor.red
45 |
46 | view.addSubview(routeFinishHint)
47 | }
48 |
49 | override func viewWillAppear(_ animated: Bool) {
50 | super.viewWillAppear(animated)
51 |
52 | // Create a session configuration
53 | let configuration = ARWorldTrackingConfiguration()
54 |
55 | // Run the view's session
56 | sceneView.session.run(configuration)
57 | }
58 |
59 | override func viewWillDisappear(_ animated: Bool) {
60 | super.viewWillDisappear(animated)
61 |
62 | // Pause the view's session
63 | sceneView.session.pause()
64 | }
65 |
66 | func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) {
67 | guard let parent = routeFinishNode.parent else { return }
68 | guard let pointOfView = renderer.pointOfView else { return }
69 |
70 | let bounds = UIScreen.main.bounds
71 |
72 | let positionInWorld = routeFinishNode.worldPosition
73 | let positionInPOV = parent.convertPosition(routeFinishNode.position, to: pointOfView)
74 | let projection = sceneView.projectPoint(positionInWorld)
75 | let projectionPoint = CGPoint(x: CGFloat(projection.x), y: CGFloat(projection.y))
76 |
77 | let screenMidToProjectionLine = CGLine(point1: bounds.mid, point2: projectionPoint)
78 | let intersection = screenMidToProjectionLine.intersection(withRect: bounds)
79 |
80 | DispatchQueue.main.async {
81 | let point: CGPoint = intersection ?? projectionPoint
82 | let isInFront = positionInPOV.z < 0
83 | let isProjectionInScreenBounds: Bool = intersection == nil
84 |
85 | self.routeFinishHint.isHidden = isInFront && intersection == nil
86 |
87 | if isInFront {
88 | self.routeFinishHint.center = point
89 | } else {
90 | if isProjectionInScreenBounds {
91 | self.routeFinishHint.center = CGPoint(
92 | x: reflect(point.x, of: bounds.mid.x),
93 | y: bounds.height
94 | )
95 | } else {
96 | self.routeFinishHint.center = CGPoint(
97 | x: reflect(point.x, of: bounds.mid.x),
98 | y: reflect(point.y, of: bounds.mid.y)
99 | )
100 | }
101 | }
102 | }
103 | }
104 |
105 | func findProjection(ofNode node: SCNNode, inSceneOfView scnView: SCNView) -> CGPoint {
106 | let nodeWorldPosition = node.worldPosition
107 | let projection = scnView.projectPoint(nodeWorldPosition)
108 | return CGPoint(x: CGFloat(projection.x), y: CGFloat(projection.y))
109 | }
110 |
111 | func isNodeInFrontOfCamera(_ node: SCNNode, scnView: SCNView) -> Bool {
112 | guard let pointOfView = scnView.pointOfView else { return false }
113 | guard let parent = node.parent else { return false }
114 | let positionInPOV = parent.convertPosition(node.position, to: pointOfView)
115 | return positionInPOV.z < 0
116 | }
117 |
118 | func createSphereNode(withRadius radius: CGFloat, color: UIColor) -> SCNNode {
119 | let geometry = SCNSphere(radius: radius)
120 | geometry.firstMaterial?.diffuse.contents = color
121 | let sphereNode = SCNNode(geometry: geometry)
122 | return sphereNode
123 | }
124 |
125 | private var routeFinishNode: SCNNode!
126 | private var routeFinishHint: UIView!
127 | }
128 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // RoutePolyline
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SceneKit
11 |
12 | struct RouteConstants {
13 | static let distanceBetweenArrows: Float = 5.0
14 | }
15 |
16 | class ViewController: UIViewController, SCNSceneRendererDelegate {
17 |
18 | var sceneView: SCNView!
19 | var restart: UIButton = UIButton(type: .system)
20 | var hideNodesButton: UIButton = UIButton(type: .system)
21 | var showNodesButton: UIButton = UIButton(type: .system)
22 | var showNextNodeButton: UIButton = UIButton(type: .system)
23 |
24 | var polylineNodes: [SCNNode] = [] {
25 | didSet {
26 | oldValue.forEach { $0.removeFromParentNode() }
27 | polylineNodes.forEach { sceneView.scene?.rootNode.addChildNode($0) }
28 | }
29 | }
30 |
31 | var animationStepNodes: [SCNNode] = [] {
32 | didSet {
33 | oldValue.forEach { $0.removeFromParentNode() }
34 | animationStepNodes.forEach { sceneView.scene?.rootNode.addChildNode($0) }
35 | }
36 | }
37 |
38 | var routePointNodes: [SCNNode] = [] {
39 | didSet {
40 | oldValue.forEach { $0.removeFromParentNode() }
41 | routePointNodes.forEach { sceneView.scene?.rootNode.addChildNode($0) }
42 | }
43 | }
44 |
45 | func update() {
46 | // Здесь x - по оси Z в SceneKit, y - по оси X в SceneKit (ось Y SceneKit смотрит при этом вверх)
47 | let route: [CGPoint] = [
48 | CGPoint.zero,
49 | CGPoint(x: 2, y: 0),
50 | CGPoint(x: 7, y: 0),
51 | CGPoint(x: 10, y: 0),
52 | CGPoint(x: 10, y: 5),
53 | CGPoint(x: 7, y: 7),
54 | CGPoint(x: 5, y: 5),
55 | CGPoint(x: 5, y: 10),
56 | CGPoint(x: 0, y: 10),
57 | CGPoint(x: -6, y: 4),
58 | CGPoint(x: 0, y: 0)
59 | ]
60 | polylineNodes = createPolyline(forRoute: route, withAnimationLength: RouteConstants.distanceBetweenArrows)
61 | let representation = createRepresentation(forRoute: route, withAnimationLength: RouteConstants.distanceBetweenArrows)
62 | routePointNodes = representation.routeNodes
63 | animationStepNodes = representation.animationNodes
64 | }
65 |
66 | @objc func hideTapped() {
67 | polylineNodes.forEach { $0.isHidden = true }
68 | }
69 |
70 | @objc func showTapped() {
71 | polylineNodes.forEach { $0.isHidden = false }
72 | }
73 |
74 | @objc func refreshTapped() {
75 | update()
76 | }
77 |
78 | @objc func showNextNodeTapped() {
79 | for polylineNode in polylineNodes {
80 | if polylineNode.isHidden {
81 | polylineNode.isHidden = false
82 | break
83 | }
84 | }
85 | }
86 |
87 |
88 | override func viewDidLoad() {
89 | super.viewDidLoad()
90 |
91 | sceneView = SCNView()
92 | view.addSubview(sceneView)
93 |
94 | // Set the view's delegate
95 | sceneView.delegate = self
96 |
97 | // Create a new scene
98 | let scene = SCNScene()
99 |
100 | // Set the scene to the view
101 | sceneView.scene = scene
102 | sceneView.showsStatistics = false
103 | sceneView.debugOptions = []
104 | sceneView.autoenablesDefaultLighting = true
105 | sceneView.allowsCameraControl = true
106 |
107 | update()
108 |
109 | let axises: SCNNode = RouteGeometryFactory.axesNode(quiverLength: 4.0, quiverThickness: 0.5)
110 | scene.rootNode.addChildNode(axises)
111 |
112 | // Buttons
113 |
114 | hideNodesButton.setTitle("Hide all", for: .normal)
115 | hideNodesButton.addTarget(self, action: #selector(hideTapped), for: .touchUpInside)
116 |
117 | showNodesButton.setTitle("Show all", for: .normal)
118 | showNodesButton.addTarget(self, action: #selector(showTapped), for: .touchUpInside)
119 |
120 | restart.setTitle("Refresh", for: .normal)
121 | restart.addTarget(self, action: #selector(refreshTapped), for: .touchUpInside)
122 |
123 | showNextNodeButton.setTitle("Show next", for: .normal)
124 | showNextNodeButton.addTarget(self, action: #selector(showNextNodeTapped), for: .touchUpInside)
125 |
126 | [hideNodesButton, showNodesButton, restart, showNextNodeButton].forEach {
127 | $0.translatesAutoresizingMaskIntoConstraints = false
128 | view.addSubview($0)
129 | $0.backgroundColor = UIColor.black.withAlphaComponent(0.8)
130 | $0.setTitleColor(UIColor.white, for: .normal)
131 | $0.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
132 | }
133 |
134 | restart.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
135 | showNextNodeButton.leftAnchor.constraint(equalTo: restart.rightAnchor, constant: 8.0).isActive = true
136 | hideNodesButton.leftAnchor.constraint(equalTo: showNextNodeButton.rightAnchor, constant: 8.0).isActive = true
137 | showNodesButton.leftAnchor.constraint(equalTo: hideNodesButton.rightAnchor, constant: 8.0).isActive = true
138 | }
139 |
140 | override func viewWillAppear(_ animated: Bool) {
141 | super.viewWillAppear(animated)
142 | }
143 |
144 | override func viewWillDisappear(_ animated: Bool) {
145 | super.viewWillDisappear(animated)
146 |
147 | }
148 |
149 | override func didReceiveMemoryWarning() {
150 | super.didReceiveMemoryWarning()
151 | // Release any cached data, images, etc that aren't in use.
152 | }
153 |
154 | override func viewDidLayoutSubviews() {
155 | super.viewDidLayoutSubviews()
156 |
157 | sceneView.frame = self.view.bounds
158 | }
159 |
160 |
161 | }
162 |
163 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/Utils/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // FinishPlacemarkHelper
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import SceneKit
12 |
13 | extension Array {
14 |
15 | public func skip(_ n: Int) -> Array {
16 | let result: [Element] = []
17 | return n > count ? result : Array(self[Int(n).. Bool) -> Bool {
21 | return self.filter(condition).count == self.count
22 | }
23 |
24 | public func any(condition: (Element) -> Bool) -> Bool {
25 | return self.filter(condition).count > 0
26 | }
27 | }
28 |
29 | public extension Swift.Collection {
30 |
31 | /// Returns the element at the specified index iff it is within bounds, otherwise nil.
32 | public subscript (safe index: Index) -> Element? {
33 | return indices.contains(index) ? self[index] : nil
34 | }
35 | }
36 |
37 | extension Sequence {
38 |
39 | /// Returns single element that sutisfies predicate
40 | /// or nil if no elements found or more than one element found
41 | /// - Parameter condition: predicate
42 | /// - Returns: the only element that sutisfies predicate or nil otherwise
43 | public func single(condition: (Element) -> Bool) -> Element? {
44 | let sutisfiableElements = self.filter(condition)
45 | if sutisfiableElements.count > 1 {
46 | return nil
47 | } else {
48 | return sutisfiableElements.first
49 | }
50 | }
51 | }
52 |
53 | public func reflect(_ value: T, of reflectionPoint: T) -> T {
54 | let diff = value - reflectionPoint
55 | return reflectionPoint - diff
56 | }
57 |
58 | extension CGRect {
59 | var mid: CGPoint {
60 | return CGPoint(x: midX, y: midY)
61 | }
62 |
63 | var topLeft: CGPoint{
64 | return origin
65 | }
66 |
67 | var topRight: CGPoint{
68 | return CGPoint(x: origin.x + width, y: origin.y)
69 | }
70 |
71 | var bottomLeft: CGPoint{
72 | return CGPoint(x: origin.x, y: origin.y + height)
73 | }
74 |
75 | var bottomRight: CGPoint{
76 | return CGPoint(x: origin.x + width, y: origin.y + height)
77 | }
78 | }
79 |
80 | struct CGLine {
81 | let point1: CGPoint
82 | let point2: CGPoint
83 | }
84 |
85 | extension CGPoint {
86 | func distance(to point: CGPoint) -> CGFloat {
87 | let dx = self.x - point.x
88 | let dy = self.y - point.y
89 | let dist = sqrt(pow(dx, 2) + pow(dy, 2))
90 | return dist
91 | }
92 | }
93 |
94 | let MT_EPS: CGFloat = 1e-4
95 |
96 | typealias CGDelta = CGPoint
97 |
98 | extension CGLine {
99 |
100 | func point(atDistance distance: CGFloat) -> CGPoint {
101 | let start = Vector2(self.point1)
102 | let end = Vector2(self.point2)
103 | let vec = start + (end - start).normalized() * Scalar(distance)
104 | return CGPoint(vec)
105 | }
106 |
107 | func contains(point: CGPoint) -> Bool {
108 | let end: CGPoint = self.point2
109 | let start: CGPoint = self.point1
110 | let startToEnd = Vector2(end) - Vector2(start)
111 | let startToPoint = Vector2(point) - Vector2(start)
112 | return (startToPoint.angle(with: startToEnd).truncatingRemainder(dividingBy: .twoPi) ~= 0.0)
113 | && (startToPoint.length <= startToEnd.length)
114 | }
115 |
116 | var length: CGFloat {
117 | return point1.distance(to: point2)
118 | }
119 |
120 | func intersection(withRect rect: CGRect) -> CGPoint? {
121 | let top = CGLine(point1: rect.topLeft, point2: rect.topRight)
122 | let right = CGLine(point1: rect.topRight, point2: rect.bottomRight)
123 | let bottom = CGLine(point1: rect.bottomLeft, point2: rect.bottomRight)
124 | let left = CGLine(point1: rect.topLeft, point2: rect.bottomLeft)
125 |
126 |
127 | let points: [CGPoint?] = [ top.intersection(withLine: self),
128 | right.intersection(withLine: self),
129 | left.intersection(withLine: self),
130 | bottom.intersection(withLine: self)]
131 |
132 | for p in points {
133 | if p != nil {
134 | return p!
135 | }
136 | }
137 |
138 | return nil;
139 | }
140 |
141 | func intersection(withLine line: CGLine) -> CGPoint? {
142 | let line1 = self
143 | let line2 = line
144 |
145 | let x1 = line1.point1.x
146 | let y1 = line1.point1.y
147 | let x2 = line1.point2.x
148 | let y2 = line1.point2.y
149 | let x3 = line2.point1.x
150 | let y3 = line2.point1.y
151 | let x4 = line2.point2.x
152 | let y4 = line2.point2.y
153 |
154 | let denom = (y4-y3) * (x2-x1) - (x4-x3) * (y2-y1)
155 | let numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3)
156 | let numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3)
157 |
158 | /* Are the lines coincident? */
159 | if (fabs(numera) < MT_EPS && fabs(numerb) < MT_EPS && fabs(denom) < MT_EPS) {
160 | return CGPoint(x: (x1 + x2) / 2.0, y: (y1 + y2) / 2.0)
161 | }
162 |
163 | /* Are the line parallel */
164 | if (fabs(denom) < MT_EPS) {
165 | return nil
166 | }
167 |
168 | /* Is the intersection along the the segments */
169 | let mua = numera / denom
170 | let mub = numerb / denom
171 | if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
172 | return nil
173 | }
174 | return CGPoint(x: x1 + mua * (x2 - x1), y: y1 + mua * (y2 - y1))
175 | }
176 | }
177 |
178 | extension UIImage {
179 | class func image(from view: UIView) -> UIImage? {
180 | UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
181 | guard let context = UIGraphicsGetCurrentContext() else { return nil }
182 |
183 | view.layer.render(in: context)
184 | let img = UIGraphicsGetImageFromCurrentImageContext()
185 | UIGraphicsEndImageContext()
186 | return img
187 | }
188 | }
189 |
190 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/ARKit+CoreLocation/GeoExtensions/GeoExtensions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import CoreLocation
3 | import SceneKit
4 | import MapKit
5 |
6 | public struct GeometryConstants {
7 | public static let EarthRadius = Double(6_371_000)
8 | public static let LatLonEps = 1e-6
9 | }
10 |
11 | public extension Double {
12 |
13 | /// Конвертирует длину в метрах в длину по меридиану (по любому, так как они все одной длины) в радианах
14 | ///
15 | /// - Returns: длины в радианах
16 | public func metersToLatitude() -> Double {
17 | return self / GeometryConstants.EarthRadius
18 | }
19 |
20 | /// Конвертирует длину в метрах в длину по параллели
21 | /// переданной в параметрах (так как длина праллели зависит от широты) в радианах
22 | /// - Parameter lat: широта в градусах
23 | /// - Returns: длину в радианах
24 | func metersToLongitude(lat: Double) -> Double {
25 | return self / GeometryConstants.EarthRadius * cos(lat.degreesToRadians)
26 | }
27 | }
28 |
29 | public extension BinaryFloatingPoint {
30 | public var degreesToRadians: Self { return self * .pi / 180 }
31 | public var radiansToDegrees: Self { return self * 180 / .pi }
32 | }
33 |
34 |
35 | public struct SceneLocationEstimate {
36 | public let location: CLLocation
37 | public let position: SCNVector3
38 | public init(location: CLLocation, position: SCNVector3) {
39 | self.location = location
40 | self.position = position
41 | }
42 | }
43 |
44 | public extension SceneLocationEstimate {
45 |
46 | /// Translates the location by comparing with a given position
47 | public func translatedLocation(to position: SCNVector3) -> CLLocation {
48 | let translation = position - self.position
49 | let translatedCoordinate = location.coordinate.transform(using: CLLocationDistance(-translation.z),
50 | longitudinalMeters: CLLocationDistance(translation.x))
51 | return CLLocation(
52 | coordinate: translatedCoordinate,
53 | altitude: location.altitude,
54 | horizontalAccuracy: location.horizontalAccuracy,
55 | verticalAccuracy: location.verticalAccuracy,
56 | timestamp: location.timestamp
57 | )
58 | }
59 | }
60 |
61 |
62 | /// Haversine formula to calculate the great-circle distance between two points
63 | ///
64 | /// - Parameters:
65 | /// - lat1: 1-st point latitude
66 | /// - lon1: 1-st point longitude
67 | /// - lat2: 2-nd point latitude
68 | /// - lon2: 2-nd point longitude
69 | /// - Returns: Distance in meters
70 | public func metersBetween(_ lat1: Double, _ lon1: Double, _ lat2: Double, _ lon2: Double) -> Double {
71 | // From here: http://www.movable-type.co.uk/scripts/latlong.html
72 |
73 | let sqr: (Double) -> Double = { $0 * $0 }
74 | let R = GeometryConstants.EarthRadius // meters
75 |
76 | let phi_1 = lat1.degreesToRadians
77 | let phi_2 = lat2.degreesToRadians
78 | let dPhi = (lat2 - lat1).degreesToRadians
79 | let dLmb = (lon2 - lon1).degreesToRadians
80 |
81 | let a = sqr(sin(dPhi/2)) + cos(phi_1) * cos(phi_2) * sqr(sin(dLmb/2))
82 | let c: Double = 2 * atan2(sqrt(a), sqrt(Double(1) - a))
83 |
84 | return R * c
85 | }
86 |
87 | public func metersBetween(_ coordinate1: CLLocationCoordinate2D, _ coordinate2: CLLocationCoordinate2D) -> Double {
88 | return metersBetween(coordinate1.latitude, coordinate1.longitude, coordinate2.latitude, coordinate2.longitude)
89 | }
90 |
91 | //(-180,180] anticlockwise is positive
92 | public func bearingBetween(_ point1: CLLocationCoordinate2D, _ point2: CLLocationCoordinate2D) -> Double {
93 | let lat1 = point1.latitude.degreesToRadians
94 | let lon1 = point1.longitude.degreesToRadians
95 |
96 | let lat2 = point2.latitude.degreesToRadians
97 | let lon2 = point2.longitude.degreesToRadians
98 |
99 | let dLon = lon2 - lon1
100 |
101 | let y = sin(dLon) * cos(lat2)
102 | let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon)
103 | let radiansBearing = atan2(y, x)
104 |
105 | return radiansBearing.radiansToDegrees
106 | }
107 |
108 | /// Translation in meters between 2 locations
109 | public struct LocationTranslation {
110 | public var latitudeTranslation: Double
111 | public var longitudeTranslation: Double
112 |
113 | public init(latitudeTranslation: Double, longitudeTranslation: Double) {
114 | self.latitudeTranslation = latitudeTranslation
115 | self.longitudeTranslation = longitudeTranslation
116 | }
117 | }
118 |
119 | extension LocationTranslation {
120 | public init(dLat: Double, dLon: Double) {
121 | self.init(latitudeTranslation: dLat, longitudeTranslation: dLon)
122 | }
123 |
124 | public var dLat: Double {
125 | return latitudeTranslation
126 | }
127 |
128 | public var dLon: Double {
129 | return longitudeTranslation
130 | }
131 | }
132 |
133 | public extension CLLocationCoordinate2D {
134 |
135 | var lat: Double {
136 | return latitude
137 | }
138 |
139 | var lon: Double {
140 | return longitude
141 | }
142 |
143 | public func transform(using latitudinalMeters: CLLocationDistance, longitudinalMeters: CLLocationDistance) -> CLLocationCoordinate2D {
144 | let region = MKCoordinateRegionMakeWithDistance(self, latitudinalMeters, longitudinalMeters)
145 | return CLLocationCoordinate2D(latitude: latitude + region.span.latitudeDelta, longitude: longitude + region.span.longitudeDelta)
146 | }
147 |
148 | /// Calculate translation between to coordinates
149 | func translation(toCoordinate coordinate: CLLocationCoordinate2D) -> LocationTranslation {
150 | let position = CLLocationCoordinate2D(latitude: self.latitude, longitude: coordinate.longitude)
151 | let distanceLat = metersBetween(coordinate, position)
152 | let dLat: Double = (coordinate.lat > position.lat ? 1 : -1) * distanceLat
153 | let distanceLon = metersBetween(self, position)
154 | let dLon: Double = (lon > position.lon ? -1 : 1) * distanceLon
155 | return LocationTranslation(dLat: dLat, dLon: dLon)
156 | }
157 |
158 | func translation2(toCoordinate coordinate: CLLocationCoordinate2D) -> LocationTranslation {
159 | let metersInOneLatDegree: Double = 2 * Double.pi * GeometryConstants.EarthRadius / 360
160 | let metersInOneLonDegree: ((Double) -> Double) = {
161 | 2 * Double.pi * GeometryConstants.EarthRadius * cos($0.degreesToRadians) / 360
162 | }
163 | let distanceLat = abs(coordinate.lat - lat)
164 | let distanceLon = abs(coordinate.lon - lon)
165 | let dLat: Double = (coordinate.lat > lat ? 1 : -1) * distanceLat
166 | let dLon: Double = (lon > coordinate.lon ? -1 : 1) * distanceLon
167 | return LocationTranslation(dLat: dLat * metersInOneLatDegree, dLon: dLon * metersInOneLonDegree(lat))
168 | }
169 | }
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline/RouteAnimationUtils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RouteAnimation.swift
3 | // RoutePolyline
4 | //
5 | // Created by Dmitry Trimonov on 16/04/2018.
6 | // Copyright © 2018 Yandex, LLC. All rights reserved.
7 | //
8 |
9 | import SceneKit
10 |
11 | func divideRoute(route: [CGPoint], toAnimationsOfLength animationLength: Float) -> [Animation] {
12 | guard route.count >= 2 else { return [] }
13 | var animations: [Animation] = []
14 | var currentAnimation: Animation = Animation(steps: [])
15 | let segmentsCount = Array(zip(route, route.skip(1))).count
16 | var currentSegmentIndex = 0
17 | var offsetInSegment: CGFloat = 0.0
18 | var lengthTailFromPrevSegment: CGFloat? = nil
19 | while currentSegmentIndex < segmentsCount {
20 | let segmentStart = route[currentSegmentIndex]
21 | let segmentEnd = route[currentSegmentIndex + 1]
22 | let segmentLine = CGLine(point1: segmentStart, point2: segmentEnd)
23 |
24 | var stepStart: CGPoint
25 | var stepEnd: CGPoint
26 |
27 | if let lengthTail = lengthTailFromPrevSegment {
28 | assert(offsetInSegment == 0.0)
29 | stepStart = segmentStart
30 | let stepEndCandidate = segmentLine.point(atDistance: lengthTail)
31 | if segmentLine.contains(point: stepEndCandidate) {
32 | stepEnd = stepEndCandidate
33 | currentAnimation.steps.append(Step(start: stepStart, end: stepEnd))
34 | animations.append(currentAnimation)
35 | currentAnimation = Animation(steps: [])
36 |
37 | if stepEnd == segmentEnd {
38 | offsetInSegment = 0.0
39 | currentSegmentIndex += 1
40 | } else {
41 | offsetInSegment = lengthTail
42 | }
43 | lengthTailFromPrevSegment = nil
44 | } else {
45 | stepEnd = segmentEnd
46 | let step = Step(start: stepStart, end: stepEnd)
47 | currentAnimation.steps.append(step)
48 |
49 | currentSegmentIndex += 1
50 | offsetInSegment = 0.0
51 | lengthTailFromPrevSegment = lengthTail - step.length
52 | }
53 | continue
54 | }
55 |
56 | stepStart = segmentLine.point(atDistance: offsetInSegment)
57 | assert(segmentLine.contains(point: stepStart))
58 | let nextOffset = offsetInSegment + CGFloat(animationLength)
59 | let stepEndCandidate = segmentLine.point(atDistance: nextOffset)
60 | if segmentLine.contains(point: stepEndCandidate) {
61 | stepEnd = stepEndCandidate
62 | currentAnimation.steps.append(Step(start: stepStart, end: stepEnd))
63 | animations.append(currentAnimation)
64 | currentAnimation = Animation(steps: [])
65 | if stepEnd == segmentEnd {
66 | offsetInSegment = 0.0
67 | currentSegmentIndex += 1
68 | } else {
69 | offsetInSegment = nextOffset
70 | }
71 | lengthTailFromPrevSegment = nil
72 | } else {
73 | if stepStart ~= segmentEnd {
74 | break
75 | }
76 | stepEnd = segmentEnd
77 | let step = Step(start: stepStart, end: stepEnd)
78 | currentAnimation.steps.append(step)
79 | currentSegmentIndex += 1
80 | offsetInSegment = 0.0
81 | lengthTailFromPrevSegment = CGFloat(animationLength) - step.length
82 | }
83 | }
84 |
85 | if currentAnimation.steps.count > 0 {
86 | animations.append(currentAnimation)
87 | }
88 | return animations
89 | }
90 |
91 | fileprivate extension CGPoint {
92 | /// Здесь x - по оси Z в SceneKit, y - по оси X в SceneKit (ось Y SceneKit смотрит при этом вверх)
93 | /// на плоскость Y = 0
94 | var positionIn3D: SCNVector3 {
95 | return SCNVector3(y, 0.0, x)
96 | }
97 | }
98 |
99 | func createRepresentation(forRoute route: [CGPoint], withAnimationLength animationLength: Float) -> (routeNodes: [SCNNode], animationNodes: [SCNNode]) {
100 | let animationPointNodes: [SCNNode] = divideRoute(route: route, toAnimationsOfLength: animationLength).map { $0.points }.flatMap { $0 }.map {
101 | let node = RoutePointNode(radius: 0.15, color: UIColor.red, transparency: 1.0, height: 0.05)
102 | node.position = $0.positionIn3D
103 | return node
104 | }
105 | let routePointNodes: [SCNNode] = route.map {
106 | let node = RoutePointNode(radius: 0.3, transparency: 0.5)
107 | node.position = $0.positionIn3D
108 | return node
109 | }
110 | return (routeNodes: routePointNodes, animationNodes: animationPointNodes)
111 | }
112 |
113 | func createResetAction(firstStep: Step) -> SCNAction {
114 | let initialPosition = firstStep.start.positionIn3D
115 | let initialAngle = Vector2.x.angle(with: firstStep.vec) // Стрелка направлена по оси Z, которая переводится в 2D (CGPoint) как к-та X
116 | let moveToInitial = SCNAction.move(to: initialPosition, duration: 0.0)
117 | let rotateToInitial = SCNAction.rotateTo(x: 0.0, y: CGFloat(initialAngle), z: 0.0, duration: 0.0)
118 | let reset = SCNAction.group([moveToInitial, rotateToInitial])
119 | return reset
120 | }
121 |
122 | func createAction(forStep step: Step, previousStep: Step?, animationLength: CGFloat,
123 | animationDuration: TimeInterval) -> SCNAction
124 | {
125 | let stepDuration = (step.length / animationLength) * CGFloat(animationDuration)
126 | let moveBy = CGPoint(step.vec).positionIn3D
127 | let move = SCNAction.move(by: moveBy, duration: TimeInterval(stepDuration))
128 | if let prevStep = previousStep {
129 | let rotationAngle = prevStep.vec.angle(with: step.vec)
130 | let rotate = SCNAction.rotateBy(x: 0, y: CGFloat(rotationAngle), z: 0, duration: 0)
131 | return SCNAction.sequence([rotate, move])
132 | } else {
133 | return move
134 | }
135 | }
136 |
137 | func createPolyline(forRoute route: [CGPoint], withAnimationLength animationLength: Float, animationDuration: TimeInterval = 2.0) -> [SCNNode] {
138 | let animations = divideRoute(route: route, toAnimationsOfLength: animationLength)
139 | let nodesCount = animations.count
140 | var nodes: [SCNNode] = []
141 | for index in 0.. [Animation] {
12 | guard route.count >= 2 else { return [] }
13 | var animations: [Animation] = []
14 | var currentAnimation: Animation = Animation(steps: [])
15 | let segmentsCount = Array(zip(route, route.skip(1))).count
16 | var currentSegmentIndex = 0
17 | var offsetInSegment: CGFloat = 0.0
18 | var lengthTailFromPrevSegment: CGFloat? = nil
19 | while currentSegmentIndex < segmentsCount {
20 | let segmentStart = route[currentSegmentIndex]
21 | let segmentEnd = route[currentSegmentIndex + 1]
22 | let segmentLine = CGLine(point1: segmentStart, point2: segmentEnd)
23 |
24 | var stepStart: CGPoint
25 | var stepEnd: CGPoint
26 |
27 | if let lengthTail = lengthTailFromPrevSegment {
28 | assert(offsetInSegment == 0.0)
29 | stepStart = segmentStart
30 | let stepEndCandidate = segmentLine.point(atDistance: lengthTail)
31 | if segmentLine.contains(point: stepEndCandidate) {
32 | stepEnd = stepEndCandidate
33 | currentAnimation.steps.append(Step(start: stepStart, end: stepEnd))
34 | animations.append(currentAnimation)
35 | currentAnimation = Animation(steps: [])
36 |
37 | if stepEnd == segmentEnd {
38 | offsetInSegment = 0.0
39 | currentSegmentIndex += 1
40 | } else {
41 | offsetInSegment = lengthTail
42 | }
43 | lengthTailFromPrevSegment = nil
44 | } else {
45 | stepEnd = segmentEnd
46 | let step = Step(start: stepStart, end: stepEnd)
47 | currentAnimation.steps.append(step)
48 |
49 | currentSegmentIndex += 1
50 | offsetInSegment = 0.0
51 | lengthTailFromPrevSegment = lengthTail - step.length
52 | }
53 | continue
54 | }
55 |
56 | stepStart = segmentLine.point(atDistance: offsetInSegment)
57 | assert(segmentLine.contains(point: stepStart))
58 |
59 | let nextOffset = offsetInSegment + CGFloat(animationLength)
60 | let stepEndCandidate = segmentLine.point(atDistance: nextOffset)
61 | if segmentLine.contains(point: stepEndCandidate) {
62 | stepEnd = stepEndCandidate
63 | currentAnimation.steps.append(Step(start: stepStart, end: stepEnd))
64 | animations.append(currentAnimation)
65 | currentAnimation = Animation(steps: [])
66 | if stepEnd == segmentEnd {
67 | offsetInSegment = 0.0
68 | currentSegmentIndex += 1
69 | } else {
70 | offsetInSegment = nextOffset
71 | }
72 | lengthTailFromPrevSegment = nil
73 | } else {
74 | if stepStart ~= segmentEnd {
75 | break
76 | }
77 | stepEnd = segmentEnd
78 | let step = Step(start: stepStart, end: stepEnd)
79 | currentAnimation.steps.append(step)
80 | currentSegmentIndex += 1
81 | offsetInSegment = 0.0
82 | lengthTailFromPrevSegment = CGFloat(animationLength) - step.length
83 | }
84 | }
85 |
86 | if currentAnimation.steps.count > 0 {
87 | animations.append(currentAnimation)
88 | }
89 | return animations
90 | }
91 |
92 | extension CGPoint {
93 | /// Здесь x - по оси Z в SceneKit, y - по оси X в SceneKit (ось Y SceneKit смотрит при этом вверх)
94 | /// на плоскость Y = 0
95 | var positionIn3D: SCNVector3 {
96 | return SCNVector3(y, 0.0, x)
97 | }
98 |
99 | init(position: SCNVector3) {
100 | self.init(x: CGFloat(position.z), y: CGFloat(position.x))
101 | }
102 | }
103 |
104 | func createRepresentation(forRoute route: [CGPoint], withAnimationLength animationLength: Float) -> (routeNodes: [SCNNode], animationNodes: [SCNNode]) {
105 | let animationPointNodes: [SCNNode] = divideRoute(route: route, toAnimationsOfLength: animationLength).map { $0.points }.flatMap { $0 }.map {
106 | let node = RoutePointNode(radius: 0.15, color: UIColor.red, transparency: 1.0, height: 0.05)
107 | node.position = $0.positionIn3D
108 | return node
109 | }
110 | let routePointNodes: [SCNNode] = route.map {
111 | let node = RoutePointNode(radius: 0.3, transparency: 0.5)
112 | node.position = $0.positionIn3D
113 | return node
114 | }
115 | return (routeNodes: routePointNodes, animationNodes: animationPointNodes)
116 | }
117 |
118 | func createResetAction(firstStep: Step) -> SCNAction {
119 | let initialPosition = firstStep.start.positionIn3D
120 | let initialAngle = Vector2.x.angle(with: firstStep.vec) // Стрелка направлена по оси Z, которая переводится в 2D (CGPoint) как к-та X
121 | let moveToInitial = SCNAction.move(to: initialPosition, duration: 0.0)
122 | let rotateToInitial = SCNAction.rotateTo(x: 0.0, y: CGFloat(initialAngle), z: 0.0, duration: 0.0)
123 | let reset = SCNAction.group([moveToInitial, rotateToInitial])
124 | return reset
125 | }
126 |
127 | func createAction(forStep step: Step, previousStep: Step?, animationLength: CGFloat,
128 | animationDuration: TimeInterval) -> SCNAction
129 | {
130 | let stepDuration = (step.length / animationLength) * CGFloat(animationDuration)
131 | let moveBy = CGPoint(step.vec).positionIn3D
132 | let move = SCNAction.move(by: moveBy, duration: TimeInterval(stepDuration))
133 | if let prevStep = previousStep {
134 | let rotationAngle = prevStep.vec.angle(with: step.vec)
135 | let rotate = SCNAction.rotateBy(x: 0, y: CGFloat(rotationAngle), z: 0, duration: 0)
136 | return SCNAction.sequence([rotate, move])
137 | } else {
138 | return move
139 | }
140 | }
141 |
142 | func createPolyline(forRoute route: [CGPoint], withAnimationLength animationLength: Float, animationDuration: TimeInterval = 2.0) -> [SCNNode] {
143 | let animations = divideRoute(route: route, toAnimationsOfLength: animationLength)
144 | let nodesCount = animations.count
145 | var nodes: [SCNNode] = []
146 | for index in 0.. SCNGeometry {
61 | let blue = SCNMaterial()
62 | blue.diffuse.contents = UIColor.blue
63 | return ARSCNPathArrow(material: blue)
64 | }
65 |
66 | static func axesNode(quiverLength: CGFloat, quiverThickness: CGFloat) -> SCNNode {
67 | let quiverThickness = (quiverLength / 50.0) * quiverThickness
68 | let chamferRadius = quiverThickness / 2.0
69 |
70 | let xQuiverBox = SCNBox(width: quiverLength, height: quiverThickness, length: quiverThickness, chamferRadius: chamferRadius)
71 | xQuiverBox.firstMaterial?.diffuse.contents = UIColor.red
72 | let xQuiverNode = SCNNode(geometry: xQuiverBox)
73 | xQuiverNode.position = SCNVector3Make(Float(quiverLength / 2.0), 0.0, 0.0)
74 |
75 | let yQuiverBox = SCNBox(width: quiverThickness, height: quiverLength, length: quiverThickness, chamferRadius: chamferRadius)
76 | yQuiverBox.firstMaterial?.diffuse.contents = UIColor.green
77 | let yQuiverNode = SCNNode(geometry: yQuiverBox)
78 | yQuiverNode.position = SCNVector3Make(0.0, Float(quiverLength / 2.0), 0.0)
79 |
80 | let zQuiverBox = SCNBox(width: quiverThickness, height: quiverThickness, length: quiverLength, chamferRadius: chamferRadius)
81 | zQuiverBox.firstMaterial?.diffuse.contents = UIColor.blue
82 | let zQuiverNode = SCNNode(geometry: zQuiverBox)
83 | zQuiverNode.position = SCNVector3Make(0.0, 0.0, Float(quiverLength / 2.0))
84 |
85 | let quiverNode = SCNNode()
86 | quiverNode.addChildNode(xQuiverNode)
87 | quiverNode.addChildNode(yQuiverNode)
88 | quiverNode.addChildNode(zQuiverNode)
89 | quiverNode.name = "Axes"
90 | return quiverNode
91 | }
92 | }
93 |
94 | /// Sphere node with text
95 | class RouteFinishNode: SCNNode {
96 |
97 | init(radius: CGFloat, color: UIColor) {
98 | super.init()
99 |
100 | let geometry = SCNSphere(radius: radius)
101 | geometry.firstMaterial?.diffuse.contents = color
102 | self.geometry = geometry
103 | self.pulseAnimationNode.geometry = geometry
104 | self.radius = radius
105 |
106 | textChildNode.geometry = textGeometry
107 | let billboardConstraint = SCNBillboardConstraint()
108 | billboardConstraint.freeAxes = SCNBillboardAxis.Y
109 | self.constraints = [billboardConstraint]
110 | addChildNode(textChildNode)
111 | addChildNode(pulseAnimationNode)
112 |
113 |
114 | let animationGroup = CAAnimationGroup.init()
115 | animationGroup.duration = 1.0
116 | animationGroup.repeatCount = .infinity
117 |
118 | let opacityAnimation = CABasicAnimation(keyPath: "opacity")
119 | opacityAnimation.fromValue = NSNumber(value: 1.0)
120 | opacityAnimation.toValue = NSNumber(value: 0.1)
121 |
122 | let scaleAnimation = CABasicAnimation(keyPath: "scale")
123 | scaleAnimation.fromValue = NSValue(scnVector3: SCNVector3(1.0, 1.0, 1.0))
124 | scaleAnimation.toValue = NSValue(scnVector3: SCNVector3(1.2, 1.2, 1.2))
125 |
126 | animationGroup.animations = [opacityAnimation, scaleAnimation]
127 | pulseAnimationNode.addAnimation(animationGroup, forKey: "animations")
128 | }
129 |
130 | required init?(coder aDecoder: NSCoder) {
131 | fatalError("init(coder:) has not been implemented")
132 | }
133 |
134 | var distance: Float = 0.0 {
135 | didSet {
136 | updateTextGeometry(plane: textGeometry, withText: "\(distance) м")
137 | }
138 | }
139 |
140 | var radius: CGFloat = 0.0 {
141 | didSet {
142 | let sphereGeometry = (geometry as? SCNSphere)
143 | sphereGeometry?.radius = radius
144 | let pulseSphereGeometry = pulseAnimationNode.geometry as? SCNSphere
145 | pulseSphereGeometry?.radius = radius
146 | textChildNode.position.y = Float(radius + 0.5)
147 | }
148 | }
149 |
150 | private func updateTextGeometry(plane: SCNPlane, withText text: String) {
151 | let image = snapshotDistanceView(withText: text)
152 | plane.width = image.size.width / 100
153 | plane.height = image.size.height / 100
154 | plane.firstMaterial!.diffuse.contents = image
155 | plane.firstMaterial!.lightingModel = .constant
156 | }
157 |
158 | private func snapshotDistanceView(withText text: String) -> UIImage {
159 | distanceView.text = text
160 | distanceView.textColor = UIColor.white
161 | distanceView.backgroundColor = UIColor.black.withAlphaComponent(0.8)
162 | let font = UIFont.systemFont(ofSize: 36.0, weight: UIFont.Weight.bold)
163 | distanceView.font = font
164 | let text = NSAttributedString.init(string: text,
165 | attributes: [NSAttributedStringKey.font: font])
166 | let textSize = text.boundingRect(
167 | with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude),
168 | options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil
169 | ).size
170 | distanceView.frame = CGRect.init(origin: .zero, size: textSize)
171 | distanceView.layoutIfNeeded()
172 | let distanceViewImage = UIImage.image(from: distanceView)
173 | return distanceViewImage!
174 | }
175 |
176 | private var distanceView: UILabel = UILabel()
177 | private let textGeometry: SCNPlane = SCNPlane()
178 | private let textChildNode: SCNNode = SCNNode()
179 | private let pulseAnimationNode: SCNNode = SCNNode()
180 | }
181 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utilities/SCNVector3Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013-2014 Kim Pedersen
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 | import SceneKit
25 |
26 | extension SCNVector3
27 | {
28 | /**
29 | * Negates the vector described by SCNVector3 and returns
30 | * the result as a new SCNVector3.
31 | */
32 | func negate() -> SCNVector3 {
33 | return self * -1
34 | }
35 |
36 | /**
37 | * Negates the vector described by SCNVector3
38 | */
39 | mutating func negated() -> SCNVector3 {
40 | self = negate()
41 | return self
42 | }
43 |
44 | /**
45 | * Returns the length (magnitude) of the vector described by the SCNVector3
46 | */
47 | func length() -> Float {
48 | return sqrtf(x*x + y*y + z*z)
49 | }
50 |
51 | /**
52 | * Normalizes the vector described by the SCNVector3 to length 1.0 and returns
53 | * the result as a new SCNVector3.
54 | */
55 | func normalized() -> SCNVector3 {
56 | return self / length()
57 | }
58 |
59 | /**
60 | * Normalizes the vector described by the SCNVector3 to length 1.0.
61 | */
62 | mutating func normalize() -> SCNVector3 {
63 | self = normalized()
64 | return self
65 | }
66 |
67 | /**
68 | * Calculates the distance between two SCNVector3. Pythagoras!
69 | */
70 | func distance(vector: SCNVector3) -> Float {
71 | return (self - vector).length()
72 | }
73 |
74 | /**
75 | * Calculates the dot product between two SCNVector3.
76 | */
77 | func dot(vector: SCNVector3) -> Float {
78 | return x * vector.x + y * vector.y + z * vector.z
79 | }
80 |
81 | /**
82 | * Calculates the cross product between two SCNVector3.
83 | */
84 | func cross(vector: SCNVector3) -> SCNVector3 {
85 | return SCNVector3Make(y * vector.z - z * vector.y, z * vector.x - x * vector.z, x * vector.y - y * vector.x)
86 | }
87 |
88 | public func angle(with v: SCNVector3) -> Float {
89 | if self.x == v.x && self.y == v.y && self.z == v.z {
90 | return 0
91 | }
92 |
93 | let selfLength = length()
94 | let vLength = v.length()
95 | if selfLength ~= 0 || vLength ~= 0 {
96 | return 0
97 | }
98 |
99 | let dotProduct = self.dot(vector: v)
100 | return acos(dotProduct / (selfLength * vLength))
101 | }
102 | }
103 |
104 | /**
105 | * Adds two SCNVector3 vectors and returns the result as a new SCNVector3.
106 | */
107 | func + (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
108 | return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
109 | }
110 |
111 | /**
112 | * Increments a SCNVector3 with the value of another.
113 | */
114 | func += (left: inout SCNVector3, right: SCNVector3) {
115 | left = left + right
116 | }
117 |
118 | /**
119 | * Subtracts two SCNVector3 vectors and returns the result as a new SCNVector3.
120 | */
121 | func - (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
122 | return SCNVector3Make(left.x - right.x, left.y - right.y, left.z - right.z)
123 | }
124 |
125 | /**
126 | * Decrements a SCNVector3 with the value of another.
127 | */
128 | func -= (left: inout SCNVector3, right: SCNVector3) {
129 | left = left - right
130 | }
131 |
132 | /**
133 | * Multiplies two SCNVector3 vectors and returns the result as a new SCNVector3.
134 | */
135 | func * (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
136 | return SCNVector3Make(left.x * right.x, left.y * right.y, left.z * right.z)
137 | }
138 |
139 | /**
140 | * Multiplies a SCNVector3 with another.
141 | */
142 | func *= (left: inout SCNVector3, right: SCNVector3) {
143 | left = left * right
144 | }
145 |
146 | /**
147 | * Multiplies the x, y and z fields of a SCNVector3 with the same scalar value and
148 | * returns the result as a new SCNVector3.
149 | */
150 | func * (vector: SCNVector3, scalar: Float) -> SCNVector3 {
151 | return SCNVector3Make(vector.x * scalar, vector.y * scalar, vector.z * scalar)
152 | }
153 |
154 | /**
155 | * Multiplies the x and y fields of a SCNVector3 with the same scalar value.
156 | */
157 | func *= (vector: inout SCNVector3, scalar: Float) {
158 | vector = vector * scalar
159 | }
160 |
161 | /**
162 | * Divides two SCNVector3 vectors abd returns the result as a new SCNVector3
163 | */
164 | func / (left: SCNVector3, right: SCNVector3) -> SCNVector3 {
165 | return SCNVector3Make(left.x / right.x, left.y / right.y, left.z / right.z)
166 | }
167 |
168 | /**
169 | * Divides a SCNVector3 by another.
170 | */
171 | func /= (left: inout SCNVector3, right: SCNVector3) {
172 | left = left / right
173 | }
174 |
175 | /**
176 | * Divides the x, y and z fields of a SCNVector3 by the same scalar value and
177 | * returns the result as a new SCNVector3.
178 | */
179 | func / (vector: SCNVector3, scalar: Float) -> SCNVector3 {
180 | return SCNVector3Make(vector.x / scalar, vector.y / scalar, vector.z / scalar)
181 | }
182 |
183 | /**
184 | * Divides the x, y and z of a SCNVector3 by the same scalar value.
185 | */
186 | func /= (vector: inout SCNVector3, scalar: Float) {
187 | vector = vector / scalar
188 | }
189 |
190 | /**
191 | * Negate a vector
192 | */
193 | func SCNVector3Negate(vector: SCNVector3) -> SCNVector3 {
194 | return vector * -1
195 | }
196 |
197 | /**
198 | * Returns the length (magnitude) of the vector described by the SCNVector3
199 | */
200 | func SCNVector3Length(vector: SCNVector3) -> Float
201 | {
202 | return sqrtf(vector.x*vector.x + vector.y*vector.y + vector.z*vector.z)
203 | }
204 |
205 | /**
206 | * Returns the distance between two SCNVector3 vectors
207 | */
208 | func SCNVector3Distance(vectorStart: SCNVector3, vectorEnd: SCNVector3) -> Float {
209 | return SCNVector3Length(vector: vectorEnd - vectorStart)
210 | }
211 |
212 | /**
213 | * Returns the distance between two SCNVector3 vectors
214 | */
215 | func SCNVector3Normalize(vector: SCNVector3) -> SCNVector3 {
216 | return vector / SCNVector3Length(vector: vector)
217 | }
218 |
219 | /**
220 | * Calculates the dot product between two SCNVector3 vectors
221 | */
222 | func SCNVector3DotProduct(left: SCNVector3, right: SCNVector3) -> Float {
223 | return left.x * right.x + left.y * right.y + left.z * right.z
224 | }
225 |
226 | /**
227 | * Calculates the cross product between two SCNVector3 vectors
228 | */
229 | func SCNVector3CrossProduct(left: SCNVector3, right: SCNVector3) -> SCNVector3 {
230 | return SCNVector3Make(left.y * right.z - left.z * right.y, left.z * right.x - left.x * right.z, left.x * right.y - left.y * right.x)
231 | }
232 |
233 | /**
234 | * Calculates the SCNVector from lerping between two SCNVector3 vectors
235 | */
236 | func SCNVector3Lerp(vectorStart: SCNVector3, vectorEnd: SCNVector3, t: Float) -> SCNVector3 {
237 | return SCNVector3Make(vectorStart.x + ((vectorEnd.x - vectorStart.x) * t), vectorStart.y + ((vectorEnd.y - vectorStart.y) * t), vectorStart.z + ((vectorEnd.z - vectorStart.z) * t))
238 | }
239 |
240 | /**
241 | * Project the vector, vectorToProject, onto the vector, projectionVector.
242 | */
243 | func SCNVector3Project(vectorToProject: SCNVector3, projectionVector: SCNVector3) -> SCNVector3 {
244 | let scale: Float = SCNVector3DotProduct(left: projectionVector, right: vectorToProject) / SCNVector3DotProduct(left: projectionVector, right: projectionVector)
245 | let v: SCNVector3 = projectionVector * scale
246 | return v
247 | }
248 |
--------------------------------------------------------------------------------
/PedestrianARNavigation/PedestrianARNavigation/Utils/Utilities/AutoLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AutoLayout.swift
3 | // YandexTransport
4 | //
5 | // Created by Aleksey Fedotov on 01.04.16.
6 | // Copyright © 2016 Yandex LLC. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 |
13 | #if os(iOS)
14 | public func attributeAxis(_ attr: NSLayoutAttribute) -> UILayoutConstraintAxis {
15 | var ret: UILayoutConstraintAxis? = nil
16 | switch attr {
17 | case .left, .right, .width, .centerX, .leftMargin, .rightMargin, .centerXWithinMargins:
18 | ret = .horizontal
19 |
20 | case .top, .bottom, .height, .centerY, .lastBaseline, .firstBaseline, .topMargin, .bottomMargin, .centerYWithinMargins:
21 | ret = .vertical;
22 |
23 | default:
24 | assert(false, "Axis can not be determined for attribute: '\(attr)'")
25 | }
26 | return ret!
27 | }
28 |
29 |
30 | public func + (priority: UILayoutPriority, value: Float) -> UILayoutPriority {
31 | return UILayoutPriority(priority.rawValue + value)
32 | }
33 |
34 | public func - (priority: UILayoutPriority, value: Float) -> UILayoutPriority {
35 | return UILayoutPriority(priority.rawValue - value)
36 | }
37 |
38 | public extension NSLayoutConstraint {
39 |
40 | @discardableResult
41 | public class func create(
42 | item view1: AnyObject,
43 | attribute attr1: NSLayoutAttribute,
44 | relatedBy relation: NSLayoutRelation = NSLayoutRelation.equal,
45 | toItem view2: AnyObject? = nil,
46 | attribute attr2: NSLayoutAttribute = NSLayoutAttribute.notAnAttribute,
47 | multiplier: CGFloat = 1.0,
48 | constant c: CGFloat = 0) -> NSLayoutConstraint {
49 |
50 | return NSLayoutConstraint(
51 | item: view1,
52 | attribute: attr1,
53 | relatedBy: relation,
54 | toItem: view2,
55 | attribute: attr2,
56 | multiplier: multiplier,
57 | constant: c
58 | )
59 | }
60 |
61 | }
62 |
63 | public extension UIView {
64 |
65 | @discardableResult
66 | public func addMargin(
67 | _ value: CGFloat, from: NSLayoutAttribute, to: NSLayoutAttribute, items: [UIView]) -> [NSLayoutConstraint] {
68 | var ret = [NSLayoutConstraint]()
69 | for v in items {
70 | let constraint = NSLayoutConstraint(
71 | item: v, attribute: to, relatedBy: .equal,
72 | toItem: self, attribute: from, multiplier: 1.0,
73 | constant: value
74 | )
75 | ret.append(constraint)
76 | addConstraint(constraint)
77 | }
78 | return ret
79 | }
80 |
81 | @discardableResult
82 | public func addVerticalSpacing(_ value: CGFloat, items: [UIView]) -> [NSLayoutConstraint] {
83 | assert(items.count > 1)
84 | var ret = [NSLayoutConstraint]()
85 | for i in 1.. [NSLayoutConstraint] {
98 | assert(items.count > 1)
99 | var ret = [NSLayoutConstraint]()
100 | for i in 1.. [NSLayoutConstraint] {
113 | assert(items.count > 1)
114 | var ret = [NSLayoutConstraint]()
115 | for i in 1.. [NSLayoutConstraint] {
128 | return addMargin(value, from: from, to: from, items: items);
129 | }
130 |
131 | @discardableResult
132 | public func addCenterMargin(_ value: CGFloat, from: NSLayoutAttribute, items: [UIView]) -> [NSLayoutConstraint] {
133 | switch attributeAxis(from) {
134 | case .horizontal:
135 | return addMargin(value, from: from, to: .centerX, items: items)
136 |
137 | case .vertical:
138 | return addMargin(value, from: from, to: .centerY, items: items)
139 | }
140 | }
141 |
142 | @discardableResult
143 | public func addEquality(of attr: NSLayoutAttribute, items: [UIView]) -> [NSLayoutConstraint] {
144 | let first = items.first!
145 | var ret = [NSLayoutConstraint]()
146 |
147 | for i in 1.. [NSLayoutConstraint] {
161 | var ret = [NSLayoutConstraint]()
162 | ret.append(contentsOf: addEquality(of: .left, items: items))
163 | ret.append(contentsOf: addEquality(of: .right, items: items))
164 | ret.append(contentsOf: addEquality(of: .top, items: items))
165 | ret.append(contentsOf: addEquality(of: .bottom, items: items))
166 | return ret
167 | }
168 |
169 | @discardableResult
170 | public func addDimension(_ value: CGFloat, attr: NSLayoutAttribute, items: [UIView]) -> [NSLayoutConstraint] {
171 | var ret = [NSLayoutConstraint]()
172 |
173 | for v in items {
174 | let constraint = NSLayoutConstraint(
175 | item: v, attribute: attr, relatedBy: .equal, toItem: nil,
176 | attribute: .notAnAttribute, multiplier: 1.0,
177 | constant: value
178 | )
179 | addConstraint(constraint)
180 | ret.append(constraint)
181 | }
182 | return ret
183 | }
184 |
185 | @discardableResult
186 | public func addWidth(_ value: CGFloat) -> NSLayoutConstraint {
187 | return addDimension(value, attr: .width, items: [self]).first!
188 | }
189 |
190 | @discardableResult
191 | public func addHeight(_ value: CGFloat) -> NSLayoutConstraint {
192 | return addDimension(value, attr: .height, items: [self]).first!
193 | }
194 |
195 | @discardableResult
196 | public func addSize(width: CGFloat, height: CGFloat) -> [NSLayoutConstraint] {
197 | var ret = [NSLayoutConstraint]()
198 | ret.append(addWidth(width))
199 | ret.append(addHeight(height))
200 | return ret
201 | }
202 |
203 | @discardableResult
204 | public func addSize(_ size: CGSize) -> [NSLayoutConstraint] {
205 | return addSize(width: size.width, height: size.height)
206 | }
207 |
208 | @discardableResult
209 | public func addConstraints( _ constraintsFormat: String,
210 | options: NSLayoutFormatOptions = NSLayoutFormatOptions(rawValue: 0),
211 | metrics:[String: CGFloat]? = nil,
212 | views: [String:UIView]) -> [NSLayoutConstraint]
213 | {
214 |
215 | var constraints: [NSLayoutConstraint] = []
216 |
217 | constraints = NSLayoutConstraint.constraints( withVisualFormat: constraintsFormat,
218 | options: options,
219 | metrics: metrics,
220 | views: views
221 | )
222 |
223 | self.addConstraints(constraints)
224 |
225 | return constraints
226 | }
227 |
228 | @discardableResult
229 | public func addConstraint(
230 | item: UIView,
231 | attribute: NSLayoutAttribute,
232 | relatedBy: NSLayoutRelation = NSLayoutRelation.equal,
233 | toItem: UIView? = nil,
234 | toAttribute: NSLayoutAttribute = NSLayoutAttribute.notAnAttribute,
235 | multiplier: CGFloat = 1.0,
236 | constant: CGFloat = 0.0,
237 | priority: UILayoutPriority = .required) -> NSLayoutConstraint
238 | {
239 | let ret = NSLayoutConstraint(
240 | item: item,
241 | attribute: attribute,
242 | relatedBy: relatedBy,
243 | toItem: toItem,
244 | attribute: toAttribute,
245 | multiplier: multiplier,
246 | constant: constant
247 | )
248 | ret.priority = priority
249 | addConstraint(ret)
250 | return ret
251 | }
252 |
253 | // MARK: layout in container
254 |
255 | @discardableResult
256 | public func fillContainerVertically() -> [NSLayoutConstraint] {
257 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
258 | return self.superview!.addConstraints("V:|[self]|", views: ["self": self])
259 | }
260 |
261 | @discardableResult
262 | public func fillContainerHorizontally() -> [NSLayoutConstraint] {
263 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
264 | return self.superview!.addConstraints("H:|[self]|", views: ["self": self])
265 | }
266 |
267 | @discardableResult
268 | public func fillContainer() -> [NSLayoutConstraint] {
269 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
270 | var constraints = [NSLayoutConstraint]()
271 | constraints = constraints + self.fillContainerVertically()
272 | constraints = constraints + self.fillContainerHorizontally()
273 | return constraints
274 | }
275 |
276 | @discardableResult
277 | public func centerHorizontallyInContainer() -> [NSLayoutConstraint] {
278 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
279 | return self.superview!.addEquality(of: NSLayoutAttribute.centerX, items: [self, self.superview!])
280 | }
281 |
282 | @discardableResult
283 | public func centerVerticallyInContainer() -> [NSLayoutConstraint] {
284 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
285 | return self.superview!.addEquality(of: NSLayoutAttribute.centerY, items: [self, self.superview!])
286 | }
287 |
288 | @discardableResult
289 | public func centerInContainer() -> [NSLayoutConstraint] {
290 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
291 | var constraints = [NSLayoutConstraint]()
292 | constraints = constraints + self.centerHorizontallyInContainer()
293 | constraints = constraints + self.centerVerticallyInContainer()
294 | return constraints
295 | }
296 |
297 | @discardableResult
298 | public func attachLeftInContainer(margin: CGFloat = 0) -> [NSLayoutConstraint] {
299 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
300 | return self.superview!.addMargin(margin, from: NSLayoutAttribute.left, items: [self])
301 | }
302 |
303 | @discardableResult
304 | public func attachRightInContainer(margin: CGFloat = 0) -> [NSLayoutConstraint] {
305 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
306 | return self.superview!.addMargin(-margin, from: NSLayoutAttribute.right, items: [self])
307 | }
308 |
309 | @discardableResult
310 | public func attachTopInContainer(margin: CGFloat = 0) -> [NSLayoutConstraint] {
311 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
312 | return self.superview!.addMargin(margin, from: NSLayoutAttribute.top, items: [self])
313 | }
314 |
315 | @discardableResult
316 | public func attachBottomInContainer(margin: CGFloat = 0) -> [NSLayoutConstraint] {
317 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
318 | return self.superview!.addMargin(-margin, from: NSLayoutAttribute.bottom, items: [self])
319 | }
320 |
321 | @discardableResult
322 | public func fillContainer(withInsets insets: UIEdgeInsets = UIEdgeInsets.zero) -> [NSLayoutConstraint] {
323 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
324 | var constraints: [NSLayoutConstraint] = []
325 | constraints.append(contentsOf: self.attachTopInContainer(margin: insets.top))
326 | constraints.append(contentsOf: self.attachBottomInContainer(margin: insets.bottom))
327 | constraints.append(contentsOf: self.attachLeftInContainer(margin: insets.left))
328 | constraints.append(contentsOf: self.attachRightInContainer(margin: insets.right))
329 | return constraints
330 | }
331 |
332 | @discardableResult
333 | public func fillContainer(withEdges edge: UIRectEdge) -> [NSLayoutConstraint] {
334 | assert(self.superview != nil && self.translatesAutoresizingMaskIntoConstraints == false)
335 | var constraints: [NSLayoutConstraint] = []
336 | if edge.contains(.top) {
337 | constraints.append(contentsOf: self.attachTopInContainer())
338 | }
339 | if edge.contains(.bottom) {
340 | constraints.append(contentsOf: self.attachBottomInContainer())
341 | }
342 | if edge.contains(.left) {
343 | constraints.append(contentsOf: self.attachLeftInContainer())
344 | }
345 | if edge.contains(.right) {
346 | constraints.append(contentsOf: self.attachRightInContainer())
347 | }
348 | return constraints
349 | }
350 |
351 |
352 | }
353 | #endif
354 |
--------------------------------------------------------------------------------
/FinishPlacemarkHint/FinishPlacemarkHelper.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8735E0EA2084D20A008BA9F4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E0E92084D20A008BA9F4 /* AppDelegate.swift */; };
11 | 8735E0EC2084D20A008BA9F4 /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 8735E0EB2084D20A008BA9F4 /* art.scnassets */; };
12 | 8735E0EE2084D20A008BA9F4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E0ED2084D20A008BA9F4 /* ViewController.swift */; };
13 | 8735E0F12084D20A008BA9F4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8735E0EF2084D20A008BA9F4 /* Main.storyboard */; };
14 | 8735E0F32084D20A008BA9F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8735E0F22084D20A008BA9F4 /* Assets.xcassets */; };
15 | 8735E0F62084D20A008BA9F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8735E0F42084D20A008BA9F4 /* LaunchScreen.storyboard */; };
16 | 8735E0FF2084D274008BA9F4 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E0FE2084D274008BA9F4 /* Utils.swift */; };
17 | 8735E1042084D3E2008BA9F4 /* VectorMath+QuartzCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1012084D3E2008BA9F4 /* VectorMath+QuartzCore.swift */; };
18 | 8735E1052084D3E2008BA9F4 /* VectorMath+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1022084D3E2008BA9F4 /* VectorMath+SceneKit.swift */; };
19 | 8735E1062084D3E2008BA9F4 /* VectorMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1032084D3E2008BA9F4 /* VectorMath.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 8735E0E62084D20A008BA9F4 /* FinishPlacemarkHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FinishPlacemarkHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
24 | 8735E0E92084D20A008BA9F4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
25 | 8735E0EB2084D20A008BA9F4 /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = ""; };
26 | 8735E0ED2084D20A008BA9F4 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
27 | 8735E0F02084D20A008BA9F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
28 | 8735E0F22084D20A008BA9F4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
29 | 8735E0F52084D20A008BA9F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
30 | 8735E0F72084D20A008BA9F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | 8735E0FE2084D274008BA9F4 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
32 | 8735E1012084D3E2008BA9F4 /* VectorMath+QuartzCore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VectorMath+QuartzCore.swift"; sourceTree = ""; };
33 | 8735E1022084D3E2008BA9F4 /* VectorMath+SceneKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VectorMath+SceneKit.swift"; sourceTree = ""; };
34 | 8735E1032084D3E2008BA9F4 /* VectorMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VectorMath.swift; sourceTree = ""; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | 8735E0E32084D20A008BA9F4 /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | 8735E0DD2084D20A008BA9F4 = {
49 | isa = PBXGroup;
50 | children = (
51 | 8735E0E82084D20A008BA9F4 /* FinishPlacemarkHelper */,
52 | 8735E0E72084D20A008BA9F4 /* Products */,
53 | );
54 | sourceTree = "";
55 | };
56 | 8735E0E72084D20A008BA9F4 /* Products */ = {
57 | isa = PBXGroup;
58 | children = (
59 | 8735E0E62084D20A008BA9F4 /* FinishPlacemarkHelper.app */,
60 | );
61 | name = Products;
62 | sourceTree = "";
63 | };
64 | 8735E0E82084D20A008BA9F4 /* FinishPlacemarkHelper */ = {
65 | isa = PBXGroup;
66 | children = (
67 | 8735E1002084D3E2008BA9F4 /* VectorMath */,
68 | 8735E0FD2084D25C008BA9F4 /* Utils */,
69 | 8735E0E92084D20A008BA9F4 /* AppDelegate.swift */,
70 | 8735E0EB2084D20A008BA9F4 /* art.scnassets */,
71 | 8735E0ED2084D20A008BA9F4 /* ViewController.swift */,
72 | 8735E0EF2084D20A008BA9F4 /* Main.storyboard */,
73 | 8735E0F22084D20A008BA9F4 /* Assets.xcassets */,
74 | 8735E0F42084D20A008BA9F4 /* LaunchScreen.storyboard */,
75 | 8735E0F72084D20A008BA9F4 /* Info.plist */,
76 | );
77 | path = FinishPlacemarkHelper;
78 | sourceTree = "";
79 | };
80 | 8735E0FD2084D25C008BA9F4 /* Utils */ = {
81 | isa = PBXGroup;
82 | children = (
83 | 8735E0FE2084D274008BA9F4 /* Utils.swift */,
84 | );
85 | path = Utils;
86 | sourceTree = "";
87 | };
88 | 8735E1002084D3E2008BA9F4 /* VectorMath */ = {
89 | isa = PBXGroup;
90 | children = (
91 | 8735E1012084D3E2008BA9F4 /* VectorMath+QuartzCore.swift */,
92 | 8735E1022084D3E2008BA9F4 /* VectorMath+SceneKit.swift */,
93 | 8735E1032084D3E2008BA9F4 /* VectorMath.swift */,
94 | );
95 | path = VectorMath;
96 | sourceTree = "";
97 | };
98 | /* End PBXGroup section */
99 |
100 | /* Begin PBXNativeTarget section */
101 | 8735E0E52084D20A008BA9F4 /* FinishPlacemarkHelper */ = {
102 | isa = PBXNativeTarget;
103 | buildConfigurationList = 8735E0FA2084D20A008BA9F4 /* Build configuration list for PBXNativeTarget "FinishPlacemarkHelper" */;
104 | buildPhases = (
105 | 8735E0E22084D20A008BA9F4 /* Sources */,
106 | 8735E0E32084D20A008BA9F4 /* Frameworks */,
107 | 8735E0E42084D20A008BA9F4 /* Resources */,
108 | );
109 | buildRules = (
110 | );
111 | dependencies = (
112 | );
113 | name = FinishPlacemarkHelper;
114 | productName = FinishPlacemarkHelper;
115 | productReference = 8735E0E62084D20A008BA9F4 /* FinishPlacemarkHelper.app */;
116 | productType = "com.apple.product-type.application";
117 | };
118 | /* End PBXNativeTarget section */
119 |
120 | /* Begin PBXProject section */
121 | 8735E0DE2084D20A008BA9F4 /* Project object */ = {
122 | isa = PBXProject;
123 | attributes = {
124 | LastSwiftUpdateCheck = 0920;
125 | LastUpgradeCheck = 0920;
126 | ORGANIZATIONNAME = "Yandex, LLC";
127 | TargetAttributes = {
128 | 8735E0E52084D20A008BA9F4 = {
129 | CreatedOnToolsVersion = 9.2;
130 | ProvisioningStyle = Automatic;
131 | };
132 | };
133 | };
134 | buildConfigurationList = 8735E0E12084D20A008BA9F4 /* Build configuration list for PBXProject "FinishPlacemarkHelper" */;
135 | compatibilityVersion = "Xcode 8.0";
136 | developmentRegion = en;
137 | hasScannedForEncodings = 0;
138 | knownRegions = (
139 | en,
140 | Base,
141 | );
142 | mainGroup = 8735E0DD2084D20A008BA9F4;
143 | productRefGroup = 8735E0E72084D20A008BA9F4 /* Products */;
144 | projectDirPath = "";
145 | projectRoot = "";
146 | targets = (
147 | 8735E0E52084D20A008BA9F4 /* FinishPlacemarkHelper */,
148 | );
149 | };
150 | /* End PBXProject section */
151 |
152 | /* Begin PBXResourcesBuildPhase section */
153 | 8735E0E42084D20A008BA9F4 /* Resources */ = {
154 | isa = PBXResourcesBuildPhase;
155 | buildActionMask = 2147483647;
156 | files = (
157 | 8735E0EC2084D20A008BA9F4 /* art.scnassets in Resources */,
158 | 8735E0F62084D20A008BA9F4 /* LaunchScreen.storyboard in Resources */,
159 | 8735E0F32084D20A008BA9F4 /* Assets.xcassets in Resources */,
160 | 8735E0F12084D20A008BA9F4 /* Main.storyboard in Resources */,
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | };
164 | /* End PBXResourcesBuildPhase section */
165 |
166 | /* Begin PBXSourcesBuildPhase section */
167 | 8735E0E22084D20A008BA9F4 /* Sources */ = {
168 | isa = PBXSourcesBuildPhase;
169 | buildActionMask = 2147483647;
170 | files = (
171 | 8735E1052084D3E2008BA9F4 /* VectorMath+SceneKit.swift in Sources */,
172 | 8735E0EE2084D20A008BA9F4 /* ViewController.swift in Sources */,
173 | 8735E0EA2084D20A008BA9F4 /* AppDelegate.swift in Sources */,
174 | 8735E1042084D3E2008BA9F4 /* VectorMath+QuartzCore.swift in Sources */,
175 | 8735E1062084D3E2008BA9F4 /* VectorMath.swift in Sources */,
176 | 8735E0FF2084D274008BA9F4 /* Utils.swift in Sources */,
177 | );
178 | runOnlyForDeploymentPostprocessing = 0;
179 | };
180 | /* End PBXSourcesBuildPhase section */
181 |
182 | /* Begin PBXVariantGroup section */
183 | 8735E0EF2084D20A008BA9F4 /* Main.storyboard */ = {
184 | isa = PBXVariantGroup;
185 | children = (
186 | 8735E0F02084D20A008BA9F4 /* Base */,
187 | );
188 | name = Main.storyboard;
189 | sourceTree = "";
190 | };
191 | 8735E0F42084D20A008BA9F4 /* LaunchScreen.storyboard */ = {
192 | isa = PBXVariantGroup;
193 | children = (
194 | 8735E0F52084D20A008BA9F4 /* Base */,
195 | );
196 | name = LaunchScreen.storyboard;
197 | sourceTree = "";
198 | };
199 | /* End PBXVariantGroup section */
200 |
201 | /* Begin XCBuildConfiguration section */
202 | 8735E0F82084D20A008BA9F4 /* Debug */ = {
203 | isa = XCBuildConfiguration;
204 | buildSettings = {
205 | ALWAYS_SEARCH_USER_PATHS = NO;
206 | CLANG_ANALYZER_NONNULL = YES;
207 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
208 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
209 | CLANG_CXX_LIBRARY = "libc++";
210 | CLANG_ENABLE_MODULES = YES;
211 | CLANG_ENABLE_OBJC_ARC = YES;
212 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
213 | CLANG_WARN_BOOL_CONVERSION = YES;
214 | CLANG_WARN_COMMA = YES;
215 | CLANG_WARN_CONSTANT_CONVERSION = YES;
216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
217 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
218 | CLANG_WARN_EMPTY_BODY = YES;
219 | CLANG_WARN_ENUM_CONVERSION = YES;
220 | CLANG_WARN_INFINITE_RECURSION = YES;
221 | CLANG_WARN_INT_CONVERSION = YES;
222 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
223 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
224 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
225 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
226 | CLANG_WARN_STRICT_PROTOTYPES = YES;
227 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
228 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
229 | CLANG_WARN_UNREACHABLE_CODE = YES;
230 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
231 | CODE_SIGN_IDENTITY = "iPhone Developer";
232 | COPY_PHASE_STRIP = NO;
233 | DEBUG_INFORMATION_FORMAT = dwarf;
234 | ENABLE_STRICT_OBJC_MSGSEND = YES;
235 | ENABLE_TESTABILITY = YES;
236 | GCC_C_LANGUAGE_STANDARD = gnu11;
237 | GCC_DYNAMIC_NO_PIC = NO;
238 | GCC_NO_COMMON_BLOCKS = YES;
239 | GCC_OPTIMIZATION_LEVEL = 0;
240 | GCC_PREPROCESSOR_DEFINITIONS = (
241 | "DEBUG=1",
242 | "$(inherited)",
243 | );
244 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
245 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
246 | GCC_WARN_UNDECLARED_SELECTOR = YES;
247 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
248 | GCC_WARN_UNUSED_FUNCTION = YES;
249 | GCC_WARN_UNUSED_VARIABLE = YES;
250 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
251 | MTL_ENABLE_DEBUG_INFO = YES;
252 | ONLY_ACTIVE_ARCH = YES;
253 | SDKROOT = iphoneos;
254 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
255 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
256 | };
257 | name = Debug;
258 | };
259 | 8735E0F92084D20A008BA9F4 /* Release */ = {
260 | isa = XCBuildConfiguration;
261 | buildSettings = {
262 | ALWAYS_SEARCH_USER_PATHS = NO;
263 | CLANG_ANALYZER_NONNULL = YES;
264 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
266 | CLANG_CXX_LIBRARY = "libc++";
267 | CLANG_ENABLE_MODULES = YES;
268 | CLANG_ENABLE_OBJC_ARC = YES;
269 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
270 | CLANG_WARN_BOOL_CONVERSION = YES;
271 | CLANG_WARN_COMMA = YES;
272 | CLANG_WARN_CONSTANT_CONVERSION = YES;
273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
274 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
275 | CLANG_WARN_EMPTY_BODY = YES;
276 | CLANG_WARN_ENUM_CONVERSION = YES;
277 | CLANG_WARN_INFINITE_RECURSION = YES;
278 | CLANG_WARN_INT_CONVERSION = YES;
279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
280 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
282 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
283 | CLANG_WARN_STRICT_PROTOTYPES = YES;
284 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
285 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
286 | CLANG_WARN_UNREACHABLE_CODE = YES;
287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
288 | CODE_SIGN_IDENTITY = "iPhone Developer";
289 | COPY_PHASE_STRIP = NO;
290 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
291 | ENABLE_NS_ASSERTIONS = NO;
292 | ENABLE_STRICT_OBJC_MSGSEND = YES;
293 | GCC_C_LANGUAGE_STANDARD = gnu11;
294 | GCC_NO_COMMON_BLOCKS = YES;
295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
296 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
297 | GCC_WARN_UNDECLARED_SELECTOR = YES;
298 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
299 | GCC_WARN_UNUSED_FUNCTION = YES;
300 | GCC_WARN_UNUSED_VARIABLE = YES;
301 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
302 | MTL_ENABLE_DEBUG_INFO = NO;
303 | SDKROOT = iphoneos;
304 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
305 | VALIDATE_PRODUCT = YES;
306 | };
307 | name = Release;
308 | };
309 | 8735E0FB2084D20A008BA9F4 /* Debug */ = {
310 | isa = XCBuildConfiguration;
311 | buildSettings = {
312 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
313 | CODE_SIGN_STYLE = Automatic;
314 | DEVELOPMENT_TEAM = ZT4G28N837;
315 | INFOPLIST_FILE = FinishPlacemarkHelper/Info.plist;
316 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
317 | PRODUCT_BUNDLE_IDENTIFIER = "Yandex--LLC.FinishPlacemarkHelper";
318 | PRODUCT_NAME = "$(TARGET_NAME)";
319 | SWIFT_VERSION = 4.0;
320 | TARGETED_DEVICE_FAMILY = "1,2";
321 | };
322 | name = Debug;
323 | };
324 | 8735E0FC2084D20A008BA9F4 /* Release */ = {
325 | isa = XCBuildConfiguration;
326 | buildSettings = {
327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
328 | CODE_SIGN_STYLE = Automatic;
329 | DEVELOPMENT_TEAM = ZT4G28N837;
330 | INFOPLIST_FILE = FinishPlacemarkHelper/Info.plist;
331 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
332 | PRODUCT_BUNDLE_IDENTIFIER = "Yandex--LLC.FinishPlacemarkHelper";
333 | PRODUCT_NAME = "$(TARGET_NAME)";
334 | SWIFT_VERSION = 4.0;
335 | TARGETED_DEVICE_FAMILY = "1,2";
336 | };
337 | name = Release;
338 | };
339 | /* End XCBuildConfiguration section */
340 |
341 | /* Begin XCConfigurationList section */
342 | 8735E0E12084D20A008BA9F4 /* Build configuration list for PBXProject "FinishPlacemarkHelper" */ = {
343 | isa = XCConfigurationList;
344 | buildConfigurations = (
345 | 8735E0F82084D20A008BA9F4 /* Debug */,
346 | 8735E0F92084D20A008BA9F4 /* Release */,
347 | );
348 | defaultConfigurationIsVisible = 0;
349 | defaultConfigurationName = Release;
350 | };
351 | 8735E0FA2084D20A008BA9F4 /* Build configuration list for PBXNativeTarget "FinishPlacemarkHelper" */ = {
352 | isa = XCConfigurationList;
353 | buildConfigurations = (
354 | 8735E0FB2084D20A008BA9F4 /* Debug */,
355 | 8735E0FC2084D20A008BA9F4 /* Release */,
356 | );
357 | defaultConfigurationIsVisible = 0;
358 | defaultConfigurationName = Release;
359 | };
360 | /* End XCConfigurationList section */
361 | };
362 | rootObject = 8735E0DE2084D20A008BA9F4 /* Project object */;
363 | }
364 |
--------------------------------------------------------------------------------
/RoutePolyline/RoutePolyline.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8735E1482084F721008BA9F4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1472084F721008BA9F4 /* AppDelegate.swift */; };
11 | 8735E14A2084F721008BA9F4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1492084F721008BA9F4 /* ViewController.swift */; };
12 | 8735E14D2084F721008BA9F4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8735E14B2084F721008BA9F4 /* Main.storyboard */; };
13 | 8735E14F2084F721008BA9F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8735E14E2084F721008BA9F4 /* Assets.xcassets */; };
14 | 8735E1522084F721008BA9F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8735E1502084F721008BA9F4 /* LaunchScreen.storyboard */; };
15 | 8735E15F2084F75B008BA9F4 /* VectorMath+QuartzCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E15A2084F75B008BA9F4 /* VectorMath+QuartzCore.swift */; };
16 | 8735E1602084F75B008BA9F4 /* VectorMath+SceneKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E15B2084F75B008BA9F4 /* VectorMath+SceneKit.swift */; };
17 | 8735E1612084F75B008BA9F4 /* VectorMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E15C2084F75B008BA9F4 /* VectorMath.swift */; };
18 | 8735E1622084F75B008BA9F4 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E15E2084F75B008BA9F4 /* Utils.swift */; };
19 | 8735E1642084F770008BA9F4 /* RouteArrowAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1632084F770008BA9F4 /* RouteArrowAnimation.swift */; };
20 | 8735E1662084F7CF008BA9F4 /* RouteAnimationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1652084F7CF008BA9F4 /* RouteAnimationUtils.swift */; };
21 | 8735E1682084F8E9008BA9F4 /* RouteNodes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8735E1672084F8E9008BA9F4 /* RouteNodes.swift */; };
22 | /* End PBXBuildFile section */
23 |
24 | /* Begin PBXFileReference section */
25 | 8735E1442084F721008BA9F4 /* RoutePolyline.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RoutePolyline.app; sourceTree = BUILT_PRODUCTS_DIR; };
26 | 8735E1472084F721008BA9F4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
27 | 8735E1492084F721008BA9F4 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
28 | 8735E14C2084F721008BA9F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
29 | 8735E14E2084F721008BA9F4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
30 | 8735E1512084F721008BA9F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
31 | 8735E1532084F721008BA9F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 8735E15A2084F75B008BA9F4 /* VectorMath+QuartzCore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VectorMath+QuartzCore.swift"; sourceTree = ""; };
33 | 8735E15B2084F75B008BA9F4 /* VectorMath+SceneKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VectorMath+SceneKit.swift"; sourceTree = ""; };
34 | 8735E15C2084F75B008BA9F4 /* VectorMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VectorMath.swift; sourceTree = ""; };
35 | 8735E15E2084F75B008BA9F4 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
36 | 8735E1632084F770008BA9F4 /* RouteArrowAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteArrowAnimation.swift; sourceTree = ""; };
37 | 8735E1652084F7CF008BA9F4 /* RouteAnimationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteAnimationUtils.swift; sourceTree = ""; };
38 | 8735E1672084F8E9008BA9F4 /* RouteNodes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteNodes.swift; sourceTree = ""; };
39 | /* End PBXFileReference section */
40 |
41 | /* Begin PBXFrameworksBuildPhase section */
42 | 8735E1412084F721008BA9F4 /* Frameworks */ = {
43 | isa = PBXFrameworksBuildPhase;
44 | buildActionMask = 2147483647;
45 | files = (
46 | );
47 | runOnlyForDeploymentPostprocessing = 0;
48 | };
49 | /* End PBXFrameworksBuildPhase section */
50 |
51 | /* Begin PBXGroup section */
52 | 8735E13B2084F721008BA9F4 = {
53 | isa = PBXGroup;
54 | children = (
55 | 8735E1462084F721008BA9F4 /* RoutePolyline */,
56 | 8735E1452084F721008BA9F4 /* Products */,
57 | );
58 | sourceTree = "";
59 | };
60 | 8735E1452084F721008BA9F4 /* Products */ = {
61 | isa = PBXGroup;
62 | children = (
63 | 8735E1442084F721008BA9F4 /* RoutePolyline.app */,
64 | );
65 | name = Products;
66 | sourceTree = "";
67 | };
68 | 8735E1462084F721008BA9F4 /* RoutePolyline */ = {
69 | isa = PBXGroup;
70 | children = (
71 | 8735E15D2084F75B008BA9F4 /* Utils */,
72 | 8735E1592084F75B008BA9F4 /* VectorMath */,
73 | 8735E1472084F721008BA9F4 /* AppDelegate.swift */,
74 | 8735E1492084F721008BA9F4 /* ViewController.swift */,
75 | 8735E14B2084F721008BA9F4 /* Main.storyboard */,
76 | 8735E14E2084F721008BA9F4 /* Assets.xcassets */,
77 | 8735E1502084F721008BA9F4 /* LaunchScreen.storyboard */,
78 | 8735E1532084F721008BA9F4 /* Info.plist */,
79 | 8735E1632084F770008BA9F4 /* RouteArrowAnimation.swift */,
80 | 8735E1652084F7CF008BA9F4 /* RouteAnimationUtils.swift */,
81 | 8735E1672084F8E9008BA9F4 /* RouteNodes.swift */,
82 | );
83 | path = RoutePolyline;
84 | sourceTree = "";
85 | };
86 | 8735E1592084F75B008BA9F4 /* VectorMath */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 8735E15A2084F75B008BA9F4 /* VectorMath+QuartzCore.swift */,
90 | 8735E15B2084F75B008BA9F4 /* VectorMath+SceneKit.swift */,
91 | 8735E15C2084F75B008BA9F4 /* VectorMath.swift */,
92 | );
93 | path = VectorMath;
94 | sourceTree = "";
95 | };
96 | 8735E15D2084F75B008BA9F4 /* Utils */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 8735E15E2084F75B008BA9F4 /* Utils.swift */,
100 | );
101 | path = Utils;
102 | sourceTree = "";
103 | };
104 | /* End PBXGroup section */
105 |
106 | /* Begin PBXNativeTarget section */
107 | 8735E1432084F721008BA9F4 /* RoutePolyline */ = {
108 | isa = PBXNativeTarget;
109 | buildConfigurationList = 8735E1562084F721008BA9F4 /* Build configuration list for PBXNativeTarget "RoutePolyline" */;
110 | buildPhases = (
111 | 8735E1402084F721008BA9F4 /* Sources */,
112 | 8735E1412084F721008BA9F4 /* Frameworks */,
113 | 8735E1422084F721008BA9F4 /* Resources */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = RoutePolyline;
120 | productName = RoutePolyline;
121 | productReference = 8735E1442084F721008BA9F4 /* RoutePolyline.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 8735E13C2084F721008BA9F4 /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastSwiftUpdateCheck = 0920;
131 | LastUpgradeCheck = 0920;
132 | ORGANIZATIONNAME = "Yandex, LLC";
133 | TargetAttributes = {
134 | 8735E1432084F721008BA9F4 = {
135 | CreatedOnToolsVersion = 9.2;
136 | ProvisioningStyle = Automatic;
137 | };
138 | };
139 | };
140 | buildConfigurationList = 8735E13F2084F721008BA9F4 /* Build configuration list for PBXProject "RoutePolyline" */;
141 | compatibilityVersion = "Xcode 8.0";
142 | developmentRegion = en;
143 | hasScannedForEncodings = 0;
144 | knownRegions = (
145 | en,
146 | Base,
147 | );
148 | mainGroup = 8735E13B2084F721008BA9F4;
149 | productRefGroup = 8735E1452084F721008BA9F4 /* Products */;
150 | projectDirPath = "";
151 | projectRoot = "";
152 | targets = (
153 | 8735E1432084F721008BA9F4 /* RoutePolyline */,
154 | );
155 | };
156 | /* End PBXProject section */
157 |
158 | /* Begin PBXResourcesBuildPhase section */
159 | 8735E1422084F721008BA9F4 /* Resources */ = {
160 | isa = PBXResourcesBuildPhase;
161 | buildActionMask = 2147483647;
162 | files = (
163 | 8735E1522084F721008BA9F4 /* LaunchScreen.storyboard in Resources */,
164 | 8735E14F2084F721008BA9F4 /* Assets.xcassets in Resources */,
165 | 8735E14D2084F721008BA9F4 /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXSourcesBuildPhase section */
172 | 8735E1402084F721008BA9F4 /* Sources */ = {
173 | isa = PBXSourcesBuildPhase;
174 | buildActionMask = 2147483647;
175 | files = (
176 | 8735E1642084F770008BA9F4 /* RouteArrowAnimation.swift in Sources */,
177 | 8735E1682084F8E9008BA9F4 /* RouteNodes.swift in Sources */,
178 | 8735E15F2084F75B008BA9F4 /* VectorMath+QuartzCore.swift in Sources */,
179 | 8735E14A2084F721008BA9F4 /* ViewController.swift in Sources */,
180 | 8735E1602084F75B008BA9F4 /* VectorMath+SceneKit.swift in Sources */,
181 | 8735E1612084F75B008BA9F4 /* VectorMath.swift in Sources */,
182 | 8735E1482084F721008BA9F4 /* AppDelegate.swift in Sources */,
183 | 8735E1662084F7CF008BA9F4 /* RouteAnimationUtils.swift in Sources */,
184 | 8735E1622084F75B008BA9F4 /* Utils.swift in Sources */,
185 | );
186 | runOnlyForDeploymentPostprocessing = 0;
187 | };
188 | /* End PBXSourcesBuildPhase section */
189 |
190 | /* Begin PBXVariantGroup section */
191 | 8735E14B2084F721008BA9F4 /* Main.storyboard */ = {
192 | isa = PBXVariantGroup;
193 | children = (
194 | 8735E14C2084F721008BA9F4 /* Base */,
195 | );
196 | name = Main.storyboard;
197 | sourceTree = "";
198 | };
199 | 8735E1502084F721008BA9F4 /* LaunchScreen.storyboard */ = {
200 | isa = PBXVariantGroup;
201 | children = (
202 | 8735E1512084F721008BA9F4 /* Base */,
203 | );
204 | name = LaunchScreen.storyboard;
205 | sourceTree = "";
206 | };
207 | /* End PBXVariantGroup section */
208 |
209 | /* Begin XCBuildConfiguration section */
210 | 8735E1542084F721008BA9F4 /* Debug */ = {
211 | isa = XCBuildConfiguration;
212 | buildSettings = {
213 | ALWAYS_SEARCH_USER_PATHS = NO;
214 | CLANG_ANALYZER_NONNULL = YES;
215 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
216 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
217 | CLANG_CXX_LIBRARY = "libc++";
218 | CLANG_ENABLE_MODULES = YES;
219 | CLANG_ENABLE_OBJC_ARC = YES;
220 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
221 | CLANG_WARN_BOOL_CONVERSION = YES;
222 | CLANG_WARN_COMMA = YES;
223 | CLANG_WARN_CONSTANT_CONVERSION = YES;
224 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
225 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
226 | CLANG_WARN_EMPTY_BODY = YES;
227 | CLANG_WARN_ENUM_CONVERSION = YES;
228 | CLANG_WARN_INFINITE_RECURSION = YES;
229 | CLANG_WARN_INT_CONVERSION = YES;
230 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
231 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
233 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
234 | CLANG_WARN_STRICT_PROTOTYPES = YES;
235 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
236 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
237 | CLANG_WARN_UNREACHABLE_CODE = YES;
238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
239 | CODE_SIGN_IDENTITY = "iPhone Developer";
240 | COPY_PHASE_STRIP = NO;
241 | DEBUG_INFORMATION_FORMAT = dwarf;
242 | ENABLE_STRICT_OBJC_MSGSEND = YES;
243 | ENABLE_TESTABILITY = YES;
244 | GCC_C_LANGUAGE_STANDARD = gnu11;
245 | GCC_DYNAMIC_NO_PIC = NO;
246 | GCC_NO_COMMON_BLOCKS = YES;
247 | GCC_OPTIMIZATION_LEVEL = 0;
248 | GCC_PREPROCESSOR_DEFINITIONS = (
249 | "DEBUG=1",
250 | "$(inherited)",
251 | );
252 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
253 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
254 | GCC_WARN_UNDECLARED_SELECTOR = YES;
255 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
256 | GCC_WARN_UNUSED_FUNCTION = YES;
257 | GCC_WARN_UNUSED_VARIABLE = YES;
258 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
259 | MTL_ENABLE_DEBUG_INFO = YES;
260 | ONLY_ACTIVE_ARCH = YES;
261 | SDKROOT = iphoneos;
262 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
263 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
264 | };
265 | name = Debug;
266 | };
267 | 8735E1552084F721008BA9F4 /* Release */ = {
268 | isa = XCBuildConfiguration;
269 | buildSettings = {
270 | ALWAYS_SEARCH_USER_PATHS = NO;
271 | CLANG_ANALYZER_NONNULL = YES;
272 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
273 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
274 | CLANG_CXX_LIBRARY = "libc++";
275 | CLANG_ENABLE_MODULES = YES;
276 | CLANG_ENABLE_OBJC_ARC = YES;
277 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
278 | CLANG_WARN_BOOL_CONVERSION = YES;
279 | CLANG_WARN_COMMA = YES;
280 | CLANG_WARN_CONSTANT_CONVERSION = YES;
281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
282 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
283 | CLANG_WARN_EMPTY_BODY = YES;
284 | CLANG_WARN_ENUM_CONVERSION = YES;
285 | CLANG_WARN_INFINITE_RECURSION = YES;
286 | CLANG_WARN_INT_CONVERSION = YES;
287 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
288 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
289 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
290 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
291 | CLANG_WARN_STRICT_PROTOTYPES = YES;
292 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
293 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
294 | CLANG_WARN_UNREACHABLE_CODE = YES;
295 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
296 | CODE_SIGN_IDENTITY = "iPhone Developer";
297 | COPY_PHASE_STRIP = NO;
298 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
299 | ENABLE_NS_ASSERTIONS = NO;
300 | ENABLE_STRICT_OBJC_MSGSEND = YES;
301 | GCC_C_LANGUAGE_STANDARD = gnu11;
302 | GCC_NO_COMMON_BLOCKS = YES;
303 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
304 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
305 | GCC_WARN_UNDECLARED_SELECTOR = YES;
306 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
307 | GCC_WARN_UNUSED_FUNCTION = YES;
308 | GCC_WARN_UNUSED_VARIABLE = YES;
309 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
310 | MTL_ENABLE_DEBUG_INFO = NO;
311 | SDKROOT = iphoneos;
312 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
313 | VALIDATE_PRODUCT = YES;
314 | };
315 | name = Release;
316 | };
317 | 8735E1572084F721008BA9F4 /* Debug */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
321 | CODE_SIGN_STYLE = Automatic;
322 | DEVELOPMENT_TEAM = ZT4G28N837;
323 | INFOPLIST_FILE = RoutePolyline/Info.plist;
324 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
325 | PRODUCT_BUNDLE_IDENTIFIER = "Yandex--LLC.RoutePolyline";
326 | PRODUCT_NAME = "$(TARGET_NAME)";
327 | SWIFT_VERSION = 4.0;
328 | TARGETED_DEVICE_FAMILY = "1,2";
329 | };
330 | name = Debug;
331 | };
332 | 8735E1582084F721008BA9F4 /* Release */ = {
333 | isa = XCBuildConfiguration;
334 | buildSettings = {
335 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
336 | CODE_SIGN_STYLE = Automatic;
337 | DEVELOPMENT_TEAM = ZT4G28N837;
338 | INFOPLIST_FILE = RoutePolyline/Info.plist;
339 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
340 | PRODUCT_BUNDLE_IDENTIFIER = "Yandex--LLC.RoutePolyline";
341 | PRODUCT_NAME = "$(TARGET_NAME)";
342 | SWIFT_VERSION = 4.0;
343 | TARGETED_DEVICE_FAMILY = "1,2";
344 | };
345 | name = Release;
346 | };
347 | /* End XCBuildConfiguration section */
348 |
349 | /* Begin XCConfigurationList section */
350 | 8735E13F2084F721008BA9F4 /* Build configuration list for PBXProject "RoutePolyline" */ = {
351 | isa = XCConfigurationList;
352 | buildConfigurations = (
353 | 8735E1542084F721008BA9F4 /* Debug */,
354 | 8735E1552084F721008BA9F4 /* Release */,
355 | );
356 | defaultConfigurationIsVisible = 0;
357 | defaultConfigurationName = Release;
358 | };
359 | 8735E1562084F721008BA9F4 /* Build configuration list for PBXNativeTarget "RoutePolyline" */ = {
360 | isa = XCConfigurationList;
361 | buildConfigurations = (
362 | 8735E1572084F721008BA9F4 /* Debug */,
363 | 8735E1582084F721008BA9F4 /* Release */,
364 | );
365 | defaultConfigurationIsVisible = 0;
366 | defaultConfigurationName = Release;
367 | };
368 | /* End XCConfigurationList section */
369 | };
370 | rootObject = 8735E13C2084F721008BA9F4 /* Project object */;
371 | }
372 |
--------------------------------------------------------------------------------