## Hey, so here's a couple functions!

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Nicholas Scott
Prole
Posts: 49
Joined: Sun Jun 07, 2015 9:12 am

### Hey, so here's a couple functions!

I take no credit for creating the concepts or the formulas, I only wrote the code , obviously xD I'm not a genius, but I did the tedious work of putting the functions together. I don't think there is any practical use for them, but I still found them interesting to play with

This is a Super Ellipse function, not much to explain here haha
Pretty basic, xOff and yOff are the positions of the center of the Ellipse, a, b, and n are variables to play with at your leisure(A and B are w and h, n is the gud stuff, detail is line segments

Code: Select all

function love.graphics.superEllipse(xOff, yOff, a, b, n, detail)
local function sgn(x) --Function for stuff :3
return x > 0 and 1 or x < 0 and -1 or 0
end
xOff, yOff, a, b, n, na, detail = xOff or 0, yOff or 0, a or 100, b or 100, n or 2, n/2, detail or 0.1
local PointTable = {}
for i=0, math.pi*2, (math.pi*2) / detail or 0.1 do
table.insert(PointTable, {x=math.pow(math.abs(math.cos(i)), na) * a * sgn(math.cos(i)),y=math.pow(math.abs(math.sin(i)), na) * b * sgn(math.sin(i))})
end
for k,v in pairs(PointTable) do
local thisVec = v
local nextVec = PointTable[k+1] or PointTable[1]
love.graphics.line(v.x + xOff, v.y + yOff, nextVec.x + xOff, nextVec.y + yOff)
end
end

Now here comes the fun stuff! SuperShapes Mwahahhahahaa, if you have no idea what it is, or what you can go do with it, go check out this page http://paulbourke.net/geometry/supershape/. It even goes over some variables you can input to have various different shapes. I'm not gonna go into super detail cuz it's allot haha. But it's cool nonetheless
Once again, xOff and yOff are positions, n1, n2, n3, m, a, and b are your children.. Don't abuse them... Naw, jk do what you want fam, it's just a letter. Detail is segments, and radius is.. well radius

Code: Select all

function love.graphics.superShape(xOff, yOff, n1, n2, n3, m, a, b, detail, radius)
--[[ Default values ]]--
n1, n2, n3, m, a, b, detail, radius, xOff, yOff = n1 or 1, n2 or 1, n3 or 1, m or 0, a or 1, b or 1, detail or 500, radius or 100, xOff or 0, yOff or 0
--[[ Function for stuff :3 ]]--
local function spshpe(theta)
local formula = math.pow((math.pow(math.abs((1 / a) * math.cos(theta * m / 4)), n2)) + (math.pow(math.abs((1 / b) * math.sin(theta * m / 4)), n3)), 1 / n1)

return formula == 0 and 0 or 1 / formula
end

local PointTable = {}
for i=0, math.pi * 2, (math.pi*2) / detail do
end
for k,v in pairs(PointTable) do
local thisVec = v
local nextVec = PointTable[k+1] or PointTable[1]
love.graphics.line(v.x + xOff, v.y + yOff, nextVec.x + xOff, nextVec.y + yOff)
end
end

Have fun guys, It's fun to tinker with

EDIT:
Here's the more optimized and ability to use outside of LOVE2D with credit from the all mighty Positive07
Positive07 wrote:Okey I had a go with the first function, trying to optimize and making it nicre, Also with lot's of comments so you can understand why I changed what I changed

Code: Select all

--Declare variables that are gonna be used EVERY time the function is called outside of it
--This is so that Lua doesn't calculate them every single time
local tau = math.pi*2
local func = { math.cos, math.sin }

function superEllipse(x, y, a, b, n, detail)
-- I used tables here because I'm actually cheating later
local offset = { x or 0, y or 0 }
local v = { a or 100, b or 100 }
--It didn't look like you needed n after all
local na = (n or 2)/2
--I declared all variables in different lines because it's easier to know which one gets which value
local detail = detail or 0.1

--ranamed for consistency
local points = {}

for i=0, tau, tau / detail do
--x and y are calculated the same so we can do it in a loop
for j=1, 2 do
--This are only used here so they must be locals
--we don't want to pollute the global scope
local f = func[j](i)
local abs = math.abs(f)
--I removed the sign function and used this which ivan suggested
local sgn = math.floor(f/abs + 0.5)

--We apply the offset directly to the points
local result = (math.pow(abs, na) * v[j] * sgn) + offset[j]
--All points are in a single list, odd enrties are x values, even are y values
--table.insert is slow in common Lua (Not that it matters with LuaJIT though)
points[#points + 1] = result
end
end

--Return the list of points
return points
end

--LÖVE specific function, the other is just math
function superEllipseDraw (...)
--love.graphics.polygon has a line mode which do the same job as your second loop
love.graphics.polygon("line", supperEllipse(...))
end


Code: Select all

local tau = math.pi*2
local func = { math.cos, math.sin }

function superEllipse(x, y, a, b, n, detail)
local offset = { x or 0, y or 0 }
local v = { a or 100, b or 100 }
local na = (n or 2)/2
local detail = detail or 0.1

local points = {}

for i=0, tau, tau / detail do
for j=1, 2 do
local f = func[j](i)
local abs = math.abs(f)
local sgn = math.floor(f/abs + 0.5)

local result = (math.pow(abs, na) * v[j] * sgn) + offset[j]
points[#points + 1] = result
end
end

return points
end

function superEllipseDraw (...)
love.graphics.polygon("line", supperEllipse(...))
end

Last edited by Nicholas Scott on Wed Dec 14, 2016 1:00 am, edited 4 times in total.

Jasoco
Inner party member
Posts: 3651
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

### Re: Hey, so here's a couple functions!

The first function (math.sgn) can be replaced with a much more compact version:

Code: Select all

function math.sgn(x)
return x > 0 and 1 or x < 0 and -1 or 0
end
And the if formula/return lines could be replaced too...

Code: Select all

return formula == 0 and 0 or 1 / formula
Sorry, I've just been obsessed with this trick lately. Probably an unhealthy obsession. No idea if they'd even make things faster or slower. Just more compact and neat looking. (As long as you understand what they do)

ivan
Party member
Posts: 1614
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

### Re: Hey, so here's a couple functions!

In this case, since you already know the absolute value you can simply write:

Code: Select all

local absValue = math.abs(value) -- already known
assert(absValue > 0)
local sign = value/absValue
Also, make sure to store intermediate stuff in locals since Lua is a dynamic language (and cannot optimize 'constant' operations):

Code: Select all

    local a = a or 100
local b = b or 100
local n = n or 2
local na = n/2
local co = math.cos(i)
local si = math.sin(i)
local aco = math.abs(co)
local asi = math.abs(si)
local x = math.pow(aco, na) * a * co/aco
local y = math.pow(asi, na) * b * si/asi
table.insert(PointTable, Vector(x, y))
Note: You'll need an extra check if aco==0 or asi==0 to avoid a division by 0
or better yet, if your math code is robust enough, that shouldn't happen at all.

PS. and move "local a = a or 100" outside of the loop, you don't need that check in every iteration.

Nicholas Scott
Prole
Posts: 49
Joined: Sun Jun 07, 2015 9:12 am

### Re: Hey, so here's a couple functions!

ivan wrote:
Jasoco wrote:
Credit to you two , I worked stuff out and just did some general changes, so there ya go
Also I can't get over that trick either Jasoco haha, I love it but don't use it for when I'm lettin others see the code cuz well.. It's kind of a hard concept for new people to understand but ye

Jasoco
Inner party member
Posts: 3651
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

### Re: Hey, so here's a couple functions!

Haha, yeah. It can be confusing to newbies, but when you get used to it, it saves a lot of code typing.

Positive07
Party member
Posts: 1006
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

### Re: Hey, so here's a couple functions!

Okey I had a go with the first function, trying to optimize and making it nicre, Also with lot's of comments so you can understand why I changed what I changed

Code: Select all

--Declare variables that are gonna be used EVERY time the function is called outside of it
--This is so that Lua doesn't calculate them every single time
local tau = math.pi*2
local func = { math.cos, math.sin }

function superEllipse(x, y, a, b, n, detail)
-- I used tables here because I'm actually cheating later
local offset = { x or 0, y or 0 }
local v = { a or 100, b or 100 }
--It didn't look like you needed n after all
local na = (n or 2)/2
--I declared all variables in different lines because it's easier to know which one gets which value
local detail = detail or 0.1

--ranamed for consistency
local points = {}

for i=0, tau, tau / detail do
--x and y are calculated the same so we can do it in a loop
for j=1, 2 do
--This are only used here so they must be locals
--we don't want to pollute the global scope
local f = func[j](i)
local abs = math.abs(f)
--I removed the sign function and used this which ivan suggested
local sgn = math.floor(f/abs + 0.5)

--We apply the offset directly to the points
local result = (math.pow(abs, na) * v[j] * sgn) + offset[j]
--All points are in a single list, odd enrties are x values, even are y values
--table.insert is slow in common Lua (Not that it matters with LuaJIT though)
points[#points + 1] = result
end
end

--Return the list of points
return points
end

--LÖVE specific function, the other is just math
function superEllipseDraw (...)
--love.graphics.polygon has a line mode which do the same job as your second loop
love.graphics.polygon("line", supperEllipse(...))
end


Code: Select all

local tau = math.pi*2
local func = { math.cos, math.sin }

function superEllipse(x, y, a, b, n, detail)
local offset = { x or 0, y or 0 }
local v = { a or 100, b or 100 }
local na = (n or 2)/2
local detail = detail or 0.1

local points = {}

for i=0, tau, tau / detail do
for j=1, 2 do
local f = func[j](i)
local abs = math.abs(f)
local sgn = math.floor(f/abs + 0.5)

local result = (math.pow(abs, na) * v[j] * sgn) + offset[j]
points[#points + 1] = result
end
end

return points
end

function superEllipseDraw (...)
love.graphics.polygon("line", supperEllipse(...))
end

Last edited by Positive07 on Mon Dec 12, 2016 10:38 pm, edited 1 time in total.
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(Github.com/Positive07)

zorg
Party member
Posts: 2995
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

### Re: Hey, so here's a couple functions!

Just to nitpick a bit, 2pi is commonly called "tau".
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

ivan
Party member
Posts: 1614
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

### Re: Hey, so here's a couple functions!

Good job, Positive, your revisions look much cleaner than the original.
Of course, I would even remove "table.insert" and "love.graphics" too
so the code would be pure Lua math (each function could return a list of points).

Ref
Party member
Posts: 690
Joined: Wed May 02, 2012 11:05 pm

### Re: Hey, so here's a couple functions!

For those just curious what super ellipses look like, see attached Love.
Definitely not an example of great code - just wanted to see what this was all about.
Key control for 'm' and 'n' parameters.
love.math.triangulate definitely doesn't like certain parameter combinations.
Have fun.
Attachments
Super.love
No credit taken

Positive07
Party member
Posts: 1006
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

### Re: Hey, so here's a couple functions!

ivan wrote:Good job, Positive, your revisions look much cleaner than the original.
Of course, I would even remove "table.insert" and "love.graphics" too
so the code would be pure Lua math (each function could return a list of points).
Okay I fixed this things, [manual]table.insert[/manual] is not slower than points[#points + 1] in LuaJIT though, because LuaJIT optimizes it
I added a superEllipseDraw function which is LÖVE specific but the supperEllipse one is just math
zorg wrote:Just to nitpick a bit, 2pi is commonly called "tau".
I fixed this too because there was actually a bug and instead of writing "pi2", I wrote "p12"... so "tau" is better
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(Github.com/Positive07)

### Who is online

Users browsing this forum: No registered users and 13 guests