lua optimize poly_draw add draw_number, poly_points modules

Change-Id: Id36e765f18234f5a4f3092d090c0adffa3da1612
diff --git a/apps/plugins/lua/include_lua/draw_num.lua b/apps/plugins/lua/include_lua/draw_num.lua
new file mode 100644
index 0000000..0f42c1f
--- /dev/null
+++ b/apps/plugins/lua/include_lua/draw_num.lua
@@ -0,0 +1,115 @@
+--[[ Lua draw number function
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2019 William Wilgus
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+]]
+
+--[[ Exposed Functions
+    _draw_nums.print; binary (base = 2) , octal (base = 8), hexadecimal (base = 16)
+    _draw_nums.nums; table of number characters
+]]
+
+if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
+
+local _draw_nums = {} do
+    local _poly = require "draw_poly"
+
+        -- every 2 elements is an x, y coord pair
+        -- n[?]  = {x,y,x,y,x,y}
+    local nums = {
+        ["b"] = {0,1,0,7,0,5,1,4,1,4,2,4,3,5,3,6,2,7,1,7,0,6,0,5},
+        ["o"] = {1,4,0,5,0,6,1,7,2,7,3,6,3,5,2,4,1,4},
+        ["x"] = {0,3,4,7,2,5,4,3,0,7},
+        [-1] = {1,4, 3,4},
+        [0] = {1,2,1,6,2,7,3,7,4,6,4,2,3,1,2,1,1,2},
+        [1] = {3,1,3,7},
+        [2] = {1,1,3,1,4,2,4,3,3,4,1,5,1,7,4,7},
+        [3] = {1,1,3,1,4,2,4,3,3,4,2,4,3,4,4,5,4,6,3,7,1,7},
+        [4] = {1,1,1,3,2,4,4,4,4,1,4,7},
+        [5] = {1,1,4,1,1,1,1,4,3,4,4,5,4,7,1,7},
+        [6] = {1,2,1,4,1,6,2,7,3,7,4,6,4,4,1,4,1,2,2,1,4,1},
+        [7] = {1,1,4,1,4,2,1,7},
+        [8] = {1,2,1,6,2,7,3,7,4,6,4,4,1,4,4,4,4,2,3,1,2,1,1,2},
+        [9] = {4,6,4,4,4,2,3,1,2,1,1,2,1,4,4,4,4,6,3,7,1,7},
+        [10] = {1,7,1,4,4,4,4,7,4,2,3,1,2,1,1,2,1,4},
+        [11] = {1,1,1,7,3,7,4,6,4,5,3,4,1,4,3,4,4,3,4,2,3,1,1,1},
+        [12] = {4,2,3,1,2,1,1,2,1,6,2,7,3,7,4,6},
+        [13] = {1,1,1,7,3,7,4,6,4,2,3,1,1,1},
+        [14] = {4,1,1,1,1,4,3,4,1,4,1,7,4,7},
+        [15] = {4,1,1,1,1,4,3,4,1,4,1,7},
+    }
+    _draw_nums.nums = nums
+
+
+    _draw_nums.print = function(img, num, x, y, chrw, color, base, prefix, bClip, scale_x, scale_y, t_nums)
+        scale_x = scale_x or 1
+        scale_y = scale_y or 1
+        chrw = chrw * scale_x
+        prefix = (prefix == nil or prefix == true) and true or false
+        t_nums = t_nums or nums
+        local max_x, max_y, digits = 0, 0, {}
+
+        if num <= 0 then
+            if num < 0 then
+                digits[-3] = -1
+                num = -num
+            else
+                digits[0] = 0
+            end
+        end
+
+        if not prefix and (base == 2 or base == 8 or base == 16) then
+            -- no prefix
+        elseif base == 2 then
+            digits[-1] = "b"
+        elseif base == 8 then
+            digits[-1] = "o"
+        elseif base == 10 then
+            -- no prefix
+        elseif base == 16 then
+            digits[-2] = 0
+            digits[-1] = "x"
+        elseif base == nil then -- default
+            base = 10
+        else
+            error("unknown number base: " .. base)
+            return nil
+        end
+
+        while num > 0 do -- get each digit (LeastSignificant)
+            digits[#digits + 1] = num % base;
+            num=num/base;
+        end
+
+        digits[#digits + 1] = digits[0]  -- zero
+        digits[#digits + 1] = digits[-1] -- base prefix
+        digits[#digits + 1] = digits[-2] -- base prefix (hex)
+        digits[#digits + 1] = digits[-3] -- neg sign
+
+        for i = #digits, 1, -1 do
+                max_x, max_y = _poly.polyline(img, x, y, t_nums[digits[i]],
+                                          color, false, bClip, scale_x, scale_y)
+                x = x + chrw
+        end
+
+        return x, y + max_y, chrw
+    end
+end
+return _draw_nums
diff --git a/apps/plugins/lua/include_lua/draw_poly.lua b/apps/plugins/lua/include_lua/draw_poly.lua
index dc27838..23e02d0 100644
--- a/apps/plugins/lua/include_lua/draw_poly.lua
+++ b/apps/plugins/lua/include_lua/draw_poly.lua
@@ -25,7 +25,11 @@
     _poly.polygon
     _poly.polyline
 ]]
-
+--[[
+     every 2 elements in t_pts is an x, y coord pair
+     p[?]  = {x,y,x,y,x,y}
+     lines get drawn between the coords
+]]
 if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
 
 local _poly = {} do
@@ -39,66 +43,83 @@
     local _copy    = rocklib_image.copy
     local _line    = rocklib_image.line
     local _newimg  = rb.new_image
-    local flood_fill = require("draw_floodfill")
+    local flood_fill
 
     -- draws a non-filled figure based on points in t-points
-    local function polyline(img, x, y, t_points, color, bClosed, bClip)
-        if #t_points < 2 then error("not enough points", 3) end
+    local function polyline(img, x, y, t_pts, color, bClosed, bClip, scale_x, scale_y)
+        scale_x = scale_x or 1
+        scale_y = scale_y or 1
 
-        local pt_first_last
+        local pt_first_last, pt1, pt2
+        local max_x, max_y = 0, 0
+        local len = #t_pts
+        if len < 4 then error("not enough points", 3) end
 
         if bClosed then
-            pt_first_last = t_points[1]
+            pt_first_last = {t_pts[1] * scale_x, t_pts[2] * scale_y}
         else
-            pt_first_last = t_points[#t_points]
+            pt_first_last = {t_pts[len - 1] * scale_x, t_pts[len] * scale_y}
         end
 
-        for i = 1, #t_points, 1 do
-            local pt1 = t_points[i]
-
-            local pt2 = t_points[i + 1] or pt_first_last-- first and last point
+        pt2 = {t_pts[1] * scale_x, t_pts[2] * scale_y}
+        for i = 3, len + 2, 2 do
+            pt1 = pt2
+            if t_pts[i + 1] == nil then 
+                pt2 = pt_first_last
+            else
+                pt2 = {t_pts[i] * scale_x, t_pts[i + 1] * scale_y}
+            end-- first and last point
 
             _line(img, pt1[1] + x, pt1[2] + y, pt2[1] + x, pt2[2] + y, color, bClip)
+            if pt1[1] > max_x then max_x = pt1[1] end
+            if pt1[2] > max_y then max_y = pt1[2] end
         end
-
+        if pt2[1] > max_x then max_x = pt2[1] end
+        if pt2[2] > max_y then max_y = pt2[2] end
+        return max_x + x, max_y + y
     end
 
-    -- draws a closed figure based on points in t_points
-    _poly.polygon = function(img, x, y, t_points, color, fillcolor, bClip)
-        if #t_points < 2 then error("not enough points", 3) end
+    -- draws a closed figure based on points in t_pts
+    _poly.polygon = function(img, x, y, t_pts, color, fillcolor, bClip, scale_x, scale_y)
+        scale_x = scale_x or 1
+        scale_y = scale_y or 1
+        if #t_pts < 2 then error("not enough points", 3) end
 
         if fillcolor then
-                local x_min, x_max = 0, 0
-                local y_min, y_max = 0, 0
-                local w, h = 0, 0
-                -- find boundries of polygon
-                for i = 1, #t_points, 1 do
-                    local pt = t_points[i]
-                    if pt[1] < x_min then x_min = pt[1] end
-                    if pt[1] > x_max then x_max = pt[1] end
-                    if pt[2] < y_min then y_min = pt[2] end
-                    if pt[2] > y_max then y_max = pt[2] end
-                end
-                w = _abs(x_max) + _abs(x_min)
-                h = _abs(y_max) + _abs(y_min)
-                x_min = x_min - 2  -- leave a border to use flood_fill
-                y_min = y_min - 2
+            flood_fill = flood_fill or require("draw_floodfill")
+            local x_min, x_max = 0, 0
+            local y_min, y_max = 0, 0
+            local w, h = 0, 0
+            local pt1, pt2
+            -- find boundries of polygon
+            for i = 1, #t_pts, 2 do
+                if t_pts[i] < x_min then x_min = t_pts[i] end
+                if t_pts[i] > x_max then x_max = t_pts[i] end
 
-                local fill_img = _newimg(w + 3, h + 3)
-                _clear(fill_img, 0x1)
+                if t_pts[i+1] < y_min then y_min = t_pts[i+1] end
+                if t_pts[i+1] > y_max then y_max = t_pts[i+1] end
+            end
+            x_max = x_max * scale_x
+            x_min = x_min * scale_x
+            y_max = y_max * scale_y
+            y_min = y_min * scale_y
+            w = _abs(x_max) + _abs(x_min)
+            h = _abs(y_max) + _abs(y_min)
+            x_min = -(x_min - 2)  -- leave a border to use flood_fill
+            y_min = -(y_min - 2)
 
-                for i = 1, #t_points, 1 do
-                    local pt1 = t_points[i]
-                    local pt2 = t_points[i + 1] or t_points[1]-- first and last point
-                    _line(fill_img, pt1[1] - x_min, pt1[2] - y_min,
-                                      pt2[1]- x_min, pt2[2] - y_min, 0)
+            local fill_img = _newimg(w + 3, h + 3)
+            _clear(fill_img, 0x1)
 
-                end
+            polyline(fill_img, x_min, y_min, t_pts,
+                     0x0, true, bClip, scale_x, scale_y)
+            -- flood the outside of the figure with 0 the inside will be fillcolor
             flood_fill(fill_img, fill_img:width(), fill_img:height() , 0x1, 0x0)
-            _copy(img, fill_img, x - 1, y - 1, _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor)
+            _copy(img, fill_img, x - 1, y - 1,
+                  _NIL, _NIL, _NIL, _NIL, bClip, BSAND, fillcolor)
         end
 
-        polyline(img, x, y, t_points, color, true, bClip)
+        polyline(img, x, y, t_pts, color, true, bClip, scale_x, scale_y)
     end
 
     -- expose internal functions to the outside through _poly table
diff --git a/apps/plugins/lua/include_lua/poly_points.lua b/apps/plugins/lua/include_lua/poly_points.lua
new file mode 100644
index 0000000..d313710
--- /dev/null
+++ b/apps/plugins/lua/include_lua/poly_points.lua
@@ -0,0 +1,118 @@
+--PolyPoints.lua
+--[[
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2017 William Wilgus
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+]]
+
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+-- decodes ascii string back to t_pts
+function points_from_ascii(encstr, scale)
+    scale = scale or 1
+    local t_pts = {}
+    encstr = encstr or "00000008"
+    local chroffset = tonumber(string.sub(encstr, 1, 3)) or 0
+    local chrlen = tonumber(string.sub(encstr, 4, 8)) or 0
+
+    if string.len(encstr) ~= chrlen then
+        error("Invalid Points String" .. string.len(encstr), 2)
+    end
+
+    for i = 9, string.len(encstr) - 1, 2 do
+        local x = string.byte(encstr, i, i) - chroffset
+        local y = string.byte(encstr, i + 1, i + 1) - chroffset
+        t_pts[#t_pts + 1] = x * scale
+        t_pts[#t_pts + 1] = y * scale
+    end
+    return t_pts
+end
+--------------------------------------------------------------------------------
+-- encodes t_pts as a ascii string non print chars are excluded so
+-- size is limited to approx ~ 90x90
+function points_to_ascii(t_pts)
+    if not t_pts then return "" end
+    local chroffset = 33
+    local maxoffset = 126 - 33
+    local t_enc = {[1] = string.format("%03d%05d", chroffset, #t_pts + 8)}
+    local max_n, min_n = 0, 0
+    for i = 1, #t_pts, 2 do
+        if t_pts[i] > max_n then max_n = t_pts[i] end
+        if t_pts[i] < min_n then min_n = t_pts[i] end
+        if t_pts[i+1] > max_n then max_n = t_pts[i+1] end
+        if t_pts[i+1] < min_n then min_n = t_pts[i+1] end
+        if max_n > maxoffset or min_n < 0 then break; end
+        t_enc[#t_enc + 1] = string.char(t_pts[i] + chroffset)
+        t_enc[#t_enc + 1] = string.char(t_pts[i+1] + chroffset)
+    end
+	if min_n >= 0 and (max_n - min_n) <= maxoffset then
+        return  table.concat(t_enc)
+    else
+        return "00000008"
+    end
+end
+--------------------------------------------------------------------------------
+-- scales t_pts by percentage (x/y)
+function points_scale_pct(t_pts, x_pct, y_pct)
+    for i = 1, #t_pts, 2 do
+        local t_pt = {t_pts[i], t_pts[i + 1]}
+        t_pt = t_pt or {0, 0}
+        t_pts[i] = (t_pt[1] * x_pct) / 100
+        t_pts[i+1] = (t_pt[2] * y_pct) / 100
+    end
+    return t_pts
+end
+--------------------------------------------------------------------------------
+-- scales t_pts by (x/y)
+function points_scale(t_pts, width, height)
+    local max_x, max_y = 0, 0
+    for i = 1, #t_pts, 2 do
+        if t_pts[i] > max_x then max_x = t_pts[i] end
+        if t_pts[i+1] > max_y then max_y = t_pts[i+1] end
+    end
+
+    local x_pct = (width * 100) / max_x
+    local y_pct = (height * 100) / max_y
+
+    return points_scale_pct(t_pts, x_pct, y_pct)
+end
+--------------------------------------------------------------------------------
+--[[
+    function scaleup(t_pts, scale_x, scale_y)
+        local t_coord
+        for key,value in pairs(t_pts) do
+            t_coord = t_pts[key]
+            t_coord[1] = t_coord[1] * scale_x
+            t_coord[2] = t_coord[2] * scale_y
+            t_pts[key] = t_coord
+        end
+    end
+
+    function scaledn(t_pts, scale_x, scale_y)
+        local t_coord
+        for key,value in pairs(t_pts) do
+            t_coord = t_pts[key]
+            t_coord[1] = t_coord[1] / scale_x
+            t_coord[2] = t_coord[2] / scale_y
+            t_pts[key] = t_coord
+        end
+    end
+]]
diff --git a/apps/plugins/lua/lua.make b/apps/plugins/lua/lua.make
index 388c5d7..66c1e67 100644
--- a/apps/plugins/lua/lua.make
+++ b/apps/plugins/lua/lua.make
@@ -17,9 +17,9 @@
 
 LUA_INCLUDEDIR := $(LUA_SRCDIR)/include_lua
 LUA_INCLUDELIST := $(addprefix $(LUA_BUILDDIR)/,audio.lua blit.lua color.lua draw.lua draw_floodfill.lua draw_poly.lua \
-						draw_text.lua image.lua image_save.lua lcd.lua math_ex.lua print.lua \
-						timer.lua playlist.lua pcm.lua sound.lua \
-						rbcompat.lua printtable.lua)
+						draw_num.lua draw_text.lua image.lua image_save.lua lcd.lua math_ex.lua \
+						print.lua timer.lua playlist.lua pcm.lua sound.lua \
+						rbcompat.lua poly_points.lua printtable.lua)
 
 
 ifndef APP_TYPE