From b99d4d7fa900a4f6cebd5b87420e2831fdb5a4f3 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Mon, 26 Aug 2019 22:17:33 -0500 Subject: lua optimize poly_draw add draw_number, poly_points modules Change-Id: Id36e765f18234f5a4f3092d090c0adffa3da1612 --- apps/plugins/lua/include_lua/draw_num.lua | 115 ++++++++++++++++++++++++++ apps/plugins/lua/include_lua/draw_poly.lua | 107 ++++++++++++++---------- apps/plugins/lua/include_lua/poly_points.lua | 118 +++++++++++++++++++++++++++ apps/plugins/lua/lua.make | 6 +- 4 files changed, 300 insertions(+), 46 deletions(-) create mode 100644 apps/plugins/lua/include_lua/draw_num.lua create mode 100644 apps/plugins/lua/include_lua/poly_points.lua 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 0000000000..0f42c1f9f5 --- /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 dc2783898a..23e02d0955 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 _poly = {} do 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 - - local fill_img = _newimg(w + 3, h + 3) - _clear(fill_img, 0x1) - - 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) - - end + 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 + + 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) + + local fill_img = _newimg(w + 3, h + 3) + _clear(fill_img, 0x1) + + 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 0000000000..d313710e5c --- /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 388c5d74d3..66c1e67855 100644 --- a/apps/plugins/lua/lua.make +++ b/apps/plugins/lua/lua.make @@ -17,9 +17,9 @@ OTHER_SRC += $(LUA_SRC) 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 -- cgit v1.2.3