summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/lualatex/bezierplot
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-06-10 20:51:02 +0000
committerKarl Berry <karl@freefriends.org>2018-06-10 20:51:02 +0000
commit4273e1b07b28f73dfa7d6b2440d8cdf803440fa1 (patch)
treeeba93c24a4f30a2743e04c1622e224f6d87c41c3 /Master/texmf-dist/tex/lualatex/bezierplot
parentbc7020ed4219d8d04e324299e468fb0b0b706222 (diff)
bezierplot (10jun18)
git-svn-id: svn://tug.org/texlive/trunk@47977 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/lualatex/bezierplot')
-rwxr-xr-xMaster/texmf-dist/tex/lualatex/bezierplot/bezierplot.lua476
-rw-r--r--Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.sty10
2 files changed, 308 insertions, 178 deletions
diff --git a/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.lua b/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.lua
index da702f987fc..8cc414f278d 100755
--- a/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.lua
+++ b/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.lua
@@ -1,6 +1,6 @@
#!/usr/bin/env lua
-- Linus Romer, published 2018 under LPPL Version 1.3c
--- version 1.0 2018-04-12
+-- version 1.1 2018-06-10
abs = math.abs
acos = math.acos
asin = math.asin
@@ -33,7 +33,7 @@ function sgn(x)
end
end
-function round(num, decimals)
+local function round(num, decimals)
local result = tonumber(string.format("%." .. (decimals or 0) .. "f", num))
if abs(result) == 0 then
return 0
@@ -45,77 +45,86 @@ end
-- 5-stencil method
-- return from a graph from f in the form {{x,y},...}
-- the derivatives in form {{x,y,dy/dx,ddy/ddx},...}
-function diffgraph(func,graph,h)
+local function diffgraph(func,graph,h)
local dgraph = {}
- local yh = func(graph[1][1]-h)
- local yhh = func(graph[1][1]-2*h)
- if yhh > -math.huge and yhh < math.huge -- if defined at all
- and yh > -math.huge and yh < math.huge then
- dgraph[1] = {graph[1][1],graph[1][2],
- (yhh-8*yh+8*graph[2][2]-graph[3][2])/(12*h),
- (-yhh+16*yh-30*graph[1][2]+16*graph[2][2]-graph[3][2])
- /(12*h^2)}
- dgraph[2] = {graph[2][1],graph[2][2],
- (yh-8*graph[1][2]+8*graph[3][2]-graph[4][2])/(12*h),
- (-yh+16*graph[1][2]-30*graph[2][2]+16*graph[3][2]-graph[4][2])
- /(12*h^2)}
- else -- take neighbour values
- dgraph[1] = {graph[1][1],graph[1][2],
- (graph[1][2]-8*graph[2][2]+8*graph[4][2]-graph[5][2])/(12*h),
- (-graph[1][2]+16*graph[2][2]-30*graph[3][2]
- +16*graph[4][2]-graph[5][2])/(12*h^2)}
- dgraph[2] = {graph[2][1],graph[2][2],
- (graph[1][2]-8*graph[2][2]+8*graph[4][2]-graph[5][2])/(12*h),
- (-graph[1][2]+16*graph[2][2]-30*graph[3][2]
- +16*graph[4][2]-graph[5][2])/(12*h^2)}
- end
local l = #graph
- for i = 3, l-2 do
- table.insert(dgraph,{graph[i][1],graph[i][2],
- (graph[i-2][2]-8*graph[i-1][2]+8*graph[i+1][2]-graph[i+2][2])
- /(12*h),
- (-graph[i-2][2]+16*graph[i-1][2]-30*graph[i][2]
- +16*graph[i+1][2]-graph[i+2][2])
- /(12*h^2)})
- end
- yh = func(graph[l][1]+h)
- yhh = func(graph[l][1]+2*h)
- if yhh > -math.huge and yhh < math.huge -- if defined at all
- and yh > -math.huge and yh < math.huge then
- dgraph[l-1] = {graph[l-1][1],graph[l-1][2],
- (graph[l-3][2]-8*graph[l-2][2]+8*graph[l][2]-yh)/(12*h),
- (-graph[l-3][2]+16*graph[l-2][2]-30*graph[l-1][2]
- +16*graph[l][2]-yh)/(12*h^2)}
- dgraph[l] = {graph[l][1],graph[l][2],
- (graph[l-2][2]-8*graph[l-1][2]+8*yh-yhh)/(12*h),
- (-graph[l-2][2]+16*graph[l-1][2]-30*graph[l][2]
- +16*yh-yhh)/(12*h^2)}
- else
- -- take neighbour values
- dgraph[l] = {graph[l][1],graph[l][2],
- (graph[l-4][2]-8*graph[l-3][2]+8*graph[l-1][2]-graph[l][2])
- /(12*h),
- (-graph[l-4][2]+16*graph[l-3][2]-30*graph[l-2][2]
- +16*graph[l-1][2]-graph[l][2])/(12*h^2)}
- dgraph[l-1] = {graph[l-1][1],graph[l-2][2],
- (graph[l-4][2]-8*graph[l-3][2]+8*graph[l-1][2]-graph[l][2])
- /(12*h),
- (-graph[l-4][2]+16*graph[l-3][2]-30*graph[l-2][2]
- +16*graph[l-1][2]-graph[l][2])/(12*h^2)}
- end
- -- add information about being extremum / inflection point (true/false)
- for i = 1, l do
- dgraph[i][5] = false -- dy/dx == 0 ? default, may change later
- dgraph[i][6] = false -- ddy/ddx == 0 ? default, may change later
- end
- for i = 1, l-1 do
- -- if no gap is inbetween
- if not (dgraph[i+1][1] - dgraph[i][1] > 1.5*h) then
- -- check for dy/dx == 0
- -- if not already determined as near dy/dx=0
- if not dgraph[i][5] then
+ if l < 4 then -- this is not worth the pain...
+ for i = 1, l do
+ table.insert(dgraph,{graph[i][1],graph[i][2],0,0})
+ end
+ else
+ local yh = func(graph[1][1]-h)
+ local yhh = func(graph[1][1]-2*h)
+ if yhh > -math.huge and yhh < math.huge -- if defined at all
+ and yh > -math.huge and yh < math.huge then
+ dgraph[1] = {graph[1][1],graph[1][2],
+ (yhh-8*yh+8*graph[2][2]-graph[3][2])/(12*h),
+ (-yhh+16*yh-30*graph[1][2]+16*graph[2][2]-graph[3][2])
+ /(12*h^2)}
+ dgraph[2] = {graph[2][1],graph[2][2],
+ (yh-8*graph[1][2]+8*graph[3][2]-graph[4][2])/(12*h),
+ (-yh+16*graph[1][2]-30*graph[2][2]+16*graph[3][2]-graph[4][2])
+ /(12*h^2)}
+ else -- take neighbour values
+ dgraph[1] = {graph[1][1],graph[1][2],
+ (graph[1][2]-8*graph[2][2]+8*graph[4][2]-graph[5][2])/(12*h),
+ (-graph[1][2]+16*graph[2][2]-30*graph[3][2]
+ +16*graph[4][2]-graph[5][2])/(12*h^2)}
+ dgraph[2] = {graph[2][1],graph[2][2],
+ (graph[1][2]-8*graph[2][2]+8*graph[4][2]-graph[5][2])/(12*h),
+ (-graph[1][2]+16*graph[2][2]-30*graph[3][2]
+ +16*graph[4][2]-graph[5][2])/(12*h^2)}
+ end
+ for i = 3, l-2 do
+ table.insert(dgraph,{graph[i][1],graph[i][2],
+ (graph[i-2][2]-8*graph[i-1][2]+8*graph[i+1][2]-graph[i+2][2])
+ /(12*h),
+ (-graph[i-2][2]+16*graph[i-1][2]-30*graph[i][2]
+ +16*graph[i+1][2]-graph[i+2][2])
+ /(12*h^2)})
+ end
+ yh = func(graph[l][1]+h)
+ yhh = func(graph[l][1]+2*h)
+ if yhh > -math.huge and yhh < math.huge -- if defined at all
+ and yh > -math.huge and yh < math.huge then
+ dgraph[l-1] = {graph[l-1][1],graph[l-1][2],
+ (graph[l-3][2]-8*graph[l-2][2]+8*graph[l][2]-yh)/(12*h),
+ (-graph[l-3][2]+16*graph[l-2][2]-30*graph[l-1][2]
+ +16*graph[l][2]-yh)/(12*h^2)}
+ dgraph[l] = {graph[l][1],graph[l][2],
+ (graph[l-2][2]-8*graph[l-1][2]+8*yh-yhh)/(12*h),
+ (-graph[l-2][2]+16*graph[l-1][2]-30*graph[l][2]
+ +16*yh-yhh)/(12*h^2)}
+ else
+ -- take neighbour values
+ dgraph[l] = {graph[l][1],graph[l][2],
+ (graph[l-4][2]-8*graph[l-3][2]+8*graph[l-1][2]-graph[l][2])
+ /(12*h),
+ (-graph[l-4][2]+16*graph[l-3][2]-30*graph[l-2][2]
+ +16*graph[l-1][2]-graph[l][2])/(12*h^2)}
+ dgraph[l-1] = {graph[l-1][1],graph[l-2][2],
+ (graph[l-4][2]-8*graph[l-3][2]+8*graph[l-1][2]-graph[l][2])
+ /(12*h),
+ (-graph[l-4][2]+16*graph[l-3][2]-30*graph[l-2][2]
+ +16*graph[l-1][2]-graph[l][2])/(12*h^2)}
+ end
+ -- add information about being extremum / inflection point (true/false)
+ for i = 1, l do
+ dgraph[i][5] = false -- dy/dx == 0 ? default, may change later
+ dgraph[i][6] = false -- ddy/ddx == 0 ? default, may change later
+ end
+ for i = 1, l-1 do
+ -- if no gap is inbetween
+ if not (dgraph[i+1][1] - dgraph[i][1] > 1.5*h) then
+ -- check for dy/dx == 0
+ -- if not already determined as near dy/dx=0
if dgraph[i][3] == 0 then
- dgraph[i][5] = true
+ if dgraph[i+1][3] == 0 then --take the later
+ dgraph[i+1][5] = true
+ dgraph[i][5] = false
+ else
+ dgraph[i][5] = true
+ end
elseif abs(dgraph[i][3]*dgraph[i+1][3])
~= dgraph[i][3]*dgraph[i+1][3] then -- this must be near
if abs(dgraph[i][4]) <= abs(dgraph[i+1][4]) then
@@ -124,12 +133,10 @@ function diffgraph(func,graph,h)
dgraph[i+1][5] = true
end
end
- end
- -- check for ddy/ddx == 0
- -- if not already determined as near ddy/ddx=0
- if not dgraph[i][6] then
- if abs(dgraph[i][4]*dgraph[i+1][4])
- ~= dgraph[i][4]*dgraph[i+1][4] then -- this must be near
+ -- check for ddy/ddx == 0
+ -- if not already determined as near ddy/ddx=0
+ if (not dgraph[i][6]) and (abs(dgraph[i][4]*dgraph[i+1][4])
+ ~= dgraph[i][4]*dgraph[i+1][4]) then -- this must be near
if abs(dgraph[i][4]) <= abs(dgraph[i+1][4]) then
dgraph[i][6] = true
else
@@ -146,7 +153,11 @@ end
-- fits the graph g (up to maxerror) after filling in
-- the parameters a, b, c, d
-- if the graph is inverted, then isinverse has to be set true
-function do_parameters_fit(a,b,c,d,funcstring,funcgraph,maxerror,isinverse)
+local function do_parameters_fit(a,b,c,d,funcstring,funcgraph,maxerror,isinverse)
+ if not (a > -math.huge and a < math.huge and b > -math.huge and b < math.huge and
+ c > -math.huge and c < math.huge and d > -math.huge and d < math.huge) then
+ return false
+ end
local funcx = string.gsub(funcstring, "a", a)
local funcx = string.gsub(funcx, "b", b)
local funcx = string.gsub(funcx, "c", c)
@@ -169,7 +180,7 @@ function do_parameters_fit(a,b,c,d,funcstring,funcgraph,maxerror,isinverse)
end
-- f(x)=a*x^3+b*x+c
-function parameters_cubic(xp,yp,xq,yq,xr,yr,xs,ys)
+local function parameters_cubic(xp,yp,xq,yq,xr,yr,xs,ys)
local a = (((xp^2 * xq) * yr) - ((xp^2 * xq) * ys)
- ((xp^2 * xr) * yq) + ((xp^2 * xr) * ys) + ((xp^2 * xs) * yq)
- ((xp^2 * xs) * yr) - ((xp * xq^2) * yr) + ((xp * xq^2) * ys)
@@ -266,7 +277,7 @@ function parameters_cubic(xp,yp,xq,yq,xr,yr,xs,ys)
end
-- f(x)=a*x+b
-function parameters_affine(xp,yp,xq,yq)
+local function parameters_affine(xp,yp,xq,yq)
local a = (yp - yq) / (xp - xq)
local b = ((xp * yq) - (xq * yp)) / (xp - xq)
return a, b
@@ -274,21 +285,25 @@ end
-- returns true iff the function is of type f(x)=a*x^3+b*x^2+c*x+d
-- a, b, c, d being real numbers
-function is_cubic(graph,maxerror)
+local function is_cubic(graph,maxerror)
local l = #graph
- local a, b, c, d = parameters_cubic(graph[1][1],graph[1][2],
- graph[math.floor(l/3)][1],graph[math.floor(l/3)][2],
- graph[math.floor(2*l/3)][1],graph[math.floor(2*l/3)][2],
- graph[l][1],graph[l][2])
- return do_parameters_fit(a,b,c,d,"a*x^3+b*x^2+c*x+d",graph,
- maxerror,false)
+ if l < 2 then
+ return false
+ else
+ local a, b, c, d = parameters_cubic(graph[1][1],graph[1][2],
+ graph[math.floor(l/3)][1],graph[math.floor(l/3)][2],
+ graph[math.floor(2*l/3)][1],graph[math.floor(2*l/3)][2],
+ graph[l][1],graph[l][2])
+ return do_parameters_fit(a,b,c,d,"a*x^3+b*x^2+c*x+d",graph,
+ maxerror,false)
+ end
end
-- returns true iff the function is of type f(x)=a*x^3+b*x^2+c*x+d
-- a, b, c, d being real numbers
-- this takes several graph parts
-- the idea is to have a possibility to avoid tan(x)
-function are_cubic(graphs,maxerror)
+local function are_cubic(graphs,maxerror)
if is_cubic(graphs[1],maxerror) then
if #graphs < 2 then
return true
@@ -310,21 +325,25 @@ end
-- returns true iff the inverse function is of type
-- f(x)=a*x^3+b*x^2+c*x+d
-- a, b, c, d being real numbers
-function is_cuberoot(graph,maxerror)
+local function is_cuberoot(graph,maxerror)
local l = #graph
- local a, b, c, d = parameters_cubic(graph[1][2],graph[1][1],
- graph[math.floor(l/3)][2],graph[math.floor(l/3)][1],
- graph[math.floor(2*l/3)][2],graph[math.floor(2*l/3)][1],
- graph[l][2],graph[l][1])
- return do_parameters_fit(a,b,c,d,"a*x^3+b*x^2+c*x+d",graph,
- maxerror,true)
+ if l < 2 then
+ return false
+ else
+ local a, b, c, d = parameters_cubic(graph[1][2],graph[1][1],
+ graph[math.floor(l/3)][2],graph[math.floor(l/3)][1],
+ graph[math.floor(2*l/3)][2],graph[math.floor(2*l/3)][1],
+ graph[l][2],graph[l][1])
+ return do_parameters_fit(a,b,c,d,"a*x^3+b*x^2+c*x+d",graph,
+ maxerror,true)
+ end
end
-- returns true iff the function is of type f(x)=a*x^3+b*x^2+c*x+d
-- a, b, c, d being real numbers
-- this takes several graph parts
-- the idea is to have a possibility to avoid tan(x)
-function are_cuberoot(graphs,maxerror)
+local function are_cuberoot(graphs,maxerror)
if is_cuberoot(graphs[1],maxerror) then
if #graphs < 2 then
return true
@@ -345,7 +364,7 @@ end
-- returns true iff function is of type f(x)=a*x+b
-- a, b being real numbers
-function is_affine(graph,maxerror)
+local function is_affine(graph,maxerror)
l = #graph
local a, b = parameters_affine(graph[1][1],graph[1][2],
graph[l][1],graph[l][2])
@@ -357,7 +376,7 @@ end
-- p.. control q and r .. s
-- with the graph g from index starti to endi
-- (looking at the points at roughly t=.33 and t=.67)
-function squareerror(f,g,starti,endi,qx,qy,rx,ry)
+local function squareerror(f,g,starti,endi,qx,qy,rx,ry)
local result = 0
for t = .33, .7, .34 do
x = (1-t)^3*g[starti][1]+3*t*(1-t)^2*qx+3*t^2*(1-t)*rx+t^3*g[endi][1]
@@ -367,13 +386,105 @@ function squareerror(f,g,starti,endi,qx,qy,rx,ry)
return result
end
-function pointstobezier(qx,qy,rx,ry,sx,sy,rndx,rndy)
- return " .. controls (" .. round(qx,rndx) .. ","
- .. round(qy,rndy) ..") and ("
- .. round(rx,rndx) .. ","
- .. round(ry,rndy) .. ") .. ("
- .. round(sx,rndx) .. ","
- .. round(sy,rndy)..")"
+-- converts a table with bezier point information
+-- to a string with rounded values
+-- the path is reversed, if rev is true
+-- e.g. if b = {{0,1},{2,3,4,5,6,7},{8,9,10,11,12,13}}
+-- then
+-- (0,1) .. controls (2,3) and (4,5) .. (6,7) .. controls
+-- (8,9) and (10,11) .. (12,13)
+-- will be returned
+-- the notation "pgfplots" will change the notation to
+-- YES: \addplot coordinates {(0,1) (6,7) (2,3) (4,5) (6,7) (12,13) (8,9) (10,11)}
+-- NO: 0 1 \\ 6 7 \\ 2 3 \\ 4 5 \\ \\ 6 7 \\ 12 13 \\ 8 9 \\ 10 11 \\
+-- As pgfplots does not connect the bezier segments
+-- reverse paths are not implemented
+local function beziertabletostring(b,rndx,rndy,rev,notation)
+ local bezierstring = ""
+ if #b > 1 then -- if not empty or single point
+ if #b == 2 and #b[2] == 2 then -- straight line
+ if rev then
+ bezierstring = "(" .. round(b[2][1],rndx) .. ","
+ .. round(b[2][2],rndy) ..")"
+ .. " -- (" .. round(b[1][1],rndx) .. ","
+ .. round(b[1][2],rndy) ..")"
+ else
+ if notation == "pgfplots" then
+ bezierstring = "\\addplot coordinates {("
+ .. round(b[1][1],rndx) .. ","
+ .. round(b[1][2],rndy) .. ") ("
+ .. round(b[2][1],rndx) .. ","
+ .. round(b[2][2],rndy) .. ") ("
+ .. round(b[1][1],rndx) .. ","
+ .. round(b[1][2],rndy) .. ") ("
+ .. round(b[2][1],rndx) .. ","
+ .. round(b[2][2],rndy) .. ") }"
+ else -- notation = tikz
+ bezierstring = "(" .. round(b[1][1],rndx) .. ","
+ .. round(b[1][2],rndy) ..")"
+ .. " -- (" .. round(b[2][1],rndx) .. ","
+ .. round(b[2][2],rndy) ..")"
+ end
+ end
+ else
+ if rev then
+ bezierstring = "(" .. round(b[#b][#b[#b]-1],rndx) .. ","
+ .. round(b[#b][#b[#b]],rndy) ..")" -- initial point
+ for i = #b, 2, -1 do
+ if #b[i] >= 6 then -- cubic bezier spline
+ bezierstring = bezierstring .. " .. controls ("
+ .. round(b[i][3],rndx) .. ","
+ .. round(b[i][4],rndy) ..") and ("
+ .. round(b[i][1],rndx) .. ","
+ .. round(b[i][2],rndy) .. ") .. ("
+ .. round(b[i-1][#b[i-1]-1],rndx) .. ","
+ .. round(b[i-1][#b[i-1]],rndy)..")"
+ else
+ bezierstring = bezierstring .. " ("
+ .. round(b[i-1][#b[i-1]-1],rndx) .. ","
+ .. round(b[i-1][#b[i-1]],rndy) ..")"
+ end
+ end
+ else
+ if notation == "pgfplots" then
+ bezierstring = "\\addplot coordinates {"
+ for i = 1, #b-1 do
+ if #b[i+1] >= 6 then -- cubic bezier spline
+ bezierstring = bezierstring .. "("
+ .. round(b[i][#b[i]-1],rndx) .. ","
+ .. round(b[i][#b[i]],rndy) .. ") ("
+ .. round(b[i+1][5],rndx) .. ","
+ .. round(b[i+1][6],rndy) .. ") ("
+ .. round(b[i+1][1],rndx) .. ","
+ .. round(b[i+1][2],rndy) .. ") ("
+ .. round(b[i+1][3],rndx) .. ","
+ .. round(b[i+1][4],rndy) .. ") "
+ end
+ end
+ bezierstring = bezierstring .. "}"
+ else -- notation = tikz
+ bezierstring = "(" .. round(b[1][1],rndx) .. ","
+ .. round(b[1][2],rndy) ..")" -- initial point
+ for i = 2, #b do
+ if #b[i] >= 6 then -- cubic bezier spline
+ bezierstring = bezierstring .. " .. controls ("
+ .. round(b[i][1],rndx) .. ","
+ .. round(b[i][2],rndy) ..") and ("
+ .. round(b[i][3],rndx) .. ","
+ .. round(b[i][4],rndy) .. ") .. ("
+ .. round(b[i][5],rndx) .. ","
+ .. round(b[i][6],rndy)..")"
+ else
+ bezierstring = bezierstring .. " ("
+ .. round(b[i][1],rndx) .. ","
+ .. round(b[i][2],rndy) ..")"
+ end
+ end
+ end
+ end
+ end
+ end
+ return bezierstring
end
-- take end points of a graph g of the function f
@@ -381,7 +492,7 @@ end
-- without extrema or inflection points inbetween
-- and try to approximate it with a cubic bezier curve
-- (round to rndx and rndy when printing)
-function graphtobezierapprox(f,g,starti,endi,rndx,rndy,maxerror)
+local function graphtobezierapprox(f,g,starti,endi,maxerror)
local px = g[starti][1]
local py = g[starti][2]
local dp = g[starti][3]
@@ -427,7 +538,7 @@ function graphtobezierapprox(f,g,starti,endi,rndx,rndy,maxerror)
end
end
if err <= maxerror then
- return pointstobezier(qx,qy,rx,ry,sx,sy,rndx,rndy)
+ return {qx,qy,rx,ry,sx,sy}
else
-- search for an intermediate point where the graph has the same
-- slope as the line from the start point to the end point:
@@ -440,14 +551,18 @@ function graphtobezierapprox(f,g,starti,endi,rndx,rndy,maxerror)
interindex = i
end
end
- return graphtobezierapprox(f,g,starti,interindex,rndx,rndy,maxerror)
- .. graphtobezierapprox(f,g,interindex,endi,rndx,rndy,maxerror)
+ local left = graphtobezierapprox(f,g,starti,interindex,maxerror)
+ local right = graphtobezierapprox(f,g,interindex,endi,maxerror)
+ for i=1, #right do --now append the right to the left:
+ left[#left+1] = right[i]
+ end
+ return left
end
end
-- like above but exact for quadratic and cubic (if not inverse)
-- resp. exact for squareroot and cuberoot (if inverse)
-function graphtobezier(g,starti,endi,rndx,rndy,isinverse)
+local function graphtobezier(g,starti,endi,isinverse)
local px = g[starti][1]
local py = g[starti][2]
local dp = g[starti][3]
@@ -459,48 +574,24 @@ function graphtobezier(g,starti,endi,rndx,rndy,isinverse)
local qy = py+(qx-px)*dp
local ry = sy+(rx-sx)*ds
if isinverse then
- return pointstobezier(qy,qx,ry,rx,sy,sx,rndy,rndx)
+ return {qy,qx,ry,rx,sy,sx}
else
- return pointstobezier(qx,qy,rx,ry,sx,sy,rndx,rndy)
+ return {qx,qy,rx,ry,sx,sy}
end
end
--- reverses a path p e.g. when p = "(0,1) -- (2,3)"
--- it returns "(2,3) -- (0,1)"
--- or when p = "(0,1) .. controls (2,3) and (4,5) .. (6,7)"
--- it returns "(6,7) .. controls (4,5) and (2,3) .. (0,1)"
-function reversepath(p)
- local r = "" -- will become the reverse path
- local temppoint ="" -- will store temporal points like "(0,1)"
- local tempbetween = "" -- will store things like " .. controls "
- for i = 1, #p do
- local c = string.sub(p,i,i)
- if c == "(" then
- if tempbetween == " .. " then
- r = " .. controls " .. r
- elseif tempbetween == " .. controls " then
- r = " .. " .. r
- else
- r = tempbetween .. r
- end
- tempbetween = ""
- temppoint = "("
- elseif c == ")" then
- r = temppoint .. ")" .. r
- temppoint = ""
- else
- if temppoint == "" then -- not reading a point
- tempbetween = tempbetween .. c
- else
- temppoint = temppoint .. c
- end
+-- just for debugging:
+local function printtable(t)
+ for i = 1,#t do
+ for j = 1, #t[i] do
+ io.write(t[i][j].." ")
end
+ io.write("\n")
end
- return r
end
-- main function
-function bezierplot(functionstring,xmin,xmax,ymin,ymax)
+function bezierplot(functionstring,xmin,xmax,ymin,ymax,notation)
local fstringreplaced = string.gsub(functionstring, "%*%*", "^")
local f = assert(load("local x = ...; return " .. fstringreplaced))
local isreverse = false
@@ -539,11 +630,19 @@ function bezierplot(functionstring,xmin,xmax,ymin,ymax)
end
local functiontype = "unknown"
- local bezierstring = ""
+ local bezierpoints = {}
+ -- the bezier path (0,1) .. controls
+ -- (2,3) and (4,5) .. (6,7) .. controls
+ -- (8,9) and (10,11) .. (12,13)
+ -- will be stored as
+ -- bezierpoints={{0,1},{2,3,4,5,6,7},{8,9,10,11,12,13}}
-- go through the connected parts
for part = 1, #graphs do
local d = diffgraph(f,graphs[part],xstep)
+ --for i = 1, #d do -- just for debugging
+ -- print(d[i][1],d[i][2],d[i][3],d[i][4],d[i][5],d[i][6])
+ --end
-- check for type of function (only for the first part)
if part == 1 then
if is_affine(d,yerror) then
@@ -555,20 +654,20 @@ function bezierplot(functionstring,xmin,xmax,ymin,ymax)
end
end
if functiontype ~= "cuberoot" then -- start with initial point
- bezierstring = bezierstring .. "(" .. round(d[1][1],rndx)
- .. "," .. round(d[1][2],rndy) .. ")"
+ bezierpoints[#bezierpoints+1] = {round(d[1][1],rndx),
+ round(d[1][2],rndy)}
end
if functiontype == "affine" then
- bezierstring = bezierstring .. " -- (" .. round(d[#d][1],
- rndx) .. "," .. round(d[#d][2],rndy) ..")"
+ bezierpoints[#bezierpoints+1] = {round(d[#d][1],rndx),
+ round(d[#d][2],rndy)}
elseif functiontype == "cubic" then
local startindex = 1
local extremainbetween = false
for k = 2, #d do
if d[k][5] then -- extrema
extremainbetween = true
- bezierstring = bezierstring
- .. graphtobezier(d,startindex,k,rndx,rndy,false)
+ bezierpoints[#bezierpoints+1] = graphtobezier(d,
+ startindex,k,false)
startindex = k
end
end
@@ -584,16 +683,16 @@ function bezierplot(functionstring,xmin,xmax,ymin,ymax)
local ry = d[#d][2]+(rx-d[#d][1])*d[#d][3]
if math.max(qy,ry) > ymax
or math.min(qy,ry) < ymin then
- bezierstring = bezierstring ..graphtobezier(
- d,startindex,k,rndx,rndy,false)
+ bezierpoints[#bezierpoints+1] = graphtobezier(
+ d,startindex,k,false)
startindex = k
end
end
end
end
if startindex ~= #d then -- if no special points inbetween
- bezierstring = bezierstring
- .. graphtobezier(d,startindex,#d,rndx,rndy,false)
+ bezierpoints[#bezierpoints+1] = graphtobezier(d,
+ startindex,#d,false)
end
elseif functiontype == "cuberoot" then
-- we determine a, b, c, d and then
@@ -619,8 +718,7 @@ function bezierplot(functionstring,xmin,xmax,ymin,ymax)
end
end
d = diffgraph(finverse,graphinverse,xstep)
- bezierstring = bezierstring .. "(" .. round(d[1][2],rndy)
- .. "," .. round(d[1][1],rndx) .. ")" -- initial point
+ bezierpoints[#bezierpoints+1] = {d[1][2],d[1][1]} -- initial point
local startindex = 1
for k = 2, #d do
if d[k][6] then -- inflection point
@@ -633,37 +731,56 @@ function bezierplot(functionstring,xmin,xmax,ymin,ymax)
local ry = d[#d][2]+(rx-d[#d][1])*d[#d][3]
if math.max(qy,ry) > xmax
or math.min(qy,ry) < xmin then
- bezierstring = bezierstring..graphtobezier(
- d,startindex,k,rndx,rndy,true)
+ bezierpoints[#bezierpoints+1] = graphtobezier(
+ d,startindex,k,true)
startindex = k
end
end
end
if startindex ~= #d then -- if no special points inbetween
- bezierstring = bezierstring
- .. graphtobezier(d,startindex,#d,rndx,rndy,true)
+ bezierpoints[#bezierpoints+1] = graphtobezier(d,
+ startindex,#d,true)
end
else
-- standard case (nothing special)
local startindex = 1
for k = 2, #d do
if d[k][5] or d[k][6] then -- extrema and inflection points
- bezierstring = bezierstring .. graphtobezierapprox(
- f,d,startindex,k,rndx,rndy,(ymax-ymin)/(0.5*10^rndy))
+ local tobeadded = graphtobezierapprox(
+ f,d,startindex,k,(ymax-ymin)/(0.5*10^rndy))
+ -- tobeadded may contain a multiple of 6 entries
+ -- e.g. {1,2,3,4,5,6,7,8,9,10,11,12}
+ for i = 1, math.floor(#tobeadded/6) do
+ bezierpoints[#bezierpoints+1] = {}
+ for j = 1, 6 do
+ bezierpoints[#bezierpoints][j] = tobeadded[(i-1)*6+j]
+ end
+ end
startindex = k
end
end
if startindex ~= #d then -- if no special points inbetween
- bezierstring = bezierstring .. graphtobezierapprox(f,d,
- startindex,#d,rndx,rndy,(ymax-ymin)/(0.5*10^rndy))
+ local tobeadded = graphtobezierapprox(f,d,
+ startindex,#d,(ymax-ymin)/(0.5*10^rndy))
+ -- tobeadded may contain a multiple of 6 entries
+ -- e.g. {1,2,3,4,5,6,7,8,9,10,11,12}
+ for i = 1, math.floor(#tobeadded/6) do
+ bezierpoints[#bezierpoints+1] = {}
+ for j = 1, 6 do
+ bezierpoints[#bezierpoints][j] = tobeadded[(i-1)*6+j]
+ end
+ end
end
end
end
- if isreverse then
- return reversepath(bezierstring)
- else
- return bezierstring
- end
+ -- only for debugging:
+ --for i = 1, #bezierpoints do
+ -- for j = 1, #bezierpoints[i] do
+ -- print(bezierpoints[i][j])
+ -- end
+ ---print("\n")
+ --end
+ return beziertabletostring(bezierpoints,rndx,rndy,isreverse,notation)
end
-- main program --
@@ -672,25 +789,38 @@ if not pcall(debug.getlocal, 4, 1) then
if #arg >= 1 then
local xmin = -5
local xmax = 5
- if #arg >= 2 then xmin = arg[2] end
+ if #arg >= 2 then
+ local tempfunc = assert(load("return " .. arg[2]))
+ xmin = tempfunc()
+ end
if #arg >= 3 then
if arg[3] == arg[2] then
xmax = xmin + 10
else
- xmax = arg[3]
+ local tempfunc = assert(load("return " .. arg[3]))
+ xmax = tempfunc()
end
end
local ymin = -5
local ymax = 5
- if #arg >= 4 then ymin = arg[4] end
+ if #arg >= 4 then
+ local tempfunc = assert(load("return " .. arg[4]))
+ ymin = tempfunc()
+ end
if #arg >= 5 then
if arg[5] == arg[4] then
ymax = ymin + 10
else
- ymax = arg[5]
+ local tempfunc = assert(load("return " .. arg[5]))
+ ymax = tempfunc()
end
end
- print(bezierplot(arg[1],xmin,xmax,ymin,ymax))
+ if #arg >= 6 then
+ notation = arg[6]
+ else
+ notation = "tikz"
+ end
+ print(bezierplot(arg[1],xmin,xmax,ymin,ymax,notation))
end
end
diff --git a/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.sty b/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.sty
index 66f404dfd34..26e76f0e25b 100644
--- a/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.sty
+++ b/Master/texmf-dist/tex/lualatex/bezierplot/bezierplot.sty
@@ -1,16 +1,16 @@
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{bezierplot}[2018/04/12 bezierplot]
+\ProvidesPackage{bezierplot}[2018/06/10 bezierplot]
\RequirePackage{xparse}
\RequirePackage{iftex}
\ifLuaTeX
\directlua{require("bezierplot")}
- \DeclareExpandableDocumentCommand{\xbezierplot}{O{-5} O{5} O{-5} O{5} m}{%
- \directlua{tex.sprint(bezierplot("#5",#1,#2,#3,#4))}
+ \DeclareExpandableDocumentCommand{\xbezierplot}{O{-5} O{5} O{-5} O{5} O{tikz} m}{%
+ \directlua{tex.sprint(bezierplot("#6",#1,#2,#3,#4,"#5"))}
}
\else
\let\xpandblinpt\@@input
- \DeclareExpandableDocumentCommand{\xbezierplot}{O{-5} O{5} O{-5} O{5} m}{%
- \xpandblinpt|"bezierplot '#5' #1 #2 #3 #4"
+ \DeclareExpandableDocumentCommand{\xbezierplot}{O{-5} O{5} O{-5} O{5} O{tikz} m}{%
+ \xpandblinpt|"bezierplot '#6' #1 #2 #3 #4 '#5'"
}
\fi
\providecommand\bezierplot{\romannumeral`\^^@\xbezierplot}