Advertisement
Guest User

Voronoi Tilemap Generation in Codea

a guest
Sep 18th, 2017
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 49.55 KB | None | 0 0
  1.  
  2. --# Main
  3. -- Voronoi Tilemap
  4. displayMode(OVERLAY)
  5. BGCOLOR = color(61,65,77)
  6. STROKECOLOR = color(67,183,45)
  7.  
  8. function setup()
  9.     parameter.watch"FPS"
  10.    
  11.     s = polygon{vec2(0,0),vec2(25,100),vec2(50,0)}
  12.     c = physics.body(CIRCLE,20)
  13.     c.x = 0
  14.     c.y = 0
  15.     FPS = 0
  16.    
  17.     map = Map()
  18. end
  19.  
  20. function draw()
  21.     background(61, 65, 77, 255)
  22.     font("GillSans-Bold")
  23.     stroke(STROKECOLOR)
  24.     map:draw()
  25.     pushStyle()
  26.     strokeWidth(5)
  27.     noFill()
  28.     ellipse(c.x,c.y,40)
  29.     popStyle()
  30.     FPS = FPS*.9+(1/DeltaTime)*.1
  31. end
  32.  
  33. function getPolyPos(poly)
  34.     local center = vec2()
  35.     for i,vertex in ipairs(poly.vertices) do
  36.         center = center + vertex
  37.     end
  38.     return center / #poly.vertices
  39. end
  40.  
  41. function setPolyPos(poly,pos)
  42.     local center = vec2()
  43.     for i,vertex in ipairs(poly.vertices) do
  44.         center = center + vertex
  45.     end
  46.     center = center / #poly.vertices
  47.     newCenter = pos
  48.     for i = 1, #poly.vertices do
  49.         poly.vertices[i] = poly.vertices[i] + (newCenter-center)
  50.     end
  51.     setEdges(poly)
  52. end
  53.  
  54. function setEdges(poly)
  55.     for i = 1, #poly.vertices do
  56.         poly.edges[i] = segment(poly.vertices[i], poly.vertices[(i)%#poly.vertices+1])
  57.     end
  58. end
  59.  
  60. function rotatePoly(poly,angle)
  61.     local pos = getPolyPos(poly)
  62.     for i,vertex in ipairs(poly.vertices) do
  63.         local d = vertex - pos
  64.         d = d:rotate(angle)
  65.         poly.vertices[i] = pos + d
  66.     end
  67.     setEdges(poly)
  68. end
  69.  
  70.  
  71. function drawPoly(poly)
  72.     for i,v in ipairs(poly.edges) do
  73.         if not v.similar then
  74.             strokeWidth(5)
  75.         else
  76.             strokeWidth(2)
  77.         end
  78.         line(v.a[1],v.a[2],v.b[1],v.b[2])
  79.     end
  80. end
  81.  
  82. function touched(t)
  83.     if t.state == ENDED then
  84.         c.x = t.x
  85.         c.y = t.y
  86.         c.linearVelocity = vec2()
  87.     end
  88. end
  89.  
  90. --# Map
  91. Map = class()
  92.  
  93. function Map:init()
  94.     self.co = coroutine.create(function()
  95.         self:setup()
  96.     end)
  97. end
  98.  
  99. function Map:setup()
  100.     self.voronoi = voronoilib:new(2^7,3,0,0,WIDTH,HEIGHT)
  101.     coroutine.yield()
  102.     self.polygons = {}
  103.     self.mesh = mesh()
  104.     self.seed = math.random(1,10000)
  105.     self.scale = 200
  106.     for i,v in pairs(self.voronoi.polygons) do
  107.         v.rpoints = {}
  108.         for j = 1, #v.points-1, 2 do
  109.             table.insert(v.rpoints,vec2(v.points[j],v.points[j+1]))
  110.         end
  111.     end
  112.     for i,v in ipairs(self.voronoi.polygons) do
  113.         if noise(self.voronoi.points[i].x/self.scale+self.seed,self.voronoi.points[i].y/self.scale+self.seed) > 0. then
  114.             table.insert(self.polygons,polygon(v.rpoints))
  115.         end
  116.     end
  117.     local function similar(e1,e2)
  118.         return (e1.a == e2.a and e1.b == e2.b) or (e1.a == e2.b and e1.b == e2.a)
  119.     end
  120.    
  121.     self.ppoly = {}
  122.     for i,v in ipairs(self.polygons) do
  123.         local b = physics.body(POLYGON,table.unpack(v.vertices))
  124.         b.type = STATIC
  125.         table.insert(self.ppoly,b)
  126.         for _,edge in ipairs(v.edges) do
  127.             for j,w in ipairs(self.polygons) do
  128.                 if j~=i and w~=v then
  129.                     for _,edge2 in ipairs(w.edges) do
  130.                         if similar(edge,edge2) then
  131.                             edge.similar = true
  132.                         end
  133.                     end
  134.                 end
  135.             end
  136.         end
  137.     end
  138.     for i,p in ipairs(self.polygons) do
  139.         self:drawPoly(p)
  140.     end
  141.     coroutine.yield()
  142.     self.doneLoading = true
  143. end
  144.  
  145. function Map:draw()
  146.     -- Codea does not automatically call this method
  147.     pushStyle()
  148.     if not self.doneLoading then
  149.         self:drawLoading()
  150.         coroutine.resume(self.co)
  151.         return
  152.     end
  153.     self.mesh:draw()
  154.     popStyle()
  155. end
  156.  
  157. function Map:drawLoading()
  158.     background(BGCOLOR)
  159.     pushStyle()
  160.     fill(255)
  161.     fontSize(90)
  162.     text("Loading...",WIDTH/2,HEIGHT/2)
  163.     popStyle()
  164. end
  165.  
  166. function Map:touched(touch)
  167.     -- Codea does not automatically call this method
  168. end
  169.  
  170. function Map:getPolyPos(poly)
  171.     local center = vec2()
  172.     for i,vertex in ipairs(poly.vertices) do
  173.         center = center + vertex
  174.     end
  175.     return center / #poly.vertices
  176. end
  177.  
  178. function Map:setPolyPos(poly,pos)
  179.     local center = vec2()
  180.     for i,vertex in ipairs(poly.vertices) do
  181.         center = center + vertex
  182.     end
  183.     center = center / #poly.vertices
  184.     newCenter = pos
  185.     for i = 1, #poly.vertices do
  186.         poly.vertices[i] = poly.vertices[i] + (newCenter-center)
  187.     end
  188.     setEdges(poly)
  189. end
  190.  
  191. function Map:setEdges(poly)
  192.     for i = 1, #poly.vertices do
  193.         poly.edges[i] = segment(poly.vertices[i], poly.vertices[(i)%#poly.vertices+1])
  194.     end
  195. end
  196.  
  197. function Map:rotatePoly(poly,angle)
  198.     local pos = getPolyPos(poly)
  199.     for i,vertex in ipairs(poly.vertices) do
  200.         local d = vertex - pos
  201.         d = d:rotate(angle)
  202.         poly.vertices[i] = pos + d
  203.     end
  204.     setEdges(poly)
  205. end
  206.  
  207.  
  208. function Map:drawPoly(poly)
  209.     for i,v in ipairs(poly.edges) do
  210.         if not v.similar then
  211.             strokeWidth(5)
  212.         else
  213.             strokeWidth(2)
  214.         end
  215.         meshLine(self.mesh,v.a.x,v.a.y,v.b.x,v.b.y)
  216.     end
  217. end
  218. --# Mesh
  219. function meshLine(m,x1,y1,x2,y2)
  220.     local dx = x2 - x1
  221.     local dy = y2 - y1
  222.     local d = math.sqrt(dx * dx + dy * dy)
  223.     local a = math.atan2(dy, dx)
  224.     local i = m:addRect(x1 + dx / 2, y1 + dy / 2, d, strokeWidth(), a)
  225.     m:setRectColor(i,stroke())
  226. end
  227.  
  228. --# polygon
  229.  
  230. function perp(v)
  231.     return vec2(v.x,-v.y)
  232. end
  233. function segment(a, b)
  234.     local obj = {a=a, b=b, dir=b-a}
  235.     obj.x = obj.dir.x; obj.y = obj.dir.y
  236.     return obj
  237. end
  238.  
  239. function polygon(vertices)
  240.     local obj = {}
  241.     obj.vertices = vertices
  242.     obj.edges = {}
  243.     for i=1,#vertices do
  244.         table.insert(obj.edges, segment(vertices[i], vertices[(i)%#vertices+1]))
  245.     end
  246.     return obj
  247. end
  248.  
  249. function polygon(vertices)
  250.     local obj = {}
  251.     obj.vertices = vertices
  252.     obj.edges = {}
  253.     for i=1,#vertices do
  254.         table.insert(obj.edges, segment(vertices[i], vertices[(i)%#vertices+1]))
  255.     end
  256.     return obj
  257. end
  258.  
  259. function project(a, axis)
  260.     axis = axis:normalize()
  261.     local min = a.vertices[1]:dot(axis)
  262.     local max = min
  263.     for i,v in ipairs(a.vertices) do
  264.         local proj =  v:dot(axis) -- projection
  265.         if proj < min then min = proj end
  266.         if proj > max then max = proj end
  267.     end
  268.    
  269.     return {min, max}
  270. end
  271.  
  272. function contains(n, range)
  273.     local a, b = range[1], range[2]
  274.     if b < a then a = b; b = range[1] end
  275.     return n >= a and n <= b
  276. end
  277.  
  278. function overlap(a_, b_)
  279.     if contains(a_[1], b_) then return true
  280.     elseif contains(a_[2], b_) then return true
  281.     elseif contains(b_[1], a_) then return true
  282.     elseif contains(b_[2], a_) then return true
  283.     end
  284.     return false
  285. end
  286.  
  287.  
  288. function sat(a, b)
  289.     for i,v in ipairs(a.edges) do
  290.         local axis = perp(v)
  291.         local a_, b_ = project(a, axis), project(b, axis)
  292.         if not overlap(a_, b_) then return false end
  293.     end
  294.     for i,v in ipairs(b.edges) do
  295.         local axis = perp(v)
  296.         local a_, b_ = project(a, axis), project(b, axis)
  297.         if not overlap(a_, b_) then return false end
  298.     end
  299.    
  300.     return true
  301. end
  302. --# Voronoi
  303. --[[
  304. Permission is hereby granted, free of charge, to any person obtaining a copy
  305. of this software and associated documentation files (the "Software"), to deal
  306. in the Software without restriction, including without limitation the rights
  307. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  308. copies of the Software, and to permit persons to whom the Software is
  309. furnished to do so, subject to the following conditions:
  310.  
  311. The above copyright notice and this permission notice shall be included in
  312. all copies or substantial portions of the Software.
  313.  
  314. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  315. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  316. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  317. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  318. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  319. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  320. THE SOFTWARE.
  321.  
  322. Based of the work David Ng (2010) and of Steve J. Fortune (1987) A Sweepline Algorithm for Voronoi Diagrams,
  323. Algorithmica 2, 153-174, and its translation to C++ by Matt Brubeck,
  324. http://www.cs.hmc.edu/~mbrubeck/voronoi.html
  325.  
  326. ]]--
  327.  
  328. -------------------------------------------------------------------------------------------------------------------------------------------------------
  329. -------------------------------------------------------------------------------------------------------------------------------------------------------
  330. -------------------------------------------------------------------------------------------------------------------------------------------------------
  331. voronoilib = { }
  332. --------------------------------------------------------------------------------------------------------------------
  333. --------------------------------------------------------------------------------------------------------------------
  334. --------------------------------------------------------------------------------------------------------------------
  335. -- creates a voronoi diagram and returns a table containing the structure.
  336. --
  337. -- polygoncount = the number of polygons wanted, this can be thought of as the total number of grid regions
  338. -- iterations = how many times you would like to run the  voronoi. the more iterations, the smoother and more regular
  339. --              the grid looks, recommend at least 3 iterations for a nice grid. any more is diminishing returns
  340. -- minx,miny,maxx,maxy = the boundary for the voronoi diagram. if you choose 0,0,100,100 the function will make a voronoi diagram inside
  341. --                       the square defined by 0,0 and 100,100 where all the points of the voronoi are inside the square.
  342. function voronoilib:new(polygoncount,iterations,minx,miny,maxx,maxy)
  343.  
  344.     local rvoronoi = { }
  345.     ----------------------------------------------------------
  346.     -- the iteration loop
  347.     for it=1,iterations do
  348.     coroutine.yield()
  349.         ------------------------------------------------
  350.         -- initalizes everything needed for this iteration
  351.         rvoronoi[it] = { }
  352.         rvoronoi[it].points = { }
  353.         rvoronoi[it].boundary = { minx,miny,minx+maxx,miny+maxy }
  354.         rvoronoi[it].vertex = { }
  355.         rvoronoi[it].segments = { }
  356.         rvoronoi[it].events = self.heap:new()
  357.         rvoronoi[it].beachline = self.doublelinkedlist:new()
  358.         rvoronoi[it].polygons = { }
  359.         rvoronoi[it].polygonmap = { }
  360.         rvoronoi[it].centroids = { }
  361.  
  362.         ---------------------------------------------------------
  363.         -- creates the random points that the polygons will be based
  364.         -- off of. if this is it > 1 then it uses the centroids of the
  365.         -- polygons from the previous iteration as the 'random points'
  366.         -- this relaxes the voronoi diagram and softens the grids so
  367.         -- the grid is more even.
  368.         if it == 1 then
  369.             -- creates a random point and then checks to see if that point is already inside the set of random points.
  370.             -- don't know what would happened but it would not return the same amount of polygons that user requested
  371.             for i=1,polygoncount do
  372.                 local rx,ry = self.tools:randompoint(rvoronoi[it].boundary)
  373.                 while self.tools:tablecontains(rvoronoi[it].points,{ 'x', 'y' }, { rx, ry }) do
  374.                     rx,ry = self.tools:randompoint(rvoronoi[it].boundary)
  375.                 end
  376.                 rvoronoi[it].points[i] = { x = rx, y = ry }
  377.             end
  378.             rvoronoi[it].points = self.tools:sortthepoints(rvoronoi[it].points)
  379.         else
  380.             rvoronoi[it].points = rvoronoi[it-1].centroids
  381.         end
  382.        
  383.         -- sets up the rvoronoi events
  384.         for i = 1,#rvoronoi[it].points do
  385.             rvoronoi[it].events:push(rvoronoi[it].points[i], rvoronoi[it].points[i].x,{i} )
  386.         end
  387.        
  388.         while not rvoronoi[it].events:isEmpty() do
  389.             local e, x = rvoronoi[it].events:pop()
  390.             if e.event then
  391.                 self.tools:processEvent(e,rvoronoi[it])
  392.             else
  393.                 self.tools:processPoint(e,rvoronoi[it])
  394.             end    
  395.         end
  396.        
  397.         self.tools:finishEdges(rvoronoi[it])     
  398.  
  399.         self.tools:dirty_poly(rvoronoi[it])
  400.  
  401.         for i,polygon in pairs(rvoronoi[it].polygons) do
  402.             local cx, cy = self.tools:polyoncentroid(polygon.points)
  403.             rvoronoi[it].centroids[i] = { x = cx, y = cy }
  404.             rvoronoi[it].polygons[i].centroid = rvoronoi[it].centroids[i] -- creating a link between the two tables
  405.         end
  406.     end
  407.  
  408.     -----------------------------
  409.     -- returns the last iteration
  410.     local returner = rvoronoi[iterations]
  411.     setmetatable(returner, self)
  412.     self.__index = self
  413.     return returner
  414. end
  415.  
  416. ------------------------------------------------
  417. -- returns the actual polygons that are the neighbors
  418. function voronoilib:getNeighbors(...)
  419.  
  420.     local returner = { }
  421.     local indexes = { }
  422.  
  423.     -- builds a table of it input polygons
  424.     for i=2,#arg do
  425.         indexes[arg[i]] = true
  426.     end
  427.  
  428.     if arg[1] == 'all' then
  429.  
  430.         -- finds all the neighbors and removes all duplicates
  431.         local returnIs = { }
  432.         for pindex,tt in pairs(indexes) do
  433.             for j,index in pairs(self.polygonmap[pindex]) do
  434.                 returnIs[index] = true
  435.             end
  436.         end
  437.  
  438.         -- sets the in polygons as nil so it doesnt' return one of the inputs as a neighbor.
  439.         for index,tt in pairs(indexes) do returnIs[index] = nil end
  440.  
  441.         -- builds the polygon table for returning
  442.         for index,tt in pairs(returnIs) do
  443.             returner[#returner+1] = self.polygons[index]
  444.         end
  445.  
  446.     elseif arg[1] == 'shared' then
  447.  
  448.         -- finds all the neighbors, counts occurances
  449.         local returnIs = { }
  450.         for pindex,tt in pairs(indexes) do
  451.             for j,index in pairs(self.polygonmap[pindex]) do
  452.                 if returnIs[index] == nil then returnIs[index] = 1
  453.                 else returnIs[index] = returnIs[index] + 1 end
  454.             end
  455.         end
  456.  
  457.         -- builds the polygon table for returning
  458.         for index,count in pairs(returnIs) do
  459.             if count == (#arg-1) then returner[#returner+1] = self.polygons[index] end
  460.         end
  461.  
  462.     else print('unknown mode in getNeighbors(...): ' .. arg[1]) end
  463.  
  464.     --[[for pindex,tt in pairs(indexes) do
  465.         returner[]
  466.         for j,index in pairs(self.polygonmap[pindex]) do
  467.             returner[#returner+1] = self.polygons[index]
  468.         end
  469.     end]]--
  470.  
  471.     return returner
  472.  
  473. end
  474.  
  475. -------------------------------------------------------
  476. -- returns the edges of a polygon. if multiple polygons are
  477. -- inputed then only the edges that are shared with at least
  478. -- two polygons are returned
  479. -- the first argument is MODE = { 'segment' or 'vertex'}
  480. -- segment --> returns edges where the line segment is shared with atleast 2 polygons
  481. -- vertex --> returns segments in which the vertexes are shared with atleast 3 polygons
  482. function voronoilib:getEdges(...)
  483.  
  484.     local returner = { }
  485.     local mode = arg[1]
  486.  
  487.     for i=2, #arg do
  488.         for j,line in pairs(self.polygons[arg[i]].edges) do returner[#returner+1] = line end
  489.     end
  490.  
  491.    
  492.  
  493.     if #arg > 2 then
  494.         local processedreturner = { }
  495.         local incount = { }
  496.  
  497.         for i,line1 in pairs(returner) do
  498.             for j,line2 in pairs(returner) do
  499.                 if (i ~= j) and (incount[i] == nil) and (incount[j] == nil) then
  500.                     if self.tools:sameedge(line1,line2) then
  501.                         processedreturner[#processedreturner+1] = returner[i]
  502.                         incount[i],incount[j] = true,true
  503.                     end
  504.                 end
  505.             end
  506.         end
  507.         returner = processedreturner
  508.  
  509.         if mode == 'segment' then
  510.             -- do nothing, everything is already done.
  511.         elseif mode == 'vertex' then
  512.             -- checks if the segment shares both points with 2 other segments
  513.             -- only returns those segments
  514.             processedreturner = { }
  515.             for indexmain,linemain in pairs(returner) do
  516.                 -- how many other segments share the same points
  517.                 local point1 = 0
  518.                 local point2 = 0
  519.  
  520.                 for indexsub,linesub in pairs(returner) do
  521.                     if ((math.abs(linemain[1] - linesub[1]) < voronoilib.constants.zero) and (math.abs(linemain[2] - linesub[2]) < voronoilib.constants.zero))
  522.                     or ((math.abs(linemain[1] - linesub[3]) < voronoilib.constants.zero) and (math.abs(linemain[2] - linesub[4]) < voronoilib.constants.zero)) then
  523.                         point1 = point1 + 1
  524.                     elseif ((math.abs(linemain[3] - linesub[1]) < voronoilib.constants.zero) and (math.abs(linemain[4] - linesub[2]) < voronoilib.constants.zero))
  525.                     or ((math.abs(linemain[3] - linesub[3]) < voronoilib.constants.zero) and (math.abs(linemain[4] - linesub[4]) < voronoilib.constants.zero)) then
  526.                         point2 = point2 + 1
  527.                     end
  528.                 end
  529.  
  530.                 if (point2 >= 2) and (point1 >= 2) then
  531.                     processedreturner[#processedreturner+1] = linemain
  532.                 end
  533.             end
  534.             returner = processedreturner
  535.  
  536.         else print('not an recognized voronoilib:getEdges(...) mode') end
  537.  
  538.     end
  539.  
  540.     return returner
  541. end
  542.  
  543. -----------------------------------------------------------------------------------
  544. -- returns the polygon that contains the point, returns nil if no polygon was found
  545. function voronoilib:polygoncontains(x,y)
  546.  
  547.     local distance = { }
  548.     for index,centroid in pairs(self.centroids) do
  549.         distance[#distance+1] = { i = index, d = math.sqrt(math.pow(x-centroid.x,2) + math.pow(y-centroid.y,2)) }
  550.     end
  551.  
  552.     table.sort(distance,function(a,b) return a.d < b.d end)
  553.  
  554.     for i,pindex in pairs({ unpack(self.polygonmap[distance[1].i]),distance[1].i }) do
  555.         if self.polygons[pindex]:containspoint(x,y) then
  556.             return self.polygons[pindex]
  557.         end
  558.     end
  559.  
  560.     return nil
  561. end
  562.  
  563. -------------------------------------------------------------------------------------------------------------------------------------------------------
  564. -------------------------------------------------------------------------------------------------------------------------------------------------------
  565. -------------------------------------------------------------------------------------------------------------------------------------------------------
  566. voronoilib.heap = { }
  567.  
  568. function voronoilib.heap:new()
  569.     local o = { heap = { }, nodes = { } }
  570.     setmetatable(o, self)
  571.     self.__index = self
  572.     return o
  573. end
  574.  
  575. function voronoilib.heap:push(k, v)
  576.     assert(v ~= nil, "cannot push nil")
  577.  
  578.     local heap_pos = #self.heap + 1 -- node position in heap array (leaf)
  579.     local parent_pos = (heap_pos - heap_pos % 2) / 2 -- parent position in heap array
  580.  
  581.     self.heap[heap_pos] = k -- insert at a leaf
  582.  
  583.     self.nodes[k] = v
  584.  
  585.     while heap_pos > 1 and self.nodes[self.heap[parent_pos]] > v do -- climb heap?
  586.         self.heap[parent_pos], self.heap[heap_pos] = self.heap[heap_pos], self.heap[parent_pos]
  587.         heap_pos = parent_pos
  588.         parent_pos = (heap_pos - heap_pos % 2) / 2
  589.     end
  590.  
  591.     return k
  592.  
  593. end
  594.  
  595. function voronoilib.heap:pop()
  596.     local heap_pos = #self.heap
  597.  
  598.     assert(heap_pos > 0, "cannot pop from empty heap")
  599.  
  600.     local heap_root = self.heap[1]
  601.     local heap_root_pos = self.nodes[heap_root]
  602.  
  603.     local current_heap = self.nodes[self.heap[heap_pos]]
  604.  
  605.     self.heap[1] = self.heap[heap_pos] -- move leaf to root
  606.     self.heap[heap_pos] = nil -- remove leaf
  607.     self.nodes[heap_root] = nil
  608.     heap_pos = heap_pos - 1
  609.  
  610.     local node_pos = 1 -- node position in heap array
  611.  
  612.     local parent_pos = 2 * node_pos -- left sibling position
  613.     if heap_pos > parent_pos and self.nodes[self.heap[parent_pos]] > self.nodes[self.heap[parent_pos + 1]] then
  614.         parent_pos = 2 * node_pos + 1 -- right sibling position
  615.     end
  616.     while heap_pos >= parent_pos and self.nodes[self.heap[parent_pos]] < current_heap do -- descend heap?
  617.         self.heap[parent_pos], self.heap[node_pos] = self.heap[node_pos], self.heap[parent_pos]
  618.         node_pos = parent_pos
  619.         parent_pos = 2 * node_pos
  620.     if heap_pos > parent_pos and self.nodes[self.heap[parent_pos]] > self.nodes[self.heap[parent_pos + 1]] then
  621.         parent_pos = 2 * node_pos + 1
  622.     end
  623. end
  624.     return heap_root, heap_root_pos
  625. end
  626.  
  627. function voronoilib.heap:isEmpty()
  628.     return self.heap[1] == nil
  629. end
  630.  
  631. -------------------------------------------------------------------------------------------------------------------------------------------------------
  632. -------------------------------------------------------------------------------------------------------------------------------------------------------
  633. -------------------------------------------------------------------------------------------------------------------------------------------------------
  634. voronoilib.doublelinkedlist = { }
  635.  
  636. function voronoilib.doublelinkedlist:new()
  637.     local o = { first = nil, last = nil } -- empty list head
  638.  
  639.     setmetatable(o, self)
  640.     self.__index = self
  641.  
  642.     return o
  643. end
  644.  
  645. function voronoilib.doublelinkedlist:insertAfter(node, data)
  646.     local new = {prev = node, next = node.next, x = data.x, y = data.y} -- creates a new node
  647.     node.next = new -- the node after node is the new node
  648.     if node == self.last then -- check if the old node is the last node...
  649.         self.last = new -- ...and set the new node as last node
  650.     else
  651.         --otherwise set the next nodes previous node to the new one
  652.         new.next.prev = new
  653.     end
  654.     return new -- return the new node
  655. end
  656.  
  657. function voronoilib.doublelinkedlist:insertAtStart(data)
  658.     local new = {prev = nil, next = self.first, x = data.x, y = data.y} -- create the new node
  659.     if not self.first then -- check if the list is empty
  660.         self.first = new -- the new node is the first and the last in this case
  661.         self.last = new
  662.    else
  663.         -- the node before the old first node is the new first node
  664.         self.first.prev = new
  665.         self.first = new -- update the list's first field
  666.    end
  667.    return new
  668. end
  669.  
  670. function voronoilib.doublelinkedlist:delete(node)
  671.     if node == self.first then -- check if the node is the first one...
  672.         -- ...and set the new first node if we remove the first
  673.         self.first = node.next
  674.     else
  675.         -- set the previous node's next node to the next node
  676.         node.prev.next = node.next
  677.     end
  678.    
  679.     if node == self.last then -- check if the node is the last one...
  680.         -- ...the new last node is the node before the deleted node
  681.         self.last = node.prev
  682.     else
  683.         node.next.prev = node.prev -- update the next node's prev field
  684.     end
  685. end
  686.  
  687. function voronoilib.doublelinkedlist:nextNode(node)
  688.     return (not node and self.first) or node.next
  689. end
  690.  
  691. -------------------------------------------------------------------------------------------------------------------------------------------------------
  692. -------------------------------------------------------------------------------------------------------------------------------------------------------
  693. -------------------------------------------------------------------------------------------------------------------------------------------------------
  694.  
  695. voronoilib.tools = { }
  696.  
  697. function voronoilib.tools:processEvent(event,ivoronoi)
  698.     if event.valid then
  699.         local segment = {startPoint = {x = event.x, y = event.y}, endPoint = {x = 0, y = 0}, done = false, type = 1}
  700.         table.insert(ivoronoi.segments, segment)
  701.         --Remove the associated arc from the front, and update segment info
  702.        
  703.         ivoronoi.beachline:delete(event.arc)
  704.        
  705.         if event.arc.prev then
  706.             event.arc.prev.seg1 = segment
  707.         end
  708.        
  709.         if event.arc.next then
  710.             event.arc.next.seg0 = segment
  711.         end
  712.        
  713.         --Finish the edges before and after arc.
  714.         if event.arc.seg0 then
  715.             event.arc.seg0.endPoint = {x = event.x, y = event.y}
  716.             event.arc.seg0.done = true
  717.         end    
  718.            
  719.         if event.arc.seg1 then
  720.             event.arc.seg1.endPoint = {x = event.x, y = event.y}
  721.             event.arc.seg1.done = true
  722.         end    
  723.        
  724.         -- debugging vertix list!!!
  725.         table.insert(ivoronoi.vertex, {x = event.x, y = event.y})
  726.        
  727.         --Recheck circle events on either side of p:
  728.         if (event.arc.prev) then
  729.             self:check_circle_event(event.arc.prev, event.x,ivoronoi)
  730.         end
  731.         if (event.arc.next) then
  732.             self:check_circle_event(event.arc.next, event.x,ivoronoi)
  733.         end    
  734.         event.arc = nil
  735.    end
  736.    event = nil
  737. end
  738.  
  739.  
  740. function voronoilib.tools:processPoint(point,ivoronoi)
  741.     --Adds a point to the beachline
  742.     --local intersect = self:intersect
  743.     if (not ivoronoi.beachline.first) then
  744.         ivoronoi.beachline:insertAtStart(point)
  745.         return
  746.     end
  747.    
  748.     --Find the current arc(s) at height p.y (if there are any).
  749.     for arc in ivoronoi.beachline.nextNode, ivoronoi.beachline do
  750.        
  751.         local z = (self:intersect(point,arc))
  752.         if z then
  753.             --New parabola intersects arc i.  If necessary, duplicate i.
  754.             -- ie if there is a next node, but there is not interation, then creat a duplicate
  755.             if not (arc.next and (self:intersect(point,arc.next))) then
  756.                 ivoronoi.beachline:insertAfter(arc, arc)
  757.             else    
  758.                 --print("test", arc.next,intersect(point,arc.next).x,intersect(point,arc.next).y, z.x,z.y  )
  759.                 return
  760.             end    
  761.             arc.next.seg1 = arc.seg1
  762.            
  763.             --Add p between i and i->next.
  764.             ivoronoi.beachline:insertAfter(arc, point)
  765.  
  766.            
  767.             local segment = {startPoint = {x = z.x, y = z.y}, endPoint = {x = 0, y = 0}, done = false, type = 2}
  768.             local segment2 = {startPoint = {x = z.x, y = z.y}, endPoint = {x = 0, y = 0}, done = false, type = 2}
  769.  
  770.             -- debugging segment list!!!
  771.             table.insert(ivoronoi.segments, segment)
  772.             table.insert(ivoronoi.segments, segment2)
  773.  
  774.            
  775.             --Add new half-edges connected to i's endpoints.
  776.             arc.next.seg0 = segment
  777.             arc.seg1 = segment
  778.             arc.next.seg1 = segment2
  779.             arc.next.next.seg0 = segment2
  780.            
  781.             --Check for new circle events around the new arc:
  782.             self:check_circle_event(arc, point.x, ivoronoi)
  783.             self:check_circle_event(arc.next, point.x, ivoronoi)
  784.             self:check_circle_event(arc.next.next, point.x, ivoronoi)
  785.  
  786.             return
  787.            
  788.         end    
  789.     end
  790.  
  791.  
  792.     --Special case: If p never intersects an arc, append it to the list.
  793.     -- Find the last node.
  794.    
  795.     ivoronoi.beachline:insertAtStart(point)
  796.  
  797.     local segment = {startPoint = {x = ivoronoi.boundary[1], y = (ivoronoi.beachline.last.y + ivoronoi.beachline.last.prev.y) / 2}, endPoint = {x = 0, y = 0}, done = false, type = 3}
  798.     table.insert(ivoronoi.segments, segment)
  799.    
  800.     ivoronoi.beachline.last.seg0 = segment
  801.     ivoronoi.beachline.last.prev.seg1 = segment
  802. end
  803.  
  804.  
  805.  
  806. function voronoilib.tools:check_circle_event(arc, x0, ivoronoi)
  807.     --Look for a new circle event for arc i.
  808.     --Invalidate any old event.
  809.  
  810.     if (arc.event and arc.event.x ~= x0) then
  811.         arc.event.valid = false
  812.     end
  813.     arc.event = nil
  814.  
  815.     if ( not arc.prev or not arc.next) then
  816.         return
  817.     end
  818.    
  819.     local a = arc.prev
  820.     local b = arc
  821.     local c = arc.next
  822.  
  823.     if ((b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y) >= 0) then
  824.         return false
  825.     end    
  826.  
  827.     --Algorithm from O'Rourke 2ed p. 189.
  828.     local A = b.x - a.x
  829.     local B = b.y - a.y
  830.     local C = c.x - a.x
  831.     local D = c.y - a.y
  832.     local E = A*(a.x+b.x) + B*(a.y+b.y)
  833.     local F = C*(a.x+c.x) + D*(a.y+c.y)
  834.     local G = 2*(A*(c.y-b.y) - B*(c.x-b.x))
  835.  
  836.     if (G == 0) then
  837.         --return false --Points are co-linear
  838.         print("g is 0")
  839.     end
  840.  
  841.     --Point o is the center of the circle.
  842.     local o = {}
  843.     o.x = (D*E-B*F)/G
  844.     o.y = (A*F-C*E)/G
  845.  
  846.     --o.x plus radius equals max x coordinate.
  847.     local x = o.x + math.sqrt( math.pow(a.x - o.x, 2) + math.pow(a.y - o.y, 2) )
  848.    
  849.     if x and x > x0 then
  850.         --Create new event.
  851.         arc.event = {x = o.x, y = o.y, arc = arc, valid = true, event = true }
  852.         ivoronoi.events:push(arc.event, x)
  853.     end
  854. end
  855.  
  856.  
  857.  
  858. function voronoilib.tools:intersect(point, arc)
  859.     --Will a new parabola at point p intersect with arc i?
  860.     local res = {}
  861.     if (arc.x == point.x) then
  862.         return false
  863.     end
  864.     local a, b = nil, nil
  865.     if (arc.prev) then
  866.         --Get the intersection of i->prev, i.
  867.         a = self:intersection(arc.prev, arc, point.x).y
  868.     end    
  869.     if (arc.next) then
  870.         --Get the intersection of i->next, i.
  871.         b = self:intersection(arc, arc.next, point.x).y
  872.     end    
  873.     --print("intersect", a,b,p.y)
  874.     if (( not arc.prev or a <= point.y) and (not arc.next or point.y <= b)) then
  875.         res.y = point.y
  876.         -- Plug it back into the parabola equation.
  877.         res.x = (arc.x*arc.x + (arc.y-res.y)*(arc.y-res.y) - point.x*point.x) / (2*arc.x - 2*point.x)
  878.         return res
  879.     end
  880.     return false
  881. end
  882.  
  883.  
  884. function voronoilib.tools:intersection(p0, p1, l)
  885.     -- Where do two parabolas intersect?
  886.    
  887.     local res = {}
  888.     local p = {x = p0.x, y = p0.y}
  889.  
  890.     if (p0.x == p1.x) then
  891.         res.y = (p0.y + p1.y) / 2
  892.     elseif (p1.x == l) then
  893.         res.y = p1.y
  894.     elseif (p0.x == l) then
  895.         res.y = p0.y
  896.         p = p1
  897.    else
  898.       -- Use the quadratic formula.
  899.       local z0 = 2*(p0.x - l);
  900.       local z1 = 2*(p1.x - l);
  901.  
  902.       local a = 1/z0 - 1/z1;
  903.       local b = -2*(p0.y/z0 - p1.y/z1);
  904.       local c = (p0.y*p0.y + p0.x*p0.x - l*l)/z0 - (p1.y*p1.y + p1.x*p1.x - l*l)/z1
  905.       res.y = ( -b - math.sqrt(b*b - 4*a*c) ) / (2*a)
  906.    end
  907.    
  908.    -- Plug back into one of the parabola equations.
  909.    res.x = (p.x*p.x + (p.y-res.y)*(p.y-res.y) - l*l)/(2*p.x-2*l)
  910.    return res
  911. end
  912.  
  913. function voronoilib.tools:finishEdges(ivoronoi)
  914.     --Advance the sweep line so no parabolas can cross the bounding box.
  915.     local l = ivoronoi.boundary[3] + (ivoronoi.boundary[3]-ivoronoi.boundary[1]) + (ivoronoi.boundary[4]-ivoronoi.boundary[2])
  916.  
  917.     --Extend each remaining segment to the new parabola intersections.
  918.     for arc in ivoronoi.beachline.nextNode, ivoronoi.beachline do
  919.         if arc.seg1 then
  920.             local p = self:intersection(arc, arc.next, l*2)
  921.             arc.seg1.endPoint = {x = p.x, y = p.y}
  922.             arc.seg1.done = true
  923.         end    
  924.     end
  925. end
  926.  
  927.  
  928. -------------------------------------------------------------------------------------------------------------------------------------------------------
  929. -------------------------------------------------------------------------------------------------------------------------------------------------------
  930. -------------------------------------------------------------------------------------------------------------------------------------------------------
  931. voronoilib.constants = { }
  932. voronoilib.constants.zero = 0.01
  933. -------------------------------------------------------------------------------------------------------------------------------------------------------
  934. -------------------------------------------------------------------------------------------------------------------------------------------------------
  935. -------------------------------------------------------------------------------------------------------------------------------------------------------
  936.  
  937. function voronoilib.tools:sortthepoints(points)
  938.     local sortedpoints = self:sorttable(points,'x',true)
  939.     sortedpoints = self:sorttable(sortedpoints,'y',true)
  940.     return sortedpoints
  941. end
  942.  
  943. function voronoilib.tools:tablecontains(tablename,attributename,value)
  944.  
  945.     if attributename == nil then
  946.         for i,v in pairs(tablename) do
  947.             if v == value then return true end
  948.         end
  949.     elseif type(attributename) == 'table' then
  950.         for i,v in pairs(tablename) do
  951.             local match = 0
  952.             for j,v2 in pairs(attributename) do
  953.                 if v[v2] == value[j] then match = match + 1 end
  954.             end
  955.             if match == #attributename then return true end
  956.         end
  957.     else
  958.         for i,v in pairs(tablename) do
  959.             if v[attributename] == value then return true end
  960.         end
  961.     end
  962.     return false
  963.  
  964. end
  965.  
  966. function voronoilib.tools:sortpolydraworder(listofpoints)
  967.  
  968.     local returner = { }
  969.  
  970.     -- sorts it assending by y
  971.     table.sort(listofpoints,function (a,b) return a.y < b.y end)
  972.  
  973.     local unpacked = { }
  974.     for i,point in pairs(listofpoints) do
  975.         unpacked[#unpacked+1] = point.x
  976.         unpacked[#unpacked+1] = point.y
  977.     end
  978.  
  979.     local midpoint = { self:polyoncentroid(unpacked) }
  980.  
  981.     local right = { }
  982.     local left = { }
  983.  
  984.     for i,point in pairs(listofpoints) do
  985.         if point.x < midpoint[1] then
  986.             left[#left+1] = point
  987.         else
  988.             right[#right+1] = point
  989.         end
  990.     end
  991.  
  992.     local tablecount= #left
  993.     for j,point in pairs(left) do
  994.         returner[tablecount+1-j] = point
  995.     end
  996.        
  997.     for j,point in pairs(right) do
  998.         returner[#returner+1] = point
  999.     end
  1000.  
  1001.     unpacked = { }
  1002.     for i,point in pairs(returner) do
  1003.         if i > 1 then
  1004.             if (math.abs(unpacked[#unpacked-1] - point.x) < voronoilib.constants.zero) and (math.abs(unpacked[#unpacked] - point.y) < voronoilib.constants.zero) then
  1005.                 -- duplicate point, so do nothing
  1006.             else
  1007.                 unpacked[#unpacked+1] = point.x
  1008.                 unpacked[#unpacked+1] = point.y
  1009.             end
  1010.         else
  1011.             unpacked[#unpacked+1] = point.x
  1012.             unpacked[#unpacked+1] = point.y
  1013.         end
  1014.     end
  1015.     returner = unpacked
  1016.  
  1017.     return returner
  1018. end
  1019.  
  1020. function voronoilib.tools:polyoncentroid(listofpoints)
  1021.     -- formula here http://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon
  1022.     local A = 0
  1023.     for i = 1,#listofpoints,2 do
  1024.         --print('point',listofpoints[i],listofpoints[i+1])
  1025.         if i > #listofpoints-2 then
  1026.             A = A + listofpoints[i]*listofpoints[2] - listofpoints[1]*listofpoints[i+1]
  1027.         else
  1028.             A = A + listofpoints[i]*listofpoints[i+3] - listofpoints[i+2]*listofpoints[i+1]
  1029.         end
  1030.     end
  1031.     A = 0.5 * A
  1032.  
  1033.     local cx = 0
  1034.     for i = 1, #listofpoints,2 do
  1035.         if i > #listofpoints-2 then
  1036.             cx = cx + (listofpoints[i]+listofpoints[1])*(listofpoints[i]*listofpoints[2] - listofpoints[1]*listofpoints[i+1])
  1037.         else
  1038.             cx = cx + (listofpoints[i]+listofpoints[i+2])*(listofpoints[i]*listofpoints[i+3] - listofpoints[i+2]*listofpoints[i+1])
  1039.         end
  1040.     end
  1041.     cx = cx / (6*A)
  1042.  
  1043.     local cy = 0
  1044.     for i = 1, #listofpoints,2 do
  1045.         if i > #listofpoints-2 then
  1046.             cy = cy + (listofpoints[i+1]+listofpoints[2])*(listofpoints[i]*listofpoints[2] - listofpoints[1]*listofpoints[i+1])
  1047.         else
  1048.             cy = cy + (listofpoints[i+1]+listofpoints[i+3])*(listofpoints[i]*listofpoints[i+3] - listofpoints[i+2]*listofpoints[i+1])
  1049.         end
  1050.     end
  1051.     cy = cy / (6*A)
  1052.     --print('cx',cx,'cy',cy,'A',A)
  1053.  
  1054.     return cx,cy
  1055. end
  1056.  
  1057. function voronoilib.tools:sorttable(datable,parameter,sortbyasending)
  1058.     local count = 0
  1059.     local startingvalue = nil
  1060.     local startingvalueindex = 0
  1061.     local sortedtable = { }
  1062.  
  1063.     for i,v in pairs(datable) do
  1064.         count = count + 1
  1065.  
  1066.         if (startingvalue == nil)
  1067.         or (sortbyasending and (startingvalue[parameter] > v[parameter]))
  1068.         or (sortbyasending == false and (startingvalue[parameter] < v[parameter])) then
  1069.             startingvalue = v
  1070.             startingvalueindex = i
  1071.         end
  1072.     end
  1073.  
  1074.     sortedtable[1] = startingvalue
  1075.     datable[startingvalueindex] = nil
  1076.  
  1077.     for i=2,count do
  1078.         local nextvalue = nil
  1079.         local nextvalueindex = 0
  1080.  
  1081.         for j,v in pairs(datable) do
  1082.             if (nextvalue == nil)
  1083.             or (sortbyasending and (nextvalue[parameter] > v[parameter]))
  1084.             or (sortbyasending == false and (nextvalue[parameter] < v[parameter])) then
  1085.                 nextvalue = v
  1086.                 nextvalueindex = j
  1087.             end
  1088.         end
  1089.         sortedtable[i] = nextvalue
  1090.         datable[nextvalueindex] = nil
  1091.     end
  1092.  
  1093.     return sortedtable
  1094. end
  1095.  
  1096. function voronoilib.tools:sortpolydraworder(listofpoints)
  1097.     -- gets the angle from some point in the center of the polygon and sorts by angle
  1098.  
  1099.     local returner = nil
  1100.     local mainpoint = { x=0, y=0 }
  1101.     local count = 0
  1102.  
  1103.     for i,v in pairs(listofpoints) do
  1104.         count = count + 1
  1105.         mainpoint.x = mainpoint.x + v.x
  1106.         mainpoint.y = mainpoint.y + v.y
  1107.     end
  1108.  
  1109.     mainpoint.x = (mainpoint.x/count)
  1110.     mainpoint.y = (mainpoint.y/count)
  1111.  
  1112.     -- sets the angle of each point with respect to the averaged centerpoint of the polygon.
  1113.     for i,v in pairs(listofpoints) do
  1114.         v.angle = math.acos(math.abs(mainpoint.y-v.y)/(math.sqrt(math.pow((mainpoint.x-v.x),2)+math.pow((mainpoint.y-v.y),2))))
  1115.         if (mainpoint.x <= v.x) and (mainpoint.y <= v.y) then
  1116.             v.angle = 3.14 - v.angle
  1117.         elseif (mainpoint.x >= v.x) and (mainpoint.y <= v.y) then
  1118.             v.angle = v.angle + 3.14
  1119.         elseif (mainpoint.x >= v.x)and (mainpoint.y >= v.y) then
  1120.             v.angle = 2*3.14 - v.angle
  1121.         end
  1122.     end
  1123.  
  1124.     -- orders the points correctly
  1125.     --table.sort(listofpoints,function(a,b) return a.angle > b.angle end)
  1126.     listofpoints = self:sorttable(listofpoints,'angle',true)
  1127.  
  1128.     for j,point in pairs(listofpoints) do
  1129.         if returner == nil then
  1130.             returner = { }
  1131.             returner[1] = point.x
  1132.             returner[2] = point.y
  1133.         else
  1134.             if (math.abs(returner[#returner-1] - point.x) < voronoilib.constants.zero) and (math.abs(returner[#returner] - point.y) < voronoilib.constants.zero) then
  1135.                 -- duplicate point, so do nothing
  1136.             else
  1137.                 returner[#returner+1] = point.x
  1138.                 returner[#returner+1] = point.y
  1139.             end
  1140.         end
  1141.     end
  1142.  
  1143.     --print('returner: ',unpack(returner))
  1144.  
  1145.     return returner
  1146.  
  1147. end
  1148.  
  1149. function voronoilib.tools:intersectionpoint(line1,line2)
  1150.  
  1151.     local slope1 = (line1[4]-line1[2])/(line1[3]-line1[1])
  1152.     local intercept1 = line1[2] - (slope1*line1[1])
  1153.     local slope2 = (line2[4]-line2[2])/(line2[3]-line2[1])
  1154.     local intercept2 = line2[2] - (slope2*line2[1])
  1155.  
  1156.     local ix = 0
  1157.     local iy = 0
  1158.  
  1159.     -- checks if there is a vertical line
  1160.     if line1[1] == line1[3] then
  1161.         --line 1 is vertical
  1162.         ix = line1[1]
  1163.         iy = slope2*ix + intercept2
  1164.     elseif line2[1] == line2[3] then
  1165.         --line 2 is vertical
  1166.         ix = line2[1]
  1167.         iy = slope1*ix + intercept1
  1168.     else
  1169.         -- do the normal math
  1170.         ix = (intercept2 - intercept1) / (slope1 - slope2)
  1171.         iy = slope1*ix + intercept1
  1172.     end
  1173.  
  1174.     local onbothlines = false
  1175.     if self:isonline(ix,iy,line1) == true and self:isonline(ix,iy,line2) == true then
  1176.         onbothlines = true
  1177.     end
  1178.  
  1179.     return ix, iy, onbothlines
  1180. end
  1181.  
  1182. function voronoilib.tools:issegmentintersect(line1,groupoflines)
  1183.     -- checks if the line segment intersects any of the line segments in the group of lines
  1184.  
  1185.     local timestrue = 0
  1186.     local timesfalse = 0
  1187.     local checkset = { }
  1188.  
  1189.     for index,line2 in pairs(groupoflines) do
  1190.         local ix,iy,onbothlines = self:intersectionpoint(line1,line2)
  1191.  
  1192.         if ((math.abs(line1[1]-ix)+math.abs(line1[2]-iy))<voronoilib.constants.zero or (math.abs(line1[3]-ix)+math.abs(line1[4]-iy))<voronoilib.constants.zero) then
  1193.             onbothlines = false
  1194.         end
  1195.  
  1196.         checkset[index] = onbothlines
  1197.  
  1198.         if onbothlines then timestrue = timestrue + 1 else timesfalse = timesfalse + 1 end
  1199.     end
  1200.  
  1201.     if timestrue > 0 then return false else return true end
  1202. end
  1203.  
  1204. function voronoilib.tools:isonline(x,y,line)
  1205.     -- checks if the point is on the line
  1206.  
  1207.     local returner = false
  1208.     local xis = false
  1209.     local yis = false
  1210.     local endpoint = false
  1211.  
  1212.     if (line[1] >= x and x >= line[3]) or (line[3] >= x and x >= line[1])  then
  1213.         xis = true
  1214.     end
  1215.  
  1216.     if (line[2] >= y and y >= line[4]) or (line[4] >= y and y >= line[2]) then
  1217.         yis = true
  1218.     end
  1219.  
  1220.     if (line[1] == x and line[2] == y) or (line[3] == x and line[4] == y) then
  1221.         endpoint = true
  1222.     end
  1223.  
  1224.     if xis == true and yis == true and endpoint == false then returner = true end
  1225.  
  1226.     return returner
  1227. end
  1228.  
  1229. function voronoilib.tools:round(num, idp)
  1230.     --http://lua-users.org/wiki/SimpleRound
  1231.     local mult = 10^(idp or 0)
  1232.     return math.floor(num * mult + 0.5) / mult
  1233. end
  1234.  
  1235. -----------------------------------------------------------------------------------------------------------------------------
  1236. -- i get lost in the arc tables. this is a way to make polygons. it might not be as fast as
  1237. -- doing it during the sweeps, but its the fastest way i can implement one and might not be too bad on the performance side.
  1238. function voronoilib.tools:dirty_poly(invoronoi)
  1239.  
  1240.     local polygon = { }
  1241.  
  1242.     -- removes the points that are outside the boundary
  1243.     local processingpoints = invoronoi.vertex
  1244.     for i=#processingpoints,1,-1 do
  1245.         -- checks the boundaries, and then removes it
  1246.         if (processingpoints[i].x < invoronoi.boundary[1]) or (processingpoints[i].x > invoronoi.boundary[3]) or (processingpoints[i].y < invoronoi.boundary[2]) or (processingpoints[i].y > invoronoi.boundary[4]) then
  1247.             -- removes the item
  1248.             --for remove=#processingpoints-1,i,-1 do processingpoints[remove] = processingpoints[remove+1] end
  1249.             --processingpoints[#processingpoints] = nil
  1250.             --print('bad point',processingpoints[i].x,processingpoints[i].y)
  1251.             processingpoints[i] = nil
  1252.         end
  1253.     end
  1254.  
  1255.     -- adds other points that are not in the vertexes, like the corners and intersections with the boundary
  1256.     local otherpoints = {
  1257.         { x = invoronoi.boundary[1], y = invoronoi.boundary[2] },
  1258.         { x = invoronoi.boundary[1], y = invoronoi.boundary[4] },
  1259.         { x = invoronoi.boundary[3], y = invoronoi.boundary[2] },
  1260.         { x = invoronoi.boundary[3], y = invoronoi.boundary[4] }
  1261.     }
  1262.  
  1263.     -- checks all the segments to see if they pass through the boundary, if they do then this section will
  1264.     -- 'trim' the line so it stops at the boundary
  1265.     for i,v in pairs(invoronoi.segments) do
  1266.         local isects = { }
  1267.         local removetheline = false
  1268.  
  1269.         -- left boundary
  1270.         if (v.startPoint.x < invoronoi.boundary[1]) or (v.endPoint.x < invoronoi.boundary[1]) then
  1271.             removetheline = true
  1272.             local px,py,onlines = self:intersectionpoint(
  1273.                 { invoronoi.boundary[1],invoronoi.boundary[2],invoronoi.boundary[1],invoronoi.boundary[4] },
  1274.                 { v.startPoint.x, v.startPoint.y, v.endPoint.x, v.endPoint.y }
  1275.             )
  1276.             isects[#isects+1] = { x=px,y=py,on=onlines }
  1277.         end
  1278.         -- right boundary
  1279.         if (v.startPoint.x > invoronoi.boundary[3]) or (v.endPoint.x > invoronoi.boundary[3]) then
  1280.             removetheline = true
  1281.             local px,py,onlines = self:intersectionpoint(
  1282.                 { invoronoi.boundary[3],invoronoi.boundary[2],invoronoi.boundary[3],invoronoi.boundary[4] },
  1283.                 { v.startPoint.x, v.startPoint.y, v.endPoint.x, v.endPoint.y }
  1284.             )
  1285.             isects[#isects+1] = { x=px,y=py,on=onlines }
  1286.         end
  1287.         --top boundary
  1288.         if (v.startPoint.y < invoronoi.boundary[2]) or (v.endPoint.y < invoronoi.boundary[2]) then
  1289.             removetheline = true
  1290.             local px,py,onlines = self:intersectionpoint(
  1291.                 { invoronoi.boundary[1],invoronoi.boundary[2],invoronoi.boundary[3],invoronoi.boundary[2] },
  1292.                 { v.startPoint.x, v.startPoint.y, v.endPoint.x, v.endPoint.y }
  1293.  
  1294.             )
  1295.             isects[#isects+1] = { x=px,y=py,on=onlines }
  1296.         end
  1297.         -- bottom boundary
  1298.         if (v.startPoint.y > invoronoi.boundary[4]) or (v.endPoint.y > invoronoi.boundary[4]) then
  1299.             removetheline = true
  1300.             local px,py,onlines = self:intersectionpoint(
  1301.                 { invoronoi.boundary[1],invoronoi.boundary[4],invoronoi.boundary[3],invoronoi.boundary[4] },
  1302.                 { v.startPoint.x, v.startPoint.y, v.endPoint.x, v.endPoint.y }
  1303.             )
  1304.             isects[#isects+1] = { x=px,y=py,on=onlines }     
  1305.         end
  1306.  
  1307.         --if removetheline then invoronoi.segments[i] = nil end
  1308.  
  1309.         -- checks if the point is in or on the boundary lines
  1310.         for index,ise in pairs(isects) do
  1311.             if ise.on then
  1312.                 otherpoints[#otherpoints+1] = { x = ise.x, y = ise.y }  
  1313.             end
  1314.         end
  1315.     end
  1316.     -- merges the points from otherpoints into the processingpoints table
  1317.     for i,v in pairs(otherpoints) do table.insert(processingpoints,v) end
  1318.  
  1319.     -----------------------------------------------------------------------------------------------------------------------------------------
  1320.     -- this is the part that actually makes the polygons. it does so by calculating the distance from the vertecies
  1321.     -- to the randomgenpoints. the shortest distance means that the vertex belongs to that randomgenpoint. voronoi diagrams are constructed
  1322.     -- on the fact that these vertexes are equi-distant from the randomgenpoints, so most vertecies will have multiple owning randomgenpoints,
  1323.     -- except for the boundary points.
  1324.     for vindex,point in pairs(processingpoints) do
  1325.         local distances = { }
  1326.         ---------------------------------------------------------------
  1327.         -- calculates the distances and sorts if from lowest to highest
  1328.         for rindex,ranpoint in pairs(invoronoi.points) do
  1329.             distances[#distances+1] = { i = rindex, d = (math.sqrt(math.pow(point.x-ranpoint.x,2)+math.pow(point.y-ranpoint.y,2))) }
  1330.         end
  1331.         distances = self:sorttable(distances,'d',true)
  1332.  
  1333.         local mindistance = distances[1].d
  1334.         local i = 1
  1335.         while (distances[i].d - mindistance < voronoilib.constants.zero) do
  1336.  
  1337.             if polygon[distances[i].i] == nil then
  1338.  
  1339.                 polygon[distances[i].i] = { }
  1340.                 polygon[distances[i].i][1] = { x = point.x, y = point.y }
  1341.             else
  1342.                 polygon[distances[i].i][#polygon[distances[i].i]+1] = { x = point.x, y = point.y }
  1343.             end
  1344.             --print(vindex,distances[i].i)
  1345.  
  1346.             i = i + 1
  1347.         end
  1348.        
  1349.         --------------------------------------------------------------------------------------------------
  1350.         -- creates the relationship between polygons, which looks like a delaunay triangulation when drawn
  1351.        
  1352.         -- gets all the related polygons here.
  1353.         i = i - 1
  1354.         local related = { }
  1355.         for j=1,i do
  1356.             related[#related+1] = distances[j].i
  1357.         end
  1358.  
  1359.         -- puts them in a structure, calling it polygonmap
  1360.         for j=1,#related do
  1361.             if invoronoi.polygonmap[related[j]] == nil then invoronoi.polygonmap[related[j]] = { } end
  1362.             for k=1,#related do
  1363.                 if not self:tablecontains(invoronoi.polygonmap[related[j]],nil,related[k]) and (related[j] ~= related[k]) then
  1364.                     invoronoi.polygonmap[related[j]][#invoronoi.polygonmap[related[j]]+1] = related[k]
  1365.                 end
  1366.             end
  1367.         end
  1368.     end
  1369.  
  1370.     for i=1,#invoronoi.points do
  1371.         -- quick fix to stop crashing
  1372.         if polygon[i] ~= nil then
  1373.             invoronoi.polygons[i] = self.polygon:new(self:sortpolydraworder(polygon[i]),i)
  1374.         end
  1375.     end
  1376. end
  1377.  
  1378. ---------------------------------------------
  1379. -- generates randompoints
  1380. function voronoilib.tools:randompoint(boundary)
  1381.  
  1382.     local x = math.random(boundary[1]+1,boundary[3]-1)
  1383.     local y = math.random(boundary[2]+1,boundary[4]-1)
  1384.  
  1385.     return x,y
  1386.  
  1387. end
  1388.  
  1389. ----------------------------------------------
  1390. -- checks if the line segment is the same
  1391. function voronoilib.tools:sameedge(line1,line2)
  1392.  
  1393.     local l1p1 = { x = line1[1], y = line1[2] }
  1394.     local l1p2 = { x = line1[3], y = line1[4] }
  1395.     local l2p1 = { x = line2[1], y = line2[2] }
  1396.     local l2p2 = { x = line2[3], y = line2[4] }
  1397.  
  1398.     local l1,l2 = { }, { }
  1399.  
  1400.     if (l1p1.x == l1p2.x) then
  1401.         if (l1p1.y < l1p2.y) then l1 = { l1p1.x,l1p1.y,l1p2.x,l1p2.y }
  1402.         else l1 = { l1p2.x,l1p2.y,l1p1.x,l1p1.y } end
  1403.     elseif (l1p1.x < l1p2.x) then l1 = { l1p1.x,l1p1.y,l1p2.x,l1p2.y  }
  1404.     else l1 = { l1p2.x,l1p2.y,l1p1.x,l1p1.y } end
  1405.  
  1406.     if (l2p1.x == l2p2.x) then
  1407.         if (l2p1.y < l2p2.y) then l2 = { l2p1.x,l2p1.y,l2p2.x,l2p2.y }
  1408.         else l2 = { l2p2.x,l2p2.y,l2p1.x,l2p1.y } end
  1409.     elseif (l2p1.x < l2p2.x) then l2 = { l2p1.x,l2p1.y,l2p2.x,l2p2.y  }
  1410.     else l2 = { l2p2.x,l2p2.y,l2p1.x,l2p1.y } end
  1411.  
  1412.     if (math.abs(l1[1] - l2[1]) < voronoilib.constants.zero) and (math.abs(l1[2] - l2[2]) < voronoilib.constants.zero)
  1413.     and (math.abs(l1[3] - l2[3]) < voronoilib.constants.zero) and (math.abs(l1[4] - l2[4]) < voronoilib.constants.zero) then
  1414.         return true
  1415.     end
  1416.  
  1417.     return false
  1418. end
  1419.  
  1420. -------------------------------------------------------------------------------------------------------------------------------------------------------
  1421. -------------------------------------------------------------------------------------------------------------------------------------------------------
  1422. -------------------------------------------------------------------------------------------------------------------------------------------------------
  1423.  
  1424. voronoilib.tools.polygon = { }
  1425.  
  1426. function voronoilib.tools.polygon:new(inpoints,inindex)
  1427.  
  1428.     if #inpoints < 3 then return nil end
  1429.  
  1430.     local returner = { points = inpoints, index = inindex }
  1431.  
  1432.     -- creates the edges
  1433.     local edgeno = 0
  1434.     returner.edges = { }
  1435.     for i=1,#returner.points-2,2 do
  1436.         edgeno = edgeno + 1
  1437.         returner.edges[edgeno] = { }
  1438.         returner.edges[edgeno][1] = returner.points[i]
  1439.         returner.edges[edgeno][2] = returner.points[i+1]
  1440.         returner.edges[edgeno][3] = returner.points[i+2]
  1441.         returner.edges[edgeno][4] = returner.points[i+3]
  1442.     end
  1443.     -- these last lines close the edges, without this the polygon would be missing an edge, usually on the top.
  1444.     edgeno = edgeno + 1
  1445.     returner.edges[edgeno] = { }
  1446.     returner.edges[edgeno][1] = returner.edges[edgeno-1][3]
  1447.     returner.edges[edgeno][2] = returner.edges[edgeno-1][4]
  1448.     returner.edges[edgeno][3] = returner.edges[1][1]
  1449.     returner.edges[edgeno][4] = returner.edges[1][2]
  1450.  
  1451.     -- lua metatable stuff...
  1452.     setmetatable(returner, self)
  1453.     self.__index = self
  1454.  
  1455.     return returner
  1456.  
  1457. end
  1458.  
  1459. ----------------------------------------------------------
  1460. -- checks if the point is inside the polygon
  1461. function voronoilib.tools.polygon:containspoint(inx,iny)
  1462.     local centroidline = { inx,iny, self.centroid.x, self.centroid.y }
  1463.  
  1464.     -- checks the point,centroid line with the edges of the polygon. if the point intersects any of the edges and is one the edge, then the point lies outside of the polygon
  1465.     for i,line2 in pairs(self.edges) do
  1466.         local x,y,onlines = voronoilib.tools:intersectionpoint(centroidline,line2)
  1467.         if onlines then return false end
  1468.     end
  1469.  
  1470.     return true
  1471. end
  1472. --@included@--
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement