CoreLocation

Would you mind posting your app or creating a test app and posting that?

Here’s a test app. It has no interface, it just logs the location info to the console.

http://dl.dropbox.com/u/553261/CoreLocationTest.zip

I tried your app, but I don’t get anything in the log, except for the error after about 40 seconds - I guess this isn’t surprising since I’m not receiving any location data here. In order to test things, I created a location object with:
set newLoc to NSLocation’s alloc()'s initWithLatitude_longitude_(40,-122). When I log newLoc, I get the same type of thing that fiftyfour123 gets - the data is all there, but in a form that I haven’t seen before. I also tried creating the location object in Objective-C and doing an NSLog of newLoc.coordinate.latitude, and that gave me a bad access error. So, I’m all out of ideas at this point.

This isn’t very elegant, and I don’t know why the other way doesn’t work, but you can get the pieces of the data using standard applescript string parsing code. Since, I’m not receiving location data, I created an NSLocation object and parsed its description like so:

on applicationWillFinishLaunching_(aNotification)
		
		set newLoc to CLLocation's alloc()'s initWithLatitude_longitude_(38, -122)
		set myData to newLoc's |description| as string
		log myData
		set s1 to ((offset of "<" in myData) + 1)
		set s2 to ((offset of "," in myData) - 1)
		set lat to text s1 thru s2 of myData
		log lat
		set s3 to ((offset of ">" in myData) - 1)
		set lon to text (s2 + 3) thru s3 of myData
		log lon
		set s4 to (offset of "m" in myData)
		set accuracy to text (s3 + 6) thru s4 of myData
		log accuracy
		set s5 to ((offset of "@" in myData) + 2)
		set mytimeStamp to text s5 thru -1 of myData
		log mytimeStamp
		
	end applicationWillFinishLaunching_

This got me the latitude, longitude, accuracy and time stamp as separate strings.

Or, you could do it this more “Cocoa’y” way:

on applicationWillFinishLaunching_(aNotification)
		set newLocation to CLLocation's alloc()'s initWithLatitude_longitude_(38, -122)
		set myData to NSString's stringWithString_(newLocation's |description| as string)
		log myData
		set charSet to NSCharacterSet's characterSetWithCharactersInString_("<>,()/@coursepd m")
		set myList to myData's componentsSeparatedByCharactersInSet_(charSet)
		log myList
		myList's removeObjectsInArray_({"", "-", "+"})
		log myList
		set lat to myList's objectAtIndex_(0)
		set lon to myList's objectAtIndex_(1)
		set accuracy to myList's objectAtIndex_(2)
		set speed to myList's objectAtIndex_(3)
		set course to myList's objectAtIndex_(4)
		set myDate to myList's objectAtIndex_(5)
		set myTime to myList's objectAtIndex_(6)
		set GMTOffset to myList's objectAtIndex_(7)
		log "Latitude= " & lat
		log "Longitude= " & lon
		log "Accuracy= " & accuracy
		log "Speed= " & speed
		log "Course= " & course
		log "Date= " & myDate
		log "Time= " & myTime
		log "Offset in hours from GMT= " & GMTOffset
		
	end applicationWillFinishLaunching_

This separates out all the data into separate variables. Note, in the line “set charSet to NSCharacterSet’s characterSetWithCharactersInString_(”<>,()/@coursepd m")" there is a space between the “d” and “m” --that’s intentional. All those characters, including a space, are used as separators to parse the string. But that function leaves you with a list that has a lot of nil elements and an extraneous “+” and “-”, so the removeObjectsInArray method is used to clean it up (you also need a property NSCharacterSet: class “NSCharacterSet” line at the top of your program to make this work).

cool, works perfectly. thanks

You should not have to parse the “description” of an object but should instead get its properties.
Unfortunately, I have not been able to get this to work with CLLocation.

The Objective-C code that works looks like this.

“coordinate” is a struct containing two values; latitude and longitude. This is one of those times I would use the Objective-C code and post an NSNotification from there that I was registered to receive notifications from in the AppleScriptObjC file. Or just update the GUI from the Objective-C file if the AppleScriptObjC file did not need the information.

Is there any advantage to doing it in Obj-C rather than ASOC? I would need the location data to be sent back to applescript, so I feel like it would just be a hassle to do that since this is working fine. Unless there is an advantage.

After much searching, I found out how to get the latitude and longitude data out of a location object directly. With some of the things I was trying, I was getting NSConcreteValue: unrecognized selector error messages. I looked in the documentation for NSConcreteValue, but there is no info on that, so I checked NSValue and tried some of the methods in that class, and pointValue: worked!

script CoreLocationAppDelegate
	property parent : class "NSObject"
	property CLLocation : class "CLLocation"
	
	on applicationWillFinishLaunching_(aNotification)
    
		set newLocation to CLLocation's alloc()'s initWithLatitude_longitude_(38.00123, -122.00987)
		log newLocation's coordinate's pointValue()'s x
		log newLocation's coordinate's pointValue()'s y
		log newLocation's horizontalAccuracy()
		log newLocation's speed()
		log newLocation's course()
		log newLocation's |timestamp|()
		
	end applicationWillFinishLaunching_
end script

Ric

cool, thanks for all the help.

I need help. I’m using rdelmar’s script:

And I want it to be MY current location and not 38, -122’s location. I tried doing set newLocation to CLLocation’s alloc()'s init() but the app won’t “wake up.” Please help. :smiley:

Dylan,
I only did it that way because I wasn’t getting any location data, so I needed to create a location object directly. If you are actually getting data, then you need to go back to the methods we discussed before, with the locationManager’s startUpdatingLocation() method providing the location data, which you then look at in the locationManager_didUpdateToLocation_fromLocation_ method. Like so:

script LocationAppDelegate
	property parent : class "NSObject"
	property CLLocationManager : class "CLLocationManager"
	
	on locationManager_didUpdateToLocation_fromLocation_(locationManager, newLocation, oldLocation)
		log newLocation's coordinate's pointValue()'s x
		log newLocation's coordinate's pointValue()'s y
		log newLocation's horizontalAccuracy()
		log newLocation's speed()
		log newLocation's course()
		log newLocation's |timestamp|()
	end locationManager_didUpdateToLocation_fromLocation_
	
	on applicationWillFinishLaunching_(aNotification)
		set locationManager to CLLocationManager's alloc()'s init()
		locationManager's setDelegate_(me)
		locationManager's startUpdatingLocation()
	end applicationWillFinishLaunching_
	
	on applicationShouldTerminate_(sender)
		locationManager's stopUpdatingLocation()
		return current application's NSTerminateNow
	end applicationShouldTerminate_
end script

I think this should work, but I don’t have any way of testing it. And remember that you need to add the CoreLocation framework to your project if you haven’t already.

Ric

Thank you. Now I can connect it.

In need help converting

[code]NSString *htmlString = [NSString stringWithFormat:
[NSString
stringWithContentsOfFile:
[[NSBundle mainBundle]
pathForResource:@“HTMLFormatString” ofType:@“html”]
encoding:NSUTF8StringEncoding
error:NULL],
newLocation.coordinate.latitude,
newLocation.coordinate.longitude,
[WhereIsMyMacAppDelegate latitudeRangeForLocation:newLocation],
[WhereIsMyMacAppDelegate longitudeRangeForLocation:newLocation]];

// Load the HTML in the WebView and set the labels
[[webView mainFrame] loadHTMLString:htmlString baseURL:nil];
[locationLabel setStringValue:[NSString stringWithFormat:@"%f, %f",
    newLocation.coordinate.latitude, newLocation.coordinate.longitude]];
[accuracyLabel setStringValue:[NSString stringWithFormat:@"%f",
    newLocation.horizontalAccuracy]];

}][/code]
:slight_smile:

Dylan,

Here is my translation of the whole project posted by Matt Gallagher. I’ve test parts of it by creating a location object, but I haven’t tested the whole thing. The pieces you asked about are in here, or you can try the whole thing and see if it works.

script LocatorAppDelegate
	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 NSCharacterSet : class "NSCharacterSet"
	property locationManager : 0
	property webView : missing value
	property locationText : missing value
	property accuracyText : missing value
	
	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 --I put this in here to see if the browser worked in the absence of location data
			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.com/maps?ll=%@,%@&spn=%@,%@", lat, lon, latRange, lonRange))
		NSWorkspace's sharedWorkspace's openURL_(browserURL)
	end openInDefaultBrowser_
	
	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)
		if newLocation's coordinate's pointValue()'s y = oldLocation's coordinate's pointValue()'s y and ¬
			newLocation's coordinate's pointValue()'s x = oldLocation's coordinate's pointValue()'s x and ¬
			newLocation's horizontalAccuracy() = oldLocation's horizontalAccuracy() then
			return
		else
			set myPath to NSBundle's mainBundle's pathForResource_ofType_("HTMLFormatString", "html")
			set urlFromFile to NSString's stringWithContentsOfFile_encoding_error_(myPath, 4, missing value)
			set lat to newLocation's coordinate's pointValue()'s x
			set lon to newLocation's coordinate's pointValue()'s y
			set latRange to latitudeRangeForLocation_(newLocation)
			set lonRange to longitudeRangeForLocation_(newLocation)
			set htmlString to NSString's stringWithFormat_(urlFromFile, lat, lon, latRange, lonRange)
			webView's mainFrame()'s loadHTMLString_baseURL_(htmlString, missing value)
			locationText's setStringValue_(NSString's stringWithFormat_("%@, %@", lat, lon))
			accuracyText's setStringValue_(NSString's stringWithFormat_("%@", newLocation's horizontalAccuracy()))
		end if
	end locationManager_didUpdateToLocation_fromLocation_
	
	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 * (cos((aLocation's coordinate's pointValue()'s x) * 3.1416 / 180.0))
	end longitudeRangeForLocation_
	
	on applicationWillFinishLaunching_(aNotification)
		set locationManager to CLLocationManager's alloc()'s init()
		locationManager's setDelegate_(me)
		locationManager's setDesiredAccuracy_(0)
		locationManager's setDistanceFilter_(0)
		locationManager's startUpdatingLocation()
	end applicationWillFinishLaunching_
	
	on killProgram_(sender) --I have this method connected to a button
		tell current application's NSApp to terminate_(me)
	end killProgram_
	
	on applicationShouldTerminate_(sender)
		locationManager's stopUpdatingLocation()
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script

One other thing that needs to be changed is the HTMLFormatString.html file. I copied that file from Matt Gallagher’s project and changed this line:
src=“http://maps.google.com/maps?ie=UTF8&ll=%@,%@&spn=%@,%@&t=m&output=embed”>
(I replaced %f to %@ in all four places). I hope this works for you.

Ric

I keep getting:

I looked over everything. It worked before. Why isn’t it working now? :confused:

EDIT: And I get


when I click on a button.

EDIT: This is my UI. I took the contents of the previous window and I copied and pasted it into the newer, current window. Image

Try putting log newLocation and log oldLocation as the first lines in the locationManager:didUpdateToLocation:fromLocation: method and see what you get.

The second problem is that the program doesn’t recognize the cos (cosine that is) symbol – I’m still working on that one.

Ric

I haven’t been able to find a way to use the cosine function in ASOC, but it can be approximated easily enough.
Add this method to your program:

on getCos_(x)
		return (1 - x ^ 2 / 2 + x ^ 4 / 24 - x ^ 6 / 720 + x ^ 8 / 40320)
	end getCos_

Then in the longitudeRangeForLocation_ method replace cos with getCos_
That should fix that problem. If anyone knows how to use math functions in ASOC, I’d like to hear how.

Ric

I don’t see any way to call C functions, other than to wrap them in an Objective-C method – which is probably overkill for cos. FWIW, this is a handler I’ve used before:

on getCosine(x)
–convert from degrees to radians
set x to x * (2 * pi) / 360
– cosine = Ï€/2 - sine, so…
set x to pi / 2 - x
set answer to 0
set numerator to x
set denominator to 1
set factor to -(x ^ 2)

repeat with i from 3 to 40 by 2
	set answer to answer + numerator / denominator
	set numerator to numerator * factor
	set denominator to denominator * i * (i - 1)
end repeat

return answer

end getCosine

Fixed an HTML error:

[code]

Google Map [/code]

Dylan,

It looks like you’re getting what you’re supposed to get – the oldLocation should be null the first time you get an update. Does it open the map in the webView after that? If not, maybe it is because the error stops it, but then on subsequent updates your oldLocation and newLocation are the same so it doesn’t get past that if statement. I’m not sure what it is you did to the HTML file ( I don’t know much about HTML), but it worked fine the way it was for me with just those changes to the %@'s.