Advertisement
Guest User

2DGeometry.lua

a guest
Jan 24th, 2015
39,647
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 25.58 KB | None | 0 0
  1. --[[
  2.     2D Geometry 1.3 by Husky
  3.     ========================================================================
  4.  
  5.     Enables you to perform geometric calculations. Since it is focused on a
  6.     2-dimensional euclidean space it is often faster and easier to use than an
  7.     implementation for a 3-dimensional space. It can be used to evaluate the
  8.     position of geometric objects to each other.
  9.  
  10.     The following classes and methods exist:
  11.  
  12.     -- Classes ----------------------------------------------------------------
  13.  
  14.     Point2(x, y)
  15.     Line2(point1, point2)
  16.     Circle2(point1, point2, radius)
  17.     LineSegment2(point1, point2)
  18.     Polygon2(point1, point2, point3, ...)
  19.  
  20.     -- Common Operations ------------------------------------------------------
  21.  
  22.     object1:getPoints()
  23.     object1:getLineSegments()
  24.     object1:distance(object2)
  25.     object1:contains(object2)
  26.     object1:insideOf(object2)
  27.     object1:intersectionPoints(object2)
  28.  
  29.     -- Point2 specific operations ----------------------------------------------
  30.  
  31.     a point is a vector in the 2d euclidean space and can be used for the usual
  32.     vector calculations like:
  33.  
  34.     point3 = point1 + point2
  35.  
  36.     additionally the following methods are supported:
  37.  
  38.     point:perpendicularFoot(line)
  39.     point:polar()
  40.     point:normalize()
  41.     point:normalized()
  42.     point:clone()
  43.  
  44.     -- Polygon2 specific operations --------------------------------------------
  45.  
  46.     polygon:triangulate()
  47.  
  48.     Changelog
  49.     ~~~~~~~~~
  50.  
  51.     1.0     - initial release with the most important shapes and operations
  52.  
  53.     1.1     - replaced triangles and quadrilaterals with the more generic shape polygon
  54.             - added a unique ID to every single shape to make them identifiable
  55.  
  56.     1.2     - added option to draw line based shapes
  57.             - fixed a few bugs
  58.  
  59.     1.3     - added a few missing functions
  60. ]]
  61.  
  62. -- Globals ---------------------------------------------------------------------
  63.  
  64. uniqueId2 = 0
  65.  
  66. -- Code ------------------------------------------------------------------------
  67.  
  68. class 'Point2' -- {
  69.     function Point2:__init(x, y)
  70.         uniqueId2 = uniqueId2 + 1
  71.         self.uniqueId2 = uniqueId2
  72.  
  73.         self.x = x
  74.         self.y = y
  75.  
  76.         self.points = {self}
  77.     end
  78.  
  79.     function Point2:__type()
  80.         return "Point2"
  81.     end
  82.  
  83.     function Point2:__eq(spatialObject)
  84.         return spatialObject:__type() == "Point2" and self.x == spatialObject.x and self.y == spatialObject.y
  85.     end
  86.  
  87.     function Point2:__unm()
  88.         return Point2(-self.x, -self.y)
  89.     end
  90.  
  91.     function Point2:__add(p)
  92.         return Point2(self.x + p.x, self.y + p.y)
  93.     end
  94.  
  95.     function Point2:__sub(p)
  96.         return Point2(self.x - p.x, self.y - p.y)
  97.     end
  98.  
  99.     function Point2:__mul(p)
  100.         if type(p) == "number" then
  101.             return Point2(self.x * p, self.y * p)
  102.         else
  103.             return Point2(self.x * p.x, self.y * p.y)
  104.         end
  105.     end
  106.  
  107.     function Point2:tostring()
  108.         return "Point2(" .. tostring(self.x) .. ", " .. tostring(self.y) .. ")"
  109.     end
  110.  
  111.     function Point2:__div(p)
  112.         if type(p) == "number" then
  113.             return Point2(self.x / p, self.y / p)
  114.         else
  115.             return Point2(self.x / p.x, self.y / p.y)
  116.         end
  117.     end
  118.  
  119.     function Point2:between(point1, point2)
  120.         local normal = Line2(point1, point2):normal()
  121.  
  122.         return Line2(point1, point1 + normal):side(self) ~= Line2(point2, point2 + normal):side(self)
  123.     end
  124.  
  125.     function Point2:len()
  126.         return math.sqrt(self.x * self.x + self.y * self.y)
  127.     end
  128.  
  129.     function Point2:normalize()
  130.         len = self:len()
  131.  
  132.         self.x = self.x / len
  133.         self.y = self.y / len
  134.  
  135.         return self
  136.     end
  137.  
  138.     function Point2:clone()
  139.         return Point2(self.x, self.y)
  140.     end
  141.  
  142.     function Point2:normalized()
  143.         local a = self:clone()
  144.         a:normalize()
  145.         return a
  146.     end
  147.  
  148.     function Point2:getPoints()
  149.         return self.points
  150.     end
  151.  
  152.     function Point2:getLineSegments()
  153.         return {}
  154.     end
  155.  
  156.     function Point2:perpendicularFoot(line)
  157.         local distanceFromLine = line:distance(self)
  158.         local normalVector = line:normal():normalized()
  159.  
  160.         local footOfPerpendicular = self + normalVector * distanceFromLine
  161.         if line:distance(footOfPerpendicular) > distanceFromLine then
  162.             footOfPerpendicular = self - normalVector * distanceFromLine
  163.         end
  164.  
  165.         return footOfPerpendicular
  166.     end
  167.  
  168.     function Point2:contains(spatialObject)
  169.         if spatialObject:__type() == "Line2" then
  170.             return false
  171.         elseif spatialObject:__type() == "Circle2" then
  172.             return spatialObject.point == self and spatialObject.radius == 0
  173.         else
  174.         for i, point in ipairs(spatialObject:getPoints()) do
  175.             if point ~= self then
  176.                 return false
  177.             end
  178.         end
  179.     end
  180.  
  181.         return true
  182.     end
  183.  
  184.     function Point2:polar()
  185.         if math.close(self.x, 0) then
  186.             if self.y > 0 then return 90
  187.             elseif self.y < 0 then return 270
  188.             else return 0
  189.             end
  190.         else
  191.             local theta = math.deg(math.atan(self.y / self.x))
  192.             if self.x < 0 then theta = theta + 180 end
  193.             if theta < 0 then theta = theta + 360 end
  194.             return theta
  195.         end
  196.     end
  197.  
  198.     function Point2:insideOf(spatialObject)
  199.         return spatialObject.contains(self)
  200.     end
  201.  
  202.     function Point2:distance(spatialObject)
  203.         if spatialObject:__type() == "Point2" then
  204.             return math.sqrt((self.x - spatialObject.x)^2 + (self.y - spatialObject.y)^2)
  205.         elseif spatialObject:__type() == "Line2" then
  206.             denominator = (spatialObject.points[2].x - spatialObject.points[1].x)
  207.             if denominator == 0 then
  208.                 return math.abs(self.x - spatialObject.points[2].x)
  209.             end
  210.  
  211.             m = (spatialObject.points[2].y - spatialObject.points[1].y) / denominator
  212.  
  213.             return math.abs((m * self.x - self.y + (spatialObject.points[1].y - m * spatialObject.points[1].x)) / math.sqrt(m * m + 1))
  214.         elseif spatialObject:__type() == "Circle2" then
  215.             return self:distance(spatialObject.point) - spatialObject.radius
  216.         elseif spatialObject:__type() == "LineSegment2" then
  217.             local t = ((self.x - spatialObject.points[1].x) * (spatialObject.points[2].x - spatialObject.points[1].x) + (self.y - spatialObject.points[1].y) * (spatialObject.points[2].y - spatialObject.points[1].y)) / ((spatialObject.points[2].x - spatialObject.points[1].x)^2 + (spatialObject.points[2].y - spatialObject.points[1].y)^2)
  218.  
  219.             if t <= 0.0 then
  220.                 return self:distance(spatialObject.points[1])
  221.             elseif t >= 1.0 then
  222.                 return self:distance(spatialObject.points[2])
  223.             else
  224.                 return self:distance(Line2(spatialObject.points[1], spatialObject.points[2]))
  225.             end
  226.         else
  227.             local minDistance = nil
  228.  
  229.             for i, lineSegment in ipairs(spatialObject:getLineSegments()) do
  230.                 if minDistance == nil then
  231.                     minDistance = self:distance(lineSegment)
  232.                 else
  233.                     minDistance = math.min(minDistance, self:distance(lineSegment))
  234.                 end
  235.             end
  236.  
  237.             return minDistance
  238.         end
  239.     end
  240. -- }
  241.  
  242. --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--
  243.  
  244. class 'Line2' -- {
  245.     function Line2:__init(point1, point2)
  246.         uniqueId2 = uniqueId2 + 1
  247.         self.uniqueId2 = uniqueId2
  248.  
  249.         self.points = {point1, point2}
  250.     end
  251.  
  252.     function Line2:__type()
  253.         return "Line2"
  254.     end
  255.  
  256.     function Line2:__eq(spatialObject)
  257.         return spatialObject:__type() == "Line2" and self:distance(spatialObject) == 0
  258.     end
  259.  
  260.     function Line2:getPoints()
  261.         return self.points
  262.     end
  263.  
  264.     function Line2:getLineSegments()
  265.         return {}
  266.     end
  267.  
  268.     function Line2:direction()
  269.         return self.points[2] - self.points[1]
  270.     end
  271.  
  272.     function Line2:normal()
  273.         return Point2(- self.points[2].y + self.points[1].y, self.points[2].x - self.points[1].x)
  274.     end
  275.  
  276.     function Line2:perpendicularFoot(point)
  277.         return point:perpendicularFoot(self)
  278.     end
  279.  
  280.     function Line2:side(spatialObject)
  281.         leftPoints = 0
  282.         rightPoints = 0
  283.         onPoints = 0
  284.         for i, point in ipairs(spatialObject:getPoints()) do
  285.             local result = ((self.points[2].x - self.points[1].x) * (point.y - self.points[1].y) - (self.points[2].y - self.points[1].y) * (point.x - self.points[1].x))
  286.  
  287.             if result < 0 then
  288.                 leftPoints = leftPoints + 1
  289.             elseif result > 0 then
  290.                 rightPoints = rightPoints + 1
  291.             else
  292.                 onPoints = onPoints + 1
  293.             end
  294.         end
  295.  
  296.         if leftPoints ~= 0 and rightPoints == 0 and onPoints == 0 then
  297.             return -1
  298.         elseif leftPoints == 0 and rightPoints ~= 0 and onPoints == 0 then
  299.             return 1
  300.         else
  301.             return 0
  302.         end
  303.     end
  304.  
  305.     function Line2:contains(spatialObject)
  306.         if spatialObject:__type() == "Point2" then
  307.             return spatialObject:distance(self) == 0
  308.         elseif spatialObject:__type() == "Line2" then
  309.             return self.points[1]:distance(spatialObject) == 0 and self.points[2]:distance(spatialObject) == 0
  310.         elseif spatialObject:__type() == "Circle2" then
  311.             return spatialObject.point:distance(self) == 0 and spatialObject.radius == 0
  312.         elseif spatialObject:__type() == "LineSegment2" then
  313.             return spatialObject.points[1]:distance(self) == 0 and spatialObject.points[2]:distance(self) == 0
  314.         else
  315.         for i, point in ipairs(spatialObject:getPoints()) do
  316.             if point:distance(self) ~= 0 then
  317.                 return false
  318.             end
  319.             end
  320.  
  321.             return true
  322.         end
  323.  
  324.         return false
  325.     end
  326.  
  327.     function Line2:insideOf(spatialObject)
  328.         return spatialObject:contains(self)
  329.     end
  330.  
  331.     function Line2:distance(spatialObject)
  332.         if spatialObject == nil then return 0 end
  333.         if spatialObject:__type() == "Circle2" then
  334.             return spatialObject.point:distance(self) - spatialObject.radius
  335.         elseif spatialObject:__type() == "Line2" then
  336.             distance1 = self.points[1]:distance(spatialObject)
  337.             distance2 = self.points[2]:distance(spatialObject)
  338.             if distance1 ~= distance2 then
  339.                 return 0
  340.             else
  341.                 return distance1
  342.             end
  343.         else
  344.             local minDistance = nil
  345.             for i, point in ipairs(spatialObject:getPoints()) do
  346.                 distance = point:distance(self)
  347.                 if minDistance == nil or distance <= minDistance then
  348.                     minDistance = distance
  349.                 end
  350.             end
  351.  
  352.             return minDistance
  353.         end
  354.     end
  355. -- }
  356.  
  357. --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--
  358.  
  359. class 'Circle2' -- {
  360.     function Circle2:__init(point, radius)
  361.         uniqueId2 = uniqueId2 + 1
  362.         self.uniqueId2 = uniqueId2
  363.  
  364.         self.point = point
  365.         self.radius = radius
  366.  
  367.         self.points = {self.point}
  368.     end
  369.  
  370.     function Circle2:__type()
  371.         return "Circle2"
  372.     end
  373.  
  374.     function Circle2:__eq(spatialObject)
  375.         return spatialObject:__type() == "Circle2" and (self.point == spatialObject.point and self.radius == spatialObject.radius)
  376.     end
  377.  
  378.     function Circle2:getPoints()
  379.         return self.points
  380.     end
  381.  
  382.     function Circle2:getLineSegments()
  383.         return {}
  384.     end
  385.  
  386.     function Circle2:contains(spatialObject)
  387.         if spatialObject:__type() == "Line2" then
  388.             return false
  389.         elseif spatialObject:__type() == "Circle2" then
  390.             return self.radius >= spatialObject.radius + self.point:distance(spatialObject.point)
  391.         else
  392.             for i, point in ipairs(spatialObject:getPoints()) do
  393.                 if self.point:distance(point) >= self.radius then
  394.                     return false
  395.                 end
  396.             end
  397.  
  398.             return true
  399.         end
  400.     end
  401.  
  402.     function Circle2:insideOf(spatialObject)
  403.         return spatialObject:contains(self)
  404.     end
  405.  
  406.     function Circle2:distance(spatialObject)
  407.         return self.point:distance(spatialObject) - self.radius
  408.     end
  409.  
  410.     function Circle2:intersectionPoints(spatialObject)
  411.         local result = {}
  412.  
  413.         dx = self.point.x - spatialObject.point.x
  414.         dy = self.point.y - spatialObject.point.y
  415.         dist = math.sqrt(dx * dx + dy * dy)
  416.  
  417.         if dist > self.radius + spatialObject.radius then
  418.             return result
  419.         elseif dist < math.abs(self.radius - spatialObject.radius) then
  420.             return result
  421.         elseif (dist == 0) and (self.radius == spatialObject.radius) then
  422.             return result
  423.         else
  424.             a = (self.radius * self.radius - spatialObject.radius * spatialObject.radius + dist * dist) / (2 * dist)
  425.             h = math.sqrt(self.radius * self.radius - a * a)
  426.  
  427.             cx2 = self.point.x + a * (spatialObject.point.x - self.point.x) / dist
  428.             cy2 = self.point.y + a * (spatialObject.point.y - self.point.y) / dist
  429.  
  430.             intersectionx1 = cx2 + h * (spatialObject.point.y - self.point.y) / dist
  431.             intersectiony1 = cy2 - h * (spatialObject.point.x - self.point.x) / dist
  432.             intersectionx2 = cx2 - h * (spatialObject.point.y - self.point.y) / dist
  433.             intersectiony2 = cy2 + h * (spatialObject.point.x - self.point.x) / dist
  434.  
  435.             table.insert(result, Point2(intersectionx1, intersectiony1))
  436.  
  437.             if intersectionx1 ~= intersectionx2 or intersectiony1 ~= intersectiony2 then
  438.                 table.insert(result, Point2(intersectionx2, intersectiony2))
  439.             end
  440.         end
  441.  
  442.         return result
  443.     end
  444.  
  445.     function Circle2:tostring()
  446.         return "Circle2(Point2(" .. self.point.x .. ", " .. self.point.y .. "), " .. self.radius .. ")"
  447.     end
  448. -- }
  449.  
  450. --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--
  451.  
  452. class 'LineSegment2' -- {
  453.     function LineSegment2:__init(point1, point2)
  454.         uniqueId2 = uniqueId2 + 1
  455.         self.uniqueId2 = uniqueId2
  456.  
  457.         self.points = {point1, point2}
  458.     end
  459.  
  460.     function LineSegment2:__type()
  461.         return "LineSegment2"
  462.     end
  463.  
  464.     function LineSegment2:__eq(spatialObject)
  465.         return spatialObject:__type() == "LineSegment2" and ((self.points[1] == spatialObject.points[1] and self.points[2] == spatialObject.points[2]) or (self.points[2] == spatialObject.points[1] and self.points[1] == spatialObject.points[2]))
  466.     end
  467.  
  468.     function LineSegment2:getPoints()
  469.         return self.points
  470.     end
  471.  
  472.     function LineSegment2:getLineSegments()
  473.         return {self}
  474.     end
  475.  
  476.     function LineSegment2:direction()
  477.         return self.points[2] - self.points[1]
  478.     end
  479.  
  480.     function LineSegment2:len()
  481.         return (self.points[1] - self.points[2]):len()
  482.     end
  483.  
  484.     function LineSegment2:contains(spatialObject)
  485.         if spatialObject:__type() == "Point2" then
  486.             return spatialObject:distance(self) == 0
  487.         elseif spatialObject:__type() == "Line2" then
  488.             return false
  489.         elseif spatialObject:__type() == "Circle2" then
  490.             return spatialObject.point:distance(self) == 0 and spatialObject.radius == 0
  491.         elseif spatialObject:__type() == "LineSegment2" then
  492.             return spatialObject.points[1]:distance(self) == 0 and spatialObject.points[2]:distance(self) == 0
  493.         else
  494.         for i, point in ipairs(spatialObject:getPoints()) do
  495.             if point:distance(self) ~= 0 then
  496.                 return false
  497.             end
  498.             end
  499.  
  500.             return true
  501.         end
  502.  
  503.         return false
  504.     end
  505.  
  506.     function LineSegment2:insideOf(spatialObject)
  507.         return spatialObject:contains(self)
  508.     end
  509.  
  510.     function LineSegment2:distance(spatialObject)
  511.         if spatialObject:__type() == "Circle2" then
  512.             return spatialObject.point:distance(self) - spatialObject.radius
  513.         elseif spatialObject:__type() == "Line2" then
  514.             return math.min(self.points[1]:distance(spatialObject), self.points[2]:distance(spatialObject))
  515.         else
  516.             local minDistance = nil
  517.             for i, point in ipairs(spatialObject:getPoints()) do
  518.                 distance = point:distance(self)
  519.                 if minDistance == nil or distance <= minDistance then
  520.                     minDistance = distance
  521.                 end
  522.             end
  523.  
  524.             return minDistance
  525.         end
  526.     end
  527.  
  528.     function LineSegment2:intersects(spatialObject)
  529.         return #self:intersectionPoints(spatialObject) >= 1
  530.     end
  531.  
  532.     function LineSegment2:intersectionPoints(spatialObject)
  533.         if spatialObject:__type()  == "LineSegment2" then
  534.             d = (spatialObject.points[2].y - spatialObject.points[1].y) * (self.points[2].x - self.points[1].x) - (spatialObject.points[2].x - spatialObject.points[1].x) * (self.points[2].y - self.points[1].y)
  535.  
  536.             if d ~= 0 then
  537.                 ua = ((spatialObject.points[2].x - spatialObject.points[1].x) * (self.points[1].y - spatialObject.points[1].y) - (spatialObject.points[2].y - spatialObject.points[1].y) * (self.points[1].x - spatialObject.points[1].x)) / d
  538.                 ub = ((self.points[2].x - self.points[1].x) * (self.points[1].y - spatialObject.points[1].y) - (self.points[2].y - self.points[1].y) * (self.points[1].x - spatialObject.points[1].x)) / d
  539.  
  540.                 if ua >= 0 and ua <= 1 and ub >= 0 and ub <= 1 then
  541.                     return {Point2 (self.points[1].x + (ua * (self.points[2].x - self.points[1].x)), self.points[1].y + (ua * (self.points[2].y - self.points[1].y)))}
  542.                 end
  543.             end
  544.         end
  545.  
  546.         return {}
  547.     end
  548.  
  549.     function LineSegment2:draw(color, width)
  550.         drawLine(self, color or 0XFF00FF00, width or 4)
  551.     end
  552. -- }
  553.  
  554. --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--
  555.  
  556. class 'Polygon2' -- {
  557.     function Polygon2:__init(...)
  558.         uniqueId2 = uniqueId2 + 1
  559.         self.uniqueId2 = uniqueId2
  560.  
  561.         self.points = {...}
  562.     end
  563.  
  564.     function Polygon2:__type()
  565.         return "Polygon2"
  566.     end
  567.  
  568.     function Polygon2:__eq(spatialObject)
  569.         return spatialObject:__type() == "Polygon2" -- TODO
  570.     end
  571.  
  572.     function Polygon2:getPoints()
  573.         return self.points
  574.     end
  575.  
  576.     function Polygon2:addPoint(point)
  577.         table.insert(self.points, point)
  578.         self.lineSegments = nil
  579.         self.triangles = nil
  580.     end
  581.  
  582.     function Polygon2:getLineSegments()
  583.         if self.lineSegments == nil then
  584.             self.lineSegments = {}
  585.             for i = 1, #self.points, 1 do
  586.                 table.insert(self.lineSegments, LineSegment2(self.points[i], self.points[(i % #self.points) + 1]))
  587.             end
  588.         end
  589.  
  590.         return self.lineSegments
  591.     end
  592.  
  593.     function Polygon2:contains(spatialObject)
  594.         if spatialObject:__type() == "Line2" then
  595.             return false
  596.         elseif #self.points == 3 then
  597.             for i, point in ipairs(spatialObject:getPoints()) do
  598.                 corner1DotCorner2 = ((point.y - self.points[1].y) * (self.points[2].x - self.points[1].x)) - ((point.x - self.points[1].x) * (self.points[2].y - self.points[1].y))
  599.                 corner2DotCorner3 = ((point.y - self.points[2].y) * (self.points[3].x - self.points[2].x)) - ((point.x - self.points[2].x) * (self.points[3].y - self.points[2].y))
  600.                 corner3DotCorner1 = ((point.y - self.points[3].y) * (self.points[1].x - self.points[3].x)) - ((point.x - self.points[3].x) * (self.points[1].y - self.points[3].y))
  601.  
  602.                 if not (corner1DotCorner2 * corner2DotCorner3 >= 0 and corner2DotCorner3 * corner3DotCorner1 >= 0) then
  603.                     return false
  604.                 end
  605.             end
  606.  
  607.             if spatialObject:__type() == "Circle2" then
  608.                 for i, lineSegment in ipairs(self:getLineSegments()) do
  609.                     if spatialObject.point:distance(lineSegment) <= 0 then
  610.                         return false
  611.                     end
  612.                 end
  613.             end
  614.  
  615.             return true
  616.         else
  617.             for i, point in ipairs(spatialObject:getPoints()) do
  618.                 inTriangles = false
  619.                 for j, triangle in ipairs(self:triangulate()) do
  620.                     if triangle:contains(point) then
  621.                         inTriangles = true
  622.                         break
  623.                     end
  624.                 end
  625.                 if not inTriangles then
  626.                     return false
  627.                 end
  628.             end
  629.  
  630.             return true
  631.         end
  632.     end
  633.  
  634.     function Polygon2:insideOf(spatialObject)
  635.         return spatialObject.contains(self)
  636.     end
  637.  
  638.     function Polygon2:direction()
  639.         if self.directionValue == nil then
  640.             local rightMostPoint = nil
  641.             local rightMostPointIndex = nil
  642.             for i, point in ipairs(self.points) do
  643.                 if rightMostPoint == nil or point.x >= rightMostPoint.x then
  644.                     rightMostPoint = point
  645.                     rightMostPointIndex = i
  646.                 end
  647.             end
  648.  
  649.             rightMostPointPredecessor = self.points[(rightMostPointIndex - 1 - 1) % #self.points + 1]
  650.             rightMostPointSuccessor   = self.points[(rightMostPointIndex + 1 - 1) % #self.points + 1]
  651.  
  652.             z = (rightMostPoint.x - rightMostPointPredecessor.x) * (rightMostPointSuccessor.y - rightMostPoint.y) - (rightMostPoint.y - rightMostPointPredecessor.y) * (rightMostPointSuccessor.x - rightMostPoint.x)
  653.             if z > 0 then
  654.                 self.directionValue = 1
  655.             elseif z < 0 then
  656.                 self.directionValue = -1
  657.             else
  658.                 self.directionValue = 0
  659.             end
  660.         end
  661.  
  662.         return self.directionValue
  663.     end
  664.  
  665.     function Polygon2:triangulate()
  666.         if self.triangles == nil then
  667.             self.triangles = {}
  668.  
  669.             if #self.points > 3 then
  670.                 tempPoints = {}
  671.                 for i, point in ipairs(self.points) do
  672.                     table.insert(tempPoints, point)
  673.                 end
  674.        
  675.                 triangleFound = true
  676.                 while #tempPoints > 3 and triangleFound do
  677.                     triangleFound = false
  678.                     for i, point in ipairs(tempPoints) do
  679.                         point1Index = (i - 1 - 1) % #tempPoints + 1
  680.                         point2Index = (i + 1 - 1) % #tempPoints + 1
  681.  
  682.                         point1 = tempPoints[point1Index]
  683.                         point2 = tempPoints[point2Index]
  684.  
  685.                         if ((((point1.x - point.x) * (point2.y - point.y) - (point1.y - point.y) * (point2.x - point.x))) * self:direction()) < 0 then
  686.                             triangleCandidate = Polygon2(point1, point, point2)
  687.  
  688.                             anotherPointInTriangleFound = false
  689.                             for q = 1, #tempPoints, 1 do
  690.                                 if q ~= i and q ~= point1Index and q ~= point2Index and triangleCandidate:contains(tempPoints[q]) then
  691.                                     anotherPointInTriangleFound = true
  692.                                     break
  693.                                 end
  694.                             end
  695.  
  696.                             if not anotherPointInTriangleFound then
  697.                                 table.insert(self.triangles, triangleCandidate)
  698.                                 table.remove(tempPoints, i)
  699.                                 i = i - 1
  700.  
  701.                                 triangleFound = true
  702.                             end
  703.                         end
  704.                     end
  705.                 end
  706.  
  707.                 if #tempPoints == 3 then
  708.                     table.insert(self.triangles, Polygon2(tempPoints[1], tempPoints[2], tempPoints[3]))
  709.                 end
  710.             elseif #self.points == 3 then
  711.                 table.insert(self.triangles, self)
  712.             end
  713.         end
  714.  
  715.         return self.triangles
  716.     end
  717.  
  718.     function Polygon2:intersects(spatialObject)
  719.         for i, lineSegment1 in ipairs(self:getLineSegments()) do
  720.             for j, lineSegment2 in ipairs(spatialObject:getLineSegments()) do
  721.                 if lineSegment1:intersects(lineSegment2) then
  722.                     return true
  723.                 end
  724.             end
  725.         end
  726.  
  727.         return false
  728.     end
  729.  
  730.     function Polygon2:distance(spatialObject)
  731.         local minDistance = nil
  732.         for i, lineSegment in ipairs(self:getLineSegment()) do
  733.             distance = point:distance(self)
  734.             if minDistance == nil or distance <= minDistance then
  735.                 minDistance = distance
  736.             end
  737.         end
  738.  
  739.         return minDistance
  740.     end
  741.  
  742.     function Polygon2:tostring()
  743.         local result = "Polygon2("
  744.  
  745.         for i, point in ipairs(self.points) do
  746.             if i == 1 then
  747.                 result = result .. point:tostring()
  748.             else
  749.                 result = result .. ", " .. point:tostring()
  750.             end
  751.         end
  752.  
  753.         return result .. ")"
  754.     end
  755.  
  756.     function Polygon2:draw(color, width)
  757.         for i, lineSegment in ipairs(self:getLineSegments()) do
  758.             lineSegment:draw(color, width)
  759.         end
  760.     end
  761. -- }
  762.  
  763. --UPDATEURL=
  764. --HASH=D2B91CB3DD8DD8D77245E8208C402F15
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement