Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- picture.lua: classes to create LaTeX pictures (and ascii representations). -- This file: -- http://angg.twu.net/dednat6/dednat6/picture.lua -- http://angg.twu.net/dednat6/dednat6/picture.lua.html -- (find-angg "dednat6/dednat6/picture.lua") -- -- This file defines a class LPicture that generates LaTeX -- pict2e diagrams, and a class AsciiPicture for ascii -- representations of the same diagrams. The classes for mixed -- LaTeX/ascii pictures are elsewhere, at: -- -- (find-dn6 "zhas.lua" "MixedPicture") -- -- This file is a full rewrite of: -- (find-angg "LUA/picture.lua" "Picture") -- -- IMPORTANT! Until 2015 I didn't know that pict2e existed, and I used -- picture-mode instead. The code here still has some fossils from -- that time. See the comments in this section: (to "pict2e") -- -- BAD NEWS: the description above may give the impression that this -- module is quite general, but this is currently not the case... this -- module is used by my super-hacky code for handling finite planar -- Heyting Algebras, a.k.a. ZHAs, and is not independent from it. =( -- -- -- «.V» (to "V") -- «.V-tests» (to "V-tests") -- «.BoundingBox» (to "BoundingBox") -- «.BoundingBox-tests» (to "BoundingBox-tests") -- «.AsciiPicture» (to "AsciiPicture") -- «.AsciiPicture-tests» (to "AsciiPicture-tests") -- «.metaopts» (to "metaopts") -- «.copyopts» (to "copyopts") -- «.copyopts-tests» (to "copyopts-tests") -- «.makepicture» (to "makepicture") -- «.makepicture-tests» (to "makepicture-tests") -- «.texarrow» (to "texarrow") -- «.pict2e» (to "pict2e") -- «.pict2e-vector» (to "pict2e-vector") -- «.pict2e-test» (to "pict2e-test") -- «.pict2evector-test» (to "pict2evector-test") -- «.LPicture» (to "LPicture") -- «.LPicture-tests» (to "LPicture-tests") -- -- Obsolete (to be deleted): -- «.Picture» (to "Picture") -- «.Picture-tests» (to "Picture-tests") require "output" -- (find-dn6 "output.lua" "formatt") -- ____ ____ _ -- |___ \| _ \ __ _____ ___| |_ ___ _ __ ___ -- __) | | | | \ \ / / _ \/ __| __/ _ \| '__/ __| -- / __/| |_| | \ V / __/ (__| || (_) | | \__ \ -- |_____|____/ \_/ \___|\___|\__\___/|_| |___/ -- -- This class supports the usual operations on 2D vectors and also the -- logical operations on elements of a ZHA - even the implication, -- IIRC... -- «V» (to ".V") V = Class { type = "V", -- __tostring = function (v) return "("..v[1]..","..v[2]..")" end, __tostring = function (v) return pformat("(%s,%s)", v[1], v[2]) end, __add = function (v, w) return V{v[1]+w[1], v[2]+w[2]} end, __sub = function (v, w) return V{v[1]-w[1], v[2]-w[2]} end, __unm = function (v) return v*-1 end, __mul = function (v, w) local ktimesv = function (k, v) return V{k*v[1], k*v[2]} end local innerprod = function (v, w) return v[1]*w[1] + v[2]*w[2] end if type(v) == "number" and type(w) == "table" then return ktimesv(v, w) elseif type(v) == "table" and type(w) == "number" then return ktimesv(w, v) elseif type(v) == "table" and type(w) == "table" then return innerprod(v, w) else error("Can't multiply "..tostring(v).."*"..tostring(w)) end end, -- -- isdd = function (s) -- return type(s) == "string" and s:match"^%d%d$" -- end, -- ispxcyp = function (s) -- return type(s) == "string" and s:match"^%((.-),(.-)%)$" -- end, -- fromdd = function (s) return V{s:sub(1,1)+0, s:sub(2,2)+0} end, -- frompxcyp = function (s) -- local x, y = a:match("^%((.-),(.-)%)$") -- return V{x+0, y+0} -- end, -- fromab = function (a, b) if type(a) == "table" then return a elseif type(a) == "number" then return V{a,b} elseif type(a) == "string" then local x, y = a:match("^%((.-),(.-)%)$") if x then return V{x+0, y+0} end local l, r = a:match("^(%d)(%d)$") if l then return V{tonumber(l), tonumber(r)}:lrtoxy() end local l, r, ensw = a:match("^(%d)(%d)([ensw])$") if l then return V{tonumber(l), tonumber(r)}:lrtoxy():walk(ensw) end error("V() got bad string: "..a) end end, __call = function () print "hi" end, __index = { xytolr = function (v) local x, y = v[1], v[2] local l = toint((y - x) / 2) local r = toint((y + x) / 2) return V{l, r} end, lrtoxy = function (v) local l, r = v[1], v[2] local x = r - l local y = r + l return V{x, y} end, todd = function (v) return v[1]..v[2] end, to12 = function (v) return v[1], v[2] end, to_x_y = function (v) return v:to12() end, to_l_r = function (v) return v:xytolr():to12() end, xy = function (v) return "("..v[1]..","..v[2]..")" end, lr = function (v) local l, r = v:to_l_r(); return l..r end, torowcol = function (v, nlines, w, rectw) local x, y = v[1], v[2] if checkrange(0, y, nlines-1) and checkrange(0, x, rectw/w - 1) then return nlines-y, x*w+1 end end, naiveprod = function (v, w) return V{v[1]*w[1], v[2]*w[2]} end, naivemin = function (v, w) return V{min(v[1], w[1]), min(v[2], w[2])} end, naivemax = function (v, w) return V{max(v[1], w[1]), max(v[2], w[2])} end, s = function (v) return v+V{ 0, -1} end, n = function (v) return v+V{ 0, 1} end, w = function (v) return v+V{-1, 0} end, e = function (v) return v+V{ 1, 0} end, se = function (v) return v+V{ 1, -1} end, sw = function (v) return v+V{-1, -1} end, ne = function (v) return v+V{ 1, 1} end, nw = function (v) return v+V{-1, 1} end, walk = function (v, ensw) return v[ensw](v) end, -- to_l_r_l_r = function (P, Q) -- local Pl,Pr = P:to_l_r() -- local Ql,Qr = Q:to_l_r() -- return Pl, Pr, Ql, Qr -- end, -- And = function (P, Q) -- local Pl, Pr, Ql, Qr = P:to_l_r_l_r(Q) local Pl, Pr = P:to_l_r() local Ql, Qr = Q:to_l_r() return V{min(Pl, Ql), min(Pr, Qr)}:lrtoxy() end, Or = function (P, Q) -- local Pl, Pr, Ql, Qr = P:to_l_r_l_r(Q) local Pl, Pr = P:to_l_r() local Ql, Qr = Q:to_l_r() return V{max(Pl, Ql), max(Pr, Qr)}:lrtoxy() end, -- above = function (P, Q) local Pl, Pr = P:to_l_r() local Ql, Qr = Q:to_l_r() return Pl >= Ql and Pr >= Qr end, below = function (P, Q) local Pl, Pr = P:to_l_r() local Ql, Qr = Q:to_l_r() return Pl <= Ql and Pr <= Qr end, leftof = function (P, Q) local Pl, Pr = P:to_l_r() local Ql, Qr = Q:to_l_r() return Pl >= Ql and Pr <= Qr end, rightof = function (P, Q) local Pl, Pr = P:to_l_r() local Ql, Qr = Q:to_l_r() return Pl <= Ql and Pr >= Qr end, }, } v = V.fromab lr = function (l, r) return V{l, r}:lrtoxy() end -- lr = function (l, r) -- if V.isdd(l) then return V.fromdd(l):lrtoxy() end -- return V{l, r}:lrtoxy() -- end -- «V-tests» (to ".V-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" = V{3,4} --> (3,4) = V{3,4} - V{2,1} --> (1,3) = V{3,4} + V{2,1} --> (5,5) = V{3,4} * V{2,1} --> 10 = V{3,4} * -10 --> (-30,-40) = -10 * V{3,4} --> (-30,-40) = V{-3,3}:xytolr() --> (3,0) = V{3,3}:xytolr() --> (0,3) = V{2,4}:xytolr() --> (1,3) dofile "zhas.lua" = V{0,0}:torowcol(4, 2, 6) --> 4 1 = V{1,0}:torowcol(4, 2, 6) --> 4 3 = V{2,0}:torowcol(4, 2, 6) --> 4 5 = V{3,0}:torowcol(4, 2, 6) --> (nothing) = V{0,1}:torowcol(4, 2, 6) --> 3 1 = V{0,2}:torowcol(4, 2, 6) --> 3 5 = V{0,3}:torowcol(4, 2, 6) --> 3 5 = V{0,4}:torowcol(4, 2, 6) --> (nothing) • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" = v{2, 3} = v(2, 3) = v(2, 3):to12() • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" = v"20" = v"02" = v"22" -- Obsolete and broken: = lr"00" -- err? = lr"10" -- err? = lr"03" -- err? = lr"03":s() -- err? --]] -- ____ _ _ ____ -- | __ ) ___ _ _ _ __ __| (_)_ __ __ _| __ ) _____ __ -- | _ \ / _ \| | | | '_ \ / _` | | '_ \ / _` | _ \ / _ \ \/ / -- | |_) | (_) | |_| | | | | (_| | | | | | (_| | |_) | (_) > < -- |____/ \___/ \__,_|_| |_|\__,_|_|_| |_|\__, |____/ \___/_/\_\ -- |___/ -- A BoundingBox object contains: -- a field "x0x0" with a V object (the lower left corner), -- a field "x1x1" with a V object (the upper right corner). -- -- «BoundingBox» (to ".BoundingBox") BoundingBox = Class { type = "BoundingBox", new = function () return BoundingBox {} end, __tostring = function (bb) -- return bb.x0y0 and tostring(bb.x0y0).." to "..tostring(bb.x1y1) or "empty" if bb.x0y0 then return "BoundingBox: \n (x1,y1)="..tostring(bb.x1y1).. "\n (x0,y0)="..tostring(bb.x0y0) else return "BoundingBox: empty" end end, __index = { addpoint = function (bb, v) if bb.x0y0 then bb.x0y0 = bb.x0y0:naivemin(v) else bb.x0y0 = v end if bb.x1y1 then bb.x1y1 = bb.x1y1:naivemax(v) else bb.x1y1 = v end return bb end, addbox = function (bb, v, delta0, delta1) bb:addpoint(v+delta0) return bb:addpoint(v+(delta1 or -delta0)) end, x0y0x1y1 = function (bb) local x0, y0 = bb.x0y0:to_x_y() local x1, y1 = bb.x1y1:to_x_y() return x0, y0, x1, y1 end, x0x1y0y1 = function (bb) local x0, y0 = bb.x0y0:to_x_y() local x1, y1 = bb.x1y1:to_x_y() return x0, x1, y0, y1 end, -- merge = function (bb1, bb2) if bb2.x0y0 then bb1:addpoint(bb2.x0y0) end if bb2.x1y1 then bb1:addpoint(bb2.x1y1) end return bb1 end, }, } -- «BoundingBox-tests» (to ".BoundingBox-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" bb = BoundingBox.new() PP(bb) = bb = bb:addpoint(v(2, 4)) PP(bb) = bb:addbox(v(6, 7), v(.5, .5)) = bb:addbox(v(1, 2), v(.5, .5)) = bb:x0x1y0y1() PP(bb) --]] -- _ _ _ ____ _ _ -- / \ ___ ___(_|_) _ \(_) ___| |_ _ _ _ __ ___ -- / _ \ / __|/ __| | | |_) | |/ __| __| | | | '__/ _ \ -- / ___ \\__ \ (__| | | __/| | (__| |_| |_| | | | __/ -- /_/ \_\___/\___|_|_|_| |_|\___|\__|\__,_|_| \___| -- -- «AsciiPicture» (to ".AsciiPicture") -- This is a minimalistic, and V-based, reimplementation of the -- ascii side of the "Picture" class from: -- (find-dn6 "picture.lua" "Picture") pad = function (spaces, str) return ((str or "")..spaces):sub(1, #spaces) end AsciiPicture = Class { type = "AsciiPicture", new = function (s) return AsciiPicture {s=s or " ", bb=BoundingBox.new()} end, __tostring = function (ap) return ap:tostring() end, __index = { get = function (ap, v) return pad(ap.s, ap:get0(v)) end, get0 = function (ap, v) local x, y = v:to_x_y() return ap[y] and ap[y][x] end, put = function (ap, v, str) local x, y = v:to_x_y() ap[y] = ap[y] or {} ap[y][x] = str ap.bb:addpoint(v) return ap end, -- tolines = function (ap) if not ap.bb.x0y0 then return {} end -- empty local x0, x1, y0, y1 = ap.bb:x0x1y0y1() local lines = {} for y=y1,y0,-1 do local line = "" for x=x0,x1 do line = line..ap:get(v(x, y)) end table.insert(lines, line) end return lines end, tostring = function (ap) return table.concat(ap:tolines(), "\n") end, print = function (ap) print(ap); return ap end, }, } -- «AsciiPicture-tests» (to ".AsciiPicture-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" ap = AsciiPicture.new(" ") ap = AsciiPicture.new(" ") ap = AsciiPicture.new(" ") for l=0,2 do for r=0,3 do local pos=lr(l, r) ap:put(pos, "..") ap:put(pos, pos:lr()) ap:put(pos, pos:xy()) end end = ap PPV(ap) • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" ap = AsciiPicture.new(" ") PP(ap) PP(ap.bb) = ap = ap.bb ap = AsciiPicture.new(" "):put(v(1,1)," ") = ap = ap:put(v(1,1), "..") = ap = ap.bb PP(ap) --]] -- _ -- ___ ___ _ __ _ _ ___ _ __ | |_ ___ -- / __/ _ \| '_ \| | | |/ _ \| '_ \| __/ __| -- | (_| (_) | |_) | |_| | (_) | |_) | |_\__ \ -- \___\___/| .__/ \__, |\___/| .__/ \__|___/ -- |_| |___/ |_| -- -- An _UGLY_ hack to let me specify options for makepicture in a compact way. -- A call to copyopts(A, B) copies the options in the table A to the table B. -- If there is a field "meta" in A it is treated in a special way: -- -- copyopts({foo=2, bar=3, meta="s ()"}, B) -- -- works as this, but in an unspecified order: -- -- copyopts({foo=2, bar=3}, B) -- copyopts(metaopts["s"], B) -- copyopts(metaopts["()"], B) -- -- Used by: (find-dn6 "zhas.lua" "MixedPicture" "LPicture.new(options)") -- (find-dn6 "picture.lua" "LPicture" "new" "copyopts(opts, lp)") -- -- «copyopts» (to ".copyopts") -- copyopts = function (A, B) if type(A) == "string" then for _,name in ipairs(split(A)) do local tbl = metaopts[name] or error("No metaopt[\""..A.."\"]") copyopts(tbl, B) end return B -- Old: -- if A:match(" ") then -- for _,str in ipairs(split(A)) do copyopts(str, B) end -- return B -- else -- local mopts = metaopts[A] or error("No metaopt[\""..A.."\"]") -- return copyopts(mopts, B) -- end end for key,val in pairs(A) do if key == "meta" then copyopts(val, B) else B[key] = val end end return B end -- «metaopts» (to ".metaopts") -- metaopts = {} metaopts["b"] = {bhbox = 1} metaopts["p"] = {paren = 1} metaopts["()"] = {paren = 1} metaopts["{}"] = {curly = 1} metaopts["s"] = {cellfont="\\scriptsize", celllower="2pt"} metaopts["ss"] = {cellfont="\\scriptscriptsize", celllower="1.5pt"} -- ? metaopts["t"] = {cellfont="\\tiny", celllower="1.5pt"} -- ? metaopts["t"] = {cellfont="\\tiny", celllower="1.25pt"} -- ? metaopts["10pt"] = {scale="10pt"} metaopts["8pt"] = {scale="8pt", meta="s"} -- -- metaopts that are mainly for TCGs: metaopts["1pt"] = {scale="1pt"} -- «copyopts-tests» (to ".copyopts-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" testcopyopts = function (A) PP(copyopts(A, {})) end testcopyopts "8pt" testcopyopts "8pt ()" testcopyopts {foo=2, bar=3} testcopyopts {foo=2, bar=3, meta="8pt"} testcopyopts {foo=2, bar=3, meta="8pt ()"} testcopyopts {foo=2, bar=3} --]] -- _ _ _ -- _ __ ___ __ _| | _____ _ __ (_) ___| |_ _ _ _ __ ___ -- | '_ ` _ \ / _` | |/ / _ \ '_ \| |/ __| __| | | | '__/ _ \ -- | | | | | | (_| | < __/ |_) | | (__| |_| |_| | | | __/ -- |_| |_| |_|\__,_|_|\_\___| .__/|_|\___|\__|\__,_|_| \___| -- |_| -- -- «makepicture» (to ".makepicture") -- (find-LATEX "edrx15.sty" "picture-cells") -- makepicture = function (options, bb, body) local x0, y0, x1, y1 = bb:x0y0x1y1() local a = {} a.xdimen = x1 - x0 a.ydimen = y1 - y0 -- a.xoffset = (x0 + x1)/2 -- a.yoffset = (y0 + y1)/2 a.xoffset = x0 a.yoffset = y0 a.setscale = "\\unitlength="..(options.scale or "10pt").."%\n" a.setlower = "\\celllower="..(options.celllower or "2.5pt").."%\n" a.setfont = "\\def\\cellfont{"..(options.cellfont or "").."}%\n" a.body = body -- local fmt = "!setscale!setlower!setfont".. -- "\\begin{picture}(!xdimen,!ydimen)(!xoffset,!yoffset)\n".. -- "!body".. -- "\\end{picture}" -- 2017nov28: a.xydimen = tostring(v(a.xdimen, a.ydimen)) a.xyoffset = tostring(v(a.xoffset, a.yoffset)) local fmt = "!setscale!setlower!setfont".. "\\begin{picture}!xydimen!xyoffset\n".. "!body".. "\\end{picture}" local latex = (fmt:gsub("!([a-z]+)", a)) -- -- 2021mar02: if not options.novcenter then latex = "\\vcenter{\\hbox{"..latex.."}}" end -- if options.bhbox then latex = "\\bhbox{$"..latex.."$}" end if options.paren then latex = "\\left("..latex.."\\right)" end if options.curly then latex = "\\left\\{"..latex.."\\right\\}" end if options.def then latex = "\\def\\"..options.def.."{"..latex.."}" end -- -- 2019apr29: -- (find-es "dednat" "defzha-and-deftcg") if options.tdef then latex = "\\deftcg{"..options.tdef.."}{"..latex.."}" end if options.zdef then latex = "\\defzha{"..options.zdef.."}{"..latex.."}" end return latex end -- «makepicture-tests» (to ".makepicture-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" bb = BoundingBox.new() bb:addpoint(v(2,5)) bb:addpoint(v(4,12)) = bb opts = {} body = " hello\n" = makepicture({}, bb, body) = makepicture({def ="foo"}, bb, body) = makepicture({tdef="foo"}, bb, body) = makepicture({zdef="foo"}, bb, body) = makepicture({meta="s"}, bb, body) --]] -- _ -- | |_ _____ ____ _ _ __ _ __ _____ __ -- | __/ _ \ \/ / _` | '__| '__/ _ \ \ /\ / / -- | || __/> < (_| | | | | | (_) \ V V / -- \__\___/_/\_\__,_|_| |_| \___/ \_/\_/ -- -- «texarrow» (to ".texarrow") -- Used in: (find-dn6 "zhas.lua" "MixedPicture") -- (find-dn6 "zhas.lua" "MixedPicture" "addarrows =") -- (find-dn6 "zhas.lua" "MixedPicture" "addarrowsexcept =") -- (find-dn6 "picture.lua" "LPicture") -- (find-dn6 "picture.lua" "LPicture" "putarrow =") -- (find-dn6 "zhas.lua" "ZHA") -- (find-dn6 "zhas.lua" "ZHA" "arrows =") -- texarrow = { nw="\\nwarrow", n="\\uparrow", ne="\\nearrow", w="\\leftarrow", e="\\rightarrow", sw="\\swarrow", s="\\downarrow", se="\\searrow", } texarrow_inv = { nw="\\searrow", n="\\downarrow", ne="\\swarrow", w="\\rightarrow", e="\\leftarrow", sw="\\nearrow", s="\\uparrow", se="\\nwarrow", } texarrow_smart = function (usewhitemoves) if usewhitemoves then return texarrow_inv end return texarrow end -- Usage: local tar = texarrow_smart(usewhitemoves) -- pic:putarrow(v"34", 0, -1, tar.s) -- _ _ ____ -- _ __ (_) ___| |_|___ \ ___ -- | '_ \| |/ __| __| __) / _ \ -- | |_) | | (__| |_ / __/ __/ -- | .__/|_|\___|\__|_____\___| -- |_| -- -- «pict2e» (to ".pict2e") -- «pict2e-vector» (to ".pict2e-vector") -- In the old picture-mode a line segment and an arrow from (x0,y0) -- to (x1,y1) had to be written as: -- -- \put(x0,y0){\line(Dx,Dy){len}} -- \put(x0,y0){\arrow(Dx,Dy){len}} -- -- respectively, where: -- -- (x1,y1) = (x0,y0) + len * (Dx,Dy), -- Dx and Dy are integers between -6 and 6, and -- Dx and Dy have no common divisor. -- -- This is explained here (Dx and Dy form a "slope pair"): -- -- (find-kopkadaly4page (+ 12 294) "Straight lines") -- (find-kopkadaly4text (+ 12 294) "Straight lines") -- (find-kopkadaly4page (+ 12 294) "Straight lines" "slope pair") -- (find-kopkadaly4text (+ 12 294) "Straight lines" "slope pair") -- (find-kopkadaly4page (+ 12 294) "Arrows") -- (find-kopkadaly4text (+ 12 294) "Arrows") -- (find-kopkadaly4page (+ 12 295) "\\vector(x,y){length}") -- (find-kopkadaly4text (+ 12 295) "\\vector(x,y){length}") -- -- As I only used lines that were either vertical or had slopes 0, 1, -- or -1, my code for calculating Dx, Dy and len was just the sequence -- of "if"s below, that would not cover cases like dy/dx = 2/3... -- -- pictvector = function (x0, y0, x1, y1) -- local dx, dy = x1 - x0, y1 - y0 -- local f = function (dx, dy, len) -- return format("\\put(%.3f,%.3f){\\vector(%.3f,%.3f){%.3f}}", -- x0, y0, dx, dy, len) -- end -- if dx > 0 then return f(1, dy/dx, dx) end -- if dx < 0 then return f(-1, -dy/dx, -dx) end -- if dx == 0 and dy > 0 then return f(0, 1, dy) end -- if dx == 0 and dy < 0 then return f(0, -1, -dy) end -- error() -- end -- -- In pict2e we can create line segments and arrows with just: -- -- \Line(x0,y0)(x1,y1) -- \put(x0,y0){\arrow(dx,dy){len}} -- -- with dx=x1-x0, dy=y1-y0, len=|dx|. See: -- -- (find-pict2epage 4 "\\line and \\vector Slopes") -- (find-pict2etext 4 "\\line and \\vector Slopes") -- (find-pict2epage 4 "\\vector Slopes" "These restrictions are eliminated") -- (find-pict2etext 4 "\\vector Slopes" "These restrictions are eliminated") -- (find-pict2epage 9 "2.4.2 Lines, polygons") -- (find-pict2etext 9 "2.4.2 Lines, polygons") -- pict2eline = function (x0, y0, x1, y1) return pformat("\\Line(%s,%s)(%s,%s)", x0,y0, x1,y1) end pict2evector = function (x0, y0, x1, y1) local dx, dy = x1-x0, y1-y0 local absdx, absdy = math.abs(dx), math.abs(dy) local veryvertical = absdy > 100*absdx local f = function (Dx,Dy,len) return pformat("\\put(%s,%s){\\vector(%s,%s){%s}}", x0,y0, Dx,Dy, len) end if veryvertical then if dy > 0 then return f(0,1, dy) else return f(0,-1, -dy) end else if dx > 0 then return f(dx,dy, dx) else return f(dx,dy, -dx) end end end -- «pict2e-test» (to ".pict2e-test") -- «pict2evector-test» (to ".pict2evector-test") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" = pict2eline (1.2, 3.4, 5.6, 7.2) = pict2evector(1.2, 3.4, 5.6, 7.2) • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) loaddednat6() lp = LPicture.new({def="foo"}) for theta=0.1,2*math.pi,0.1 do local vunit = v(math.cos(theta), math.sin(theta)) lp:addlineorvector(v(0,0), vunit*theta, "vector") end lp:print() --]] -- _ ____ _ _ -- | | | _ \(_) ___| |_ _ _ _ __ ___ -- | | | |_) | |/ __| __| | | | '__/ _ \ -- | |___| __/| | (__| |_| |_| | | | __/ -- |_____|_| |_|\___|\__|\__,_|_| \___| -- -- «LPicture» (to ".LPicture") -- This is a minimalistic, and V-based, reimplementation of the -- LaTeX side of the "Picture" class from: -- (find-dn6 "picture.lua" "Picture") -- This is used by: -- (find-dn6 "zhas.lua" "MixedPicture") -- (find-dn6 "zhas.lua" "MixedPicture" "both an ascii representation and a LaTeX") LPicture = Class { type = "LPicture", new = function (opts) local lp = {latex="", bb=BoundingBox.new()} -- start empty -- for k,v in pairs(opts or {}) do lp[k] = v end -- copy options copyopts(opts, lp) return LPicture(lp) -- set metatable end, __tostring = function (lp) return lp:tolatex() end, __index = { addpoint = function (lp, v) lp.bb:addpoint(v); return lp end, put = function (lp, v, tex) local x, y = v:to_x_y() lp.latex = lp.latex .. " \\put("..x..","..y.."){\\cell{"..tex.."}}\n" lp:addpoint(v-V{.5,.5}) lp:addpoint(v+V{.5,.5}) return lp end, putarrow = function (lp, v, dx, dy, tex) lp:put(v+V{dx,dy}*0.5, tex) end, -- -- Old version with obsolete picture-mode-isms: -- addlineorvector = function (lp, src, tgt, cmd) -- lp:addpoint(src) -- lp:addpoint(tgt) -- local x0, y0 = src:to_x_y() -- local x1, y1 = tgt:to_x_y() -- local dx, dy = x1-x0, y1-y0 -- local adx, ady = math.abs(dx), math.abs(dy) -- local len = max(adx, ady) -- local udx, udy = dx/len, dy/len -- local put = " \\put("..x0..","..y0..")".. -- "{\\"..(cmd or "line").."("..udx..","..udy.."){"..len.."}}" -- lp.latex = lp.latex..put.."\n" -- end, -- addlineorvector = function (lp, src, tgt, cmd) lp:addpoint(src) lp:addpoint(tgt) local x0, y0 = src:to_x_y() local x1, y1 = tgt:to_x_y() local tex = (cmd == "vector") and pict2evector(x0,y0, x1,y1) or pict2eline (x0,y0, x1,y1) lp.latex = lp.latex.." "..tex.."\n" end, -- tolatex = function (lp) return makepicture(lp, lp.bb, lp.latex) end, -- -- 2016dec08: addtex = function (lp, tex) lp.latex = lp.latex.." "..tex.."\n"; return lp; end, addt = function (lp, ...) return lp:addtex(formatt(...)) end, rawput = function (lp, v, tex) return lp:addt("\\put%s{%s}", v, tex) end, print = function (lp) print(lp); return lp end, lprint = function (lp) print(lp:tolatex()); return lp end, output = function (lp) output(lp:tolatex()); return lp end, -- -- 2019apr28: -- (find-es "dednat" "LPicture.addrect") addrect4 = function (lp, x0, y0, x1, y1) return lp:addt("\\polygon(%s,%s)(%s,%s)(%s,%s)(%s,%s)", x0,y0, x1,y0, x1,y1, x0,y1) end, addrect2 = function (lp, x0y0, x1y1) local x0,y0 = x0y0:to_x_y() local x1,y1 = x1y1:to_x_y() return lp:addt("\\polygon(%s,%s)(%s,%s)(%s,%s)(%s,%s)", x0,y0, x1,y0, x1,y1, x0,y1) end, addrectr = function (lp, cxcy, rxry) return lp:addrect2(cxcy-rxry, cxcy+rxry) end, -- -- 2019apr28. Calls this: -- (find-LATEX "edrxtikz.lua" "Line") -- (find-LATEX "edrxtikz.lua" "Line" "pictv =") -- or: (find-dn6 "tcgs.lua" "Line") -- (find-dn6 "tcgs.lua" "Line" "pictv =") addarrow = function (lp, A, B, t0, t1) lp:addtex(Line.newAB(A, B, t0, t1):pictv()) end, }, } -- «LPicture-tests» (to ".LPicture-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" lp = LPicture.new {cellfont="\\scriptsize"} for l=0,2 do for r=0,3 do local pos=lr(l, r) lp:put(pos, pos:xy()) end end = lp • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" -- (find-angg "LUA/lua50init.lua" "pformat") V.__tostring = function (v) return format("(%.3f,%.3f)", v[1], v[2]) end V.__tostring = function (v) return format("(%s,%s)", myntos(v[1]), myntos(v[2])) end V.__tostring = function (v) return "("..myntos(v[1])..","..myntos(v[2])..")" end = v(1/3, 2/3) = tostring(v(1/3, 2/3)) LPicture.__index.addLine = function (lp, src, tgt) lp:addpoint(src) lp:addpoint(tgt) local Line = " \\Line"..tostring(src)..tostring(tgt) lp.latex = lp.latex..Line.."\n" end LPicture.__index.setthickness = function (lp, src, tgt) lp.latex = lp.latex.." \linethickness{"..thickness.."}\n" end lp = LPicture.new {} x0, x1 = 0, 10 lp:addLine(v(x0, 1/3), v(x0, 2/3)) = lp --]] -- ___ _ _ _ -- / _ \| |__ ___ ___ | | ___| |_ ___ _ -- | | | | '_ \/ __|/ _ \| |/ _ \ __/ _ (_) -- | |_| | |_) \__ \ (_) | | __/ || __/_ -- \___/|_.__/|___/\___/|_|\___|\__\___(_) -- -- ____ _ _ _ -- | _ \(_) ___| |_ _ _ _ __ ___ ___| | __ _ ___ ___ -- | |_) | |/ __| __| | | | '__/ _ \ / __| |/ _` / __/ __| -- | __/| | (__| |_| |_| | | | __/ | (__| | (_| \__ \__ \ -- |_| |_|\___|\__|\__,_|_| \___| \___|_|\__,_|___/___/ -- -- «Picture» (to ".Picture") -- We can ":put" things one by one into a Picture object, and ":totex" -- will generate a "\begin{picture}...\end{picture}" LaTeX block with -- the right size and offset. Also, ":toascii" generates an ascii -- rendering of that picture object, great for debugging and stuff. Picture = Class { type = "Picture", new = function (opts) local p = {whats={}, other={}} -- start empty for k,v in pairs(opts or {}) do p[k] = v end -- copy options return Picture(p) -- set metatable end, __index = { adjustbounds = function (p, x, y) p.minx, p.maxx = Min(p.minx, x), Max(x, p.maxx) p.miny, p.maxy = Min(p.miny, y), Max(y, p.maxy) end, put = function (p, x, y, what, what0) p:adjustbounds(x, y) -- p.minx = p.minx and min(x, p.minx) or x -- p.miny = p.miny and min(y, p.miny) or y -- p.maxx = p.maxx and max(p.maxx, x) or x -- p.maxy = p.maxy and max(p.maxy, y) or y table.insert(p.whats, {x=x, y=y, what=what, what0=what0}) return p end, lrput = function (p, l, r, what, what0) local x = r - l local y = r + l p:put(x, y, what, what0) return p end, lrputline = function (p, l, r, dxdy, len) return p:lrput(l, r, nil, format("\\line(%s){%s}", dxdy, len)) end, togrid = function (p) local lines = {} for y=p.miny,p.maxy do lines[y] = {} end for _,what in ipairs(p.whats) do lines[what.y][what.x] = what.what end return lines end, toasciilines = function (p, whitespace) local asciilines = {} local grid = p:togrid() for y=p.miny,p.maxy do for x=p.minx,p.maxx do local ascii = grid[y][x] or whitespace or " " asciilines[y] = (asciilines[y] or "")..ascii end end return asciilines end, toascii = function (p, whitespace) local asciilines = p:toasciilines(whitespace) local lines = {} for y=p.maxy,p.miny,-1 do table.insert(lines, asciilines[y]) end return table.concat(lines, "\n") end, -- -- (find-es "tex" "dags") -- (find-kopkadaly4page (+ 12 289) "13.1.3 The positioning commands") -- (find-kopkadaly4text (+ 12 289) "13.1.3 The positioning commands") -- (find-kopkadaly4page (+ 12 298) "\\put") -- (find-kopkadaly4text (+ 12 298) "\\put") totex1 = function (p, what) -- local fmt = " \\put(%s,%s){%s}\n" if what.what0 then return format(" \\put(%s,%s){%s}\n", what.x, what.y, what.what0) end local fmt = " \\put(%s,%s){\\hbox to 0pt{\\hss %s%s\\hss}}\n" return format(fmt, what.x, what.y, p.font or "", what.what) end, totexputs = function (p) local f = function (what) return p:totex1(what) end return mapconcat(f, p.whats) end, -- -- (find-kopkadaly4page (+ 12 301) "13.1.6 Shifting a picture environment") -- (find-kopkadaly4text "13.1.6 Shifting a picture environment") -- (find-texbookpage (+ 12 66) "\\raise") -- (find-texbooktext (+ 12 66) "\\raise") totex = function (p) local a = {} a.scale = p.scale or "1ex" a.xdimen = p.maxx - p.minx + 1 a.ydimen = p.maxy - p.miny + 1 a.xoffset = p.minx - 0.5 -- a.yoffset = (p.miny + p.maxy + 1) / 2 a.yoffset = p.miny a.lower = (p.maxy - p.miny) / 2 -- a.body = p:totexputs() a.body = p:totexputs()..table.concat(p.other) local fmt = "{\\unitlength=!scale\n".. "\\lower!lower\\unitlength\\hbox{".. "\\begin{picture}(!xdimen,!ydimen)(!xoffset,!yoffset)\n".. "!body".. "\\end{picture}\n".. "}}" return (fmt:gsub("!([a-z]+)", a)) end, }, } -- «Picture-tests» (to ".Picture-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "picture.lua" p = Picture.new() p:put(2, 3, "23") p:put(4, 7, "47") PP(p) PP(p:togrid()) = p:toascii() = p:totexputs() p.scale = "10pt" = p:totex() -- (find-LATEX "tmp.tex") f1 = function (p, lr) local l = lr:sub(1,1)+0 local r = lr:sub(2,2)+0 p:lrput(l, r, lr) end f = function (p, str) for _,lr in ipairs(split(str)) do f1(p, lr) end end p = Picture {whats={}} f(p, "00 01 02 03 04") f(p, "10 11 12 13 14") f(p, "22 23 24") f(p, "32 33 34") = p:toascii() p.scale = "10pt" = p:totex() -- broken --]] -- Local Variables: -- coding: utf-8-unix -- End: