Archive for the 'CLLocationManager' Category

2015/12/06 現在地点の緯度経度情報を取得する v2

Cocoaの機能を用いて、Macの現在位置の緯度経度情報を取得するAppleScriptです。実行時にWiFiがオンになっている必要があります。

だんだん、ASOCのScriptも書きこなれてきて、「この場合にはこう書く」的な方法論が蓄積され、便利に書けるようになってきました。処理系の方もCocoaを用いた記述に最適化されてきているのでしょうか(OS X 10.10ではForegroundで実行することを要求されましたが、OS X 10.11ではとくに文句も言われないので、、、)。

AppleScript名:GetCurrentLocation_ElCapitan v4
– Created 2015-03-04 by Takaaki Naganoya, Shane Stanley
– Modified 2015-12-06 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “CoreLocation”

property locationManager : missing value
property curLatitude : 0
property curLongitude : 0

set {aLat, aLong} to getCurrentGeoLocation() of me

on getCurrentGeoLocation()
  set locationManager to current application’s CLLocationManager’s alloc()’s init()
  
  
set locE to locationManager’s locationServicesEnabled()
  
if (locE as boolean) = true then
    locationManager’s setDelegate:me
    
locationManager’s setDesiredAccuracy:(current application’s kCLLocationAccuracyNearestTenMeters)
    
locationManager’s setDistanceFilter:500
    
locationManager’s startUpdatingLocation()
  else
    return false –error in init
  end if
  
  
set hitF to false
  
repeat 3000 times
    if {curLatitude, curLongitude} is not equal to {0, 0} then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
  end repeat
  
  
if hitF = false then return false
  
return {curLatitude, curLongitude}
end getCurrentGeoLocation

on locationManager:manager didUpdateLocations:locations
  set location to (locations’s lastObject())
  
set eventDate to (location’s timestamp())
  
set howRecent to (eventDate’s timeIntervalSinceNow())
  
set howRecent to howRecent as real
  
set howRecent to absNum(howRecent)
  
  
if howRecent < 15.0 then
    set alt to location’s altitude –>(NSNumber) 46.356517791748
    
set aSpeed to location’s speed –>(NSNumber) -1.0
    
set aCourse to location’s course –North:0, East:90, South:180, West:270
    
–>  (NSNumber) -1.0
    
set theDescription to location’s |description|()
    
–> (NSString) “< +35.xxxxx,+139.xxxxxx> +/- 65.00m (speed -1.00 mps / course -1.00) @ 2015/03/04 8時56分41秒 日本標準時”
    
set anNSScanner to current application’s NSScanner’s scannerWithString:theDescription
    
