#StackBounty: #beginner #computational-geometry #lua 3D torus in Lua

Bounty: 350

I’m a total beginoob in Lua. The aim is to display a 3D Torus in dots (see Figure1), or at least compute the positions, privileging clarity over performance. Pseudocode link.

Don’t hesitate to be picky, I’d like to learn proper Lua idioms.
For instance, I was pleased to find operator overloading, but couldn’t find a neat way to bind it to my "matrix type" by default.

enter image description here

-- 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


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.