changeset 430:8efbb045d44d

weather: Implement searching for nearest of measurement stations based on given lat/long coordinates. The distance calculation is naive pythagoraean one, should be changed to "Great circle distance" https://en.wikipedia.org/wiki/Great-circle_distance. (C implementation already done, just needs TCL-ization.)
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 08 Jan 2017 05:08:38 +0200
parents 1ada0cb9bdd9
children 5763716060a0
files config.weather.example weather.tcl
diffstat 2 files changed, 50 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/config.weather.example	Sun Jan 08 04:56:54 2017 +0200
+++ b/config.weather.example	Sun Jan 08 05:08:38 2017 +0200
@@ -35,7 +35,7 @@
 ###
 ### Messages
 ###
-set weather_msg_list_station [list "\002@station@\002 ( http://www.google.fi/maps/@@c_lat@,@c_lng@,15z )"]
+set weather_msg_list_station [list "\002@station@\002 ( http://www.google.fi/maps/@@c_lat@,@c_lng@,18z )"]
 
 
 set weather_msg_result [list "\002@station@\002, mitattu klo @ctime@: \002@temp@°C\002"]
@@ -51,6 +51,12 @@
 set weather_msg_usage_prefix_1 "Käyttö: !sää "
 set weather_msg_usage_prefix_2 "        !sää "
 
+set weather_msg_list_nearest $weather_msg_list_station
+set weather_msg_usage_nearest "lähin <lat>\[, \]<long> -- näyttää annettuja koordinaatteja lähimpänä olevat mittausasemat"
+set weather_msg_usage_nearest_invalid "lähin <lat>\[, \]<long> -- näyttää annettuja koordinaatteja lähimpänä olevat mittausasemat"
+set weather_msg_nearest_stations "Lähimmät mittausasemat (%1, %2): %3"
+
+
 set weather_msg_usage_def_set "vakio <paikka>\[;<paikka2>\] -- asettaa vakiohavaintoaseman\nvakio -- näyttää nykyisen"
 set weather_msg_usage_alias "alias <alias> = <nimi> (Lisää alias-nimen, esim. alias perse = turku)"
 set weather_msg_usage_unalias "unalias <alias> (Poistaa aliaksen)"
--- a/weather.tcl	Sun Jan 08 04:56:54 2017 +0200
+++ b/weather.tcl	Sun Jan 08 05:08:38 2017 +0200
@@ -286,7 +286,8 @@
   global weather_msg_aliased weather_msg_unaliased weather_msg_no_access
   global weather_msg_def_set weather_msg_def_not_set weather_msg_aliases
   global weather_msg_usage_stations weather_msg_stations weather_msg_list_station
-  global weather_msg_result
+  global weather_msg_list_nearest weather_msg_usage_nearest weather_msg_usage_nearest_invalid
+  global weather_msg_nearest_stations weather_msg_result
 
   # Check and handle arguments
   set rarglist [::textutil::split::splitx $uargs {\s+}]
@@ -316,6 +317,47 @@
     set res [join $result " ; "]
     weather_msg $upublic $unick $uchan $weather_msg_stations [list $res]
     return 0
+  } elseif {$rarg == "lahin" || $rarg == "lähin" || $rarg == "closest" || $rarg == "nearest"} {
+    # List stations nearest to given coordinates
+    set qlist [::textutil::split::splitx [join [lrange $rarglist 1 end] " "] {\s*,\s*}]
+    set nlist [lsearch -all -inline -not -exact $qlist ""]
+    if {[llength $nlist] < 2} {
+      weather_usage $upublic $unick $uchan $weather_msg_usage_nearest
+      return 0
+    }
+
+    # Check argument types
+    set d_lat [lindex $nlist 0]
+    set d_lng [lindex $nlist 1]
+    if {![string is double -strict $d_lat] || ![string is double -strict $d_lng]} {
+      weather_msg $upublic $unick $uchan $weather_msg_usage_nearest_invalid
+      return 0
+    }
+
+    # Calculate distances between given coordinates for each location
+    set result {}
+    foreach {ukey uvalue} [array get weather_data] {
+      if {![string match "w_*" $ukey]} {
+        set delta_lat [expr {$d_lat - [lindex $uvalue 2]}]
+        set delta_lng [expr {$d_lng - [lindex $uvalue 3]}]
+        set dist [expr { sqrt($delta_lat * $delta_lat + $delta_lng * $delta_lng) }]
+        lappend result [list $ukey $dist]
+      }
+    }
+
+    # Sort the list by distance
+    set usorted [lsort -real -index 1 $result]
+
+    # Create a result list for few best/first matches
+    set uresult {}
+    foreach {uval} [lrange $usorted 0 2] {
+      lappend uresult [weather_get_str $weather_data([lindex $uval 0]) $weather_msg_list_nearest]
+    }
+
+    # Print out the result
+    set res [join $uresult " ; "]
+    weather_msg $upublic $unick $uchan $weather_msg_nearest_stations [list $d_lat $d_lng $res]
+    return 0
   } elseif {$rarg == "vakio" || $rarg == "default" || $rarg == "vakiot" || $rarg == "defaults"} {
     # List or set the default weather station name patterns for this user