Thread Tools Display Modes
08-25-14, 09:13 PM   #1
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
A way to fill a polygon with the lowest possible number of rectangles

Well, I know this forum is not about graphics programming ... and the topic is not even wow-specific (at least not right now *g*).
But, I've searched for hours now and I can't figure out how to do it. So, I'm just hoping that there's someone out here, who knows a way or at least has an idea where to search for it.

I am looking for a fast way to fill a polygon (non-convex, no intersections) with the lowest possible number of rectangles.

Any idea anyone?

Last edited by Duugu : 08-25-14 at 09:32 PM.
  Reply With Quote
08-25-14, 09:57 PM   #2
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Do you mean triangles? Rectangles can't fill arbitrary polygons.
  Reply With Quote
08-25-14, 10:03 PM   #3
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
No. I mean rectangles. Of variable sizes of course. (smallest ones of 1x1 units)

I would like to fill a polygon ingame. So I can't use triangles.
  Reply With Quote
08-25-14, 10:49 PM   #4
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Originally Posted by Duugu View Post
I would like to fill a polygon ingame. So I can't use triangles.
Of course you can, just make a half transparent texture and skew it..


  Reply With Quote
08-25-14, 11:00 PM   #5
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Ehm. So, you use Settexcoords to rotate/modify the triangle texture to the required shape?
I don't get it. Maybe I'm a bit slow today.
  Reply With Quote
08-25-14, 11:39 PM   #6
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
The only addon examples for this that I can think of off the top of my head are AVR, which used triangles to draw shapes, and QuestHelper, which used triangles to fill quest blobs on the map.

I think they started with a right triangle with 1 pixel of transparency along the edges and used SetTexCoord to skew it into the desired format.

I don't have a polygon triangulation formula for you to start with since it wasn't necessary for what I was doing, but you should be able to get an idea from looking at those addons.
  Reply With Quote
08-25-14, 11:51 PM   #7
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851


I've peeked into the AVR code. I'll triangulate the polygon and use DrawTriangle from AVR as a black box.

Thank you so much for pushing me in this direction Semlar.
  Reply With Quote
08-30-14, 11:10 PM   #8
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Ok, the triangulation part is done ... but ...

I'm again in a need of something to fill a polygon with rectangles.
This time I would like to fill a polygon with secure buttons - which surly can't be done with triangles.

Any thoughts?


[e]
As building this was no fun: if someone ever has to triangulate a polygon in lua, here's the code (it's a simple ear clipping approach).
Triangulate() expects a table containing a sorted list of verticles data (n tables with x and y values) and returns a table containing n tables with triangle data (point 1, 2, 3 each containing a index number from the verticle table that was passed to the function).
Verticle list can be clockWise or anti-clockwise. Works with convex and concave polygons. Does not work with self intersecting polygons or polygons with holes.
No optimization right now. Could surly be faster.

Lua Code:
  1. function IntersectionPoint(x1, y1, x2, y2, x3, y3, x4, y4)
  2.     if x1 and y1 and x2 and y2 and x3 and y3 and x4 and y4 then
  3.         local d = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
  4.         local Ua
  5.         local Ub
  6.         if d ~= 0 then
  7.             Ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / d
  8.             Ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / d
  9.         end
  10.         if Ua and Ub then
  11.             if Ua >= -0.0 and Ua <= 1.0 and Ub >= -0.0 and Ub <= 1.0 then
  12.                 x = x1 + Ua * (x2 - x1)
  13.                 y = y1 + Ua * (y2 - y1)
  14.                 return math.floor(x), math.floor(y), Ua
  15.             end
  16.         end
  17.     end
  18. end      
  19.  
  20. function LineCenter(sx, sy, ex, ey)
  21.     return (sx + ex) * 0.5, (sy + ey ) * 0.5
  22. end
  23.  
  24. function InPolygon(pMeshVerticles, a, b)
  25.     local count = 0
  26.     for x = 1, table.getn(pMeshVerticles) do
  27.         local s, e = x, x + 1
  28.         if s < 1 then s = table.getn(pMeshVerticles) end
  29.         if e > table.getn(pMeshVerticles) then e = 1 end
  30.         if  ((a.x ~= pMeshVerticles[s].x and a.y ~= pMeshVerticles[s].y)  and (b.x ~= pMeshVerticles[e].x and b.y ~= pMeshVerticles[e].y)) and ((b.x ~= pMeshVerticles[s].x and b.y ~= pMeshVerticles[s].y) and (a.x ~= pMeshVerticles[e].x and a.y ~= pMeshVerticles[e].y)) then
  31.             if IntersectionPoint(a.x, a.y, b.x, b.y, pMeshVerticles[s].x, pMeshVerticles[s].y, pMeshVerticles[e].x, pMeshVerticles[e].y) then
  32.                 count = count + 1
  33.             end
  34.         end
  35.     end
  36.     if count > 0 then
  37.         return false
  38.     else
  39.         count = 0
  40.         local ax, ay = LineCenter(a.x, a.y, b.x, b.y)
  41.         if not ax and ay then print("!!! FAIL") return false end
  42.  
  43.         for x = 1, getn(pMeshVerticles) do
  44.             local s, e = x, x + 1
  45.             if s < 1 then s = getn(pMeshVerticles) end
  46.             if e > getn(pMeshVerticles) then e = 1 end
  47.             if IntersectionPoint(ax, ay, 5000, 5000, pMeshVerticles[s].x, pMeshVerticles[s].y, pMeshVerticles[e].x, pMeshVerticles[e].y) then
  48.                 count = count + 1
  49.             end
  50.         end
  51.         local _, b = math.modf(count / 2)
  52.         if b > 0 then
  53.             return true
  54.         else
  55.             return false
  56.         end
  57.     end
  58.  
  59.     return false
  60. end
  61.  
  62. function Triangulate(pMeshVerticles)
  63.     local tTriangles = {}
  64.     local currentVerticle
  65.  
  66.     local tMaxY = -10000
  67.     for x = 1, table.getn(pMeshVerticles) do
  68.         if pMeshVerticles[x].y > tMaxY then
  69.             currentVerticle = x
  70.             tMaxY = pMeshVerticles[x].y
  71.         end
  72.         if x == 1 then
  73.             pMeshVerticles[x].prev = table.getn(pMeshVerticles)
  74.             pMeshVerticles[x].next = x + 1
  75.         elseif x == table.getn(pMeshVerticles) then
  76.             pMeshVerticles[x].prev = x - 1
  77.             pMeshVerticles[x].next = 1
  78.         else
  79.             pMeshVerticles[x].prev = x - 1
  80.             pMeshVerticles[x].next = x + 1
  81.         end
  82.         pMeshVerticles[x].out = false
  83.     end
  84.    
  85.     if not currentVerticle then print("!!! FAIL") return end
  86.  
  87.     local tFailCounter = 0
  88.     local tTriCounter = 0
  89.     local numberPointsLeft = table.getn(pMeshVerticles)
  90.     while numberPointsLeft >= 3 do
  91.         if InPolygon(pMeshVerticles, pMeshVerticles[pMeshVerticles[currentVerticle].prev], pMeshVerticles[pMeshVerticles[currentVerticle].next]) == true then
  92.             insert(tTriangles, {
  93.                 [1] = pMeshVerticles[currentVerticle].prev,
  94.                 [2] = currentVerticle,
  95.                 [3] = pMeshVerticles[currentVerticle].next
  96.                 })
  97.             tTriCounter = tTriCounter + 1
  98.             pMeshVerticles[pMeshVerticles[currentVerticle].prev].next = pMeshVerticles[currentVerticle].next
  99.             pMeshVerticles[pMeshVerticles[currentVerticle].next].prev = pMeshVerticles[currentVerticle].prev
  100.             pMeshVerticles[currentVerticle].out = true
  101.             currentVerticle = pMeshVerticles[currentVerticle].next
  102.             numberPointsLeft = numberPointsLeft -1
  103.         else
  104.             currentVerticle = pMeshVerticles[currentVerticle].next
  105.         end
  106.         tFailCounter = tFailCounter + 1
  107.         if tFailCounter > table.getn(pMeshVerticles) * 3 then
  108.             print("FAIL: ", tFailCounter)
  109.             print("currentVerticle:", currentVerticle, "prev:", pMeshVerticles[currentVerticle].prev, "next: ", pMeshVerticles[currentVerticle].next)
  110.             return
  111.         end
  112.     end
  113.  
  114.     return tTriangles
  115. end

Last edited by Duugu : 08-30-14 at 11:51 PM.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » A way to fill a polygon with the lowest possible number of rectangles


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off