|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://angg.twu.net/LATEX/2022pict2e.lua.html
-- http://angg.twu.net/LATEX/2022pict2e.lua
-- (find-angg "LATEX/2022pict2e.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- (defun l () (interactive) (find-angg "LATEX/2022pict2e.lua"))
-- (defun e () (interactive) (find-angg "LATEX/2022pict2e.tex"))
-- (defun eb () (interactive) (find-angg "LATEX/2022pict2e-body.tex"))
-- (defun o () (interactive) (find-angg "LATEX/2021pict2e.lua"))
-- (defun v () (interactive) (find-pdftools-page "~/LATEX/2022pict2e.pdf"))
-- (defun tb () (interactive) (find-ebuffer (eepitch-target-buffer)))
-- (defun etv () (interactive) (find-wset "13o2_o_o" '(tb) '(v)))
-- «.Show» (to "Show")
-- «.Show-tests» (to "Show-tests")
--
-- «.Pict2e» (to "Pict2e")
-- «.Pict2e-tests» (to "Pict2e-tests")
-- «.Pict2e-test-nums» (to "Pict2e-test-nums")
-- «.Pict2eVector» (to "Pict2eVector")
-- «.Pict2eVector-tests» (to "Pict2eVector-tests")
-- «.Points2» (to "Points2")
-- «.Points2-tests» (to "Points2-tests")
-- «.PictBounds» (to "PictBounds")
-- «.PictBounds-tests» (to "PictBounds-tests")
--
-- «.PwSpec» (to "PwSpec")
-- «.PwSpec-tests» (to "PwSpec-tests")
-- «.PwFunction» (to "PwFunction")
-- «.PwFunction-Riemann» (to "PwFunction-Riemann")
-- «.PwFunction-tests» (to "PwFunction-tests")
--
-- «.Expr» (to "Expr")
-- «.Expr-tests» (to "Expr-tests")
--
-- «.V3» (to "V3")
-- «.V3-tests» (to "V3-tests")
-- «.Surface0» (to "Surface0")
-- «.Surface0-tests» (to "Surface0-tests")
-- «.Surface» (to "Surface")
-- «.Surface-tests» (to "Surface-tests")
loaddednat6("dednat6/")
-- _____ _
-- |_ _|__ ___| |_
-- | |/ _ \/ __| __|
-- | | __/\__ \ |_
-- |_|\___||___/\__|
--
-- «Show» (to ".Show")
-- Show a chunk of tex code by saving it to 2022pict2e-body.tex,
-- latexing 2022pict2e.tex, and displaying the resulting PDF.
Show = Class {
type = "Show",
new = function (o) return Show {bigstr = tostring(o)} end,
try = function (bigstr) return Show.new(bigstr):write():compile() end,
__tostring = function (test)
return format("Show: %s => %s", test.fname_body, test.success or "?")
end,
__index = {
fname_body = "~/LATEX/2022pict2e-body.tex",
fname_tex = "~/LATEX/2022pict2e.tex",
-- (find-LATEX "2022pict2e.tex")
--
write = function (test)
ee_writefile(test.fname_body, test.bigstr)
return test
end,
cmd = function (test)
local cmd = "cd ~/LATEX/ && lualatex "..test.fname_tex.." < /dev/null"
return cmd
end,
compile = function (test)
local log = getoutput(test:cmd())
local success = log:match "Success!!!"
Show.log = log
test.success = success
return test
end,
print = function (test) print(test); return test end,
},
}
-- «Show-tests» (to ".Show-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
= Show.try "Hello"
* (etv)
= Show.try [[$$ \ln x $$]]
* (etv)
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
* (etv)
= Show.try()
* (etv)
--]==]
-- ____ _ _ ____
-- | _ \(_) ___| |_|___ \ ___
-- | |_) | |/ __| __| __) / _ \
-- | __/| | (__| |_ / __/ __/
-- |_| |_|\___|\__|_____\___|
--
-- «Pict2e» (to ".Pict2e")
--
Pict2e = Class {
type = "Pict2e",
new = function () return Pict2e {lines={}, pb=nil} end,
from = function (o)
if otype(o) == "Pict2e" then
return Pict2e {lines = copy(o.lines), pb = o.pb}
end
if type(o) == "string" then return Pict2e {lines = splitlines(o)} end
if type(o) == "table" then return Pict2e {lines = copy(o)} end
error("From?")
end,
Line = function (...) return Points2({...}):Line() end,
bounds = function (...) return Pict2e.new():setbounds(...) end,
bgat = function (...) return Pict2e.bounds(...):grid():axesandticks() end,
unitlength = function (str) return Pict2e.new():Unitlength(str) end,
--
sw = v(-2,-1),
ne = v(6,4),
--
__tostring = function (p) return p:tostring() end,
--
__mul = function (prefix, p)
local f = function (li) return prefix..li end
return Pict2e {lines = map(f, p.lines), pb = p.pb}
end,
__add = function (a, b)
a = Pict2e.from(a)
b = Pict2e.from(b)
a.pb = a.pb or b.pb
for _,li in ipairs(b.lines) do
table.insert(a.lines, li)
end
return a
end,
--
__index = {
--
-- Functions to convert a Pict2e object to a string.
-- Inside dednat6 it is better to make suffix = "%".
--
suffix = "",
tolatex = function (p) return p:tostring("%") end,
tostring = function (p, suffix)
local f = function (li) return li..(suffix or p.suffix) end
return mapconcat(f, p.lines, "\n")
end,
output = function (p) output(p:tolatex()); return p end,
--
-- Append lines.
add = function (p, p2)
for _,line in ipairs(Pict2e.from(p2).lines) do
table.insert(p.lines, line)
end
return p
end,
--
beginend = function (p, str1, str2) return str1 + (" " * p) + str2 end,
wrapin = function (p, str1, str2) return str1 + (" " * (p + str2)) end,
as = function (p, str) return p:wrapin("{"..str, "}") end,
color = function (p, color) return p:as("\\color{"..color.."}") end,
grid_ = "\\color{GrayPale}\\linethickness{0.3pt}",
axes_ = "\\linethickness{0.5pt}",
asgrid = function (p) return p:as(p.grid_) end,
asaxes = function (p) return p:as(p.axes_) end,
def = function (p, name) return p:wrapin("\\def\\"..name.."{", "}") end,
--
bep = function (p) return p:beginend(p.pb:beginpicture(), "\\end{picture}") end,
bepc = function (p) return p:bep():wrapin("\\myvcenter{", "}") end,
bepcb = function (p) return p:bepc():wrapin("\\bhbox{$", "$}") end,
--
-- Set or change the PictBounds field.
setbounds = function (p, ab, cd, e)
ab,cd = ab or Pict2e.sw, cd or Pict2e.ne
p.pb = PictBounds.new(ab, cd, e)
return p
end,
--
-- Append grids, axes, and ticks to an existing Pict2e object.
grid0 = function (p) return p.pb:grid() end,
grid = function (p) return p:add(p:grid0():asgrid()) end,
axesandticks0 = function (p) return p.pb:axesandticks() end,
axesandticks = function (p) return p:add(p:axesandticks0():asaxes()) end,
grat = function (p) return p:grid():axesandticks() end,
--
-- Append other things.
Line = function (p, ...) return p:add(Pict2e.Line(...)) end,
Thick = function (p, str) return p:add("\\linethickness{"..str.."}") end,
Unitlength = function (p, str) return p:add("\\unitlength="..str) end,
put = function (p, xy, str) return p:add(pformat("\\put%s{%s}", xy, str)) end,
putcell = function (p, xy, str) return p:put(xy, "\\cell{"..str.."}") end,
puttext = function (p, xy, str) return p:putcell(xy, "\\text{"..str.."}") end,
run = function (p, f) f(p); return p end,
--
show = function (p) return Show.try(p:tolatex()) end,
bshow = function (p, sw, ne)
-- local sw = sw or Pict2e.sw
-- local ne = ne or Pict2e.ne
return Pict2e.bounds(sw, ne):grid():axesandticks():add(p):bep():show()
end,
b0show = function (p, sw, ne)
-- local sw = sw or Pict2e.sw
-- local ne = ne or Pict2e.ne
return Pict2e.bounds(sw, ne):add(p):bep():show()
end,
},
}
-- «Pict2e-tests» (to ".Pict2e-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
= Pict2e.from "A"
= Pict2e.from {"A", "B"}
= Pict2e.from( Pict2e.from {"A", "B"} )
p = Pict2e.from({"aa", "bbb"})
= p
= p :tostring("%!")
= " " * p
= p + p
= p + "cccc"
= p + {"cccc", "dd"}
= "00" + p
= {"1", "2"} + p
= p:beginend("\\begin{foo}", "\\end{foo}")
= p:wrapin ("\\begin{foo}", "\\end{foo}")
= p:color("red")
= p:asgrid()
= p:asaxes()
p = Pict2e.from({"aa", "bbb", "cccc"})
PPPV(p)
= p:tostring("%")
= p:tostring("")
= p
= p:color("red")
= p
= Pict2e.Line(v(1,2), v(3,4)):Line(v(0,1), v(2,3), v(4,5))
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
p = Pict2e.bounds(v(0,0), v(3,2))
= p.pb
= p:Line(v(0,1), v(2,3)):color("red")
= p:Line(v(0,1), v(2,3)):color("red").pb
= Pict2e.bounds(v(0,0), v(3,2)):grid():axesandticks()
= Pict2e.bounds(v(0,0), v(3,2)):grid():axesandticks():bep()
= Pict2e.bounds(v(0,0), v(3,2)):grid():axesandticks():bep():show()
* (etv)
= Pict2e.bounds(v(-2,-1), v(6,4)):grid():axesandticks():bep():show()
* (etv)
--]]
-- «Pict2e-test-nums» (to ".Pict2e-test-nums")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
Pict2e.sw = v(-3,-3)
Pict2e.nw = v(3,3)
prep = Pict2e.unitlength("12pt"):add("\\celllower=3pt")
pnums = Pict2e.bounds():axesandticks():color("gray")
pnums:run(function (p)
p:puttext(v(0,2), "-6")
p:puttext(v(0,1), "-4")
p:puttext(v(1,1), "-2")
end)
= pnums
= pnums:bep()
= prep + pnums:bep()
= (prep + pnums:bep()):show()
* (etv)
--]]
-- ____ _ _ ____ __ __ _
-- | _ \(_) ___| |_|___ \ __\ \ / /__ ___| |_ ___ _ __
-- | |_) | |/ __| __| __) / _ \ \ / / _ \/ __| __/ _ \| '__|
-- | __/| | (__| |_ / __/ __/\ V / __/ (__| || (_) | |
-- |_| |_|\___|\__|_____\___| \_/ \___|\___|\__\___/|_|
--
-- «Pict2eVector» (to ".Pict2eVector")
-- Based on: (find-dn6 "picture.lua" "pict2evector-test")
Pict2eVector = Class {
type = "Pict2eVector",
lowlevel = 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 Dx,Dy, len
-- 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,
--
eps = 1/4,
latex = function (x0, y0, x1, y1)
local norm = math.sqrt((x1-x0)^2 + (y1-y0)^2)
if norm < Pict2eVector.eps then
return pformat("\\put%s{}", v(x0,y0)) -- if very short draw nothing
end
local Dx,Dy, len = Pict2eVector.lowlevel(x0, y0, x1, y1)
return pformat("\\put%s{\\vector%s{%s}}", v(x0,y0), v(Dx,Dy), len)
end,
fromto = function (x0y0, x1y1)
local x0,y0, x1,y1 = x0y0[1],x0y0[2], x1y1[1],x1y1[2]
return Pict2e.from(Pict2eVector.latex(x0,y0, x1,y1))
end,
fromwalk = function (x0y0, dxdy)
PP(x0y0, dxdy)
return Pict2eVector.fromto(x0y0, x0y0+dxdy)
end,
__index = {
},
}
-- «Pict2eVector-tests» (to ".Pict2eVector-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
loaddednat6()
dofile "2022pict2e.lua"
x0y0 = v(3,2)
= x0y0
f = function (ang, len)
return Pict2eVector.fromwalk(x0y0, v(math.cos(ang),math.sin(ang))*len)
end
= f(0, 2)
p = Pict2e.bounds(v(0,0), v(5,4)):grid():axesandticks()
-- for i=0,2,1/8 do p:add(f(i*math.pi, i)) end
-- for i=0,1,1/8 do p:add(f(i*math.pi, i)) end
for i=0,1/2,1/8 do p:add(f(i*math.pi, i)) end
= p
= p:bep():show()
* (etv)
--]]
-- ____ _ _
-- | _ \ ___ (_)_ __ | |_ ___
-- | |_) / _ \| | '_ \| __/ __|
-- | __/ (_) | | | | | |_\__ \
-- |_| \___/|_|_| |_|\__|___/
--
-- «Points2» (to ".Points2")
--
Points2 = Class {
type = "Points2",
new = function () return Points2 {} end,
__tostring = function (pts) return pts:tostring() end,
__index = {
tostring = function (pts, sep)
return mapconcat(tostring, pts, sep or "")
end,
add = function (pts, pt)
table.insert(pts, pt)
return pts
end,
adds = function (pts, pts2)
for _,pt in ipairs(pts2) do table.insert(pts, pt) end
return pts
end,
rev = function (pts)
local pr = Points2.new()
for i=#pts,1,-1 do
table.insert(pr, pts[i])
end
return pr
end,
--
pict2e = function (pts, prefix)
return Pict2e.from(prefix .. tostring(pts))
end,
Line = function (pts) return pts:pict2e("\\Line") end,
polygon = function (pts) return pts:pict2e("\\polygon") end,
region0 = function (pts) return pts:pict2e("\\polygon*") end,
region = function (pts, color) return pts:region0():color(color) end,
--
polygon = function (pts, s) return pts:pict2e("\\polygon"..(s or "")) end,
},
}
-- «Points2-tests» (to ".Points2-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
pts = Points2 {v(1,2), v(3,4), v(5,2)}
= pts
= pts:Line()
= pts:rev()
= pts:add(pts:rev()):region("red")
pts = Points2 {v(1,2), v(3,4), v(5,2)}
= pts:region("red"):bshow()
* (etv)
= pts:Line():bshow()
* (etv)
--]]
-- ____ _ _ ____ _
-- | _ \(_) ___| |_| __ ) ___ _ _ _ __ __| |___
-- | |_) | |/ __| __| _ \ / _ \| | | | '_ \ / _` / __|
-- | __/| | (__| |_| |_) | (_) | |_| | | | | (_| \__ \
-- |_| |_|\___|\__|____/ \___/ \__,_|_| |_|\__,_|___/
--
-- «PictBounds» (to ".PictBounds")
-- (find-LATEX "edrxpict.lua" "pictp0-pictp3")
-- (find-es "pict2e" "picture-mode")
-- (find-kopkadaly4page (+ 12 288) "\\begin{picture}(x dimen,y dimen)")
-- (find-kopkadaly4text (+ 12 288) "\\begin{picture}(x dimen,y dimen)")
-- (find-kopkadaly4page (+ 12 301) "13.1.6 Shifting a picture environment")
-- (find-kopkadaly4text (+ 12 301) "13.1.6 Shifting a picture environment")
-- (find-kopkadaly4page (+ 12 302) "\\begin{picture}(x dimen,y dimen)(x offset,y offset)")
-- (find-kopkadaly4text (+ 12 302) "\\begin{picture}(x dimen,y dimen)(x offset,y offset)")
PictBounds = Class {
type = "PictBounds",
new = function (ab, cd, e)
local a,b = ab[1], ab[2]
local c,d = cd[1], cd[2]
local x1,x2 = min(a,c), max(a,c)
local y1,y2 = min(b,d), max(b,d)
return PictBounds {x1=x1, y1=y1, x2=x2, y2=y2, e=e or .2}
end,
__tostring = function (pb) return pb:tostring() end,
__index = {
x0 = function (pb) return pb.x1 - pb.e end,
x3 = function (pb) return pb.x2 + pb.e end,
y0 = function (pb) return pb.y1 - pb.e end,
y3 = function (pb) return pb.y2 + pb.e end,
p0 = function (pb) return v(pb.x1 - pb.e, pb.y1 - pb.e) end,
p1 = function (pb) return v(pb.x1, pb.y1 ) end,
p2 = function (pb) return v(pb.x2, pb.y2 ) end,
p3 = function (pb) return v(pb.x2 + pb.e, pb.y2 + pb.e) end,
tostring = function (pb)
return pformat("LL=(%s,%s) UR=(%s,%s) e=%s",
pb.x1, pb.y1, pb.x2, pb.y2, pb.e)
end,
--
beginpicture = function (pb)
local dimen = pb:p3() - pb:p0()
local center = (pb:p3() + pb:p0()) * 0.5
local offset = pb:p0()
return pformat("\\begin{picture}%s%s", dimen, offset)
end,
--
grid = function (pb)
local p = Pict2e.from {"% Grid", "% Horizontal lines:"}
for y=pb.y1,pb.y2 do p:Line(v(pb:x0(), y), v(pb:x3(), y)) end
p:add("% Vertical lines:")
for x=pb.x1,pb.x2 do p:Line(v(x, pb:y0()), v(x, pb:y3())) end
return p
end,
ticks = function (pb, e)
e = e or .2
local p = Pict2e.from {"% Ticks", "% On the vertical axis:"}
for y=pb.y1,pb.y2 do p:Line(v(-e, y), v(e, y)) end
p:add("% On the horizontal axis: ")
for x=pb.x1,pb.x2 do p:Line(v(x, -e), v(x, e)) end
return p
end,
axes = function (pb)
return "% Axes"
+ Pict2e.Line(v(pb:x0(), 0), v(pb:x3(), 0))
+ Pict2e.Line(v(0, pb:y0()), v(0, pb:y3()))
end,
axesandticks = function (pb)
return pb:axes() + pb:ticks()
end,
},
}
-- «PictBounds-tests» (to ".PictBounds-tests")
-- (find-LATEX "edrxpict.lua" "pictp0-pictp3")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2021pict2e.lua"
= PictBounds.new(v(-1,-2), v( 3, 5))
= PictBounds.new(v( 3, 5), v(-1,-2))
= PictBounds.new(v( 3, 5), v(-1,-2), 0.5)
pb = PictBounds.new(v(-1,-2), v( 3, 5))
= pb:p0()
= pb:p1()
= pb:p2()
= pb:p3()
= pb:grid()
= pb:ticks()
= pb:axes()
= pb
= pb:beginpicture()
= pb:p0()
= (pb:p0() + pb:p3())
= (pb:p0() + pb:p3()) * 0.5
--]]
-- ____ ____
-- | _ \__ __/ ___| _ __ ___ ___
-- | |_) \ \ /\ / /\___ \| '_ \ / _ \/ __|
-- | __/ \ V V / ___) | |_) | __/ (__
-- |_| \_/\_/ |____/| .__/ \___|\___|
-- |_|
--
-- «PwSpec» (to ".PwSpec")
-- A "spec" for a piecewise function is something like this:
--
-- "(0,1)c--(2,3)o (2,2)c (2,1)o--(4,1)--(5,2)"
--
-- Note that its segments can be non-horizontal.
--
-- An object of this class starts with a spec, immediately calculates
-- its lists of "dxyoc"s, and from that it can generate lots of other
-- data. The list of "dxyoc"s for the spec above is:
--
-- PwSpec.from("(0,1)c--(2,3)o (2,2)c (2,1)o--(4,1)--(5,2)").dxyocs
-- = { {"dash"="" , "x"=0, "y"=1, "oc"="c"},
-- {"dash"="-", "x"=2, "y"=3, "oc"="o"},
-- {"dash"="" , "x"=2, "y"=2, "oc"="c"},
-- {"dash"="" , "x"=2, "y"=1, "oc"="o"},
-- {"dash"="-", "x"=4, "y"=1, "oc"="" },
-- {"dash"="-", "x"=5, "y"=2, "oc"="" } }
--
PwSpec = Class {
type = "PwSpec",
from = function (src)
return PwSpec({src=src, dxyocs={}}):add(src)
end,
dxyoc_to_string = function (dxyoc)
return format("%s(%s,%s)%s",
(dxyoc.dash == "-" and "--" or " "),
dxyoc.x, dxyoc.y, dxyoc.oc or "")
end,
__tostring = function (pws) return pws:tostring() end,
__index = {
npoints = function (pw) return #pw.points end,
--
-- Add points and segments.
-- Example: pws:add("(0,1)o--(1,1)o (1,2)c (1,3)o--(2,3)c--(3,2)--(4,2)c")
add = function (pws, str)
local patn = "%s*([-+.%d]+)%s*"
local pat = "(%-?)%("..patn..","..patn.."%)([oc]?)"
for dash,x,y,oc in str:gfind(pat) do
table.insert(pws.dxyocs, {dash=dash, x=x+0, y=y+0, oc=oc})
end
return pws
end,
--
tostring = function (pws)
return mapconcat(PwSpec.dxyoc_to_string, pws.dxyocs, "")
end,
--
-- Express a piecewise function as a Lua function.
conds_tbl = function (pws)
local conds = {}
for i=1,#pws.dxyocs do
local P0,P1,P2 = pws.dxyocs[i], pws.dxyocs[i+1], pws.dxyocs[i+2]
local p0,p1,p2 = P0, P1 or {}, P2 or {}
local x0,y0,oc0 = p0.x, p0.y, p0.oc
local x1,y1,oc1,dash1 = p1.x, p1.y, p1.oc, p1.dash
local x2,y2,oc2,dash2 = p2.x, p2.y, p2.oc, p2.dash
if oc0 ~= "o" then
local cond = format("(%s == x) and %s", x0, y0)
table.insert(conds, cond)
end
if dash1 == "-" then
local cond = format("(%s < x and x < %s)", x0, x1)
if y1 == y0 then
cond = format("%s and %s", cond, y0)
else
cond = format("%s and (%s + (x - %s)/(%s - %s) * (%s - %s))",
cond, y0, x0, x1, x0, y1, y0 )
end
table.insert(conds, cond)
end
end
return conds
end,
conds = function (pws) return table.concat(pws:conds_tbl(), " or\n") end,
fun0 = function (pws) return "function (x) return (\n"..pws:conds().."\n) end" end,
fun = function (pws) return expr(pws:fun0()) end,
--
-- Get lines and open/closed points, for drawing.
getj = function (pws, i)
return (pws.dxyocs[i+1]
and (pws.dxyocs[i+1].dash == "-")
and pws:getj(i+1)) or i
end,
getijs = function (pws)
local i, j, ijs = 1, pws:getj(1), {}
while true do
if i < j then table.insert(ijs, {i, j}) end
i = j + 1
j = pws:getj(i)
if #pws.dxyocs < i then return ijs end
end
end,
getpoint = function (pws, i) return v(pws.dxyocs[i].x, pws.dxyocs[i].y) end,
getpoints = function (pws, i, j)
local ps = Points2.new()
for k=i,j do ps:add(pws:getpoint(k)) end
return ps
end,
topict = function (pws)
cmds = Pict2e.new()
for _,ij in ipairs(pws:getijs()) do
cmds:add(pws:getpoints(ij[1], ij[2]):Line())
end
for i,p in ipairs(pws.dxyocs) do
if p.oc == "o" then
cmds:add(formatt("\\put%s{\\opendot}", pws:getpoint(i)))
elseif p.oc == "c" then
cmds:add(formatt("\\put%s{\\closeddot}", pws:getpoint(i)))
end
end
return cmds
end,
},
}
-- «PwSpec-tests» (to ".PwSpec-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
spec = "(0,1)c--(2,3)o (2,2)c (2,1)o--(4,1)--(5,2)"
PPPV(PwSpec.from(spec).dxyocs)
spec = "(0,1)o--(1,1)o (1,4)c (1,3)o--(2,3)c--(3,2)--(4,2)c"
spec = "(0,1)c--(2,3)o (2,2)c (2,1)o--(4,1)c"
pws = PwSpec.from(spec)
= pws
= pws:conds()
= pws:fun0()
= pws:topict()
= pws:topict():bshow()
* (etv)
f = pws:fun()
= f(0.1)
= f(1.9)
= f(2)
= f(2.1)
= f(2.2)
--]==]
-- ____ _____ _ _
-- | _ \__ _| ___| _ _ __ ___| |_(_) ___ _ __
-- | |_) \ \ /\ / / |_ | | | | '_ \ / __| __| |/ _ \| '_ \
-- | __/ \ V V /| _|| |_| | | | | (__| |_| | (_) | | | |
-- |_| \_/\_/ |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|
--
-- «PwFunction» (to ".PwFunction")
-- An object of the class PwFunction starts with a function and with
-- its sets of "important points", and it can produce lots of data
-- from that.
--
-- The most typical use of "PwFunction" is like this:
--
-- f = function (x) if x < 2 then return x^2 else return 2 end end
-- pwf = PwFunction.from(f, seq(0, 2, 0.5), 4)
-- pict = pwf:pw(1, 3)
-- pict:bshow()
--
-- We convert the function f (plus its important points) to a
-- PwFunction, and then we generate a PwSpec that draws its graph in a
-- certain interval, and we convert that PwSpec to a Pict2e object and
-- we draw it. Note that the method ":pw(...)" does two conversions:
--
-- PwFunction -> PwSpec -> Pict2e
--
PwFunction = Class {
type = "PwFunction",
from = function (f, ...)
return PwFunction({f=f}):setpoints(...)
end,
__index = {
--
-- The "important points" are stored in a "Set".
-- Example: pwf:setpoints(seq(0, 4, 0.25), 5, 6, 7)
setpoints = function (pwf, ...)
pwf.points = Set.new() -- (find-angg "LUA/lua50init.lua" "Set")
return pwf:addpoints(...)
end,
addpoints = function (pwf, ...)
for _,o in ipairs({...}) do
if type(o) == "number" then pwf:addpoint(o)
elseif type(o) == "table" then pwf:addlistofpoints(o)
else PP("not a point or a list of points:", o); error()
end
end
return pwf
end,
addpoint = function (pwf, p)
if type(p) ~= "number" then PP("Not a number:", p); error() end
pwf.points:add(p)
return pwf
end,
addlistofpoints = function (pwf, A)
for _,p in ipairs(A) do pwf:addpoint(p) end
return pwf
end,
--
-- All important points in the interval (a,b).
pointsin = function (pwf, a, b)
local A = {}
for _,x in ipairs(pwf.points:ks()) do
if a < x and x < b then table.insert(A, x) end
end
return A
end,
--
-- Detect discontinuities using a heuristic.
eps = 1/32768,
delta = 1/128,
hasjump = function (pwf, x0, x1)
local y0,y1 = pwf.f(x0), pwf.f(x1)
return math.abs(y1-y0) > pwf.delta
end,
hasjumpl = function (pwf, x) return pwf:hasjump(x - pwf.eps, x) end,
hasjumpr = function (pwf, x) return pwf:hasjump(x, x + pwf.eps) end,
--
xy = function (pwf, x, y) return pformat("(%s,%s)", x, y or pwf.f(x)) end,
xyl = function (pwf, xc) return pwf:xy(xc - pwf.eps) end,
xyr = function (pwf, xc) return pwf:xy(xc + pwf.eps) end,
jumps_and_xys = function (pwf, xc)
local xyl, xyc, xyr = pwf:xyl(xc), pwf:xy(xc), pwf:xyr(xc)
local jumpl = pwf:hasjumpl(xc) and "l" or ""
local jumpr = pwf:hasjumpr(xc) and "r" or ""
local jumps = jumpl..jumpr -- "lr", "l", "r", or ""
return jumps, xyl, xyc, xyr
end,
--
xym = function (pwf, xc)
local jumps, xyl, xyc, xyr = pwf:jumps_and_xys(xc)
if jumps == "" then str = xyc
elseif jumps == "l" then str = format("%so %sc", xyl, xyc)
elseif jumps == "r" then str = format( "%sc %so", xyc, xyr)
elseif jumps == "lr" then str = format("%so %sc %so", xyl, xyc, xyr)
end
return str
end,
--
-- pwf:pwspec(a, b) converts a pwf to a "piecewise spec".
-- This is tricky, so let's see an example. Suppose that:
--
-- pwf:pointsin(a, b) = {c}.
--
-- Then in the simplest case pwf:piecewise(a, b) would generate a
-- piecewise spec like this,
--
-- "(a,f(a))--(c,f(c))--(b,f(b))"
--
-- but we have tricks for dealing with discontinuites and drawing
-- closed dots and open dots... for example, we can generate
-- something like this:
--
-- "(a,f(a))--(c-eps,f(c-eps))o (c,f(c))c--(b,f(b))"
--
-- The hard work to convert c to
--
-- "(c-eps,f(c-eps))o (c,f(c))c"
--
-- is done by the function xym, defined above; the case "_o _c"
-- corresponds to jumps == "l". Note that the "eps"s usually
-- disappear when each coordinate of the "(x,y)"s is rounded to at
-- most three decimals.
--
-- Btw, I think that the extremities are "(a+eps,f(a+eps))" and
-- "(b-eps,f(b+eps))", not "(a,f(a))" and "(b,f(b))"... TODO:
-- check that.
--
-- Btw 2: pwf:pwspec(...) can generate other kinds of output if
-- it is called with the right hackish optional arguments.
--
pwspec = function (pwf, a, b, method, sep)
local method = method or "xym"
local sep = sep or "--"
local xym = function (x) return pwf[method](pwf, x) end
local str
--
-- Add points (including discontinuities) and "--"s to str.
str = pwf:xyr(a)
for _,x in ipairs(pwf:pointsin(a, b)) do str = str..sep..xym(x) end
str = str..sep..pwf:xyl(b)
return str
end,
--
-- :pw(a,b) generates a Pict2e object that
-- draws f in the interval [a,b].
pw = function (pwf, a, b)
return PwSpec.from(pwf:pwspec(a, b)):topict()
end,
--
--
--
-- Methods that call pwspec in hackish ways.
-- TODO: fix names, write tests.
--
-- :lineify(...) only works when there are no discontinuities.
--
lineify = function (pwi, a, b)
return "\\Line"..pwi:piecewise(a, b, nil, "")
end,
--
-- ____ _
-- | _ \(_) ___ _ __ ___ __ _ _ __ _ __ ___ _ _ _ __ ___ ___
-- | |_) | |/ _ \ '_ ` _ \ / _` | '_ \| '_ \ / __| | | | '_ ` _ \/ __|
-- | _ <| | __/ | | | | | (_| | | | | | | | \__ \ |_| | | | | | \__ \
-- |_| \_\_|\___|_| |_| |_|\__,_|_| |_|_| |_| |___/\__,_|_| |_| |_|___/
--
-- «PwFunction-Riemann» (to ".PwFunction-Riemann")
-- The methods below are used to draw several kinds (or "methods")
-- of Riemann sums as rectangles touching the x axis, and to draw
-- the differences between two methods as rectangles "floating in
-- the air".
-- See: (find-LATEX "2021pict2e.lua" "Piecewisify")
-- (find-LATEX "2021pict2e.lua" "Piecewisify" "pol1")
--
piecewise_pol1 = function (pwi, xc) -- for polygons
local jumps, xyl, xyc, xyr = pwi:jumps_and_xys(xc)
if jumps == ""
then return xyc
else return format("%s%s", xyl, xyr)
end
end,
piecewise_pol = function (pwi, a, b)
local a0, b0 = pwi:xy(a, 0), pwi:xy(b, 0)
return a0..pwi:piecewise(a, b, "piecewise_pol1", "")..b0
end,
pol = function (pwi, a, b, star)
-- return "\\polygon"..(star or "")..pwi:piecewise_pol(a, b)
return Pict2e.from("\\polygon"..(star or "")..pwi:piecewise_pol(a, b))
end,
--
inforsup = function (pwi, maxormin, a, b)
local y = pwi.f(a)
local consider = function (x) y = maxormin(y, pwi.f(x)) end
consider(a + pwi.eps)
for _,x in ipairs(pwi:pointsin(a, b)) do
consider(x - pwi.eps)
consider(x)
consider(x + pwi.eps)
end
consider(b - pwi.eps)
consider(b)
return y
end,
inf = function (pwi, a, b) return pwi:inforsup(min, a, b) end,
sup = function (pwi, a, b) return pwi:inforsup(max, a, b) end,
max = function (pwi, a, b) return max(pwi.f(a), pwi.f(b)) end,
min = function (pwi, a, b) return min(pwi.f(a), pwi.f(b)) end,
zero = function (pwi) return 0 end,
method = function (pwi, mname, a, b) return pwi[mname](pwi, a, b) end,
rct = function (pwi, mname1, mname2, a, b)
local y1 = pwi:method(mname1, a, b)
local y2 = pwi:method(mname2 or "zero", a, b)
return pformat("(%s,%s)(%s,%s)(%s,%s)(%s,%s)", a,y1, a,y2, b,y2, b,y1)
end,
rects = function (pwi, ptn, mname1, mname2, star)
local p = Pict2e.new()
for i=1,ptn:N() do
local ai,bi = ptn:ai(i), ptn:bi(i)
local rct = pwi:rct(mname1, mname2, ai, bi)
p:add(format("\\polygon%s%s\n", star or "*", rct))
end
return p
end,
},
}
-- «PwFunction-tests» (to ".PwFunction-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
f = function (x) if x < 2 then return x^2 else return 2 end end
pwf = PwFunction.from(f, seq(0, 2, 0.5), 4)
PPPV(pwf)
spec = pwf:pwspec(0, 4)
PPPV(spec)
spec = pwf:pwspec(1, 3)
PPPV(spec)
pws = PwSpec.from(spec)
PPPV(pws)
pict = pws:topict()
PPPV(pict)
= pict
f = function (x) if x < 2 then return x^2 else return 2 end end
pwf = PwFunction.from(f, seq(0, 2, 0.5), 4)
= pwf:pwspec(0, 4)
= pwf:pw (0, 4)
= pwf:pwspec(1, 3)
= pwf:pw (1, 3)
= pwf:pw (1, 3):bshow()
* (etv)
= pwf:pw (0, 4):bshow()
* (etv)
--]]
-- _____
-- | ____|_ ___ __ _ __
-- | _| \ \/ / '_ \| '__|
-- | |___ > <| |_) | |
-- |_____/_/\_\ .__/|_|
-- |_|
--
-- «Expr» (to ".Expr")
Expr = Class {
type = "Expr",
__tostring = function (expr) return expr:tostring() end,
__index = {
expandskel1 = function (expr, str)
local key = tonumber(str) or str
return expr[key]
end,
expandskel = function (expr, skel)
local expand1 = function (akey)
local strkey = akey:sub(2,-2)
local key = tonumber(strkey) or strkey
PP(akey, strkey, key)
return expr[key]
end
return (skel:gsub("%b<>", expand1))
end,
tostring = function (expr)
return expr:expandskel(expr.skel)
end,
},
}
-- «Expr-tests» (to ".Expr-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
PP(tonumber("aaa"))
PP(tonumber("123") or "123")
skel = [[∫<1>\,d<v>]]
= skel
PP(skel:match("%b<>"))
PP(skel:match("%b<>"):sub(2,-2))
e = Expr {skel = [[∫<1>\,d<v>]], v="x", [1]="foo"}
= e
= e:expandskel1("1")
= e:expandskel1("v")
PPPV(e)
--]==]
-- (c3m212dnp 9 "point-of-view")
-- (c3m212dna "point-of-view")
-- (find-LATEX "2021-1-C3-3D.lua")
-- V3.__index.tostring = function (v) return v:v2string() end
-- __ _______
-- \ \ / /___ /
-- \ \ / / |_ \
-- \ V / ___) |
-- \_/ |____/
--
-- «V3» (to ".V3")
-- (find-es "dednat" "V3")
--
V3 = Class {
type = "V3",
--
output = "3D",
output2D = function () V3.output = "2D" end,
output3D = function () V3.output = "3D" end,
p1 = V{2,-1},
p2 = V{2,1},
p3 = V{0,2},
--
__tostring = function (v) return v:tostring() end,
__add = function (v, w) return V3{v[1]+w[1], v[2]+w[2], v[3]+w[3]} end,
__sub = function (v, w) return V3{v[1]-w[1], v[2]-w[2], v[3]-w[3]} end,
__unm = function (v) return v*-1 end,
__mul = function (v, w)
local ktimesv = function (k, v) return V3{k*v[1], k*v[2], k*v[3]} end
local innerprod = function (v, w) return v[1]*w[1] + v[2]*w[2] + v[3]*w[3] 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,
__index = {
tostring = function (v)
if V3.output == "3D"
then return v:v3string()
else return v:v2string()
end
end,
v3string = function (v) return pformat("(%s,%s,%s)", v[1], v[2], v[3]) end,
v2string = function (v) return tostring(v:tov2()) end,
--
-- Convert v3 to v2 using a primitive kind of perspective.
-- Adjust p1, p2, p3 to change the perspective.
tov2 = function (v) return v[1]*V3.p1 + v[2]*V3.p2 + v[3]*V3.p3 end,
--
Line = function (A, v) return pformat("\\Line%s%s", A, A+v) end,
-- Lines = function (A, v, w, i, j)
-- local bprint, out = makebprint()
-- for k=i,j do bprint((A+k*w):Line(v)) end
-- return out()
-- end,
Lines = function (A, v, w, i, j)
local out = Pict2e.new()
for k=i,j do out = out + (A+k*w):Line(v) end
return out
end,
--
xticks = function (o,n,eps)
eps = eps or 0.15
return v3(0,-eps,0):Lines(v3(0,2*eps,0), v3(1,0,0), 0, n)
end,
yticks = function (o,n,eps)
eps = eps or 0.15
return v3(-eps,0,0):Lines(v3(2*eps,0,0), v3(0,1,0), 0, n)
end,
zticks = function (o,n,eps)
eps = eps or 0.15
return v3(-eps,0,0):Lines(v3(2*eps,0,0), v3(0,0,1), 0, n)
end,
axeswithticks = function (o,x,y,z)
out = Pict2e.new()
out = out + v3(0,0,0):Line(v3(x+0.5, 0, 0))
out = out + v3(0,0,0):Line(v3(0, y+0.5, 0))
out = out + v3(0,0,0):Line(v3(0, 0, z+0.5))
out = out + o:xticks(x)
out = out + o:yticks(y)
out = out + o:zticks(z)
return out
end,
xygrid = function (o,x,y)
out = Pict2e.new()
out = out + v3(0,0,0):Lines(v3(0,y,0), v3(1,0,0), 0, x)
out = out + v3(0,0,0):Lines(v3(x,0,0), v3(0,1,0), 0, y)
return out
end,
gridandticks = function (o,x,y,z)
return o:xygrid(x,y):color("gray")
+ o:axeswithticks(x,y,z)
end,
},
}
v3 = function (x,y,z) return V3{x,y,z} end
-- Old way:
-- V3.__index.tostring = function (v) return v:v2string() end
-- V3.__index.tostring = function (v) return v:v3string() end
-- «V3-tests» (to ".V3-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
o = v3(2,3,4)
= o
= o:v3string()
= o:v2string()
V3.output2D(); print(o)
V3.output3D(); print(o)
V3.output3D(); print(o:xticks(4, 0.2))
V3.output3D(); print(o:axeswithticks(2, 3, 4))
V3.output2D(); print(o:axeswithticks(2, 3, 4))
V3.output2D(); print(o:xygrid(2, 3))
V3.output2D(); print(o:xygrid(2, 3):color("gray"))
V3.output2D(); print(o:axeswithticks(2, 3, 4):bshow())
* (etv)
Pict2e.sw = v(-1,-3); Pict2e.ne = v(7,9)
V3.output2D(); print(o:axeswithticks(2, 3, 4):bshow())
* (etv)
V3.output2D(); print(o:axeswithticks(2, 3, 4):b0show())
* (etv)
V3.output2D(); print((o:xygrid(2, 3):color("gray") +
o:axeswithticks(2, 3, 4)
):b0show())
* (etv)
V3.output2D(); print(o:gridandticks(2, 3, 4):b0show())
* (etv)
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
Pict2e.sw = v(-1,-3); Pict2e.ne = v(7,9)
V3.output2D();
gt = v3(0,0,0):gridandticks(2, 3, 4)
pu = Pict2e.new()
pu = Pict2e.new():Unitlength("2.5pt")
pu = Pict2e.unitlength("2.5pt")
= pu
= gt
= pu + gt
V3.output2D(); print((pu + gt):b0show())
* (etv)
--]]
-- ____ __
-- / ___| _ _ _ __ / _| __ _ ___ ___
-- \___ \| | | | '__| |_ / _` |/ __/ _ \
-- ___) | |_| | | | _| (_| | (_| __/
-- |____/ \__,_|_| |_| \__,_|\___\___|
--
-- «Surface0» (to ".Surface0")
-- (find-dn6 "picture.lua" "V")
-- (find-dn6 "diagforth.lua" "newnode:at:")
--
Surface0 = Class {
type = "Surface0",
new = function (f, x0, y0)
return Surface0 {f=f, x0=x0, y0=y0, xy0=v(x0, y0),
p=Pict2e.bounds()}
end,
__index = {
xyz = function (s, xy, zvalue)
return v3(xy[1], xy[2], zvalue or s.f(xy[1], xy[2]))
end,
xyztow = function (s, xy1, xy2, zvalue, k)
return s:xyz(tow(xy1, xy2, k), zvalue)
end,
segment = function (s, xy1, xy2, zvalue, n)
local pts = Points2.new()
for i=0,n do pts:add(s:xyztow(xy1, xy2, zvalue, i/n)) end
return pts:Line()
end,
pillar = function (s, xy)
return Points2 {s:xyz(xy, 0), s:xyz(xy, nil)} :Line()
end,
pillars = function (s, xy1, xy2, n)
local str = Pict2e.new()
for i=0,n do str = str + s:pillar(tow(xy1, xy2, i/n)) end
return str
end,
segmentstuff = function (s, xy1, xy2, n, what)
local str = Pict2e.new()
if what:match"0" then str = str + s:segment(xy1, xy2, 0, 1) end
if what:match"c" then str = str + s:segment(xy1, xy2, nil, n) end
if what:match"p" then str = str + s:pillars(xy1, xy2, n) end
return str
end,
--
stoxy = function (s, str)
expr(format("v(%s)", str))
end,
squarestuff = function (s, dxy0s, dxy1s, n, what)
local dxy0 = expr(format("v(%s)", dxy0s))
local dxy1 = expr(format("v(%s)", dxy1s))
local xy1 = s.xy0 + dxy0
local xy2 = s.xy0 + dxy1
return s:segmentstuff(xy1, xy2, n, what)
end,
squarestuffp = function (s, n, what, pair)
local dxy0,dxy1 = unpack(split(pair))
return s:squarestuff(dxy0, dxy1, n, what)
end,
squarestuffps = function (s, n, what, listofpairs)
local str = Pict2e.new()
for _,pair in ipairs(listofpairs) do
str = str + s:squarestuffp(n, what, pair)
end
return str
end,
--
horizontals = function (s, n, what)
return s:squarestuffps(n, what, {
"-1,-1 1,-1", "-1,0 1,0", "-1,1 1,1"
})
end,
verticals = function (s, n, what)
return s:squarestuffps(n, what, {
"-1,-1 -1,1", "0,-1 0,1", "1,-1 1,1"
})
end,
diagonals = function (s, n, what)
return s:squarestuffps(n, what, {
"-1,-1 1,1", "-1,1 1,-1"
})
end,
square = function (s, n, what)
return s:horizontals(n, what)
+ s:verticals (n, what)
end,
},
}
-- «Surface0-tests» (to ".Surface0-tests")
-- (defun st () (interactive) (find-LATEXfile "2022pict2e.lua" "Surface0-tests"))
--
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
V3.output2D();
Pict2e.sw = v(-1,-3); Pict2e.ne = v(7,9)
pu = Pict2e.unitlength("10pt")
gt = v3():gridandticks(5, 4, 3)
= pu + gt
V3.output2D(); print((pu + gt):b0show())
= Show.log
* (etv)
fun = function (x, y) return (x-4)^2+(y-3)^2 end
srf = Surface0.new(fun, 4, 3)
fig = srf:segment(v(3,2), v(5,2), 0, 2)
fig = srf:segment(v(3,2), v(5,2), nil, 16)
fig = srf:segmentstuff(v(3,2), v(5,2), 16, "0cp")
print((pu + gt + fig):b0show())
* (etv)
= srf:xyz(v(3, 2))
= srf:xyz(v(3, 2), 0)
= srf:xyz(v(3, 3))
= srf:xyz(v(3, 3), 0)
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
F = function (x, y) return 10*x + y end
F = function (x, y) return math.sin(x) * math.sin(y) + 2 end
srf = Surface0.new(F, 3, 4)
= srf:xyz(v(2, 5))
= srf:xyz(v(2, 5), 0)
= srf:xyztow(v(2,5), v(22,25), nil, 0.5)
= srf:xyztow(v(2,5), v(22,25), 0, 0.5)
= srf:segment(v(2,5), v(22,25), 0, 2)
= srf:segment(v(2,5), v(22,25), nil, 2)
= srf:pillar(v(2,5))
= srf:segmentstuff(v(2,5), v(22,25), 2, "0cp")
V3.output2D()
= srf:segmentstuff(v(2,5), v(22,25), 2, "0cp")
= srf:segmentstuff(v(2,5), v(22,25), 2, "0cp"):show()
V3.output3D()
* (etv)
= srf:squarestuff("0,0", "2,2", 2, "0")
= srf:squarestuff("0,0", "2,2", 2, "c")
= srf:squarestuff("0,0", "2,2", 2, "p")
= srf:squarestuffp( 2, "p", "0,0 2,2")
= srf:square (2, "p")
= srf:square (4, "p")
= srf:square (2, "c")
= srf:square (4, "c")
= srf:square (8, "c")
= srf:diagonals(2, "p")
fw = function (x) return max(min(x-2, 6-x), 0) end
FP = function (x,y) return min(fw(x), fw(y)) end
FC = function (x,y) return max(fw(x), fw(y)) end
sP = Surface0.new(FP, 4, 4)
= sP:segment(v(0,4), v(6,4), nil, 6)
-- Pict2e.sw = v();
-- Pict2e.ne = v();
-- ^ Used by:
-- (c3m211cnp 15 "figura-piramide")
-- (c3m211cna "figura-piramide")
-- (c3m211cnp 16 "cruz")
-- (c3m211cna "cruz")
--]]
-- ____ __
-- / ___| _ _ _ __ / _| __ _ ___ ___
-- \___ \| | | | '__| |_ / _` |/ __/ _ \
-- ___) | |_| | | | _| (_| | (_| __/
-- |____/ \__,_|_| |_| \__,_|\___\___|
--
-- «Surface» (to ".Surface")
Surface_fmt = [[
Pict2e: <unitlength:nv> <sw:nv> <ne:nv>
V3: <p1:nv> <p2:nv> <p3:nv>
Surface: <maxx:nv> <maxy:nv> <maxz:nv>
<x0:nv> <y0:nv>
<f:nv>
<xya:nv> <xyb:nv> <nsteps:nv>
]]
Surface = Class {
type = "Surface",
new = function (A) return Surface(copy(A)) end,
__tostring = function (s2) return s2:tostring() end,
__index = {
mod = function (df, A) -- returns a modified copy
df = copy(df)
for key,val in pairs(A) do df[key] = val end
return Surface(df)
end,
--
fmt = function () return Surface_fmt end,
--
tostring = function (df, fmt)
local angtostring = function (name, how)
if how == "nv" then return df:nv(name) end
if how == "n2D" then return df:nmethod("v3string", name) end
if how == "n3D" then return df:nmethod("v2string", name) end
return format("[%s by %s]", name, how)
end
local pat = "<([!-~]-):([!-~]-)>"
local out = (fmt or df:fmt()):gsub(pat, angtostring)
return out
end,
nv = function (df, name)
return format("%s=%s", name, tostring(df[name]))
end,
nmethod = function (df, methodname, name)
local o = df[name]
local f = (type(o) == "table") and o[methodname]
return format("%s=%s", name, (f and f(o)) or tostring(o))
end,
--
setbounds = function (s2)
Pict2e.sw = s2.sw
Pict2e.ne = s2.ne
end,
setperspective = function (s2)
V3.p1 = s2.p1
V3.p2 = s2.p2
V3.p3 = s2.p3
end,
pu = function (s2) return Pict2e.unitlength(s2.unitlength) end,
gt = function (s2) return v3():gridandticks(s2.maxx, s2.maxy, s2.maxz) end,
xy0 = function (s2) return v(s2.x0, s2.y0) end,
xyz = function (s2, xy, zspec)
local x,y = xy[1], xy[2]
local z = (type(zspec) == "number") and zspec or s2.f(x,y)
return v3(x,y,z)
end,
xyab = function (s2, alpha) return tow(s2.xya, s2.xyb, alpha) end,
xyzab = function (s2, alpha, zspec) return s2:xyz(s2:xyab(alpha), zspec) end,
curve = function (s2, zspec)
local pts = Points2.new()
for k=0,s2.nsteps do
local alpha = k/s2.nsteps
pts:add(s2:xyzab(alpha, zspec))
end
return pts:Line()
end,
curverelative = function (s2, zspec, Dxya, Dxyb)
local s2alt = s2:mod {xya=s2:xy0()+Dxya, xyb=s2:xy0()+Dxyb}
return s2alt:curve(zspec)
end,
--
sixcurves = function (s2, zspec)
local out = Pict2e.new()
out = out + s2:curverelative(zspec, v(-1,-1), v(1,-1))
out = out + s2:curverelative(zspec, v(-1, 0), v(1, 0))
out = out + s2:curverelative(zspec, v(-1, 1), v(1, 1))
out = out + s2:curverelative(zspec, v(-1,-1), v(-1,1))
out = out + s2:curverelative(zspec, v( 0,-1), v( 0,1))
out = out + s2:curverelative(zspec, v( 1,-1), v( 1,1))
return out
end,
pillar = function (s2, xy) return Points2({s2:xyz(xy,0), s2:xyz(xy,nil)}):Line() end,
pillars0 = function (s2, xa, xb, xstep, ya, yb, ystep)
local out = Pict2e.new()
for y=ya,yb,ystep do
for x=xa,xb,xstep do
out = out + s2:pillar(v(x,y))
end
end
return out
end,
pillars = function (s2)
return s2:pillars0(s2.x0-1, s2.x0+1, 1, s2.y0-1, s2.y0+1, 1)
end,
--
base = function (s2)
s2:setbounds()
s2:setperspective()
V3:output2D()
return s2:pu() + s2:gt()
end,
twoDgrid = function (s2)
s2:setbounds()
return Pict2e.bounds():grid():axesandticks()
end,
fig = function (s2, what)
what = what or "0pc"
local out = Pict2e.new()
if what:match"0" then out = out + s2:sixcurves(0) end
if what:match"p" then out = out + s2:pillars(0) end
if what:match"c" then out = out + s2:sixcurves(nil) end
return out
end,
},
}
-- «Surface-tests» (to ".Surface-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "2022pict2e.lua"
s2 = Surface {
unitlength="10pt", sw=v(-1,-3), ne=v(7,9),
p1=v(2,-0.5), p2=v(0.5,1.5), p3=v(0,0.5),
maxx=5, maxy=4, maxz=3,
x0=4, y0=3, nsteps=16,
-- f = function (x, y) return (x-4)^2 + (y-3)^2 end,
f = function (x, y) return (x-3) + (y-2) end,
}
s2b = s2:mod {xya=v(1,2), xyb=v(3,4)}
= s2b
= s2
print(( s2:base() + s2:fig()):b0show())
print((s2:twoDgrid() + s2:base() + s2:fig()):b0show())
* (etv)
= Show.log
--]]
-- Local Variables:
-- coding: utf-8-unix
-- ee-tla: "p22"
-- End: