├── 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 | --------------------------------------------------------------------------------