anNSScanner’s setCharactersToBeSkipped:(current application’s NSCharacterSet’s characterSetWithCharactersInString:“< ,")
    
set {theResult, aLat} to anNSScanner’s scanDouble:(reference)
    
set {theResult, aLng} to anNSScanner’s scanDouble:(reference)
    
copy {aLat, aLng} to {my curLatitude, my curLongitude}
  else
    locationManager’s stopUpdatingLocation()
  end if
  
end locationManager:didUpdateLocations:

on locationManager:anCLLocationManager didFailWithError:anNSError
  display dialog (anNSError’s localizedDescription() as text)
end locationManager:didFailWithError:

on absNum(aNum)
  if aNum > 0 then
    return aNum
  else
    return (aNum * -1)
  end if
end absNum

★Click Here to Open This Script 

2015/03/04 現在地点の緯度経度情報を取得する

This AppleScript get current location of your Mac by using CoreLocation. There is need to enable WiFi to get location using this AppleScript.

You can get altitude, timestamp, speed and course easily. But latitude and longitude were difficult to get.

I asked to Shane how to do this. His answer is “get description”.

You must execute this AppleScript in foreground. Original Script is made for a part of ASOC project on Xcode.

loc1.png
▲システム環境設定の「セキュリティとプライバシー」でScript EditorもしくはASObjC Explorer 4に位置情報の取得を許可しておく必要があります

loc2.png
▲許可しないとエラーが表示されます

本AppleScriptはお使いのMacの現在位置の緯度経度情報を取得するものです。CoreLocationを用いて、高度、タイムスタンプ、スピード、進行方向については容易に取得できました(位置情報を取得するためにWiFiをオンにしておく必要あり)。ただ、肝心の緯度経度情報だけはなかなか取得できず、Shaneに聞いてみたところ・・・「descriptionを取得しろ」とのこと(サンプルつきで)。

本AppleScriptの実行時には、foregroundで明示的に実行させる必要があります。オリジナルのScriptはASOC on Xcodeの一部として書いたもので、位置情報の取得/許可については本Scriptの方がうまくいっていない感じです(ASObjC Explorerがコケたりする)。

AppleScript名:GetCurrentLocation_Yosemite v3
– Created 2015-03-04 by Takaaki Naganoya, Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “CoreLocation”
use framework “AppKit”

property curLatitude : 0
property curLongitude : 0

on run
  startStandardUpdates()
end run

on startStandardUpdates()
  –Listing 1-1 Starting the standard location service
  
set locationManager to current application’s CLLocationManager’s alloc()’s init()
  
  
set locE to locationManager’s locationServicesEnabled()
  
if (locE as boolean) = true then
    locationManager’s setDelegate:me
    
locationManager’s setDesiredAccuracy:(current application’s kCLLocationAccuracyNearestTenMeters)
    
locationManager’s setDistanceFilter:500
    
locationManager’s startUpdatingLocation()
  end if
  
end startStandardUpdates

on locationManager:manager didUpdateLocations:locations
  
  
–Listing 1-3 Processing an incoming location event
  
set location to (locations’s lastObject())
  
set eventDate to (location’s timestamp())
  
set howRecent to (eventDate’s timeIntervalSinceNow())
  
  
–Calc ABS
  
set howRecent to howRecent as real
  
set howRecent to absNum(howRecent)
  
  
if howRecent < 15.0 then
    
    
set alt to location’s altitude
    
–>  (NSNumber) 46.356517791748
    
    
set aSpeed to location’s speed
    
–>  (NSNumber) -1.0
    
    
set aCourse to location’s course –North:0, East:90, South:180, West:270
    
–>  (NSNumber) -1.0
    
    
–By Shane Stanley
    
set theDescription to location’s |description|()
    
–> (NSString) “< +35.xxxxx,+139.xxxxxx> +/- 65.00m (speed -1.00 mps / course -1.00) @ 2015/03/04 8時56分41秒 日本標準時”
    
    
set anNSScanner to current application’s NSScanner’s scannerWithString:theDescription
    
anNSScanner’s setCharactersToBeSkipped:(current application’s NSCharacterSet’s characterSetWithCharactersInString:“< ,")
    
set {theResult, aLat} to anNSScanner’s scanDouble:(reference)
    
set {theResult, aLng} to anNSScanner’s scanDouble:(reference)
    
    
copy {aLat, aLng} to {my curLatitude, my curLongitude}
    
  else
    stopUpdatingLocation()
  end if
  
end locationManager:didUpdateLocations:

on locationManager:anCLLocationManager didFailWithError:anNSError
  display dialog (anNSError’s localizedDescription() as text)
end locationManager:didFailWithError:

on absNum(aNum)
  if aNum > 0 then
    return aNum
  else
    return (aNum * -1)
  end if
end absNum

★Click Here to Open This Script 

2013/09/16 AppleScriptObjCで位置情報を取得

AppleScriptObjCでLocationManagerを利用して、現在位置の情報を取得するサンプルです。

あまりよく理解していないのですが、MacScripterの議論を参考に、不必要なコードを除去して最低限の機能だけ利用できればと考えて整理したものです。

こうした位置情報を取得する機能はAppleScript/AppleScriptObjCのプログラムでも、気軽に使いたいところです。

ただ、「気軽に利用できる」のと「気軽に配布できる」の間にはずいぶんと距離があります。利用するだけなら、そうした機能をAppleScriptに提供するソフトウェアが存在していますが……配布するとなると、それを一緒に配布するわけにもいきませんし、その程度の機能で「有償ソフトウェア」といわれても困ります。

位置情報の取得まわりは、かなり高機能なAPIが揃っているのが見て取れるのですが、緯度経度情報から住所情報に変換する「逆住所ジオコーダー」(reverse geocoder)がiOSにしか見当たらないため、直接GoogleのAPIを使うほかないのかと考えていますが……10.9になったらさっくりMac OS Xからも逆住所ジオコーダーを使えそうな気が……。

loc1.png
▲Xcodeプロジェクトをビルドして実行すると、位置情報を使用してよいかダイアログが表示される

loc2.png
▲緯度、経度の情報と誤差情報が表示される

loc3.png
▲「Open In Browser」ボタンをクリックすると、Google Map(日本語版)で取得位置の確認が行える

→ Xcodeプロジェクトのダウンロード(42KB)

AppleScriptObjCファイル名:coreLocationASOCAppDelegate.applescript

– coreLocationASOCAppDelegate.applescript
– coreLocationASOC

– Created by Takaaki Naganoya on 10/09/15.
– Copyright 2010 Takaaki Naganoya. All rights reserved.

–http://macscripter.net/viewtopic.php?id=32763&p=3

script coreLocationASOCAppDelegate
  
  property parent : class “NSObject”
  
  property CLLocation : class “CLLocation”
  
property CLLocationManager : class “CLLocationManager”
  
  property NSString : class “NSString”
  
property nsurl : class “NSURL”
  
property NSDate : class “NSDate”
  
property NSWorkspace : class “NSWorkspace”
  
property NSBundle : class “NSBundle”
  
  property locationManager : missing value
  
  property locationText : missing value
  
property accuracyText : missing value
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    set locationManager to CLLocationManager’s alloc()’s init()
    
    locationManager’s setDesiredAccuracy_(current application’s kCLLocationAccuracyHundredMeters)
    
locationManager’s setDelegate_(me)
    
locationManager’s startUpdatingLocation()
    
  end applicationWillFinishLaunching_
  
  
  on locationManager_didFailWithError_(locationManager, myError)
    
    set errorString to NSString’s stringWithFormat_(“Location manager failed with error: %@”, myError’s localizedDescription())
    
webView’s mainFrame()’s loadHTMLString_baseURL_(errorString, missing value)
    
locationText’s setStringValue_(“No Data Available”)
    
accuracyText’s setStringValue_(“”)
    
  end locationManager_didFailWithError_
  
  
  on locationManager_didUpdateToLocation_fromLocation_(locationManager, newLocation, oldLocation)
    
    set latitude to newLocation’s coordinate’s pointValue()’s x
    
set longitude to newLocation’s coordinate’s pointValue()’s y
    
    locationText’s setStringValue_(NSString’s stringWithFormat_(“%@, %@”, latitude, longitude))
    
accuracyText’s setStringValue_(NSString’s stringWithFormat_(“%@”, newLocation’s horizontalAccuracy()))
    
    locationManager’s stopUpdatingLocation()
    
    
  end locationManager_didUpdateToLocation_fromLocation_
  
  
  on clicked_(sender)
    set aTag to tag of sender
    
set aTag to aTag as integer
    
    if aTag = 100 then
      tell current application to quit
    else if aTag = 200 then
      openInDefaultBrowser_(sender)
    end if
    
  end clicked_
  
  
  
  on applicationShouldTerminate_(sender)
    locationManager’s stopUpdatingLocation()
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  
  –Webブラウザで現在の緯度、経度情報を元にGoogle Mapを表示
  
on openInDefaultBrowser_(sender) –Connected to a button in IB
    
    set currentLocation to locationManager’s location()
    
    if currentLocation is not missing value then
      set lat to currentLocation’s coordinate’s pointValue()’s x
      
set lon to currentLocation’s coordinate’s pointValue()’s y
      
set latRange to latitudeRangeForLocation_(currentLocation)
      
set lonRange to longitudeRangeForLocation_(currentLocation)
    else
      set lat to 37.76
      
set lon to -122.434
      
set latRange to 0.15
      
set lonRange to 0.15
    end if
    
    set browserURL to nsurl’s URLWithString_(NSString’s stringWithFormat_(“http://maps.google.co.jp/maps?ll=%@,%@&spn=%@,%@”, lat, lon, latRange, lonRange))
    
    NSWorkspace’s sharedWorkspace’s openURL_(browserURL)
    
  end openInDefaultBrowser_
  
  
  
  
  on latitudeRangeForLocation_(aLocation)
    
    set M to 6.367E+6 –approximate average meridional radius of curvature of earth
    
set metersToLatitude to 1.0 / ((3.1416 / 180.0) * M)
    
set accuracyToWindowScale to 2.0
    
    return (aLocation’s horizontalAccuracy()) * metersToLatitude * accuracyToWindowScale
    
  end latitudeRangeForLocation_
  
  on longitudeRangeForLocation_(aLocation)
    
    set latRange to latitudeRangeForLocation_(aLocation)
    
return latRange * (getCos_((aLocation’s coordinate’s pointValue()’s x) * 3.1416 / 180.0))
    
  end longitudeRangeForLocation_
  
  
  on getCos_(x)
    return (1 - x ^ 2 / 2 + x ^ 4 / 24 - x ^ 6 / 720 + x ^ 8 / 40320)
  end getCos_
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に