zoukankan      html  css  js  c++  java
  • 用Lua做了个绘制二元等式或不等式的图像的软件

    输入任意的包含x和y两个变量的Lua表达式就可以绘制出对应的图像。Lua支持的运算符如下:

    算术 + - * / % ^
    比较 == ~= < > <= >=
    逻辑 and or not

    其中%是求余,^是乘方;需要注意的是相等用==,写=则报语法错误。 Lua预定义的数学函数参见Reference Manual的mathlib。软件界面如下:

    绘图的算法很简单,遍历每一个像素点,如果对应的坐标区域满足表达式给出的条件就给这个像素着色。

    需要特别说明的是Pixel Split的含义,每个像素点并不是对应一对坐标值,而是对应一个矩形区域,因此对于某些函数需要做细分才能画准确一点。比如输入8表示细分为8x8=64个网格点,只要有一个格点满足表达式给出的条件就给像素着色。细分的数字越大所需的计算量也就越大,建议取1到50之间的数字。

    在表达式中使用逻辑运算符可以将一些图形组合起来显示,比如:

    画布的大小和一些参数的默认值可以在配置文件中修改,配置文件中还包括了收藏夹的定义,预置一些比较有趣的表达式,文件名是Favorites.lua,可以用记事本编辑,然后重新打开程序生效。

    做这个软件的想法是看了《几个令人惊叹的函数图像》一文,文中提到作图软件GrafEq比较古老,很多系统不兼容了。另外最近正在学Lua,正好实践一下。而且用Lua很适合,提供了以下几个便利:

    1. 可以把用户输入的表达式文本转化为一个函数:

        local expr = iup.GetDialogChild(dlg, "exprtext").value
        
    local func, err = loadstring("return function (x,y) return ".. expr.." end")
        
    if func==nil then iup.Message("Error""Expression has syntax errors:\r\n"..err) return end
        equation 
    = func()

    2. 一句话就能载入配置文件:

    dofile("Favorites.lua")

    3. 配置文件本身是一个合法的Lua程序,因而用户可以在里面自定义一些函数。

    比如这个图用到了自定义的belongto函数:

    function between(x, minValue, maxValue)
        
    return x >= minValue and x <= maxValue
    end

    function belongto(x, ranges)
       
    for _,range in ipairs(ranges) do
            
    if between(x, range[1], range[2]) then return true end
       
    end
       
    return false
    end

    表达式为:belongto(sin(sqrt((x+5)^2+y^2))*cos(8*atan(y/(x+5)))*sin(sqrt((x-5)^2+(y-5)^2))*cos(8*atan((y-5)/(x-5)))*sin(sqrt(x^2+(y+5)^2))*cos(8*atan((y+5)/x)), {{-0.1,0},{0.2,math.huge}})

    这个软件有两种玩法:一是输入表达式观察对应的图形,二是预想一个图案,然后设计表达式生成想要的图形。

    就实用性而言,一是对学数学的中学生会很有用,二是生成的图案可以用于其他的平面或3D绘图软件。

    可以设定画布的背景色和画笔的颜色,可以保存图片到文件中。

    下面是程序的源代码,只有204行:

    View Code
      1 -- GraphPlot.wlua
      2 -- Plot any Lua expression in two variables x and y
      3 -- Junfeng Liu @ 2011-06-27
      4 
      5 require"cdlua"
      6 require"iuplua"
      7 require"iupluacd"
      8 
      9 setmetatable(_G, { __index = math })
     10 = exp(1)
     11 
     12 -- Load Config and Favorites
     13 dofile("Favorites.lua")
     14 pixels = {}
     15 for r=1,Config.Height do
     16   pixels[r] = {}
     17   for c=1,Config.Width do
     18         pixels[r][c] = false
     19   end
     20 end
     21 
     22 cnv = iup.canvas{ rastersize=string.format("%dx%d", Config.Width, Config.Height) }
     23 treeFavorite = iup.tree{ size = "100x100"}
     24 
     25 canvasColor = cd.EncodeColor(255,255,255)
     26 penColor = cd.EncodeColor(0,0,0)
     27 
     28 function selectColor(self)
     29   r,g,b = iup.GetColor(iup.CENTER,iup.CENTER)
     30  self.bgcolor = string.format("%d %d %d",r,g,b)
     31  if self.name == "btnPen" then penColor = cd.EncodeColor(r,g,b)
     32  else canvasColor = cd.EncodeColor(r,g,b) end
     33 end
     34 
     35 dlg = iup.dialog
     36 {
     37     title="Plot graphs of equations and inequalities in two vairables",
     38     resize="NO",
     39     minbox="NO",
     40     iup.hbox
     41     {
     42         iup.vbox
     43         {
     44            iup.frame
     45            {
     46                title = "Color",
     47                iup.hbox
     48                {
     49                     iup.label{title = " Canvas: "},
     50                     iup.button{ name = "btnCanvas", size = "22x10", bgcolor="255 255 255", flat="YES", action = selectColor},
     51                     iup.label{title = " Pen: "},
     52                     iup.button{ name = "btnPen", size = "22x10", bgcolor="0 0 0", flat="YES", action = selectColor},
     53                     alignment = "ACENTER"
     54                }
     55            },
     56            iup.frame
     57            {
     58                title = "Range",
     59                iup.vbox
     60                {
     61                     iup.hbox
     62                     {
     63                         iup.label{title = "X: "},
     64                         iup.text{ name = "txtXMin", size = "38x10", value = Config.Xmin},
     65                         iup.label{title = " ~ "},
     66                         iup.text{ name = "txtXMax", size = "38x10", value = Config.Xmax}
     67                     },
     68                     iup.hbox
     69                     {
     70                         iup.label{title = "Y: "},
     71                         iup.text{ name = "txtYMin", size = "38x10", value = Config.Ymin},
     72                         iup.label{title = " ~ "},
     73                         iup.text{ name = "txtYMax", size = "38x10", value = Config.Ymax}
     74                     }
     75                }
     76            },
     77            iup.hbox
     78            {
     79                 iup.label{ title = "Pixel Split: " },
     80                 iup.text{ name = "txtSplit", value = Config.Split},
     81                 alignment = "ACENTER"
     82            },
     83            treeFavorite,
     84            margin = "2x2"
     85         },
     86         iup.vbox
     87         {
     88             iup.hbox
     89             {
     90                 iup.label{title = "Expression: "},
     91                 iup.text{ name = "exprtext", rastersize = (Config.Width-120).."x22", value = "abs(x - y) % 20 < 0.0001"},
     92                 iup.button{title = "Plot", size = "34x12", action = function() plotExpression() end},
     93                 alignment = "ACENTER"
     94             },
     95             cnv,
     96             margin = "2x2"
     97         }
     98     }
     99 }
    100 
    101 function getNumber(name)
    102     return tonumber(iup.GetDialogChild(dlg, name).value)
    103 end
    104 
    105 function setTextValue(name, value)
    106     iup.GetDialogChild(dlg, name).value = value
    107 end
    108 
    109 function plotExpression()
    110     local expr = iup.GetDialogChild(dlg, "exprtext").value
    111     local func, err = loadstring("return function (x,y) return ".. expr.." end")
    112     if func==nil then iup.Message("Error""Expression has syntax errors:\r\n"..err) return end
    113     equation = func()
    114     drawing = true
    115     iup.Redraw(cnv, 0)
    116 end
    117 
    118 function cnv:map_cb()
    119   canvas = cd.CreateCanvas(cd.IUP, self)
    120 end
    121 
    122 drawing = false
    123 function cnv:action()
    124   canvas:Activate()
    125   canvas:Background(canvasColor)
    126   canvas:Clear()
    127   local width = Config.Width
    128   local height = Config.Height
    129   if drawing == false then
    130     for r=height,1,-1 do
    131       for c=1,width do
    132           if pixels[r][c] then
    133             canvas:Pixel(c, r, penColor)
    134           end
    135       end
    136     end
    137     return
    138   end
    139 
    140   dlg.active = "NO"
    141   local xMin = getNumber("txtXMin")
    142   local xMax = getNumber("txtXMax")
    143   local yMin = getNumber("txtYMin")
    144   local yMax = getNumber("txtYMax")
    145   local split = getNumber("txtSplit")
    146   local DX = (xMax - xMin)/width
    147   local DY = (yMax - yMin)/height
    148   local dx = DX / split
    149   local dy = DY / split
    150   local x = xMin
    151   local y = yMax
    152   for r=height,1,-1 do
    153       for c=1,width do
    154         local fill = isSolution(x,y,dx,dy,split)
    155         pixels[r][c] = fill
    156         if fill then
    157             canvas:Pixel(c, r, penColor)
    158         end
    159         x = x + DX
    160       end
    161       x = xMin
    162       y = y - DY
    163   end
    164   drawing = false
    165   dlg.active = "YES"
    166 end
    167 
    168 function isSolution(x0,y0,dx,dy,split)
    169     local x = x0
    170     local y = y0
    171     for i=1,split do
    172         for j=1,split do
    173             if equation(x, y) then return true end
    174             x = x + dx
    175         end
    176         x = x0
    177         y = y - dy
    178     end
    179     return false
    180 end
    181 
    182 function treeFavorite:selection_cb(id, status)
    183     if status == 1 then
    184         node = Favorites[id]
    185         setTextValue("exprtext", node.tip)
    186         if node.config ~= nil then
    187             setTextValue("txtXMin", node.config.Xmin)
    188             setTextValue("txtXMax", node.config.Xmax)
    189             setTextValue("txtYMin", node.config.Ymin)
    190             setTextValue("txtYMax", node.config.Ymax)
    191             setTextValue("txtSplit", node.config.Split)
    192         end
    193     end
    194 end
    195 
    196 function dlg:close_cb()
    197   canvas:Kill()
    198   self:destroy()
    199   return iup.IGNORE
    200 end
    201 
    202 dlg:show()
    203 iup.TreeAddNodes(treeFavorite, Favorites)
    204 iup.MainLoop()

    最后程序用wsrlua工具做了打包,不需要安装Lua环境就能运行,由于是GUI程序需要msvcr100.dll,没有的话另外下载。

    下载地址1

    下载地址2

  • 相关阅读:
    spring boot 2 统一异常处理
    spring boot 2.0.4 Redis缓存配置
    windows下consul利用json文件注册服务
    docker安装portainer
    Docker 清理命令
    git command line 提交代码
    java应用健康检查
    springboot @Value获取值为空,解决办法
    解决You have new mail in /var/spool/mail/root提示
    kafka之kafka的伪分布式安装
  • 原文地址:https://www.cnblogs.com/rufi/p/GraphPlot.html
Copyright © 2011-2022 走看看