Browse Source

ffho-site-auto-select: backport from master

Karsten Böddeker 8 years ago
parent
commit
6924b13a8d

+ 6 - 2
ffho/ffho-site-auto-select/Makefile

@@ -4,6 +4,8 @@ PKG_NAME:=ffho-site-auto-select
 PKG_VERSION:=1
 PKG_RELEASE:=$(GLUON_VERSION).$(GLUON_SITE_CODE)-$(GLUON_RELEASE).$(GLUON_CONFIG_VERSION)
 
+PFG_BUILD_DEPENDS := lua-cjson/host
+
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
 include $(INCLUDE_DIR)/package.mk
@@ -12,7 +14,7 @@ define Package/ffho-site-auto-select
   SECTION:=ffho
   CATEGORY:=Gluon
   TITLE:=Toolset to autodetect the site.
-  DEPENDS:=+gluon-cron +gluon-neighbour-info +ffho-site-generate
+  DEPENDS:=+gluon-core +gluon-cron +gluon-neighbour-info +ffho-site-generate
   MAINTAINER:=Freifunk Hochstift <maschinenraum@paderborn.freifunk.net>
   URL:=https://git.c3pb.de/freifunk-pb/ffho-packages
   SOURCE:=git@git.c3pb.de:freifunk-pb/ffho-packages.git
@@ -36,7 +38,9 @@ define Package/ffho-site-auto-select/preinst
 endef
 
 define Package/ffho-site-auto-select/install
-  $(CP) ./files/* $(1)/
+	$(CP) ./files/* $(1)/
+	$(INSTALL_DIR) $(1)/lib/gluon/site-select
+	lua -e 'print(require("cjson").encode(require("cjson").decode(io.open("$(GLUON_SITEDIR)/extra/geo.json"):read("*a"))))' > $(1)/lib/gluon/site-select/geo.json
 endef
 
 $(eval $(call BuildPackage,ffho-site-auto-select))

+ 39 - 14
ffho/ffho-site-auto-select/files/lib/gluon/upgrade/003-site-auto-select

@@ -1,20 +1,25 @@
 #!/usr/bin/lua
 
-local config = require 'gluon.sites'
 local uci = require('luci.model.uci').cursor()
+local json = require 'luci.json'
+local tools = require 'gluon.site_generate'
+local shape = require 'gluon.pointwithinshape'
 
-function is_site_valid(site)
-  for _, tmp in pairs(config) do
-    if tmp.site_code == site then
-      return true
-    end
+local geo_default_site = "ffho_yho"
+
+function get_config(file)
+  local f = io.open(file)
+  if f then
+    local config = json.decode(f:read('*a'))
+    f:close()
+    return config
   end
-  return false
+  return nil
 end
 
-function set_currentsite(site)
-  if site and is_site_valid(site) then
-    uci:set('currentsite', 'current', 'name', site)
+function set_currentsite(site_code)
+  if site_code and tools.validate_site(site_code) then
+    uci:set('currentsite', 'current', 'name', site_code)
     uci:save('currentsite')
     uci:commit('currentsite')
     return true
@@ -23,13 +28,33 @@ function set_currentsite(site)
 end
 
 function get_site_by_geo(latitude, longitude)
-  return nil
+  if not latitude or not longitude then
+    return nil
+  end
+
+  local sites = tools.get_config('/lib/gluon/site-select/geo.json').features
+  for _,site in ipairs(sites) do
+    if site.geometry and site.geometry.coordinates then
+      local tmp1 = {}
+      for _, val in ipairs(site.geometry.coordinates[1]) do
+        local tmp2 = {}
+        tmp2.x=val[2]
+        tmp2.y=val[1]
+        table.insert(tmp1, tmp2)
+      end
+      if shape.PointWithinShape(tmp1, tonumber(latitude), tonumber(longitude)) then
+        return site.properties.site_code
+      end
+    end
+  end
+
+  return geo_default_site
 end
 
 local currentsite = uci:get('currentsite', 'current', 'name')
-local configured = is_site_valid(currentsite)
+local configured = tools.validate_site(currentsite)
 
-if configured == false then
+if not configured then
   local latitude = uci:get_first('gluon-node-info', 'location', 'latitude')
   local longitude = uci:get_first('gluon-node-info', 'location', 'longitude')
   if latitude and longitude then
@@ -38,7 +63,7 @@ if configured == false then
   end
 end
 
-if configured == false then
+if not configured then
   local minute = math.random(0, 59)
   local f = io.open('/lib/gluon/cron/ffho-site-auto-select', 'w')
   f:write(string.format('%i * * * * /usr/sbin/ffho-site-auto-select\n', minute))

+ 126 - 0
ffho/ffho-site-auto-select/files/usr/lib/lua/gluon/pointwithinshape.lua

@@ -0,0 +1,126 @@
+#!/usr/bin/lua
+
+module('gluon.pointwithinshape', package.seeall)
+
+-- Begin https://love2d.org/wiki/PointWithinShape
+function PointWithinShape(shape, tx, ty)
+	if #shape == 0 then
+		return false
+	elseif #shape == 1 then
+		return shape[1].x == tx and shape[1].y == ty
+	elseif #shape == 2 then
+		return PointWithinLine(shape, tx, ty)
+	else
+		return CrossingsMultiplyTest(shape, tx, ty)
+	end
+end
+
+function BoundingBox(box, tx, ty)
+	return	(box[2].x >= tx and box[2].y >= ty)
+		and (box[1].x <= tx and box[1].y <= ty)
+		or  (box[1].x >= tx and box[2].y >= ty)
+		and (box[2].x <= tx and box[1].y <= ty)
+end
+
+function colinear(line, x, y, e)
+	e = e or 0.1
+	m = (line[2].y - line[1].y) / (line[2].x - line[1].x)
+	local function f(x) return line[1].y + m*(x - line[1].x) end
+	return math.abs(y - f(x)) <= e
+end
+
+function PointWithinLine(line, tx, ty, e)
+	e = e or 0.66
+	if BoundingBox(line, tx, ty) then
+		return colinear(line, tx, ty, e)
+	else
+		return false
+	end
+end
+
+-------------------------------------------------------------------------
+-- The following function is based off code from
+-- [ http://erich.realtimerendering.com/ptinpoly/ ]
+--
+--[[
+ ======= Crossings Multiply algorithm ===================================
+ * This version is usually somewhat faster than the original published in
+ * Graphics Gems IV; by turning the division for testing the X axis crossing
+ * into a tricky multiplication test this part of the test became faster,
+ * which had the additional effect of making the test for "both to left or
+ * both to right" a bit slower for triangles than simply computing the
+ * intersection each time.  The main increase is in triangle testing speed,
+ * which was about 15% faster; all other polygon complexities were pretty much
+ * the same as before.  On machines where division is very expensive (not the
+ * case on the HP 9000 series on which I tested) this test should be much
+ * faster overall than the old code.  Your mileage may (in fact, will) vary,
+ * depending on the machine and the test data, but in general I believe this
+ * code is both shorter and faster.  This test was inspired by unpublished
+ * Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
+ * Related work by Samosky is in:
+ *
+ * Samosky, Joseph, "SectionView: A system for interactively specifying and
+ * visualizing sections through three-dimensional medical image data",
+ * M.S. Thesis, Department of Electrical Engineering and Computer Science,
+ * Massachusetts Institute of Technology, 1993.
+ *
+ --]]
+
+--[[ Shoot a test ray along +X axis.  The strategy is to compare vertex Y values
+ * to the testing point's Y and quickly discard edges which are entirely to one
+ * side of the test ray.  Note that CONVEX and WINDING code can be added as
+ * for the CrossingsTest() code; it is left out here for clarity.
+ *
+ * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
+ * _point_, returns 1 if inside, 0 if outside.
+ --]]
+function CrossingsMultiplyTest(pgon, tx, ty)
+	local i, yflag0, yflag1, inside_flag
+	local vtx0, vtx1
+
+	local numverts = #pgon
+
+	vtx0 = pgon[numverts]
+	vtx1 = pgon[1]
+
+	-- get test bit for above/below X axis
+	yflag0 = ( vtx0.y >= ty )
+	inside_flag = false
+
+	for i=2,numverts+1 do
+		yflag1 = ( vtx1.y >= ty )
+
+		--[[ Check if endpoints straddle (are on opposite sides) of X axis
+		 * (i.e. the Y's differ); if so, +X ray could intersect this edge.
+		 * The old test also checked whether the endpoints are both to the
+		 * right or to the left of the test point.  However, given the faster
+		 * intersection point computation used below, this test was found to
+		 * be a break-even proposition for most polygons and a loser for
+		 * triangles (where 50% or more of the edges which survive this test
+		 * will cross quadrants and so have to have the X intersection computed
+		 * anyway).  I credit Joseph Samosky with inspiring me to try dropping
+		 * the "both left or both right" part of my code.
+		 --]]
+		if ( yflag0 ~= yflag1 ) then
+			--[[ Check intersection of pgon segment with +X ray.
+			 * Note if >= point's X; if so, the ray hits it.
+			 * The division operation is avoided for the ">=" test by checking
+			 * the sign of the first vertex wrto the test point; idea inspired
+			 * by Joseph Samosky's and Mark Haigh-Hutchinson's different
+			 * polygon inclusion tests.
+			 --]]
+			if ( ((vtx1.y - ty) * (vtx0.x - vtx1.x) >= (vtx1.x - tx) * (vtx0.y - vtx1.y)) == yflag1 ) then
+				inside_flag =  not inside_flag
+			end
+		end
+
+		-- Move to the next pair of vertices, retaining info as possible.
+		yflag0  = yflag1
+		vtx0    = vtx1
+		vtx1    = pgon[i]
+	end
+
+	return  inside_flag
+end
+-- End https://love2d.org/wiki/PointWithinShape
+

+ 7 - 26
ffho/ffho-site-auto-select/files/usr/sbin/ffho-site-auto-select

@@ -2,28 +2,9 @@
 
 local util = require("luci.util")
 local json = require("luci.json")
-local config = require 'gluon.sites'
 local uci = require('luci.model.uci').cursor()
-local site = require 'gluon.site_config'
-
-function is_site_valid(site)
-  for _, tmp in pairs(config) do
-    if tmp.site_code == site then
-      return true
-    end
-  end
-  return false
-end
-
-function set_currentsite(site)
-  if site and is_site_valid(site) then
-    uci:set('currentsite', 'current', 'name', site)
-    uci:save('currentsite')
-    uci:commit('currentsite')
-    return true
-  end
-  return false
-end
+local site_code = require('gluon.site_config').side_code
+local tools = require 'gluon.site_generate'
 
 function neighbours(ifname)
   local info = util.exec("gluon-neighbour-info -d ff02::2:1001 -p 1001 -r nodeinfo -t 2 -i " .. ifname)
@@ -48,7 +29,7 @@ function get_neighbour_site()
     for _, node in pairs(macs) do
       if node["system"] then
         local node_site = node["system"]["site_code"]
-        if node_site and is_site_valid(node_site) then
+        if node_site and tools.validate_site(node_site) then
           return node_site
         end
       end
@@ -59,16 +40,16 @@ function get_neighbour_site()
 end
 
 local currentsite = uci:get('currentsite', 'current', 'name')
-local configured = is_site_valid(currentsite)
+local configured = tools.validate_site(currentsite)
 
 if configured == false then
   currentsite = get_neighbour_site()
-  configured = set_currentsite(currentsite)
+  configured = tools.set_site_code(currentsite)
 end
 
 if configured then
-  os.execute("rm -f /lib/gluon/cron/ffho-site-auto-select >/dev/null 2>&1")
-  if site.site_code ~= currentsite then
+  os.remove("/lib/gluon/cron/ffho-site-auto-select")
+  if site_code ~= currentsite then
     os.execute("/lib/gluon/site-select/site-upgrade >/dev/null 2>&1")
     os.execute("reboot >/dev/null 2>&1")
   end