Skip to content

Instantly share code, notes, and snippets.

@bobcgausa
Created August 3, 2014 22:58
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bobcgausa/8649a726c846b1791b83 to your computer and use it in GitHub Desktop.
Save bobcgausa/8649a726c846b1791b83 to your computer and use it in GitHub Desktop.
Lua Arcs and Ellipses
Ellipse = {
--declare constants
format='%d %d %d %d ',
class=',Ellipse,class,'
}
function Ellipse:tostring()
return string.format(self.format,self.x,self.y,self.width,self.height)
end --tostring
function Ellipse:new(centerX, centerY, wide, tall)
assert(wide>=0 and tall>=0)
local r = {x=centerX, y=centerY,
width=wide, height=tall}
setmetatable(r, {__tostring = Ellipse.tostring, __index = Ellipse} )
r.tostring=Ellipse.tostring
return r
end --new
function Ellipse:isInstance(name)
local where=string.find(self.class, ',' .. name .. ',', 1, true)
return where ~= nil
end --isInstance
function Ellipse:setFormat(string)
Ellipse.format = string
end
function Ellipse:getXY()
return self.x, self.y
end
function Ellipse:getWH()
return self.width, self.height
end
function Ellipse:copy()
local u = { }
for k, v in pairs(self) do u[k] = v end
setmetatable(u, {__tostring = Ellipse.tostring, __index = Ellipse} )
u.tostring=Ellipse.tostring
return u
end
function Ellipse:setXY(centerX, centerY)
self.x=centerX self.y=centerY
return self
end
function Ellipse:setWH(width, height)
assert(width>=0 and height>=0)
self.width=width self.height=height
return self
end
function Ellipse:set(el)
self.x,self.y,self.width,self.height=el.x,el.y,el.width,el.height
return self
end
function Ellipse:isEqual(ellipse)
if math.abs(self.x-ellipse.x)>1e-4 then return false end
if math.abs(self.y-ellipse.y)>1e-4 then return false end
if math.abs(self.width-ellipse.width)>1e-4 then return false end
return math.abs(self.height-ellipse.height)<=1e-4
end
function Ellipse:area()
return math.pi * self.width * self.height * 0.25
end
function Ellipse:circumference() --see wikipedia ellipse/Ramanujan approximation
local a=self.width/2
local b=self.height/2
return math.pi * ( (a + b)*3 - math.sqrt( (a*3+b)*(a+b*3) ) )
end
function Ellipse:isPntWithin(x, y)
local a=self.width/2
local b=self.height/2
return ( (x-self.x)*(x-self.x)/(a*a) +
(y-self.y)*(y-self.y)/(b*b) ) <= 1
end
function Ellipse:isEllipseWithin(ellipse)
local points=ellipse:vertices(16,0,6.28)
for i=1,#points-1,2 do
if not self:isPntWithin(points[i], points[i+1]) then return false end
end
return true
end
function Ellipse:isIntersecting(ellipse)
local points=ellipse:vertices(16,0,6.28)
for i=1,#points-1,2 do
if self:isPntWithin(points[i], points[i+1]) then return true end
end
return false
end
function Ellipse:union(ellipse) --use rectangle code
local x1 = math.min(self.x-self.width/2, ellipse.x-ellipse.width/2)
local y1 = math.min(self.y-self.height/2, ellipse.y-ellipse.height/2)
local x2 = math.max(self.x+self.width/2, ellipse.x+ellipse.width/2)-x1
local y2 = math.max(self.y+self.height/2, ellipse.y+ellipse.height/2)-y1
self.x,self.y,self.width,self.height=x1+x2/2, y1+y2/2, x2, y2
return self
end
function Ellipse:translate(x, y)
self.x=self.x+x self.y=self.y+y
return self
end
function Ellipse:scale(x, y)
self.width=self.width*x self.height=self.height*y
return self
end
function Ellipse:parse(string)
local i=1
for w in string.gmatch (string, "[%+%-]?%d+%.?%d*[eE]?[%+%-]?%d*") do
if i==1 then self.x=w
elseif i==2 then self.y=w
elseif i==3 then self.width=w
elseif i==4 then self.height=w
end
i = i+1
end --for w
end
--[[local Vector=require('Vector')
function Ellipse:points(n,startAngle,stopAngle) --in radians, 0..pi*2
local a=self.width/2
local b=self.height/2
local addin = (stopAngle-startAngle)/(n-1)
local step=startAngle
local poly={}
for i=1,n do
poly[i]=Vector:fromAngle(step):scale(a,b):translate(self.x,self.y)
step = step + addin
end
return poly
end--]]
function Ellipse:vertices(n,startAngle,stopAngle) --in radians, 0..pi*2
local a=self.width/2
local b=self.height/2
local addin = (stopAngle-startAngle)/(n-1)
local step=startAngle
local poly={}
for i=1,n do
poly[i*2-1] = math.cos(step)*a+self.x
poly[i*2] = math.sin(step)*b+self.y
step = step + addin
end
return poly
end
return Ellipse
Ellipse=require('Ellipse')
local r=Ellipse:new(display.contentCenterX,display.contentCenterY-100,440,120)
print(r)
local r2=Ellipse:new(0,0,150,80)
local function draw(el)
local rd=el:vertices(40,0,6.28) --40 points, 0 to 2pi degrees of arc
return display.newPolygon(el.x,el.y,rd)
end --draw
local r3,r4
local t1,t2,t3,t4,t5
local arc
local poly
local g
r4=Ellipse:new(0,0,0,0)
local t=display.newText('union',display.contentCenterX,170,system.defaultFont,32)
t:setFillColor(1,1,0)
arc=Ellipse:new(display.contentCenterX/2,display.contentHeight-100,200,150)
local function touch(event)
r2:setXY(event.x, event.y)
display.remove(r3)
display.remove(t5)
display.remove(t4)
display.remove(t1)
display.remove(t2)
display.remove(t3)
display.remove(poly)
display.remove(g)
r3=draw(r2)
r3:setFillColor(0,0,1)
t1=display.newText(string.format('(%d,%d) isPntWithin '..tostring(r:isPntWithin(event.x,event.y)),event.x,event.y),display.contentCenterX,50,system.defaultFont,32)
t2=display.newText(string.format('isEllipseWithin '..tostring(r:isEllipseWithin(r2))),
display.contentCenterX,80,system.defaultFont,32)
t3=display.newText(string.format('isIntersecting '..tostring(r:isIntersecting(r2))),
display.contentCenterX,110,system.defaultFont,32)
r4:set(r):union(r2)
r4:translate(0,200)
t5=draw(r4)
t5:setFillColor(1,1,0)
local rd=arc:vertices(40,math.random()*3,math.random()*3.14+3.14)
rd[#rd+1]=arc.x rd[#rd+1]=arc.y
poly=display.newPolygon(arc.x,arc.y,rd)
poly.fill=nil
poly:setStrokeColor(1,0,0)
poly.strokeWidth=2
poly:translate(250,0)
g=display.newGroup()
for i=1,#rd-4,2 do
local l=display.newLine(rd[i],rd[i+1],rd[i+2],rd[i+3])
l.strokeWidth=2
l:setStrokeColor(1,0,0)
g:insert(l)
end
end --touch
draw(r)
Runtime:addEventListener('tap', touch)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment