Building on this solution: AppleScript - Geographic Location, I'm trying to use CLLocation's distance method to create a simple geo-fencing script (setting my status based on distance from certain locations).
I'm not an AppleScript pro, so I'm struggling with the concept of how to initialise a CLLocation object in the script (with latitude and longitude) to compare to my current location returned by the original answer's script.
So I'm looking for something like this, where myCurrentLocation is the location object returned from the original script (obviously wrong, just some pseudo obj-c stuff):
set tagetLatitude to "50.850206"
set targetLongitude to "5.690947"
set targetLocation to CLLocation's initWithLatitude:tagetLatitude longitude:targetLongitude
set distance to targetLocation's distance:myCurrentLocation
return distance
This is the original script by CJK for reference:
use framework "CoreLocation"
use framework "Foundation"
use scripting additions
property this : a reference to the current application
property nil : a reference to missing value
property _1 : a reference to reference
property CLLocationManager : a reference to CLLocationManager of this
property kCLLocationAccuracyThreeKilometers : a reference to 3000.0
--------------------------------------------------------------------------------
property running : false
property result : missing value -- Lat./long. or error description
property number : 0 -- Error code
property seconds : 10 -- Maximum time to allow script to run
--------------------------------------------------------------------------------
# IMPLEMENTATION:
my performSelectorOnMainThread:"getLocation" withObject:nil waitUntilDone:true
return my result
--------------------------------------------------------------------------------
# HANDLERS & SCRIPT OBJECTS:
to getLocation()
set locationManager to CLLocationManager's new()
locationManager's setDelegate:me
locationManager's setDesiredAccuracy:kCLLocationAccuracyThreeKilometers
set my running to true
set started to current date
locationManager's startUpdatingLocation()
repeat while my running
delay 0.5
if (current date) - started > my seconds then exit repeat
end repeat
end getLocation
on locationManager:locationManager didUpdateLocations:locations
local locationManager, locations
locationManager's stopUpdatingLocation()
set my running to false
set my result to (locations's valueForKey:"coordinate") as record
end locationManager:didUpdateLocations:
on locationManager:locationManager didFailWithError:err
local locationManager, err
tell err's code()
set my number to it
set my result to item (it + 1) in my enum's kCLError
if it ≠ 0 then set my running to false
end tell
end locationManager:didFailWithError:
script enum
property kCLError : {¬
"Location Unknown", ¬
"Denied", ¬
"Network", ¬
"Heading Failure", ¬
"Region Monitoring Denied", ¬
"Region Monitoring Failure", ¬
"Region Monitoring Setup Delayed", ¬
"Region Monitoring Response Delayed", ¬
"Geocode Found No Result", ¬
"Geocode Found Partial Result", ¬
"Geocode Canceled", ¬
"Deferred Failed", ¬
"Deferred Not Updating Location", ¬
"Deferred Accuracy Too Low", ¬
"Deferred Distance Filtered", ¬
"Deferred Canceled", ¬
"Ranging Unavailable", ¬
"Ranging Failure"}
property CLAuthorizationStatus : {¬
"Not Determined", ¬
"Restricted", ¬
"Denied", ¬
"Authorized (Always)", ¬
"Authorized When In Use"}
end script
---------------------------------------------------------------------------❮END❯
You aren't far off actually:
on distance to {latitude:|𝝓|, longitude:|λ|}
((my location)'s distanceFromLocation:(CLLocation's ¬
alloc()'s initWithLatitude:|𝝓| longitude:|λ|)) ¬
as real
end distance
where my location
is an instance of CLLocation
. Therefore, in the original script, instead of:
set my result to (locations's valueForKey:"coordinate")
you want:
set my result to item 1 in locations
since locations
ought to be an NSArray
of CLLocation
values.
However, since writing that script, there's been a new instance method added to the CLLocationManager
class, namely requestLocation()
So, the script can probably be shortened a little to something like this:
--------------------------------------------------------------------------------
use framework "Foundation"
use framework "CoreLocation"
--------------------------------------------------------------------------------
property this : a reference to current application
property nil : a reference to missing value
property CLLocation : a reference to CLLocation of this
property CLLocationManager : a reference to CLLocationManager of this
--------------------------------------------------------------------------------
property location : []
--------------------------------------------------------------------------------
# IMPLEMENTATION:
my performSelectorOnMainThread:"findMe" withObject:nil waitUntilDone:yes
return the distance to {latitude:-90.0, longitude:0.0}
to findMe()
tell CLLocationManager's new()
setDelegate_(me)
setDesiredAccuracy_(3000.0)
requestLocation()
end tell
repeat until my location ≠ []
delay 1
end repeat
end findMe
--------------------------------------------------------------------------------
# MAIN HANDLERS:
on distance from A as {record, reference} : [] to B as {record, reference}
local A, B
if A = [] then set A to my location
if A's class = record then
set {latitude:|𝝓|, longitude:|λ|} to A
tell CLLocation's alloc() to set A to ¬
initWithLatitude_longitude_(|𝝓|, |λ|)
end if
if B's class = record then
set {latitude:|𝝓|, longitude:|λ|} to B
tell CLLocation's alloc() to set B to ¬
initWithLatitude_longitude_(|𝝓|, |λ|)
end if
(B's distanceFromLocation:A) as meters as kilometers
end distance
--------------------------------------------------------------------------------
# DELEGATED HANDLERS:
on locationManager:[] didUpdateLocations:here
set [my location] to here
end locationManager:didUpdateLocations:
on locationManager:[] didFailWithError:E
error E's localizedDescription() as text
end locationManager:didFailWithError:
---------------------------------------------------------------------------❮END❯
I haven't tested this script yet as I'm in High Sierra, and it requires Mojave or later. I will reboot into Catalina at some point and check it for errors.