Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Can a polygon's vertices be accessed after creation?
Started by XeduR @Spyric Dec 12 2019 12:26 PM

10 replies to this topic
polygon vertices display.newpolygon
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

Another recent thread brought up an issue about how certain information for some display objects is still accessible after creating them, such as the radius of a circle or the path of a rect, but I was wondering if a polygon's vertices are still somehow stored and accessible after the display object has been created?



[TOPIC: post.html]
#2

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

I added some texture stuff that landed in a recent build. One of these is like a texture-based cousin of contentBounds and I wanted it for some shaders, e.g. when I needed 0-1 coordinates on a sprite frame. I added another property called textureVertices because it basically came for free when calculating the bounds.

 

The tests / example with my PR:

--- Frame test.

--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the
-- "Software"), to deal in the Software without restriction, including
-- without limitation the rights to use, copy, modify, merge, publish,
-- distribute, sublicense, and/or sell copies of the Software, and to
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
--
-- The above copyright notice and this permission notice shall be
-- included in all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
--

print("# of available vertex texture units:", system.getInfo("maxVertexTextureUnits"))
print("")

local tex = graphics.newTexture{ type = "canvas", width = 128, height = 128 }
local back = display.newRect(0, 0, 128, 128)

back:setFillColor(1, 0, 0)

local rect = display.newRect(0, 0, 32, 64)

rect:setFillColor(0, 0, 1)

tex:draw(back)
tex:draw(rect)
tex:invalidate()

local fill = { type = "image", filename = tex.filename, baseDir = tex.baseDir }

local function Bounds (object)
  local bounds = object.path.textureBounds

  return "Bounds: uMin = " .. bounds.uMin .. ", vMin = " .. bounds.vMin .. ", uMax = " .. bounds.uMax .. ", vMax = " .. bounds.vMax
end

local function Vertices (object)
  local vertices, t = object.path.textureVertices, {}

  for i = 1, #vertices, 2 do
    t[#t + 1] = "\t(" .. vertices[i] .. ", " .. vertices[i + 1] .. ")"
  end

  return "Vertices:\n" .. table.concat(t, "\n")
end

local vanilla = display.newRect(50, 50, 30, 30)

vanilla.fill = fill

print("VANILLA RECT")
print(Bounds(vanilla))
print(Vertices(vanilla))
print("")

local polygon = display.newPolygon(150, 120, { 0, -110, 27, -35, 105, -35, 43, 16, 65, 90, 0, 45, -65, 90, -43, 15, -105, -35, -27, -35, })

polygon.fill = fill

print("STAR POLYGON")
print(Bounds(polygon))
print(Vertices(polygon))
print("")

local mesh = display.newMesh{
  x = 300, y = 100,
  mode = "triangles",
  vertices = {
    -5, 0, 90, 0, 0, 100,
    0, 100, 90, 0, 130, 100,
    130, 100, 90, 0, 100, 0
  },
  uvs = {
    0, 0, 0.25, 0, 0, .9,
    0, .9, 0.25, 0, 1, .75,
    1, .75, 0.25, 0, 1, 0
  }
}

mesh:translate(mesh.path:getVertexOffset())  -- Translate mesh so that vertices have proper world coordinates
 
mesh.fill = fill

print("MESH")
print(Bounds(mesh))
print(Vertices(mesh))
print("")

local options = {
  frames = {
    {
      x = 64 - 16,
      y = 64 - 32,
      width = 32,
      height = 64
    }
  }
}

local sheet = graphics.newImageSheet(tex.filename, tex.baseDir, options)
local image = display.newImage(sheet, 1)

image.x, image.y = 500, 100

print("SHEET-BASED IMAGE")
print(Bounds(image))
print(Vertices(image))
print("")

local sprite = display.newSprite(sheet, { name = "state", start = 1, count = 1 })

sprite.x, sprite.y = 600, 150

print("SPRITE FRAME")
print(Bounds(sprite))
print(Vertices(sprite))

If I'm remembering correctly (and really, just from observation), the texture coordinates for anything other than meshes and sprites will be the normalized (0-1) coordinates based on the object's content bounds. So in theory you could take the texture vertices here and apply them in reverse.


  • sporkfin, XeduR @Spyric and pixec like this

[TOPIC: post.html]
#3

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

I just downloaded the newest daily build and tried your textureVertices. I must admit, that's awesome!

 

It's been a while since I worked with normalized vectors, so my memory is a bit hazy, but isn't it impossible to reverse the normalization without knowing where the vertices start and how long each vector is?

 

For instance, if we take the star shape vertices from Corona docs for newPolygon, we start with:

vertices = { 0,-110, 27,-35, 105,-35, 43,16, 65,90, 0,45, -65,90, -43,15, -105,-35, -27,-35 }
-- From where we get the values for the normalized vectors (rounded values to save space).
normalized = { 0.37, 0.38, 0.5, 0, 0.63, 0.38, 0.63, 0.38, 1, 0.38, 0.7, 0.63, 0.7, 0.63, 0.81, 1, 0.5, 0.77, 0.5, 0.77, 0.19, 1, 0.3, 0.63, 0.3, 0.63, 0, 0.38, 0.37, 0.38, 0.37, 0.38, 0.63, 0.38, 0.7, 0.63, 0.7, 0.63, 0.5, 0.77, 0.3, 0.63, 0.3, 0.63, 0.37, 0.38, 0.7, 0.63 }

But, since all we know are the content bounds as well as the object's x and y coordinates, that shouldn't be enough to reverse the process, or am I forgetting about something?

At times like these, I really wish I still remembered some C++ so I could just go code in this feature to Corona myself. Perhaps I should pick up a book, this level of feature shouldn't be too much.


  • sporkfin and pixec like this

[TOPIC: post.html]
#4

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

Just in case there's any confusion, by normalized I just mean between values between 0 and 1, as opposed to integer offsets as you'd see in sprite sheets, say. No unit vectors here.  :)

 

I believe going from xMin, yMin (0, 0) to xMax, yMax (1, 1), as supplied by the contentBounds, will get you the content coordinates. It's kind of noisy, but the results were (again, if I'm remembering right) basically a stream like { x1, y1, x2, y2, x3, y3 ... }, but three at a time like that (triangles), so sort of like the somewhat redundant input a non-indexed mesh would take.


  • XeduR @Spyric and pixec like this

[TOPIC: post.html]
#5

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

I seem to have indeed misunderstood what you said. Serves me right for waking up at 5:30 to read about math and programming! :D

 

I was able to get the vertices with your advice with the following code. Now I just need to figure out how to get rid of said triangles and merge them back into the original shape... but I'll do that after I've had some tea and breakfast. :D

local star = display.newPolygon( display.contentCenterX, display.contentCenterY, { 0,-110, 27,-35, 105,-35, 43,16, 65,90, 0,45, -65,90, -43,15, -105,-35, -27,-35 } )
star.alpha = 0.5
local vertices = { unpack( star.path.textureVertices ) }

for i = 1, #vertices, 2 do
	vertices[i] = vertices[i]*star.width
	vertices[i+1] = vertices[i+1]*star.height
end

for i = 1, #vertices, 2 do
	display.newLine(
		star.contentBounds.xMin+vertices[i],
		star.contentBounds.yMin+vertices[i+1],
		vertices[i+2] and star.contentBounds.xMin+vertices[i+2] or star.contentBounds.xMin+vertices[1],
		vertices[i+3] and star.contentBounds.yMin+vertices[i+3] or star.contentBounds.yMin+vertices[2]
	)
end

  • StarCrunch and pixec like this

[TOPIC: post.html]
#6

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

Well, never mind breakfast. I may have figured this out before I got to the kitchen.

 

The above scenario can be solved by adding this bit of code to it.

local verticesNew = {}
local overlap = false

for i = 1, #vertices, 2 do
	for j = 1, #verticesNew, 2 do
		if vertices[i] == verticesNew[j] and vertices[i+1] == verticesNew[j+1] then
			overlap = true
			break
		end
	end

	if not overlap then
		verticesNew[#verticesNew+1] = vertices[i]
		verticesNew[#verticesNew+1] = vertices[i+1]
	end
	overlap = false
end

local starNew = display.newPolygon( 240, 160, verticesNew )

i.e. just checking if a vertex already exists and disregard it if it does. This leads me to the question of how did you program this? Can I assume that this kind of solution will always be valid, or should I slice the vertices into numerous polygons (namely to said triangles) and then apply polygon union on them? This is really just a question of using a lightweight or a heavyweight algorithm, I have both ready to go.


  • pixec likes this

[TOPIC: post.html]
#7

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

Sounds valid to me.

 

If you want to see the details, the whole PR is actually fairly small, so shouldn't be overwhelming even if your C++ is rusty.  :)

 

The CalculateUV() call there was something Corona was already doing, just pulled out into a function so I could reuse it.


  • XeduR @Spyric and pixec like this

[TOPIC: post.html]
#8

pixec

[GLOBAL: userInfoPane.html]
pixec
  • Contributor

  • 102 posts
  • Corona SDK

Seems like kewl and high level discussion. I only know lua, but cant vertexes be added to that c++ with like a line of code? If the input is newPolygon( x, y, vertexes ) then cant those vertexes just be taken from that and be put to ”object.path.vertices” or something easy like that just like that? Cool topic anyway!!

[TOPIC: post.html]
#9

XeduR @Spyric

[GLOBAL: userInfoPane.html]
XeduR @Spyric
  • Corona Geek

  • 1,103 posts
  • Corona SDK

@pixec, it should be fairly easy, but it'll definitely take more than just a single line of code. I doubt anyone else will do it, so I might look into refreshing my C++ skills over the holidays and see if I could implement it.


  • StarCrunch and pixec like this

[TOPIC: post.html]
#10

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 842 posts
  • Corona SDK

@pixec In its raw form this would mean basically keeping around two copies of the same information, which might add up with a lot of polygons. But maybe a property doing what XeduR's code does would be handy.

 

@XeduR On that note, best of luck! There is definitely a learning curve, and these objects in particular have paths and adapters and so on, but it's fun.  :)


  • pixec likes this

[TOPIC: post.html]
#11

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 711 posts
  • Corona SDK

@StarCrunch - nice work as always my friend!


  • StarCrunch likes this


[topic_controls]
[/topic_controls]

Also tagged with one or more of these keywords: polygon, vertices, display.newpolygon