-- luadraw_fields2d.lua -- date 2026/05/29 -- version 3.1 -- Copyright 2026 Patrick Fradin -- This work may be distributed and/or modified under the -- conditions of the LaTeX Project Public License. -- The latest version of this license is in -- https://www.ctan.org/license/lppl -- to draw vector fields or gradient fields local ld = luadraw local graph = ld.graph local cpx = ld.cpx local Z = cpx.Z function ld.field(f,x1,x2,y1,y2,grid,long) -- champ de vecteurs dans le pavé [x1,x2]x[y1,y2] -- f fonction de deux variables à valeurs dans R^2 -- grid = {nbx, nby} : nombre de vecteurs suivant x et suivant y -- long = longueur d'un vecteur if grid == nil then grid = {25,25} end local deltax, deltay = (x2-x1)/(grid[1]-1), (y2-y1)/(grid[2]-1) -- pas suivant x et y if long == nil then long = math.min(deltax,deltay) end -- longueur par défaut local vectors = {} -- contiendra la liste des vecteurs local x, y, v = x1 for _ = 1, grid[1] do -- parcours suivant x y = y1 for _ = 1, grid[2] do -- parcours suivant y v = f(x,y) -- on suppose que v est bien défini v = Z(v[1],v[2]) -- passage en complexe v = cpx.normalize(v) if v ~= nil then table.insert(vectors, {Z(x,y)-long/2*v, Z(x,y)+long/2*v} ) -- on ajoute le vecteur end y = y+deltay end x = x+deltax end return vectors -- on renvoie le résultat (ligne polygonale) end function graph:Dvectorfield(f,args) -- dessine un champ de vecteurs -- f fonction de deux variables à valeurs dans R^2 -- args table à 4 champs : -- { view={x1,x2,y1,y2}, grid={nbx,nby}, length=, draw_options=""} args = args or {} local view = args.view or {self:Xinf(),self:Xsup(),self:Yinf(),self:Ysup()} -- repère utilisateur par défaut local vectors = ld.field(f,view[1],view[2],view[3],view[4],args.grid,args.length) -- calcul du champ self:Dpolyline(vectors,false,args.draw_options,view) -- le dessin (ligne polygonale non fermée) end function graph:Dgradientfield(f,args) -- dessine un champ de gradient -- f fonction de deux variables à valeurs dans R -- args table à 4 champs : -- { view={x1,x2,y1,y2}, grid={nbx,nby}, length=, draw_options=""} local h = 1e-6 local grad_f = function(x,y) -- fonction gradient de f return { (f(x+h,y)-f(x-h,y))/(2*h), (f(x,y+h)-f(x,y-h))/(2*h) } end self:Dvectorfield(grad_f,args) -- on utilise la méthode précédente end function graph:DplotXY(X,Y,draw_options) -- X est une liste de réels ou de chaînes -- Y est une liste de réels de même longueur que X local L = {} -- liste des points à dessiner if type(X[1]) == "number" then for k,x in ipairs(X) do table.insert(L,Z(x,Y[k])) end else local noms = {} -- liste des labels à placer for k = 1, #X do table.insert(L,Z(k,Y[k])) ld.insert(noms,{X[k],k,{pos="E",node_options="rotate=-90"}}) end self:Dlabel(table.unpack(noms)) end self:Dpolyline(L,draw_options) end