Advertisement
MattiasBuelens

CCGUI geometry

Jul 5th, 2012
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.41 KB | None | 0 0
  1. --[[
  2.  
  3.     ComputerCraft GUI
  4.     Geometry
  5.  
  6. --]]
  7.  
  8. ccgui = ccgui or {}
  9. os.loadAPI("/rom/apis/vector")
  10.  
  11. --[[
  12.  
  13.     Margins
  14.  
  15. ]]--
  16.  
  17. local Margins = common.newClass{
  18.     top = 0,
  19.     right = 0,
  20.     bottom = 0,
  21.     left = 0
  22. }
  23. ccgui.Margins = Margins
  24.  
  25. function ccgui.newMargins(...)
  26.     local args = { ... }
  27.     local n = #args
  28.     local top, right, bottom, left
  29.  
  30.     if n >= 4 then
  31.         top, right, bottom, left = unpack(args)
  32.     elseif n == 1 then
  33.         local m = args[1]
  34.         if type(m) == "table" then
  35.             -- Clone margins
  36.             top, right, bottom, left = m.top, m.right, m.bottom, m.left
  37.         else
  38.             -- All margins
  39.             top, right, bottom, left = m, m, m, m
  40.         end
  41.     elseif n == 2 then
  42.         -- Vertical and horizontal margins
  43.         top, right, bottom, left = args[1], args[2], args[1], args[2]
  44.     elseif n == 3 then
  45.         -- Top, horizontal and bottom margins
  46.         top, right, bottom, left = args[1], args[2], args[3], args[2]
  47.     end
  48.  
  49.     return Margins:new{
  50.         top     = tonumber(top),
  51.         right   = tonumber(right),
  52.         bottom  = tonumber(bottom),
  53.         left    = tonumber(left)
  54.     }
  55. end
  56.  
  57. function Margins:vertical()
  58.     return self.top + self.bottom
  59. end
  60.  
  61. function Margins:horizontal()
  62.     return self.left + self.right
  63. end
  64.  
  65. function Margins:add(m)
  66.     return ccgui.newMargins(self.top + m.top, self.right + m.right, self.bottom + m.bottom, self.left + m.left)
  67. end
  68.  
  69. function Margins:multiply(m)
  70.     return ccgui.newMargins(self.top * m, self.right * m, self.bottom * m, self.left * m)
  71. end
  72.  
  73. function Margins:__add(o)
  74.     return self:add(o)
  75. end
  76.  
  77. function Margins:__unm()
  78.     return self:multiply(-1)
  79. end
  80.  
  81. function Margins:__eq(o)
  82.     return self.top == o.top and self.right == o.right
  83.         and self.bottom == o.bottom and self.left == o.left
  84. end
  85.  
  86. function Margins:__tostring(o)
  87.     return "Margins["..self.top..","..self.right..","..self.bottom..","..self.left.."]"
  88. end
  89.  
  90. --[[
  91.  
  92.     Line
  93.  
  94. ]]--
  95.  
  96. local Line = common.newClass{
  97.     start = nil,
  98.     stop = nil
  99. }
  100. ccgui.Line = Line
  101.  
  102. function ccgui.newLine(start, stop)
  103.     return Line:new{
  104.         start = start,
  105.         stop = stop
  106.     }
  107. end
  108.  
  109. function Line:delta()
  110.     return self.stop - self.start
  111. end
  112.  
  113. function Line:length()
  114.     return self:delta():length() + 1
  115. end
  116.  
  117. function Line:isHorizontal()
  118.     return self:delta().y == 0
  119. end
  120.  
  121. function Line:isVertical()
  122.     return self:delta().x == 0
  123. end
  124.  
  125. function Line:points()
  126.     local delta, length = self:delta(), self:length()
  127.     if length <= 0 then
  128.         return { self.start }
  129.     end
  130.  
  131.     -- Shifts per unit length
  132.     local dx, dy = delta.x / length, delta.y / length
  133.  
  134.     -- Walk along line
  135.     local points = {}
  136.     table.insert(points, self.start)
  137.     for i=1, math.floor(length - 0.5) do
  138.         local x, y = math.floor(i*dx), math.floor(i*dy)
  139.         table.insert(points, self.start + vector.new(x, y))
  140.     end
  141.     table.insert(points, self.stop)
  142.  
  143.     return points
  144. end
  145.  
  146. function Line:__tostring()
  147.     return "Line["..tostring(self.start).." to "..tostring(self.stop).."]"
  148. end
  149.  
  150. function Line:__eq(o)
  151.     return self.start.x == o.start.x and self.start.y == o.start.y
  152.         and self.stop.x == o.stop.x and self.stop.x == o.stop.y
  153. end
  154.  
  155. --[[
  156.  
  157.     Polygon
  158.  
  159. ]]--
  160.  
  161. local Polygon = common.newClass{
  162.     ___vertices = nil
  163. }
  164. ccgui.Polygon = Polygon
  165.  
  166. function Polygon:init()
  167.     local vertices = self.___vertices
  168.  
  169.     -- Vertices passed as table
  170.     while table.getn(vertices) == 1 do
  171.         vertices = vertices[1]
  172.     end
  173.  
  174.     -- Check amount of vertices
  175.     if #vertices < 2 then
  176.         error("Polygon requires at least two vertices")
  177.     end
  178.  
  179.     -- Protect vertices from modifications
  180.     setmetatable(vertices, {
  181.         __newindex = function()
  182.             error("Polygon vertices list is immutable")
  183.         end
  184.     })
  185.  
  186.     self.___vertices = vertices
  187. end
  188.  
  189. function Polygon:vertices()
  190.     return self.___vertices
  191. end
  192.  
  193. function Polygon:sides()
  194.     local vertices = self:vertices()
  195.  
  196.     -- Add last side first
  197.     local v1, v2 = vertices[#vertices], vertices[1]
  198.     local sides = { ccgui.newLine(v1, v2) }
  199.  
  200.     -- Walk over vertices
  201.     for i=2, #vertices do
  202.         v1, v2 = v2, vertices[i]
  203.         table.insert(sides, ccgui.newLine(v1, v2))
  204.     end
  205.  
  206.     return sides
  207. end
  208.  
  209. function Polygon:points()
  210.     local sides = self:sides()
  211.  
  212.     local points = {}
  213.     for i,side in ipairs(sides) do
  214.         -- Get points from side
  215.         local sidePoints = side:points()
  216.         -- Remove last point, since the next side
  217.         -- will have it as its first point
  218.         table.remove(sidePoints, #sidePoints)
  219.         -- Add to polygon points
  220.         for j=1, #sidePoints do
  221.             table.insert(points, sidePoints[j])
  222.         end
  223.     end
  224.     return points
  225. end
  226.  
  227. function Polygon:bbox()
  228.     local vertices = self:vertices()
  229.  
  230.     -- Upper and lower coordinates
  231.     local ux, uy = vertices[1].x, vertices[1].y
  232.     local lx, ly = ux, ly
  233.  
  234.     -- Walk over vertices
  235.     for i=2, #vertices do
  236.         local v = vertices[i]
  237.         ux = math.max(ux, v.x)
  238.         ux = math.max(uy, v.y)
  239.         lx = math.min(lx, v.x)
  240.         ly = math.min(ly, v.y)
  241.     end
  242.  
  243.     -- Return as rectangle
  244.     return ccgui.newRectangle(lx, ly, ux - lx, uy - ly)
  245. end
  246.  
  247. function Polygon:__tostring()
  248.     return "Polygon["..table.getn(self:vertices()).."]"
  249. end
  250.  
  251. --[[
  252.  
  253.     Rectangle
  254.  
  255. ]]--
  256.  
  257. local Rectangle = common.newClass({
  258.     x = 0,
  259.     y = 0,
  260.     w = 0,
  261.     h = 0
  262. }, Polygon)
  263. ccgui.Rectangle = Rectangle
  264.  
  265. function ccgui.newRectangle(x, y, w, h)
  266.     -- Position as vector
  267.     if type(x) == "table" then
  268.         return ccgui.newRectangle(x.x, x.y, y, w)
  269.     end
  270.     -- Size as vector
  271.     if type(w) == "table" then
  272.         return ccgui.newRectangle(x, y, w.x, w.y)
  273.     end
  274.    
  275.     return Rectangle:new{
  276.         x = x,
  277.         y = y,
  278.         w = math.max(0, w),
  279.         h = math.max(0, h)
  280.     }
  281. end
  282.  
  283. function Rectangle:init()
  284.     self.___vertices = self:vertices()
  285. end
  286.  
  287. function Rectangle:vertices()
  288.     return { self:tl(), self:tr(), self:br(), self:bl() }
  289. end
  290.  
  291. function Rectangle:bbox()
  292.     return self
  293. end
  294.  
  295. function Rectangle:__tostring()
  296.     return "Rectangle["..tostring(self:tl()).." to "..tostring(self:br()).."]"
  297. end
  298.  
  299. function Rectangle:__eq(o)
  300.     return self.x == o.x and self.y == o.y
  301.         and self.w == o.w and self.h == o.h
  302. end
  303.  
  304. -- Vertices
  305. function Rectangle:tl()
  306.     return vector.new(self.x, self.y)
  307. end
  308.  
  309. function Rectangle:tr()
  310.     return vector.new(self.x + self.w - 1, self.y)
  311. end
  312.  
  313. function Rectangle:bl()
  314.     return vector.new(self.x, self.y + self.h - 1)
  315. end
  316.  
  317. function Rectangle:br()
  318.     return vector.new(self.x + self.w - 1, self.y + self.h - 1)
  319. end
  320.  
  321. -- Sides
  322. function Rectangle:left()
  323.     return ccgui.newLine(self:tl(), self:bl())
  324. end
  325.  
  326. function Rectangle:right()
  327.     return ccgui.newLine(self:tr(), self:br())
  328. end
  329.  
  330. function Rectangle:top()
  331.     return ccgui.newLine(self:tl(), self:tr())
  332. end
  333.  
  334. function Rectangle:bottom()
  335.     return ccgui.newLine(self:bl(), self:br())
  336. end
  337.  
  338. -- Size
  339. function Rectangle:size()
  340.     return vector.new(self.w, self.h)
  341. end
  342.  
  343. function Rectangle:area()
  344.     return self.w * self.h
  345. end
  346.  
  347. -- Queries
  348. function Rectangle:contains(x, y)
  349.     if type(x) == "table" then 
  350.         -- Vector given
  351.         return self:contains(x.x, x.y)
  352.     end
  353.  
  354.     return self.x <= x and x < self.x + self.w
  355.         and self.y <= y and y < self.y + self.h
  356. end
  357.  
  358. -- Modifications
  359. function Rectangle:shift(v)
  360.     return ccgui.newRectangle(self.x + v.x, self.y + v.y, self.w, self.h)
  361. end
  362.  
  363. function Rectangle:expand(m)
  364.     m = ccgui.newMargins(m)
  365.     return ccgui.newRectangle(
  366.         self.x - m.left, self.y - m.top,
  367.         self.w + m:horizontal(), self.h + m:vertical()
  368.     )
  369. end
  370.  
  371. function Rectangle:contract(m)
  372.     return self:expand(-m)
  373. end
  374.  
  375. -- Intersections
  376. function Rectangle:intersects(rect)
  377.     if rect == nil then return false end
  378.  
  379.     return self.x <= rect.x + rect.w
  380.        and self.x + self.w >= rect.x
  381.        and self.y <= rect.y + rect.h
  382.        and self.y + self.h >= rect.y
  383. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement