Major circles of Latitude: Searching for GPS coordinates in Photos using an Apple Script
Have you ever tried to find in Photos all photos taken while standing on the Equator or at the Arctic circle or similar?
It is easy to search for photo in Photos by the locations, if we see the places markers on the map or we can guess the name of the location that Photos assigned automatically. But typing the GPS coordinates into the search field simply does not work. We cannot use the GPS coordinates in smart albums either.
But we can search for GPS coordinates with the help of an Apple Script. The Photos dictionary gives access to these properties of the media items:
altitude (real) : The GPS altitude in meters.
location (list of real) : The GPS latitude and longitude, in an ordered list of 2 numbers. Latitude in range -90.0 to 90.0, longitude in range -180.0 to 180.0.
The location property can be read and written since macOS 10.12 Sierra, the altitude seems still to be read-only (at least I am getting continually error messages when I try to assign an altitude tag to a photo).
Just for the fun of it and as an example for scripting the GPS properties I wrote this little script to search for photos taken along the five major circles of latitude: the equator, the Arctic Circle, the Antarctic Circle, the Tropic of Capricorn, the Tropic of Cancer. ( A second version of the script will also search for the meridians - scroll further down to see this version).
It will find all photos taken within a given distance of one of the five major circles of latitude and create five albums - one for each circle. The script is ignoring that the location of these circles is depending on the date and the circles are moving slowly due to the nutation. So expect the results to be off a few meters for older photos. These albums will be created when the script is running. It may take a few minutes for a large library. I select the photos in a smart album with the rule "Photos is tagged with GPS" to avoid unnecessary checks.
-- snip : copy from below this line to the end
(*
This script will take a set of photos selected in Photos and then search for photos taken close to the five major circles of latitude - the equator, the Arctic Circles, the tropics
*)
(* How to use this script:
Select some photos to be searched for photos that have been taken close to one of the five major circles of latitude
This script will split the selection and add the photos to six albums:
- EquatorPhotosAlbum: an album with photos taken close to the equator
- TropicOfCapricornAlbum: an album with photos taken close to the southern tropic - the tropic of capricorn
- TropicOfCancerAlbum: an album with photos taken close to the norther tropic - the tropic of cancer
- ArcticCircleAlbum: an album with photos taken close to the northern Arctic circle
- AntarcticCircleAlbum: an album with photos taken close to the nsouthern Arctic circle
Open this script in Script Editor. Launch Photos.
Select the Photos you want to distribute between the albums.
A photo is considered to be taken close to one of the circles, if the distance of the location is less than the distance threshold in km.
When all all photo are selected, press the "Run" button in Script Editor.
Author: léonie
*)
-- The latitudes of the major five circles of latitude - the script does not take into account, that these circles are shifting because of the motion of the axis of the earth
set TropicOfCapricornLatitude to -23.43703 --latitude of the southern tropic.
set TropicOfCancerLatitude to 23.43703 --latitude of the northern tropic.
set ArcticCircleLatitude to 66 + 33 / 60 + 46.7 / 3600 -- -66°33′46.7″
set AntarcticCircleLatitude to -ArcticCircleLatitude
set EquatorLatitude to 0.0
set defaultDistanceThreshold to 10.0 -- (10 km) allow 10 km distance from the circle, when searching for photos taken there.
set km2degreeLatitude to 1.0 / 111.32
set dialogResult to display dialog ¬
"Enter the distance threshold for the distance from the circle in km : " buttons {"Cancel", "OK"} ¬
default answer (defaultDistanceThreshold as text)
set DistanceThreshold to ((text returned of dialogResult) as real) * km2degreeLatitude
--return DistanceThreshold
tell application "Photos"
activate
try
set imageSel to (get selection)
on error errTexttwonumbererrNumtwo
display dialog "Cannot get the selection: " & errNumtwo & return & errTexttwo
end try
end tell
on findPhotosInLatitudeRange(latitudeOfCircle, latiAlbumName, selectedPhotos, DistanceThreshold)
set thisLatis to {} -- the list of portrait photos
set skipped to {}
set lowerBound to latitudeOfCircle - DistanceThreshold
set upperBound to latitudeOfCircle + DistanceThreshold
set latiValues to {}
tell application "Photos"
activate
-- Ensure that the albums do exist
try
if not (exists container latiAlbumName) then
makenewalbumnamedlatiAlbumName
end if
set theLatiAlbum to containerlatiAlbumName
on error errTexttwonumbererrNumtwo
display dialog "Cannot open albums: " & latiAlbumName & errNumtwo & return & errTexttwo
end try
-- check, if the album or the selected photos do contain images
if selectedPhotos is {} then
error "Please select some images."
else
repeat with im in selectedPhotos
try
tell im--get the pixel size
set loc to get the location--retrieve longitude and latitude as list
set lati to (the first item of loc) -- as string
-- set longi to (the second item of loc) as string
end tell
on error errText number errNum
display dialog "Error: " & errNum & return & errText & "Trying again"
try
delay 2
tell im
set loc to get the location--retrieve longitude and latitude as list
set lati to (the first item of loc) -- as string
-- set longi to (the second item of loc) as string
end tell
on error errTexttwonumbererrNumtwo
display dialog "Skipping image due to repeated error: " & errNumtwo & return & errTexttwo
end try
end try
set noLocation to (lati is missing value)
if noLocation then
set skipped to {im} & skipped -- for testing
else
set lati to lati as number
if (lati < upperBound) and (lati > lowerBound) then
set thisLatis to {im} & thisLatis
-- set latiValues to {lati} & latiValues
end if
end if
end repeat
addthisLatistotheLatiAlbum
-- return latiValues & {lowerBound, upperBound}
end if
end tell
end findPhotosInLatitudeRange
findPhotosInLatitudeRange(EquatorLatitude, "EquatorPhotosAlbum", imageSel, DistanceThreshold)
findPhotosInLatitudeRange(TropicOfCapricornLatitude, "TropicOfCapricornAlbum", imageSel, DistanceThreshold)
findPhotosInLatitudeRange(TropicOfCancerLatitude, "TropicOfCancerAlbum", imageSel, DistanceThreshold)
findPhotosInLatitudeRange(ArcticCircleLatitude, "ArcticCircleAlbum", imageSel, DistanceThreshold)
findPhotosInLatitudeRange(AntarcticCircleLatitude, "AntarcticCircleAlbum", imageSel, DistanceThreshold)
This user tip was generated from the following discussion: Major circles of Latitude: Searching for GPS coordinates in Photos using an Apple Script
-- ------------------------------------------------------------------------------- ------------------------------------
-- A second version: This version will also search for photos taken close major meridians
-- Additionally, it will return the filename of the photo closest to each meridian as well as the distance in kilometers.
-- ------------------------------------------------------------------------------- ------------------------------------
(*
This script will take a set of photos selected in Photos and then search for photos taken close to the five major circles of latitude - the equator, the Arctic Circles, the tropics
How to use this script:
Select some photos to be searched for photos that have been taken close to one of the five major circles of latitude
This script will split the selection and add the photos to six albums:
- EquatorPhotosAlbum: an album with photos taken close to the equator
- TropicOfCapricornAlbum: an album with photos taken close to the southern tropic - the tropic of capricorn
- TropicOfCancerAlbum: an album with photos taken close to the norther tropic - the tropic of cancer
- ArcticCircleAlbum: an album with photos taken close to the northern Arctic circle
- AntarcticCircleAlbum: an album with photos taken close to the nsouthern Arctic circle
Open this script in Script Editor. Launch Photos.
Select the Photos you want to distribute between the albums.
A photo is considered to be taken close to one of the circles, if the distance of the location is less than the distance threshold in km.
When all all photo are selected, press the "Run" button in Script Editor.
Author: léonie
*)
-- The latitudes of the major five circles of latitude - the script does not take into account, that these circles are shifting because of the motion of the axis of the earth
set TropicOfCapricornLatitude to -23.43703 --latitude of the southern tropic.
set TropicOfCancerLatitude to 23.43703 --latitude of the northern tropic.
set ArcticCircleLatitude to 66 + 33 / 60 + 46.7 / 3600 -- -66°33′46.7″
set AntarcticCircleLatitude to -ArcticCircleLatitude
set EquatorLatitude to 0.0
-- Meridians
set PrimeMeridianGreenwichLongitude to 0.0 --
set InternationalDateLineLongitude to 180.0
set defaultDistanceThreshold to 10.0 -- (10 km) allow 10 km distance from the circle, when searching for photos taken there.
set dialogResult to display dialog ¬
"Enter the distance threshold for the distance from the circle in km : " buttons {"Cancel", "OK"} ¬
default answer (defaultDistanceThreshold as text)
set DistanceThreshold to ((text returned of dialogResult) as real)
--return DistanceThreshold
tell application "Photos"
activate
try
set imageSel to (get selection)
on error errTexttwonumbererrNumtwo
display dialog "Cannot get the selection: " & errNumtwo & return & errTexttwo
end try
end tell
on findPhotosInLatitudeRange(latitudeOfCircle, latiAlbumName, selectedPhotos, DistanceThreshold)
-- latitudeOfCircle: the latitude in degrees, real number
-- latiAlbumName: the name of the album to collect the photos, string
-- selectedPhotos: a list of media items
-- DistanceThreshold: the threshold for the distance from the circle, in km, real number
set km2degreeLatitude to 1.0 / 111.32 -- the distance of the circles of latitude is independent of the latitude
set thisLatis to {} -- the list ofphotos close to the circle of latitude
set skipped to {}
set latiValues to {}
set closestDistance to 42000 / 4.0 -- initial value, distance from the equator to the pole
if selectedPhotos is {} then
error "Please select some images."
else
set closestPhoto to item 1 of selectedPhotos-- the currently closest photo to the circle
set closestFilename to "no value"
end if
tell application "Photos"
activate
-- Ensure that the albums do exist
try
if not (exists container latiAlbumName) then
makenewalbumnamedlatiAlbumName
end if
set theLatiAlbum to containerlatiAlbumName
on error errTexttwonumbererrNumtwo
display dialog "Cannot open albums: " & latiAlbumName & errNumtwo & return & errTexttwo
end try
-- check, if the album or the selected photos do contain images
if selectedPhotos is {} then
error "Please select some images."
else
repeat with im in selectedPhotos
try
tell im--get the pixel size
set loc to get the location--retrieve longitude and latitude as list
set lati to (the first item of loc)
end tell
on error errText number errNum
display dialog "Error: " & errNum & return & errText & "Trying again"
try
delay 2
tell im
set loc to get the location--retrieve longitude and latitude as list
set lati to (the first item of loc)
end tell
on error errTexttwonumbererrNumtwo
display dialog "Skipping image due to repeated error: " & errNumtwo & return & errTexttwo
end try
end try
set noLocation to (lati is missing value)
if noLocation then
set skipped to {im} & skipped -- for testing
else
set lati to lati as number
set dfc to lati - latitudeOfCircle
if (dfc < 0.0) then
set distanceFromCircle to -dfc / km2degreeLatitude
else
set distanceFromCircle to dfc / km2degreeLatitude
end if
if (distanceFromCircle ≤ DistanceThreshold) then
set thisLatis to {im} & thisLatis
end if
if (distanceFromCircle ≤ closestDistance) then
set closestDistance to distanceFromCircle
set closestPhoto to im
tell im
set closestFilename to its filename
end tell
end if
end if
end repeat
addthisLatistotheLatiAlbum
add {closestPhoto} totheLatiAlbum
return {distance:closestDistance, the_file:closestFilename}
end if
end tell
end findPhotosInLatitudeRange
-- Part 2: Compute the photos close to a meridian circle.
-- while circles of latitude have a constant distance, independant of the latitude, the merians are closer at the poles than at the equator. we need the cosine of the latitude to calculate the distance correctly.
script Trigonometry
-- Since Apple Script does not provide trigonometric functions, you need to inlude an extension to provide some math.
-- I simply include the following functions from the URL below:
-- from http://macosxautomation.com/applescript/sbrt/pgs/sbrt.02.htm
on is_odd(this_number)
if this_number mod 2 is not 0 then
return true
else
return false
end if
end is_odd
on sine_of(x)
repeat until x ≥ 0 and x < 360
if x ≥ 360 then
set x to x - 360
end if
if x < 0 then
set x to x + 360
end if
end repeat
--convert from degrees to radians
set x to x * (2 * pi) / 360
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 sine_of
on cosine_of(x)
repeat until x ≥ 0 and x < 360
if x ≥ 360 then
set x to x - 360
end if
if x < 0 then
set x to x + 360
end if
end repeat
--convert from degrees to radians
set x to x * (2 * pi) / 360
set answer to 0
set numerator to 1
set denominator to 1
set factor to -(x ^ 2)
repeat with i from 2 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 cosine_of
--x is in degrees
on tan(x)
set answer to sine_of(x) / (cosine_of(x))
return answer
end tan
--x is ratio of opposite to adjacent sides of triangle
on inverse_tangent_of(x)
set complimentFlag to false
if x > 1 or x < -1 then
set x to 1 / x
set complimentFlag to true
else if x = 1 then
return 45.0
end if
set answer to 0
set numerator to x
set denominator to 1
set ratio to x
set factor to -(x ^ 2)
repeat while abs(ratio) > 1.0E-4
set answer to answer + ratio
set numerator to numerator * factor
set denominator to denominator + 2
set ratio to numerator / denominator
end repeat
--convert from radians to degrees
set answer to answer * 360 / (2 * pi)
if complimentFlag is true then
set answer to 90 - answer
end if
return answer
end inverse_tangent_of
on abs(numericVariable)
if numericVariable < 0 then
return -numericVariable
else
return numericVariable
end if
end abs
end script -- Trigonometry
-- Search for photos taken close to a meridian
on findPhotosInLongitudeRange(longitudeOfMeridian, longiAlbumName, selectedPhotos, DistanceThreshold)
-- longitudeOfMeridian: the meridian in degrees, real number
-- latiAlbumName: the name of the album to collect the photos, string
-- selectedPhotos: a list of media items
-- DistanceThreshold: the threshold for the distance from the circle, in km, real number
set thisLongis to {} -- the list of portrait photos
set skipped to {} -- not yet used, just for debugging
set longiValues to {} -- list of photos taken close to the meridian
set closestDistance to 42000 / 2.0 -- half the length of the equator
set km2degreeLongitude to 1.0 / 111.32 --at the equator
if selectedPhotos is {} then
error "Please select some images."
else
set closestPhoto to item 1 of selectedPhotos-- the currently closest photo to the circle
set closestFilename to "no value"
end if
tell application "Photos"
activate
-- Ensure that the albums do exist
try
if not (exists container longiAlbumName) then
makenewalbumnamedlongiAlbumName
end if
set theLongiAlbum to containerlongiAlbumName
on error errTexttwonumbererrNumtwo
display dialog "Cannot open albums: " & longiAlbumName & errNumtwo & return & errTexttwo
end try
-- check, if the album or the selected photos do contain images
if selectedPhotos is {} then
error "Please select some images."
else
repeat with im in selectedPhotos
try
tell im--get the pixel size
set loc to get the location--retrieve longitude and latitude as list
set lati to (the first item of loc)
set longi to (the second item of loc)
end tell
on error errText number errNum
display dialog "Error: " & errNum & return & errText & "Trying again"
try
delay 2
tell im
set loc to get the location--retrieve longitude and latitude as list
set lati to (the first item of loc)
set longi to (the second item of loc)
end tell
on error errTexttwonumbererrNumtwo
display dialog "Skipping image due to repeated error: " & errNumtwo & return & errTexttwo
end try
end try
set noLocation to (lati is missing value) or (longi is missing value)
if noLocation then
set skipped to {im} & skipped -- for testing
else
set lati to lati as number
set longi to longi as number
set dfc to (longi - longitudeOfMeridian) * (Trigonometry'scosine_of(lati)) / km2degreeLongitude
if (dfc < 0.0) then
set distanceFromCircle to -dfc
else
set distanceFromCircle to dfc
end if
if (distanceFromCircle ≤ DistanceThreshold) then
set thisLongis to {im} & thisLongis
end if
if (distanceFromCircle ≤ closestDistance) then
set closestDistance to distanceFromCircle
set closestPhoto to im
tell im
set closestFilename to its filename
end tell
end if
end if
end repeat
addthisLongistotheLongiAlbum
add {closestPhoto} totheLongiAlbum
return {distance:closestDistance, the_file:closestFilename}
end if
end tell
end findPhotosInLongitudeRange
-- call the script for the circles you want
set closestToEquator to findPhotosInLatitudeRange(EquatorLatitude, "EquatorPhotosAlbum", imageSel, DistanceThreshold)
set closestToTropicOfCapricorn to findPhotosInLatitudeRange(TropicOfCapricornLatitude, "TropicOfCapricornAlbum", imageSel, DistanceThreshold)
set closestToTropicOfCancer to findPhotosInLatitudeRange(TropicOfCancerLatitude, "TropicOfCancerAlbum", imageSel, DistanceThreshold)
set closestToArcticCircle to findPhotosInLatitudeRange(ArcticCircleLatitude, "ArcticCircleAlbum", imageSel, DistanceThreshold * 6)
set closestToAntarcticCircle to findPhotosInLatitudeRange(AntarcticCircleLatitude, "AntarcticCircleAlbum", imageSel, DistanceThreshold * 15)
set closestToPrimeMeridian to findPhotosInLongitudeRange(PrimeMeridianGreenwichLongitude, "PrimeMeridianPhotosAlbum", imageSel, DistanceThreshold)
set closestToInternationalDateLine to findPhotosInLongitudeRange(InternationalDateLineLongitude, "InternationalDateLineAlbum", imageSel, DistanceThreshold * 40)
-- return a list of the closest distances to the circles
return {"closest To the Equator: ", closestToEquator, ", closest To the Tropic Of Capricorn: ", closestToTropicOfCapricorn, ", closest To the Tropic Of Cancer: ", closestToTropicOfCancer, ", Closest To Arctic Circle: ", closestToArcticCircle, ", Closest To The AntarcticCircle: ", closestToAntarcticCircle, ", Closest To The Prime Meridian: ", closestToPrimeMeridian, ", Closest To The International Date Line: ", closestToInternationalDateLine}