Whitemambaa

qmath.lua

Dec 7th, 2013
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.55 KB | None | 0 0
  1. --By xXxMoNkEyMaNxXx elsez
  2. --Regular Lua
  3. local type=type
  4. local newproxy=newproxy
  5. local getmetatable=getmetatable
  6. local setmetatable=setmetatable
  7.  
  8. local pi=math.pi
  9. local tau=2*pi
  10. local sqrt=math.sqrt
  11. local atan2=math.atan2
  12. local exp,log=math.exp,math.log
  13. local cos,sin=math.cos,math.sin
  14. local acos,asin=math.acos,math.asin
  15.  
  16. local function TYPE(x)
  17.     local xMet=getmetatable(x)
  18.     if type(xMet)=="table" and xMet.__type then
  19.         return xMet.__type
  20.     else
  21.         return type(x)
  22.     end
  23. end
  24.  
  25. local Q={}
  26. local iq=newproxy(true)
  27. local metatable=getmetatable(iq)
  28. metatable.__type="quaternion"
  29. local data=setmetatable({[iq]={w=1,x=0,y=0,z=0}},{__mode="k"})
  30. function metatable.__index(q,i)
  31.     local dq=data[q]
  32.     if dq then
  33.         return dq[i]
  34.     end
  35. end
  36. local function new(w,x,y,z)
  37.     local q=newproxy(iq)
  38.     data[q]={w=w or 1,x=x or 0,y=y or 0,z=z or 0}
  39.     return q
  40. end
  41. Q.new=new
  42. local function inv(q)
  43.     local w,x,y,z=q.w,q.x,q.y,q.z
  44.     local m=w*w+x*x+y*y+z*z
  45.     if m>0 then
  46.         return new(w/m,-x/m,-y/m,-z/m)
  47.     else
  48.         return new(0)
  49.     end
  50. end
  51. Q.inv=inv
  52.  
  53. --Unary minus; -q
  54. local function unm(q)
  55.     return new(-q.w,-q.x,-q.y,-q.z)
  56. end
  57. metatable.__unm=unm
  58. Q.unm=unm
  59. local function add(q0,q1)
  60.     local t0,t1=TYPE(q0),TYPE(q1)
  61.     if t0=="quaternion" and t1=="quaternion" then
  62.         return new(q0.w+q1.w,q0.x+q1.x,q0.y+q1.y,q0.z+q1.z)
  63.     elseif t0=="quaternion" and t1=="number" then
  64.         return new(q0.w+q1,q0.x,q0.y,q0.z)
  65.     elseif t0=="number" and t1=="quaternion" then
  66.         return new(q0+q1.w,q1.x,q1.y,q1.z)
  67.     end
  68. end
  69. metatable.__add=add
  70. Q.add=add
  71. local function sub(q0,q1)
  72.     local t0,t1=TYPE(q0),TYPE(q1)
  73.     if t0=="quaternion" and t1=="quaternion" then
  74.         return new(q0.w-q1.w,q0.x-q1.x,q0.y-q1.y,q0.z-q1.z)
  75.     elseif t0=="quaternion" and t1=="number" then
  76.         return new(q0.w-q1,q0.x,q0.y,q0.z)
  77.     elseif t0=="number" and t1=="quaternion" then
  78.         return new(q0-q1.w,-q1.x,-q1.y,-q1.z)
  79.     end
  80. end
  81. metatable.__sub=sub
  82. Q.sub=sub
  83. local function mul(q0,q1)
  84.     local t0,t1=TYPE(q0),TYPE(q1)
  85.     if t0=="quaternion" and t1=="quaternion" then
  86.         local w0,x0,y0,z0,w1,x1,y1,z1=q0.w,q0.x,q0.y,q0.z,q1.w,q1.x,q1.y,q1.z
  87.         return new(w0*w1-x0*x1-y0*y1-z0*z1,w0*x1+x0*w1+y0*z1-z0*y1,w0*y1-x0*z1+y0*w1+z0*x1,w0*z1+x0*y1-y0*x1+z0*w1)
  88.     elseif t0=="quaternion" and t1=="number" then
  89.         return new(q0.w*q1,q0.x*q1,q0.y*q1,q0.z*q1)
  90.     elseif t0=="number" and t1=="quaternion" then
  91.         return new(q0*q1.w,q0*q1.x,q0*q1.y,q0*q1.z)
  92.     end
  93. end
  94. metatable.__mul=mul
  95. Q.mul=mul
  96. local function div(q0,q1)
  97.     local t0,t1=TYPE(q0),TYPE(q1)
  98.     if t0=="quaternion" and t1=="quaternion" then
  99.         local w0,x0,y0,z0,w1,x1,y1,z1=q0.w,q0.x,q0.y,q0.z,q1.w,q1.x,q1.y,q1.z
  100.         local m1=w1*w1+x1*x1+y1*y1+z1*z1
  101.         if m1>0 then--This is the quaternion that gets you from q1 to q0 from q1: mul(inv(q1),q0).  (quaternion division is actually ambiguous)
  102.             return new((w1*w0+x1*x0+y1*y0+z1*z0)/m1,(w1*x0-x1*w0-y1*z0+z1*y0)/m1,(w1*y0+x1*z0-y1*w0-z1*x0)/m1,(w1*z0-x1*y0+y1*x0-z1*w0)/m1)
  103.         else
  104.             return new(0)
  105.         end
  106.     elseif t0=="quaternion" and t1=="number" then
  107.         return new(q0.w/q1,q0.x/q1,q0.y/q1,q0.z/q1)
  108.     elseif t0=="number" and t1=="quaternion" then
  109.         local w1,x1,y1,z1=q1.w,q1.x,q1.y,q1.z
  110.         local m1=w1*w1+x1*x1+y1*y1+z1*z1
  111.         if m1>0 then
  112.             local m=q0/m1
  113.             return new(m*w1,-m*x1,-m*y1,-m*z1)
  114.         else
  115.             return new(0)
  116.         end
  117.     end
  118. end
  119. metatable.__div=div
  120. Q.div=div
  121. local function pow(q0,q1)
  122.     local t0,t1=TYPE(q0),TYPE(q1)
  123.     if t0=="quaternion" and t1=="quaternion" then
  124.         local w0,x0,y0,z0=q0.w,q0.x,q0.y,q0.z
  125.         local vv=x0*x0+y0*y0+z0*z0
  126.         local mm=w0*w0+vv
  127.         if mm>0 then
  128.             if vv>0 then
  129.                 local m=sqrt(mm)
  130.                 local s=acos(w0/m)/sqrt(vv)
  131.                 w0,x0,y0,z0=log(m),x0*s,y0*s,z0*s
  132.             else
  133.                 w0,x0,y0,z0=0.5*log(mm),0,0,0
  134.             end
  135.         else
  136.             w0,x0,y0,z0=-math.huge,0,0,0
  137.         end
  138.         local w1,x1,y1,z1=q1.w,q1.x,q1.y,q1.z
  139.         local m=exp(w0*w1-x0*x1-y0*y1-z0*z1)
  140.         local x,y,z=w0*x1+x0*w1+y0*z1-z0*y1,w0*y1-x0*z1+y0*w1+z0*x1,w0*z1+x0*y1-y0*x1+z0*w1
  141.         local vv=x*x+y*y+z*z
  142.         if vv>0 then
  143.             local v=sqrt(vv)
  144.             local s=m*sin(v)/v
  145.             return new(m*cos(v),x*s,y*s,z*s)
  146.         else
  147.             return new(m)
  148.         end
  149.         --return Q.exp(q1*Q.log(q0))
  150.     elseif t0=="quaternion" and t1=="number" then
  151.         local w,x,y,z=q0.w,q0.x,q0.y,q0.z
  152.         local vv=x*x+y*y+z*z
  153.         if vv>0 then
  154.             local v=sqrt(vv)
  155.             local m=(w*w+vv)^(0.5*q1)
  156.             local theta=q1*atan2(v,w)
  157.             local s=m*sin(theta)/v
  158.             return new(m*cos(theta),x*s,y*s,z*s)
  159.         else
  160.             if w<0 then
  161.                 local m=(-w)^q1
  162.                 local s=m*sin(pi*q1)*0.57735026918962576450914878050196--3^-0.5
  163.                 return new(m*cos(pi*q1),s,s,s)
  164.             else
  165.                 return new(w^q1)
  166.             end
  167.         end
  168.     elseif t0=="number" and t1=="quaternion" then
  169.         local w,x,y,z=q1.w,q1.x,q1.y,q1.z
  170.         if q0>0 then
  171.             local m=q0^w
  172.             local vv=x*x+y*y+z*z
  173.             if vv>0 then
  174.                 local v=sqrt(vv)
  175.                 local s=m*sin(v)/v
  176.                 return new(m*cos(v),x*s,y*s,z*s)
  177.             else
  178.                 return new(m)
  179.             end
  180.         elseif q0<0 then--Not a good idea to use this.
  181.             local m=(-q0)^w
  182.             local mc,ms=m*cos(pi*w),m*sin(pi*w)
  183.             local vv=x*x+y*y+z*z
  184.             if vv>0 then
  185.                 local v=sqrt(vv)
  186.                 local c,s=cos(v),sin(v)/v
  187.                 local vc,vs=mc*s,ms*c*0.57735026918962576450914878050196
  188.                 return new(mc*c-ms*s,vc*x+vs,vc*y+vs,vc*z+vs)--This is probably TERRIBLY wrong, but raising a negative number to the power of a quaternion is ill-defined in the first place.
  189.             else
  190.                 return new(c,s,s,s)
  191.             end
  192.         elseif w*w+x*x+y*y+z*z>0 then
  193.             return new(0)
  194.         else
  195.             return new()--anyeting to da powa of 0 is 1 dud
  196.         end
  197.     end
  198. end
  199. metatable.__pow=pow
  200. Q.pow=pow
  201. local function length(q)
  202.     local w,x,y,z=q.w,q.x,q.y,q.z
  203.     return sqrt(w*w+x*x+y*y+z*z)
  204. end
  205. metatable.__len=length
  206. Q.length=length
  207. local function Qtostring(q,precision)
  208.     precision=precision or 3
  209.     return (", %."..precision.."f"):rep(4):sub(3):format(q.w,q.x,q.y,q.z)
  210. end
  211. metatable.__tostring=Qtostring
  212. Q.tostring=Qtostring
  213.  
  214. local function Qlog(q)
  215.     local w,x,y,z=q.w,q.x,q.y,q.z
  216.     local vv=x*x+y*y+z*z
  217.     local mm=w*w+vv
  218.     if mm>0 then
  219.         if vv>0 then
  220.             local m=sqrt(mm)
  221.             local s=acos(w/m)/sqrt(vv)
  222.             return new(log(m),x*s,y*s,z*s)
  223.         else
  224.             return new(0.5*log(mm))--lim v->0 x/v*acos(a/sqrt(a*a+v*v))=0 when a is positive
  225.         end
  226.     else
  227.         return new(-math.huge)
  228.     end
  229. end
  230. Q.log=Qlog
  231.  
  232. local function Qexp(q)
  233.     local m=exp(q.w)
  234.     local x,y,z=q.x,q.y,q.z
  235.     local vv=x*x+y*y+z*z
  236.     if vv>0 then
  237.         local v=sqrt(vv)
  238.         local s=m*sin(v)/v
  239.         return new(m*cos(v),x*s,y*s,z*s)
  240.     else
  241.         return new(m)
  242.     end
  243. end
  244. Q.exp=Qexp
  245.  
  246. local function Qnormalize(q)
  247.     local w,x,y,z=q.w,q.x,q.y,q.z
  248.     local mm=w*w+x*x+y*y+z*z
  249.     if mm>0 then
  250.         local m=sqrt(mm)
  251.         return new(w/m,x/m,y/m,z/m)
  252.     else
  253.         return new()
  254.     end
  255. end
  256. Q.normalize=Qnormalize
  257. Q.unit=Qnormalize
  258.  
  259. return Q
Advertisement
Add Comment
Please, Sign In to add comment