Skip to content

Instantly share code, notes, and snippets.

@DUznanski
Created May 20, 2016 06:50
Show Gist options
  • Save DUznanski/04ff354b2fac27ab687cf0e733469853 to your computer and use it in GitHub Desktop.
Save DUznanski/04ff354b2fac27ab687cf0e733469853 to your computer and use it in GitHub Desktop.
do
local ArcGroup_class_table = {}
function ArcGroup(x, y)
-- construct an ArcGroup around the chosen point. The starting interval is a single arc,
-- containing the whole circle.
return setmetatable({x = x, y = y, intervals = {{0, 2*math.pi}}}, { __index = ArcGroup_class_table })
end
function ArcGroup_class_table:width()
-- figures out the amount of the circle that's left to look at.
-- I use this to figure out how often random things will land on this circle.
local width = 0
for _, v in ipairs(self.intervals) do
width = width + v[2] - v[1]
end
return width
end
function ArcGroup_class_table:remove_segment(lo, hi)
-- delete arcs and portions of arcs that are between the ends of the segment.
if lo > hi then
-- this arc goes through the end of the fundamental circle; to make my life easier I instead
-- make two segments to remove.
self:remove_segment(-1, hi) -- -1 and 7 are beyond the end.
self:remove_segment(lo, 7)
else
-- I have to iterate through the list of remaining arcs, and I modify the list as I go.
local i = 1
while i <= #self.intervals do
local interval = self.intervals[i]
if interval[2] <= lo then
-- This interval is entirely before the segment.
i = i + 1
elseif hi <= interval[1] then
-- we've passed the end of the segment.
break
elseif lo <= interval[1] and interval[2] <= hi then
-- this interval is entirely within the segment.
table.remove(self.intervals, i)
elseif lo <= interval[1] and hi < interval[2] then
-- this interval's top end sticks out of the segment.
interval[1] = hi
break -- after the top end is fixed, we're done.
elseif interval[1] < lo and interval[2] <= hi then
-- this interval's bottom end sticks out of the segment.
interval[2] = lo
i = i + 1
elseif interval[1] < lo and hi < interval[2] then
-- this interval is split in two by the segment.
table.insert(self.intervals, i + 1, {hi, interval[2]})
interval[2] = lo
break
end
end
end
end
function ArcGroup_class_table:proximity_delete(x, y)
-- To figure out what segment I have to delete, I see what part is close to other objects.
local offset_x = x - self.x
local offset_y = y - self.y
-- this is the distance. All the circles are size 1, so if the distance is more than 2 there's
-- nothing to do.
local distance = math.sqrt(offset_x * offset_x + offset_y * offset_y)
if distance > 2 then
return
end
-- the half width is the angle between the line through the two points, and the intersection of
-- the two circles.
local half_width = math.acos(distance / 2)
-- and the target angle is the direction towards the other center.
local target_angle = math.atan2(offset_y, offset_x)
local lo = target_angle - half_width
-- both lo and hi have to get rolled back into the fundamental circle, between 0 and 2pi.
if lo < 0 then
lo = lo + 2 * math.pi
end
if lo > 2 * math.pi then
lo = lo - 2 * math.pi
end
local hi = target_angle + half_width
if hi < 0 then
hi = hi + 2 * math.pi
end
if hi > 2 * math.pi then
hi = hi - 2 * math.pi
end
self:remove_segment(lo, hi)
end
function ArcGroup_class_table:point(t)
-- Generate a random point on the arcs.
local angle
for _,interval in ipairs(self.intervals) do
if t + interval[1] < interval[2] then
-- if t would land us on this arc, we've found the point.
angle = t + interval[1]
break
else
-- otherwise, lower t and move on to the next arc.
t = t + interval[1] - interval[2]
end
end
-- calculate the actual location of the point, as opposed to the direction.
return self.x + math.cos(angle), self.y + math.sin(angle)
end
function ArcGroup_class_table:draw()
--white circle for the node.
love.graphics.setColor(255,255,255)
love.graphics.circle("fill", self.x, self.y, 0.1, 64)
for _, interval in ipairs(self.intervals) do
-- red arcs for the remaining arcs.
--love.graphics.setColor(255,0,0)
--open_arc(self.x, self.y, 1, interval[1], interval[2], math.max(10, math.ceil(32 * (interval[2] - interval[1]) / math.pi)))
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment