3D тор в Lua

Я полный новичок в Lua. Цель состоит в том, чтобы отобразить трехмерный тор в точках (см. Рисунок 1) или, по крайней мере, вычислить позиции, отдавая предпочтение ясности перед производительностью. Псевдокодовая ссылка.

Не стесняйтесь быть разборчивым, я бы хотел выучить правильные идиомы Lua. Например, мне было приятно обнаружить перегрузку оператора, но я не смог найти удобный способ привязать его к моему «типу матрицы» по умолчанию.

введите описание изображения здесь

-- Bake dot-donut. Based on pseudo-code here:
-- https://64nops.wordpress.com/2021/01/21/rosetta-sugar-japprends-a-coder-avec-mon-cpc/

-- Main parameters to play with.
r, r2 = 100, 20  -- Major and minor radius
dist = 200       -- Distance from observator. Should be greater than major radius
zoom = 300       
dots_per_circle = 100
nbcircles = 200   

-- pi is wrong!
local tau = 2*math.pi
local cos = math.cos
local sin = math.sin

-- For operator overloading
metamatrix = {}
-- Rotation matrice around x axis
function rotx(a) 
  local c, s = cos(a), sin(a)
  res = {{1,  0,  0},
         {0,  c, -s},
         {0,  s,  c}}
  setmetatable(res, metamatrix)
  return res
end
-- Rotation matrice around y axis
function roty(a) 
  local c, s = cos(a), sin(a)
  res = {{c,  0, -s},
         {0,  1,  0},
         {s,  0, c}}
  setmetatable(res, metamatrix)
  return res
end
-- Rotation matrice around z axis
function rotz(a) 
  local c, s = cos(a), sin(a)
  res = {{c, -s,  0},
         {s,  c,  0},
         {0,  0,  1}}
  setmetatable(res, metamatrix)
  return res
end

-- Multiplication of matrices (m rows n cols) * (n rows p cols) 
function metamatrix.__mul(A, B) 
   local res = {}
   for i = 1, #A do
     res[i] = {}
     for j = 1, #B[1] do   -- TODO? Handle empty matrix.
       local s = 0
       for k = 1, #B do
          s = s + A[i][k] * B[k][j]
       end
       res[i][j] = s
     end
   end
   setmetatable(res, metamatrix)
   return res
end

-- Abstract the encoding of position (x y z).
-- Here, we choose column vector convention,
-- to be compatible with left multiplication by rotation matrices.
function dot(x, y, z)
  return {{x},
          {y},
          {z}}
end
function undot(dot)
  return dot[1][1],
         dot[2][1],
         dot[3][1]
end

-- 3d to 2d
function proj(x, y, z)
  local z2 = z + dist
  return x/z2 * zoom, y/z2 * zoom
end

-- List of regularly spaced dots from a circle of radius r' at distance x = r in the plane XOY.
circle = {}
for i = 1, dots_per_circle do
  local a = (i-1) * tau / dots_per_circle
  circle[i] = dot(cos(a)*r2+r, sin(a)*r2, 0)
end

-- Now the torus is a surface of revolution.
torus = {}
for i = 1, nbcircles do
  local a = (i-1) * tau / nbcircles
  for _, dot in pairs(circle) do
    table.insert(torus, roty(a) * dot)
  end
end

-- Let's tilt it.
tilt = rotx(0.5) * rotz(0.3)
torus2 = {} 
for _, dot in pairs(torus) do
  table.insert(torus2, tilt * dot)
end

-- Project to 2D and serialize.
for _, dot in pairs(torus2) do
   local x, y, z = undot(dot)
   xp, yp = proj(x, y, z)
   print(xp, yp)
end

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *