Skip to content

WIP - Polylines in ARCL (hacking ARCL, currently) #22

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: feature/ARCL-polylines
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
3604F21022145D2400D2EFA7 /* EndpointLocationNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3604F20F22145D2400D2EFA7 /* EndpointLocationNode.swift */; };
3604FC77217150AB00B46BAA /* GeoTrackStatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3604FC76217150AB00B46BAA /* GeoTrackStatisticsTests.swift */; };
36302DB9210E17B400834A1D /* GeoTrackKitErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36302DB8210E17B400834A1D /* GeoTrackKitErrorTests.swift */; };
3645779F22873E7A00D39FF5 /* DirectionNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3645779E22873E7A00D39FF5 /* DirectionNode.swift */; };
366B1C672209271E003C19F8 /* TrackList.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 366B1C662209271E003C19F8 /* TrackList.storyboard */; };
366B1C69220927F4003C19F8 /* TrackListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366B1C68220927F4003C19F8 /* TrackListTableViewController.swift */; };
366B652D21963A7D00BA5EB7 /* reference-track-2.json in Resources */ = {isa = PBXBuildFile; fileRef = 366B652C21963A7D00BA5EB7 /* reference-track-2.json */; };
366B653021963AEE00BA5EB7 /* GeoTrackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366B652F21963AEE00BA5EB7 /* GeoTrackTests.swift */; };
366B6532219650CF00BA5EB7 /* reference-track-3.json in Resources */ = {isa = PBXBuildFile; fileRef = 366B6531219650CF00BA5EB7 /* reference-track-3.json */; };
366CE43C1DFCAC360090BD42 /* GeoTrackSerializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366CE43B1DFCAC360090BD42 /* GeoTrackSerializationTests.swift */; };
36838E93222A094A00F4F714 /* TrackOverviewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36838E92222A094A00F4F714 /* TrackOverviewCell.swift */; };
3677FFF9220C679A0036DA27 /* ARCLViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3677FFF8220C679A0036DA27 /* ARCLViewController.swift */; };
3677FFFB220C68C10036DA27 /* ARCL.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3677FFFA220C68C10036DA27 /* ARCL.storyboard */; };
36838E93222A094A00F4F714 /* TrackOverviewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36838E92222A094A00F4F714 /* TrackOverviewCell.swift */; };
368A87AE1E6332C1003D115A /* reference-track-1.json in Resources */ = {isa = PBXBuildFile; fileRef = 368A87AD1E6332C1003D115A /* reference-track-1.json */; };
368A87B11E63332E003D115A /* TrackReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 368A87B01E63332E003D115A /* TrackReader.swift */; };
368A87B71E636FCE003D115A /* GeoTrackAnalyzerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 368A87B61E636FCE003D115A /* GeoTrackAnalyzerTests.swift */; };
Expand Down Expand Up @@ -73,15 +74,16 @@
3604F20F22145D2400D2EFA7 /* EndpointLocationNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndpointLocationNode.swift; sourceTree = "<group>"; };
3604FC76217150AB00B46BAA /* GeoTrackStatisticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoTrackStatisticsTests.swift; sourceTree = "<group>"; };
36302DB8210E17B400834A1D /* GeoTrackKitErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoTrackKitErrorTests.swift; sourceTree = "<group>"; };
3645779E22873E7A00D39FF5 /* DirectionNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectionNode.swift; sourceTree = "<group>"; };
366B1C662209271E003C19F8 /* TrackList.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TrackList.storyboard; sourceTree = "<group>"; };
366B1C68220927F4003C19F8 /* TrackListTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackListTableViewController.swift; sourceTree = "<group>"; };
366B652C21963A7D00BA5EB7 /* reference-track-2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reference-track-2.json"; sourceTree = "<group>"; };
366B652F21963AEE00BA5EB7 /* GeoTrackTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoTrackTests.swift; sourceTree = "<group>"; };
366B6531219650CF00BA5EB7 /* reference-track-3.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reference-track-3.json"; sourceTree = "<group>"; };
366CE43B1DFCAC360090BD42 /* GeoTrackSerializationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoTrackSerializationTests.swift; sourceTree = "<group>"; };
36838E92222A094A00F4F714 /* TrackOverviewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackOverviewCell.swift; sourceTree = "<group>"; };
3677FFF8220C679A0036DA27 /* ARCLViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARCLViewController.swift; sourceTree = "<group>"; };
3677FFFA220C68C10036DA27 /* ARCL.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ARCL.storyboard; sourceTree = "<group>"; };
36838E92222A094A00F4F714 /* TrackOverviewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackOverviewCell.swift; sourceTree = "<group>"; };
368A87AD1E6332C1003D115A /* reference-track-1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reference-track-1.json"; sourceTree = "<group>"; };
368A87B01E63332E003D115A /* TrackReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrackReader.swift; sourceTree = "<group>"; };
368A87B61E636FCE003D115A /* GeoTrackAnalyzerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoTrackAnalyzerTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -192,6 +194,7 @@
3677FFFA220C68C10036DA27 /* ARCL.storyboard */,
3604F20D2214564A00D2EFA7 /* ArrowLocationNode.swift */,
3604F20F22145D2400D2EFA7 /* EndpointLocationNode.swift */,
3645779E22873E7A00D39FF5 /* DirectionNode.swift */,
);
path = ARCL;
sourceTree = "<group>";
Expand Down Expand Up @@ -472,6 +475,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
Expand Down Expand Up @@ -611,6 +615,7 @@
368B12CA222DB1E200B22C72 /* SelectTrackDialog.swift in Sources */,
36C45E451DCE2D3500E87710 /* AppDelegate.swift in Sources */,
368B12C8222D847A00B22C72 /* StringExtensions.swift in Sources */,
3645779F22873E7A00D39FF5 /* DirectionNode.swift in Sources */,
36838E93222A094A00F4F714 /* TrackOverviewCell.swift in Sources */,
36A7C6C72100B0980073407A /* EventLogAppender.swift in Sources */,
3677FFF9220C679A0036DA27 /* ARCLViewController.swift in Sources */,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class ARCLViewController: UIViewController {
mapView.showPoints = true
}
NotificationCenter.default.addObserver(self, selector: #selector(selectedAnnotationPoint(_:)), name: Notification.Name.GeoTrackKit.selectedAnnotationPoint, object: nil)
let item = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveScene(_:)))
navigationItem.setRightBarButton(item, animated: false)
}

override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -76,6 +78,48 @@ class ARCLViewController: UIViewController {
}
}

@IBAction
func saveScene(_ source: Any) {
guard let docsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return assertionFailure("Failed to get docs folder")
}
prepareSceneNodesForSave()
let sceneUrl = URL(fileURLWithPath: "ARCL-Saved.scn", relativeTo: docsFolder)
sceneView.scene.write(to: sceneUrl, options: nil, delegate: nil) { (percentage, error, _) in
if let error = error {
print("ERROR: \(error.localizedDescription)")
assertionFailure("Failed to save scene")
}
print("save scene: \(percentage) complete")
if percentage == 1.0 {
assert(FileManager.default.fileExists(atPath: sceneUrl.path))
guard let attrs = try? FileManager.default.attributesOfItem(atPath: sceneUrl.path) else {
return assertionFailure("poof")
}
assert(attrs[.size] as? Int ?? 0 > 1024)
DispatchQueue.main.async { [weak self] in
guard let data = try? Data(contentsOf: sceneUrl) else {
return
}
let activityVC = UIActivityViewController(activityItems: ["SCN File", data], applicationActivities: nil)
self?.present(activityVC, animated: true, completion: nil)
}
}
}
}

func prepareSceneNodesForSave() {
guard let container = sceneView.scene.rootNode.childNodes.filter({ !$0.childNodes.isEmpty }).first else {
return // couldn't find the container
}
container.name = "Container"
let noNameNodes = container.childNodes.filter({ $0.name == nil })

for idx in 0..<noNameNodes.count {
noNameNodes[idx].name = "Polyline\(idx)"
}
}

}

// MARK: - Notification Handlers
Expand Down Expand Up @@ -177,25 +221,54 @@ extension ARCLViewController {

/// Renders directions to a specific location.
func renderDirections() {
let request = MKDirections.Request()
request.source = MKMapItem.forCurrentLocation()
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: CLLocationCoordinate2D(latitude: 39.9390932, longitude: -105.0150254)))
request.requestsAlternateRoutes = false
guard let track = track else {
return assertionFailure("no track")
}

let directions = MKDirections(request: request)
var points = track.points.filter({ $0.horizontalAccuracy < 8 })
// mutated points
var mutatedPoints = [CLLocation]()
for idx in 0..<points.count {
// let elevation = points[0].altitude - 2 + CLLocationDistance(idx * 2)
let elevation = points[idx].altitude - 2
mutatedPoints.append(CLLocation(coordinate: points[idx].coordinate, altitude: elevation))
}
points = mutatedPoints


// raw points
sceneView.addRoute(points: points)
// let directions = DirectionNode.build(from: points)
// sceneView.addLocationNodesWithConfirmedLocation(locationNodes: directions)
//// renderSpheres(for: points)
// var last: DirectionNode?
// directions.forEach {
// last?.look(at: $0)
// last = $0
// }
// guard let lastPoint = points.last else {
// return
// }
// let endpoint = EndpointLocationNode(location: lastPoint)
// sceneView.addLocationNodesWithConfirmedLocation(locationNodes: [endpoint])
// directions.last?.look(at: endpoint)

directions.calculate(completionHandler: {(response, error) in
if error != nil {
return print("Error getting directions")
}
guard let response = response else {
return
}
}

DispatchQueue.main.async { [weak self] in
self?.sceneView.addRoutes(routes: response.routes)
}
})
func renderSpheres(for points: [CLLocation]) {
for idx in 0..<points.count {
let point = points[idx]

let node = LocationNode(location: point)
let sphere = SCNSphere(radius: 0.2)
let material = SCNMaterial()
material.diffuse.contents = UIColor.red
sphere.materials = [material]
let sphereNode = SCNNode(geometry: sphere)
node.addChildNode(sphereNode)
node.name = "point \(idx)"
sceneView.addLocationNodeWithConfirmedLocation(locationNode: node)
}
}

func renderFloatingArrows() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// DirectionNode.swift
// GeoTrackKitExample
//
// Created by Eric Internicola on 5/11/19.
// Copyright © 2019 Eric Internicola. All rights reserved.
//

import ARCL
import CoreLocation
import SceneKit
import UIKit

class DirectionNode: LocationNode {

class func build(startPoint: CLLocation, endPoint: CLLocation) -> DirectionNode {
let node = DirectionNode(location: startPoint)
let distance = startPoint.distance(from: endPoint)
let arrow = node.loadDirectionModel(height: distance)
node.addChildNode(arrow)

return node
}

class func build(from points: [CLLocation]) -> [DirectionNode] {
var nodes = [DirectionNode]()

for idx in 0..<points.count - 1 {
let current = points[idx]
let next = points[idx+1]

nodes.append(build(startPoint: current, endPoint: next))
}

return nodes
}

/// Performs a rotation of this node to point at the provided node.
///
/// - Parameter node: The node that this node should be pointing at.
func look(at node: LocationNode) {
look(at: node.position, up: SCNVector3.yAxisUp, localFront: SCNVector3.yAxisUp)
}

}

private extension DirectionNode {

/// Loads the arrow model from the arrow scene.
///
/// - Returns: The arrow node from the arrow scene.
func loadDirectionModel(height: CLLocationDistance) -> SCNNode {

let box = SCNBox(width: 1, height: CGFloat(height), length: 1, chamferRadius: 0.5)
let material = SCNMaterial()
material.diffuse.contents = UIColor.green
box.materials = [material]
let node = SCNNode(geometry: box)
node.position.y = Float(height / 2)

return node
}
}
Binary file not shown.
16 changes: 16 additions & 0 deletions GeoTrackKitExample/Pods/ARCL/ARCL/Source/Nodes/LocationNode.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading