Advertisement
Guest User

Voronoi tilemap generation in Codea

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