how to find HKMetadataKeyMaximumSpeed - ios

I am wondering how to find a user's top speed using HealthKit.
I have come across this HKMetadataKeyMaximumSpeed but have no idea how to implement/use it. The docs are not very clear to me.
Can anyone provide any help here?

Apple indicates thath :
HKMetadataKeyMaximumSpeed Set this key on a workout, workout segment, or a quantity sample that represents distance. Set its value to an HKQuantity object with a length/time unit (for example, m/s)
So you can use this function with this property :
func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent) {
if event.type == .segment {
let maxSpeed = event.metadata?[HKMetadataKeyMaximumSpeed]
// do it here your logic
}
Regarding to your comment: You can not genererate these events on the simulator.

There is example provided by Apple in docs.
func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent) {
// Check to see if the event is a segment.
if event.type == .segment {
// Get the segment's start and end times.
let startTime = event.dateInterval.start
let endTime = event.dateInterval.end
// Get the segment's metadata.
let averageSpeed = event.metadata?[HKMetadataKeyAverageSpeed]
let maxSpeed = event.metadata?[HKMetadataKeyMaximumSpeed]
let alpineSlope = event.metadata?[HKMetadataKeyAlpineSlopeGrade]
let elevationAscended = event.metadata?[HKMetadataKeyElevationAscended]
let elevationDescended = event.metadata?[HKMetadataKeyElevationDescended]
// Do something with the segment data here...
}
// Also handle any other event types...
}

Related

iOS fast image difference comparison

Im looking for a fast way to compare two frames of video, and decide if a lot has changed between them. This will be used to decide if I should send a request to image recognition service over REST, so I don't want to keep sending them, until there might be some different results. Something similar is doing Vuforia SDK. Im starting with a Framebuffer from ARKit, and I have it scaled to 640:480 and converted to RGB888 vBuffer_image. It could compare just few points, but it needs to find out if difference is significant nicely.
I started by calculating difference between few points using vDSP functions, but this has a disadvantage - if I move camera even very slightly to left/right, then the same points have different portions of image, and the calculated difference is high, even if nothing really changed much.
I was thinking about using histograms, but I didn't test this approach yet.
What would be the best solution for this? It needs to be fast, it can compare just smaller version of image, etc.
I have tested another approach using VNFeaturePointObservation from Vision. This works a lot better, but Im afraid it might be more CPU demanding. I need to test this on some older devices. Anyway, this is a part of code that works nicely. If someone could suggest some better approach to test, please let know:
private var lastScanningImageFingerprint: VNFeaturePrintObservation?
// Returns true if these are different enough
private func compareScanningImages(current: VNFeaturePrintObservation, last: VNFeaturePrintObservation?) -> Bool {
guard let last = last else { return true }
var distance = Float(0)
try! last.computeDistance(&distance, to: current)
print(distance)
return distance > 10
}
// After scanning is done, subclass should prepare suggestedTargets array.
private func performScanningIfNeeded(_ sender: Timer) {
guard !scanningInProgress else { return } // Wait for previous scanning to finish
guard let vImageBuffer = deletate?.currentFrameScalledImage else { return }
guard let image = CGImage.create(from: vImageBuffer) else { return }
func featureprintObservationForImage(image: CGImage) -> VNFeaturePrintObservation? {
let requestHandler = VNImageRequestHandler(cgImage: image, options: [:])
let request = VNGenerateImageFeaturePrintRequest()
do {
try requestHandler.perform([request])
return request.results?.first as? VNFeaturePrintObservation
} catch {
print("Vision error: \(error)")
return nil
}
}
guard let imageFingerprint = featureprintObservationForImage(image: image) else { return }
guard compareScanningImages(current: imageFingerprint, last: lastScanningImageFingerprint) else { return }
print("SCANN \(Date())")
lastScanningImageFingerprint = featureprintObservationForImage(image: image)
executeScanning(on: image) { [weak self] in
self?.scanningInProgress = false
}
}
Tested on older iPhone - as expected this causes some frame drops on camera preview. So I need a faster algorithm

Accessing state information in swift - DJI Mobile SDK iOS

I can't get my head around how to get out simple status data, like the current gimbal pitch for example.
I have not found a solid connection between the DJI SDK and what actually works in xcode. The SDK gives me hints and together with xcode autocompletion a go forwards, slowly..
Class GimbalState has member getAttitudeInDegrees() with description:
"The current gimbal attitude in degrees. Roll, pitch and yaw are 0 if the gimbal is level with the aircraft and points in the forward direction of North Pole." - Great!
However, it does not autocomplete in xcode nor does it compile.
Other approaches tested:
var gimbalStateInformation = DJIGimbalState()
print(gimbalStateInformatoin.attitudeInDegrees.pitch.description)
--> All pitch roll and yaw values come out as 0.0
var gimbalStateInformation = DJUGimbalAttitude()
print(gimbalStateInformatoin.pitch.description)
--> All pitch roll and yaw values come out as 0.0
I've tried to reach the information via keys, but my app crashes when I run the code.
func getGimbalAttitude(){
// Get the key
guard let gimbalAttitudeKey = DJIGimbalKey(param: DJIGimbalParamAttitudeInDegrees) else {
print("Could not create DJIGimbalParamAttitudeInDegrees key")
return
}
// Get the keyManager
guard let keyManager = DJISDKManager.keyManager() else {
print("Could not get the key manager, manke sure you are registered")
return
}
// Test if key is available
let testing = keyManager.isKeySupported(gimbalAttitudeKey)
self.statusLabel.text = String(testing) // This comes out true
// Use key to retreive info
let gimbalAttitudeValue = keyManager.getValueFor(gimbalAttitudeKey)
let gimbalAttitude = gimbalAttitudeValue?.value as! DJIGimbalState
_ = gimbalAttitude.attitudeInDegrees.pitch
// --> Application crashes on the line above
}
I'm working towards a Mavic Mini.
Please advise in general terms how to connect the DJI Mobile SDK to Swift and specifically how I can read out the current gimbal pitch value.
You can access the current Gimbal pitch through its didUpdate state delegate function
import DJISDK
class GimbalController: NSObject, DJIGimbalDelegate {
let gimbal: DJIGimbal
init(gimbal: DJIGimbal) {
self.gimbal = gimbal
super.init()
gimbal.delegate = self
}
func gimbal(_ gimbal: DJIGimbal, didUpdate state: DJIGimbalState) {
print(state.attitudeInDegrees.pitch)
}
}
// create an instance of the custom gimbal controller in some other class
// and pass it the gimbal instance
if let aircraft = DJISDKManager.product() as? DJIAircraft {
if let gimbal = aircraft.gimbal {
let gimbalController = GimbalController(gimbal: gimbal)
}
}

SKScene and URLQueryItems in Swift3?

Ok, I am new to URL querying and this whole aspect of Swift and need help. As is, I have an iMessage app that contains and SKScene. For the users to take turns playing the game, I need to send the game back and forth in messages within 1 session as I learned here : https://medium.com/lost-bananas/building-an-interactive-imessage-application-for-ios-10-in-swift-7da4a18bdeed.
So far I have my scene all working however Ive poured over Apple's ice cream demo where they send the continuously-built ice cream back and forth, and I cant understand how to "query" everything in my SKScene so I can send the scene.
I'm unclear as to how URLQueryItems work as the documentation does not relate to sprite kit scenes.
Apple queries their "ice cream" in its current state like this:
init?(queryItems: [URLQueryItem]) {
var base: Base?
var scoops: Scoops?
var topping: Topping?
for queryItem in queryItems {
guard let value = queryItem.value else { continue }
if let decodedPart = Base(rawValue: value), queryItem.name == Base.queryItemKey {
base = decodedPart
}
if let decodedPart = Scoops(rawValue: value), queryItem.name == Scoops.queryItemKey {
scoops = decodedPart
}
if let decodedPart = Topping(rawValue: value), queryItem.name == Topping.queryItemKey {
topping = decodedPart
}
}
guard let decodedBase = base else { return nil }
self.base = decodedBase
self.scoops = scoops
self.topping = topping
}
}
fileprivate func composeMessage(with iceCream: IceCream, caption: String, session: MSSession? = nil) -> MSMessage {
var components = URLComponents()
components.queryItems = iceCream.queryItems
let layout = MSMessageTemplateLayout()
layout.image = iceCream.renderSticker(opaque: true)
layout.caption = caption
let message = MSMessage(session: session ?? MSSession())
message.url = components.url!
message.layout = layout
return message
}
}
But I cant find out how to "query" an SKScene. How can I "send" an SKScene back and forth? Is this possible?
You do not need to send an SKScene back and forth :) What you need to do is send the information relating to your game set up - such as number of turns, or whose turn it is, or whatever, as information that can be accessed by your app at the other end to build the scene.
Without knowing more about how your scene is set up and how it interacts with the information received for the other player's session, I can't tell you a lot in terms of specifics. But, what you need to do, if you are using URLQueryItems to pass the information, simply retrieve the list of query items in your scene and set up the scene based on the received values.
If you have specific questions about how this could be done, if you either share the full project, or post the relevant bits of code as to where you send out a message from one player and how the other player receives the information and sets up the scene, I (or somebody else) should be able to help.
Also, if you look at composeMessage in the code you posted above, you will see how in that particular code example the scene/game information was being sent to the other user. At the other end of the process, the received message's URL parameter would be decomposed to get the values for the various query items and then the scene would be set up based on those values. Look at how that is done in order to figure out how your scene should be set up.

How would I use the same viewcontroller, but pass different information through it?

so, my current problem is as follows.
I would like to essentially use my current viewcontroller, but change the location settings somewhere else within the app and have the data pass though the viewcontroller with the updated location information.
I'll elaborate. I'm currently utilizing the following code for reverse geocoding, and obtaining the users location.
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
locationManager.stopUpdatingLocation()
if(locations.count > 0){
let location = locations[0] as! CLLocation
// println(location.coordinate)
if let currentLocatino = currLocation {
if CLLocation(latitude: currentLocatino.latitude, longitude: currentLocatino.longitude).distanceFromLocation(location) > 500 {
currLocation = location.coordinate
self.skip = 0
self.loadObjects()
}
}
else {
currLocation = location.coordinate
self.skip = 0
self.loadObjects()
}
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currLocation!.latitude, longitude: currLocation!.longitude), completionHandler: {(placemarks, error) -> Void in
if error != nil {
println("Reverse geocoder failed with error" + error.localizedDescription)
return
}
if placemarks.count > 0 {
let date = NSDate()
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
formatter.stringFromDate(date)
let pm = placemarks[0] as! CLPlacemark
var testifempty = "\(pm.subLocality)"
if testifempty == "nil"
{
self.locationManager.startUpdatingLocation()
if let lbutton = self.lbutton{
lbutton.text = "Hey " + "\(pm.locality)" //+ "\n" + formatter.stringFromDate(date)
}
}
else
{
self.locationManager.startUpdatingLocation()
if let lbutton = self.lbutton {
lbutton.text = "Hey " + "\(pm.subLocality)\n" // + formatter.stringFromDate(date)
}
}
}
else {
println("Problem with the data received from geocoder")
}
})
} else {
println("Cannot fetch your location")
}
}
What I would like, it to essentially pass through a NEW location and set a boolean of sorts so that if said boolean is set to false, the NEW location information is passed through the app.
I'm thinking about using a switch on the main viewcontroller, and changing the location on a secondary viewcontroller.
I'm sorry if this is a long post, but I feel as though I'm right on the edge of figuring out how to do this but I need to be sure I'm going in the right direction.
Maybe I could use a mapkit and use annotations?
I would not recommend using a view of any type to pass or hold information. A switch (like a UISwitch) should represent some other data in a graphical way for the user.
If you're new to mobile development, I'd recommend taking a look at the MVC design pattern. Here, are a couple different resources to get you started on that.
If you need to keep some data somewhere in your app that you can access from any class (viewController, view, custom object, etc.) then a Singleton would be a great solution. You can have map data that comes in be accessible across the entire app, you can store variables and be able to re-assign them from other classes, and you always end up with only one instance so your logical wires never get crossed.
Singletons get use fairly often, so I'd recommend looking at what the implementation code looks like and getting familiar with it. Here's a brief example of an implementation.
For your problem, the delegation pattern seems like the most appropriate choice.
If you create a protocol for your primary view controller that declares a method to update its data, such as locationDidUpdate:, then the primary view controller can be set as a delegate of the secondary view controller. The secondary view controller can then call this delegate method and update the primary view controller with new data.
As an example, a protocol can be declared in your first view controller like:
protocol LocationViewControllerDelegate: class {
func locationDidUpdate(location: CLLocation)
}
Then have your secondary view controller conform to the protocol and create a delegate property:
weak var delegate: LocationViewControllerDelegate?
When you need to update the location, call the delegate method with:
delegate.locationDidUpdate(myNewLocation)
Having a protocol for managing event-based updates is an advantage, in general, because it provides a clear contract that can easily be implemented by other classes.

Finding the current Accelerometer values

I'm trying to get a label to rotate based on the tit of the device in an app I'm making in swift. Given that I should be fine with rotating the label, does anybody know how to find the current accelerometer values of an iPhone? For example, getting it to print its x, y and z values once every second or so.
Thanks in advance.
Sample code:
Add the framework
Add the following code in the appropriate places
import CoreMotion
var motionManager = CMMotionManager()
var AccelX: CGFloat = 0
// Setup accelemeter detection
if motionManager.accelerometerAvailable == true {
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue(), withHandler: { (data, error) -> Void in
self.outputAccelertionData(data.acceleration)
})
}
func outputAccelertionData (acceleration: CMAcceleration) {
AccelX = 0
if fabs(CGFloat(acceleration.x)) > fabs(AccelX) {
AccelX = CGFloat(acceleration.x)
}
}

Resources