Last active
March 21, 2018 09:45
-
-
Save HoraceBury/636e18da5f8bfc9cab6197fe3184d7e2 to your computer and use it in GitHub Desktop.
Graphics extension library.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- graphics extension library | |
require("mathlib") -- https://gist.github.com/HoraceBury/9431861 | |
require("displaylib") -- https://gist.github.com/HoraceBury/1e2ce033e3441823038eb88b551ad981 | |
-- https://math.stackexchange.com/questions/2269589/calculate-angle-of-the-next-point-on-a-circle | |
--[[ | |
Generates a table of points containing the outline of a circle with each point 'step' pixels from the previous. | |
Parameters: | |
x, y: The centre of the circle | |
radius: The radius of the circle to generate | |
step: Distance between one point and the next around the edge of the circel | |
length: Length around the circumference to travel. Allows the generation of segments. | |
initialrotation: Angle of the first generated point. | |
innerradius: If a positive number, the generated path is copied, reversed and attach to the end of the path to make a segment. | |
Returns: | |
Table of {x,y} tables | |
Table of {x,y,x,y,...} point values (as accepted by physics.addBody outline parameter) | |
Notes: | |
The first and last point are not likely to be 'step' distance from each other because the circumference around a | |
circle is not likely to be evenly divisible by 'step'. | |
]]-- | |
function graphics.newCircleOutline( ... ) | |
local x, y, radius, step, length, initialrotation, innerradius | |
if (#arg == 1) then | |
x, y, radius, step, length, initialrotation, innerradius = arg[1].x, arg[1].y, arg[1].radius, arg[1].step, arg[1].length, arg[1].initialrotation, arg[1].innerradius | |
else | |
x, y, radius, step, length, initialrotation, innerradius = unpack(arg) | |
end | |
local tbl, pts = {}, {} | |
if (length == nil or length < 0 or length > 360) then length=360 end | |
local centre = {x=x,y=y} | |
local r = step/(2*radius) | |
local angle = math.deg(math.asin(r)) * 2 | |
local origin = {x=0,y=-radius} | |
origin = math.rotateTo( origin, initialrotation or 0, {x=0,y=0} ) | |
local a = 0 | |
while (a < length) do | |
local pt = math.rotateTo( origin, a, {x=0,y=0} ) | |
tbl[#tbl+1] = pt | |
pts[#pts+1] = pt.x | |
pts[#pts+1] = pt.y | |
a = a + angle | |
end | |
if (innerradius ~= nil and innerradius > 0) then | |
local innertbl = graphics.newCircleOutline( x, y, innerradius, step, length, initialrotation, nil ) | |
innertbl = table.reverse( innertbl ) | |
tbl = table.copy( tbl, innertbl ) | |
for i=1, #innertbl do | |
pts[#pts+1] = innertbl[i].x | |
pts[#pts+1] = innertbl[i].y | |
end | |
end | |
return tbl, pts | |
end | |
--[[ | |
Generates a semi-circle set of points, starting at a given angle and continuing for half a turn. | |
Parameters: | |
x, y: The centre of the would-be circle | |
radius: Radius of the circle | |
ptcount: Number of graphics location points to generate | |
startangle: The initial angle to have a point at. Last point will be 180 degrees rotated from this point around the x,y centre. | |
Returns: | |
tbl: Table of {x,y} locations | |
pts: Collection of {x,y,x,y,x,y,...} points as accepted by display.newLine(unpack(pts)) | |
]]-- | |
function graphics.newSemiCircle( x, y, radius, ptcount, startangle ) | |
local tbl = {} | |
local pts = {} | |
local centre = {x=x,y=y} | |
local origin = {x=x,y=y-radius} | |
for i=0, ptcount-1 do | |
local pt = math.rotateTo( origin, startangle+i*(180/(ptcount-1)), centre ) | |
tbl[#tbl+1] = pt | |
pts[#pts+1] = pt.x | |
pts[#pts+1] = pt.y | |
end | |
return tbl, pts | |
end | |
-- requires displaylib | |
function graphics.multiElementShapesFromGroup( group, defaultprops ) | |
local shapes = {} | |
for i=1, group.numChildren do | |
local shape = group[i] | |
if (shape.type == "newRect" or shape.type == "newImage" or shape.type == "newImageRect") then | |
-- rect | |
local ax, ay = shape:localToContent( -shape.width/2, -shape.height/2 ) | |
ax, ay = shape.parent:contentToLocal( ax, ay ) | |
local bx, by = shape:localToContent( shape.width/2, -shape.height/2 ) | |
bx, by = shape.parent:contentToLocal( bx, by ) | |
local cx, cy = shape:localToContent( shape.width/2, shape.height/2 ) | |
cx, cy = shape.parent:contentToLocal( cx, cy ) | |
local dx, dy = shape:localToContent( -shape.width/2, shape.height/2 ) | |
dx, dy = shape.parent:contentToLocal( dx, dy ) | |
local body = { ax, ay, bx, by, cx, cy, dx, dy } | |
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=body } ) | |
elseif (shape.type == "newCircle") then | |
-- circle | |
local _, left = graphics.newSemiCircle( shape.x, shape.y, shape.path.radius, 8, 180 ) | |
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=left } ) | |
local _, right = graphics.newSemiCircle( shape.x, shape.y, shape.path.radius, 8, 0 ) | |
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=right } ) | |
elseif (shape.type == "newRoundedRect") then | |
-- rounded rect | |
local ax, ay = shape:localToContent( -shape.width/2+shape.path.radius, -shape.height/2 ) | |
ax, ay = shape.parent:contentToLocal( ax, ay ) | |
local bx, by = shape:localToContent( shape.width/2-shape.path.radius, -shape.height/2 ) | |
bx, by = shape.parent:contentToLocal( bx, by ) | |
local cx, cy = shape:localToContent( shape.width/2-shape.path.radius, shape.height/2 ) | |
cx, cy = shape.parent:contentToLocal( cx, cy ) | |
local dx, dy = shape:localToContent( -shape.width/2+shape.path.radius, shape.height/2 ) | |
dx, dy = shape.parent:contentToLocal( dx, dy ) | |
local body = { ax, ay, bx, by, cx, cy, dx, dy } | |
local lx, ly = shape:localToContent( -shape.width/2+shape.path.radius, 0 ) | |
lx, ly = shape.parent:contentToLocal( lx, ly ) | |
local rx, ry = shape:localToContent( shape.width/2-shape.path.radius, 0 ) | |
rx, ry = shape.parent:contentToLocal( rx, ry ) | |
local _, left = graphics.newSemiCircle( lx, ly, shape.path.radius, 8, shape.rotation+180 ) | |
local _, right = graphics.newSemiCircle( rx, ry, shape.path.radius, 8, shape.rotation ) | |
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=left } ) | |
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=body } ) | |
shapes[ #shapes+1 ] = table.replicate( defaultprops, { shape=right } ) | |
end | |
end | |
return shapes | |
end | |
local function testShapesFromGroup() | |
physics.start() | |
physics.setGravity(0,0) | |
physics.setDrawMode("hybrid") | |
local group = display.newGroup() | |
group.x, group.y = 300, 300 | |
local b = display.newRect( group, 200, 300, 200, 100 ) | |
b.rotation = 45 | |
b.fill = {0,0,0} | |
local c = display.newRoundedRect( group, 0, -100, 100, 50, 25 ) | |
c.rotation = 0 | |
c.fill = {0,0,1} | |
local c = display.newRoundedRect( group, 0, 100, 100, 50, 25 ) | |
c.rotation = 0 | |
c.fill = {0,0,1} | |
local a = display.newCircle( group, 0, 0, 50 ) | |
a.fill = {1,0,0} | |
local bodies = graphics.multiElementShapesFromGroup( group, {} ) | |
physics.addBody( group, "static", unpack( bodies ) ) | |
end | |
--testShapesFromGroup() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment