Skip to content

Instantly share code, notes, and snippets.

@nobiot
Last active July 30, 2023 17:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nobiot/bcccc1033d74b16eefc19e936a4fdba1 to your computer and use it in GitHub Desktop.
Save nobiot/bcccc1033d74b16eefc19e936a4fdba1 to your computer and use it in GitHub Desktop.
Show a list of node IDs that has geo coords within a certain distance of kilometers.
(defun my/list-node-IDs-within-range-of-distance ()
"Show a list of node IDs in a separate window within a KM.
Use it in a buffer with a GEO property. Its value is assumed to
be geographic coordinates, where the latitude and longitude are
separated by a single space.
37.3927 -122.042"
(interactive)
(when-let* ((origin (my/prop-to-pair-of-numbers
(car (org-property-values "GEO"))))
(max-km (read-number "Enter a number (KM): "))
(max-distance (* max-km 1000)))
(cl-flet ((list-distance (node)
(cons (car node) ;; ID
(my/calc-distance origin (cdr node)))) ;; Distance
(distancep (node)
(and (> (cdr node) 0)
(>= max-distance (cdr node)))))
(let ((nodes
(seq-filter
#'distancep
(mapcar #'list-distance (my/get-geo-nodes)))))
;; List the IDs with distance from the origin in a pop-up
;; buffer.
(pop-to-buffer
(get-buffer-create
(format "*List of nodes within %d km" (/ max-distance 1000))))
(erase-buffer)
(dolist (node nodes)
(insert (concat
(car node)
" "
(format "%d m\n" (cdr node)))))))))
(defun my/prop-to-pair-of-numbers (val)
"Convert VAL to cons of numbers.
Utility function. VAL is a string of GEO coordinates like
37.3927 -122.042
GEO coordinates are assumed to be decimal degrees and a string
separated by a space."
(let ((pair (mapcar #'string-to-number (split-string val))))
(cons (car pair) (cadr pair))))
(defun my/get-geo-nodes ()
"Return (ID (LAT . LON)).
LAT and LON are decimal degrees of type number (not string)."
(let ((nodes (org-roam-db-query
[:select [properties id]
:from nodes
:where (like properties '"%geo%")])))
(cl-flet ((convert (node)
;; convert the output of db query to the list in the
;; return format (ID . (LAT . LON)). LAT and LON are
;; convereted from a string to number.
(let ((geo-cons
(my/prop-to-pair-of-numbers
(cdr (assoc "GEO" (car node)))))
(id (cadr node)))
(cons id geo-cons))))
(mapcar #'convert nodes))))
;; Calculate distance of two geo coordinates
;; https://www.movable-type.co.uk/scripts/latlong.html
;; Destination point given distance and bearing from start point
;; https://en.wikipedia.org/wiki/Decimal_degrees
;; Mountain View: 37.3927 -122.042
;; Olga Park 37.3587 -122.075
;; It should be about Distance: 4.775 km (to 4 SF*)
;; Excel: =ACOS( SIN(lat1)*SIN(lat2) + COS(lat1)*COS(lat2)*COS(lon2-lon1) ) * 6371000
;; The lat, lon are all decimal degrees.
(defun my/calc-distance (latlon1 latlon2)
"LONLAT is a cons cell of this form (LAT . LON)"
;; arguments are all decimal degrees.
;; convert them to radians to make the notation easier for later
(let ((lat1 (* (car latlon1) (/ pi 180)))
(lon1 (* (cdr latlon1) (/ pi 180)))
(lat2 (* (car latlon2) (/ pi 180)))
(lon2 (* (cdr latlon2) (/ pi 180))))
(round (* (acos (+ (* (sin lat1) (sin lat2))
(* (cos lat1) (cos lat2) (cos (- lon2 lon1)))))
6371000))))
;; Test
(let ((latlon1 '(37.3927 . -122.042))
(latlon2 '(37.3587 . -122.075)))
(round (my/calc-distance latlon1 latlon2)))
;; => 4775
;; The unit of measure is meter (m)
@nobiot
Copy link
Author

nobiot commented Jul 30, 2023

File 1 (the origin)

:properties:
:modified: 2023-07-30T182055
:ID:       2023-07-30T163232
:geo: 37.3927 -122.042
:end:
#+title: test GEO Mountain View
#+filetags: test

File 2

:properties:
:modified: 2023-07-30T164943
:ID:       2023-07-30T164720
:geo: 37.3587 -122.075
:end:
#+title: test GEO 10km Ortega park
#+filetags:

File 3

:properties:
:modified: 2023-07-30T165100
:ID:       2023-07-30T165039
:geo: 37.0154 -122.211
:end:
#+title: test GEO more than 10km Devon Port
#+filetags: test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment