Kain2030

2DGeometry.lua

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