-- Contains coordinate streamers, i.e. classes which generate coordinates and stream them to some output stream local math=math local pgfplotsmath = pgfplots.pgfplotsmath local type=type local tostring=tostring local error=error local table=table do -- all globals will be read from/defined in pgfplots: local _ENV = pgfplots ----------------------------------- CoordOutputStream = newClass() function CoordOutputStream:constructor() end -- @param pt an instance of Coord function CoordOutputStream:coord(pt) end ----------------------------------- SurveyCoordOutputStream = newClassExtends(CoordOutputStream) function SurveyCoordOutputStream:constructor(targetPlothandler) if not targetPlothandler then error("arguments must not be nil") end self.plothandler= targetPlothandler end function SurveyCoordOutputStream:coord(pt) self.plothandler:surveypoint(pt) end ------------- -- This is a partial reimplementation of \addplot expression: it samples points -- but entirely in LUA. Only the results are serialized back to TeX. AddplotExpressionCoordinateGenerator = newClass() function AddplotExpressionCoordinateGenerator:constructor(coordoutputstream, expressionsByDimension, domainMin, domainMax, samples, variableNames) if not coordoutputstream or not expressionsByDimension or not domainMin or not domainMax or not samples or not variableNames then error("arguments must not be nil") end if #variableNames ~= 2 then error("Expected 2 variableNames") end self.coordoutputstream = coordoutputstream self.is3d = #expressionsByDimension == 3 self.expressions = expressionsByDimension self.domainMin = domainMin self.domainMax = domainMax self.samples = samples self.variableNames = variableNames -- log("initialized " .. tostring(self) .. "\n") end -- @return true on success or false if the operation cannot be carried out. -- this method is a replicate of \pgfplots@addplotimpl@expression@@ function AddplotExpressionCoordinateGenerator:generateCoords() local stringToFunctionMap = pgfluamathfunctions.stringToFunctionMap -- create a backup of the 'x' and 'y' math expressions which -- have been defined in \pgfplots@coord@stream@start: local old_global_function_x = stringToFunctionMap["x"] local old_global_function_y = stringToFunctionMap["y"] local coordoutputstream = self.coordoutputstream local is3d = self.is3d local expressions = self.expressions local xExpr = expressions[1] local yExpr = expressions[2] local zExpr = expressions[3] local domainMin = self.domainMin local domainMax = self.domainMax local samples = self.samples local h = {} for i = 1,#domainMin do h[i] = (domainMax[i] - domainMin[i]) / (samples[i]-1) end local variableNames = self.variableNames local x,y local sampleLine = #samples==1 local function pseudoconstantx() return x end local pseudoconstanty if sampleLine then if yExpr ~= variableNames[2] then -- suppress the warning - we want to allow (x,y,x^2) in this case. pseudoconstanty = function() return 0 end else local didWarn = false pseudoconstanty = function() if not didWarn then log("Sorry, you can't use 'y' in this context. PGFPlots expected to sample a line, not a mesh. Please use the [mesh] option combined with [samples y>0] and [domain y!=0:0] to indicate a twodimensional input domain\n") didWarn = true end return 0 end end else pseudoconstanty = function() return y end end local pgfmathparse = pgfluamathparser.pgfmathparse local prepareX if xExpr == variableNames[1] then prepareX = function() return x end else prepareX = function() return pgfmathparse(xExpr) end end local prepareY if yExpr == variableNames[2] then prepareY = function() return y end else prepareY = function() return pgfmathparse(yExpr) end end local function computeXYZ() stringToFunctionMap[variableNames[1]] = pseudoconstantx stringToFunctionMap[variableNames[2]] = pseudoconstanty local X = prepareX() local Y = prepareY() local Z = nil if is3d then Z = pgfmathparse(zExpr) else -- FIXME BUG: we need to do something else with 'Z' if this is a 2d plot inside of a 3d axis! end local pt = Coord.new() pt.x = { X, Y, Z} -- restore 'x' and 'y' -- FIXME : defining the resulting x/y coordinates as 'x' and 'y' constants was a really really bad idea in the first place :-( stringToFunctionMap["x"] = old_global_function_x stringToFunctionMap["y"] = old_global_function_y coordoutputstream:coord(pt) end if not sampleLine then local xmin = domainMin[1] local ymin = domainMin[2] local hx = h[1] local hy = h[2] local max_i = samples[1]-1 local max_j = samples[2]-1 -- samples twodimensionally (a lattice): for j = 0,max_j do -- FIXME : pgfplots@plot@data@notify@next@y y = ymin + j*hy -- log("" .. j .. "\n") for i = 0,max_i do -- FIXME : pgfplots@plot@data@notify@next@x x = xmin + i*hx computeXYZ() end -- FIXME : \pgfplotsplothandlernotifyscanlinecomplete end else local xmin = domainMin[1] local hx = h[1] local max_i = samples[1]-1 for i = 0,max_i do -- FIXME : pgfplots@plot@data@notify@next@x x = xmin + i*hx computeXYZ() end end stringToFunctionMap[variableNames[1]] = nil stringToFunctionMap[variableNames[2]] = nil return true end function AddplotExpressionCoordinateGenerator:__tostring() local result = "AddplotExpressionCoordinateGenerator[\n" result = result .. "\n variable(s)=" .. self.variableNames[1] .. " " .. self.variableNames[2] result = result .. "\n expressions=" for i = 1,#self.expressions do result = result .. self.expressions[i] ..", " end result = result .. "\n domain=" .. self.domainMin[1] .. ":" .. self.domainMax[1] result = result .. "\n samples=" .. self.samples[1] if #self.domainMin == 2 then result = result .. "\n domain y=" .. self.domainMin[2] .. ":" .. self.domainMax[2] result = result .. "\n samples y=" .. self.samples[2] end result = result .. "]" return result end end