Created
May 20, 2016 06:50
-
-
Save DUznanski/04ff354b2fac27ab687cf0e733469853 to your computer and use it in GitHub Desktop.
This file contains 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
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