# outline triangulate()'ed meshes with a line()

the thing is, I want to make my life easier and just use triangulate() on a set of vertices for a polygon. then I want to give the whole shape an outline. how can I filter out the relevant polygons to use this in a loop and connect them with line()?

EDIT: I know I could have a table set of vertices for use with line() and then another table with the triangulated set of verts for drawing the mesh, but this just increases the memory usage…

Also another question, how could I automate the packing of the verts into the texture atlas?

The way I do it is set my shape say an irregular hexagon and place 6 vertices around the screen then use line through this table then triangulate the same table and draw the mesh from the points, assuming that’s what you wanted?

I’m not sure if its what you want, but you could sort by angle, then calculate the centre point of your vertices and connect it to two adjacent vertices to create a triangle, and repeat all the way round. The line around the outside is formed by the sorted list of vertices.

Of course this assumes all the vertices are on the edge of the polygon…

@Luatee won’t it be too heavy on memory if i would triangulate on each draw() loop?

Depends what you do, I wouldn’t triangulate it in draw. If it needs to be updated regularly then make a function and you can create a sort of timed stack which is my way of creating and executing functions at an interval, others might not like this method. This way you can triangulate the mesh every 0.2 seconds or so making it look smoother but if the polygon is complex then you could experience jolts in frames because of memory usage, otherwise if the mesh polygon is only set once then create the vertices in setup and triangulate them in setup, this way you can create two variables of the two different vertices and whenever the non triangulated vertices are updated then triangulate them and set your old variable to this.

As an example here’s a terrain class I made which updates using this method:

``````function Terrain:BodyChanged(verts)
local bool = false
if #verts ~= #self.verts then
bool = true
return bool
end
for i=1,#verts do
local vc = verts[i]
local nc = self.verts[i]
if vc ~= nc then
bool = true

end
end
return bool
end

function Terrain:draw()
if ElapsedTime > self.oe+0.2 and 1/DeltaTime > 30 then
self.oe = ElapsedTime
if self:BodyChanged(self.floor.points) then
self.floor:destroy()
self.floor = physics.body(POLYGON,unpack(self.verts))
self.floor.type = STATIC
self.oldverts = self.verts
tween.delay(0.1,function()
self.m.vertices = triangulate(self.verts)
end)
end
end
self.m:draw()
local sv = self.verts
for i=1,#sv do
sprite(txture,sv[i].x,sv[i].y,5,5)
end
end
``````

The function BodyChanged checks all the current vertices against the stored vertices (self.verts) and if they are different then it returns true otherwise false, this saves on memory as you aren’t executing the triangulate function every frame, it can have a negative effect with complex polygons.

As you can see in the draw loop I have used a timer using ElapsedTime and adding 0.2 seconds on to it, this is different from a ‘timed’ stack which looks like this:

``````function tstack()
tween.delay(0.2,function() print("execute") tstack() end)
end
``````

The recreating of the physics body in the draw loop takes up a lot of performance but that doesn’t matter too much as I assume you’re not using the physics engine. Also instead of creating a triangulated variable in this code it’s better to just triangulate it when you need to pass the stored vertices (self.verts) to the mesh.

Here’s an example of this

``````
--# Main
-- destructable

-- Use this function to perform your initial setup
function setup()

ter = Terrain(vec2(WIDTH/2,HEIGHT/4),vec2(WIDTH,HEIGHT/2))
circ = {}
circn = 0
holding = nil
end

function collide(c)
local cp = circ.position
if c.state == BEGAN and c.normalImpulse > 2 then
for k,v in pairs(ter:getTable()) do
for a,b in pairs(circ) do
if v:dist(b.position) < 50 then
ter:setVert(k, v + (v-b.position):normalize()*(50-v:dist(b.position)))
ter:setVert(k, v + (c.normal*-1)*c.normalImpulse*(3-v:dist(b.position)/19))
end
end
end
end
end

function touched(t)
for a,b in pairs(circ) do
local cp = b.position
if vec2(t.x,t.y):dist(cp) < 40 and t.state == BEGAN then
holding = {b,vec2(t.x,t.y)}
end
if holding and t.state == MOVING then
holding = {b,vec2(t.x,t.y)}
end
if t.state == ENDED then
holding = nil
end
end
if not holding then
ter:touched(t)
end
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(5)
local n = math.random(20)
if n == 15 and circn < 2 then
circn = circn + 1
circ[circn] = physics.body(CIRCLE,15)
circ[circn].position = vec2(math.random(50,WIDTH-50),math.random(HEIGHT/2+50,HEIGHT-50))
end
for k,v in pairs(circ) do
if holding ~= nil and holding[1] == v then
v:applyForce(holding[2]-v.position-v.linearVelocity/4)
end
end
ter:draw()
for k,v in pairs(circ) do
sprite("Documents:circle",v.x,v.y,30,30)
end
pushStyle()
fill(255, 255, 255, 255)
text(math.floor(1/DeltaTime),100,100)
popStyle()
end

--# Terrain
Terrain = class()

function Terrain:init(pos,size)
self.pos = pos
self.size = size
local verts = {}
local width,height = (size.x/WIDTH)*20,(size.y/HEIGHT)*20
for x=1,width do
table.insert(verts,vec2(pos.x-size.x/2+(size.x/width)*x,pos.y+size.y/2))
end
for y=1,height do
table.insert(verts,vec2(pos.x+size.x/2,pos.y+size.y/2-(size.y/height)*y))
end
for x=1,width do
table.insert(verts,vec2(pos.x+size.x/2-(size.x/width)*x,pos.y-size.y/2))
end
for y=1,height do
table.insert(verts,vec2(pos.x-size.x/2,pos.y-size.y/2+(size.y/height)*y))
end
self.verts = verts
self.m = mesh()
self.m:setColors(255,255,255,255)
self.m.vertices = triangulate(verts)
self.floor = physics.body(POLYGON,unpack(verts))
self.floor.type = STATIC

self.bound = vec2(width,height):len()
self.tbound = 30
print(self.bound)
self.oe = ElapsedTime
self.oldverts = {}
end

function Terrain:BodyChanged(verts)
local bool = false
if #verts ~= #self.verts then
bool = true
return bool
end
for i=1,#verts do
local vc = verts[i]
local nc = self.verts[i]
if vc ~= nc then
bool = true

end
end
return bool
end

function Terrain:draw()
if ElapsedTime > self.oe+0.2 and 1/DeltaTime > 10 then
self.oe = ElapsedTime
if self:BodyChanged(self.floor.points) then
self.floor:destroy()
self.floor = physics.body(POLYGON,unpack(self.verts))
self.floor.type = STATIC
self.oldverts = self.verts
tween.delay(0.1,function()
self.m.vertices = triangulate(self.verts)
end)
end
end
self.m:draw()
local sv = self.verts
for i=1,#sv do
sprite(txture,sv[i].x,sv[i].y,5,5)
strokeWidth(3)
if i > 1 then
line(sv[i].x,sv[i].y,sv[i-1].x,sv[i-1].y)
end
end
end

function Terrain:getTable()
return self.verts
end

function Terrain:setVert(i,v)
self.verts[i] = v
end

function Terrain:touched(t)
self.t = true
if t.state == ENDED then
self.t = false
end
local p,s = self.pos,self.size
local tp = vec2(t.x,t.y)
local sp = #self.verts
for i=1,sp do
local sv = self.verts[i]
local svi
if i > 1 then
svi = self.verts[i-1]
else
svi = self.verts[#self.verts]
end
if sv and sv:dist(tp) < self.bound then
self.verts[i] = sv + (tp-sv):normalize()*0.2
end
if sv ~= nil then
if sv:dist(svi)>self.tbound*1.5 then
local d = (sv+svi)/2
if d.x > p.x-s.x/2-5 and d.x < p.x+s.x/2+5 and d.y > p.y-s.y/2-5 then
table.insert(self.verts,i,d)
return
else
table.remove(self.verts,i)
end
end
end
for j=1,sp do
if sv and self.verts[j] and sv:dist(self.verts[j])<self.tbound/2 and j~=i then
table.remove(self.verts,i)
end
end
if sv and sv:dist(tp) < self.tbound then
local dir = (sv-tp):normalize()*5+vec2(t.deltaX,t.deltaY)
self.verts[i] = self.verts[i] + dir
end
end
end

``````