mirror of
https://github.com/CommunityOx/ox_lib.git
synced 2026-08-18 23:46:03 +01:00
refactor(client/zones): redo triangle algorithm
This commit is contained in:
@@ -14,19 +14,9 @@ local glm = require 'glm'
|
|||||||
---@type { [number]: CZone }
|
---@type { [number]: CZone }
|
||||||
Zones = {}
|
Zones = {}
|
||||||
|
|
||||||
local function makeTriangles(t)
|
|
||||||
local t1, t2
|
|
||||||
if t[3] and t[4] then
|
|
||||||
t1 = mat(t[1], t[2], t[3])
|
|
||||||
t2 = mat(t[2], t[3], t[4])
|
|
||||||
else
|
|
||||||
t1 = mat(t[1], t[2], t[3] or t[4])
|
|
||||||
end
|
|
||||||
return t1, t2
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getTriangles(polygon)
|
local function getTriangles(polygon)
|
||||||
local triangles = {}
|
local triangles = {}
|
||||||
|
|
||||||
if polygon:isConvex() then
|
if polygon:isConvex() then
|
||||||
for i = 2, #polygon - 1 do
|
for i = 2, #polygon - 1 do
|
||||||
triangles[#triangles + 1] = mat(polygon[1], polygon[i], polygon[i + 1])
|
triangles[#triangles + 1] = mat(polygon[1], polygon[i], polygon[i + 1])
|
||||||
@@ -34,198 +24,171 @@ local function getTriangles(polygon)
|
|||||||
return triangles
|
return triangles
|
||||||
end
|
end
|
||||||
|
|
||||||
local points = {}
|
local verticals = {}
|
||||||
local sides = {}
|
local verticalGroups = {}
|
||||||
local horizontals = {}
|
|
||||||
for i = 1, #polygon do
|
|
||||||
local h
|
|
||||||
local point = polygon[i]
|
|
||||||
local unique = true
|
|
||||||
|
|
||||||
for j = 1, #horizontals do
|
for i = 1, #polygon do
|
||||||
if point.y == horizontals[j][1].y then
|
local point = polygon[i]
|
||||||
h = j
|
local x = point.x
|
||||||
horizontals[j][#horizontals[j] + 1] = point
|
local vertical = verticalGroups[x]
|
||||||
unique = false
|
|
||||||
break
|
if vertical then
|
||||||
|
vertical[#vertical + 1] = point
|
||||||
|
else
|
||||||
|
verticalGroups[x] = { point }
|
||||||
|
verticals[#verticals + 1] = x
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(verticals, function(a, b)
|
||||||
|
return a < b
|
||||||
|
end)
|
||||||
|
|
||||||
|
local sides = {}
|
||||||
|
|
||||||
|
for i = 1, #polygon do
|
||||||
|
local point = polygon[i]
|
||||||
|
local side = {}
|
||||||
|
|
||||||
|
for k, v in pairs(verticalGroups) do
|
||||||
|
local newPoint, d, d2 = glm.line.closestSegment(v[1], vec3(0, 1, 0), point, polygon[i + 1] or polygon[1])
|
||||||
|
|
||||||
|
if d ~= 0 and d2 > 0 and d2 < 1 then
|
||||||
|
local internal
|
||||||
|
|
||||||
|
for j = 1, #v do
|
||||||
|
if polygon:containsSegment(glm.segment.getPoint(v[j], newPoint, 0.01), glm.segment.getPoint(v[j], newPoint, 0.99)) then
|
||||||
|
internal = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if internal then
|
||||||
|
side[#side + 1] = newPoint
|
||||||
|
v[#v + 1] = newPoint
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if unique then
|
if next(side) then
|
||||||
h = #horizontals + 1
|
sides[point] = side
|
||||||
horizontals[h] = { point }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sides[i] = { polygon[i], polygon[i + 1] or polygon[1] }
|
|
||||||
points[polygon[i]] = { side = i, horizontal = h, uses = 0 }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local extremes = { polygon.projectToAxis(polygon, vec(1, 0, 0)) }
|
for k, v in pairs(verticalGroups) do
|
||||||
for i = 1, #horizontals do
|
table.sort(v, function(a, b)
|
||||||
local horizontal = horizontals[i]
|
return a.y < b.y
|
||||||
local hLineStart, hLineEnd = vec(extremes[1], horizontal[1].yz), vec(extremes[2], horizontal[1].yz)
|
end)
|
||||||
for j = 1, #sides do
|
end
|
||||||
local sideStart, sideEnd = sides[j][1], sides[j][2]
|
|
||||||
local bool, d, d2 = glm.segment.intersectsSegment(hLineStart, hLineEnd, sideStart, sideEnd)
|
local orderedPoints = {}
|
||||||
if d > 0.001 and d < 0.999 and d2 > 0.001 and d2 < 0.999 then
|
local count = 1
|
||||||
local newPoint = glm.segment.getPoint(hLineStart, hLineEnd, d)
|
|
||||||
local valid
|
for i = 1, #polygon do
|
||||||
for l = 1, #horizontal do
|
local point = polygon[i]
|
||||||
local point = horizontal[l]
|
orderedPoints[point] = count
|
||||||
valid = polygon.contains(polygon, (point + newPoint) / 2, 0.1)
|
count += 1
|
||||||
if valid then
|
local sidePoints = sides[point]
|
||||||
for m = 1, #sides do
|
|
||||||
local sideStart, sideEnd = sides[m][1], sides[m][2]
|
if sidePoints then
|
||||||
local bool, d, d2 = glm.segment.intersectsSegment(point, newPoint, sides[m][1], sides[m][2])
|
local direction = (#point - #(polygon[i + 1] or polygon[1])) > 0
|
||||||
if d > 0.001 and d < 0.999 and d2 > 0.001 and d2 < 0.999 then
|
table.sort(sidePoints, function(a, b)
|
||||||
valid = false
|
if direction then
|
||||||
|
return #a > #b
|
||||||
|
end
|
||||||
|
return #a < #b
|
||||||
|
end)
|
||||||
|
|
||||||
|
for j = 1, #sidePoints do
|
||||||
|
orderedPoints[sidePoints[j]] = count
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #verticals - 1 do
|
||||||
|
local verticalGroupA = verticalGroups[verticals[i]]
|
||||||
|
local countA = #verticalGroupA
|
||||||
|
local sections = {}
|
||||||
|
|
||||||
|
for j = i + 1, #verticals do
|
||||||
|
local verticalGroupB = verticalGroups[verticals[j]]
|
||||||
|
local countB = #verticalGroupB
|
||||||
|
local adjacent
|
||||||
|
|
||||||
|
for l = 1, countA do
|
||||||
|
local pointA = verticalGroupA[l]
|
||||||
|
local numA = orderedPoints[pointA]
|
||||||
|
|
||||||
|
for m = 1, countB do
|
||||||
|
local pointB = verticalGroupB[m]
|
||||||
|
local numB = orderedPoints[pointB]
|
||||||
|
local difference = math.abs(numA - numB)
|
||||||
|
|
||||||
|
if difference == 1 or difference == count - 2 then
|
||||||
|
adjacent = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if adjacent then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if adjacent then
|
||||||
|
if countA < 3 and countB < 3 then
|
||||||
|
sections[1] = {
|
||||||
|
a = verticalGroupA[1],
|
||||||
|
b = verticalGroupA[2],
|
||||||
|
c = verticalGroupB[1],
|
||||||
|
d = verticalGroupB[2],
|
||||||
|
}
|
||||||
|
else
|
||||||
|
local paired = {}
|
||||||
|
|
||||||
|
for l = 1, countA do
|
||||||
|
local pointA = verticalGroupA[l]
|
||||||
|
local numA = orderedPoints[pointA]
|
||||||
|
|
||||||
|
for m = 1, countB do
|
||||||
|
local pointB = verticalGroupB[m]
|
||||||
|
local numB = orderedPoints[pointB]
|
||||||
|
local difference = math.abs(numA - numB)
|
||||||
|
|
||||||
|
if difference == 1 or difference == count - 2 then
|
||||||
|
paired[#paired + 1] = { pointA, pointB }
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if valid then
|
|
||||||
horizontals[i][#horizontals[i] + 1] = newPoint
|
for l = 1, #paired - 1 do
|
||||||
sides[j][#sides[j] + 1] = newPoint
|
sections[#sections + 1] = {
|
||||||
points[newPoint] = { side = j, horizontal = i, uses = 0 }
|
a = paired[l][1],
|
||||||
break
|
b = paired[l + 1][1],
|
||||||
|
c = paired[l][2],
|
||||||
|
d = paired[l + 1][2],
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local function up(a, b)
|
for j = 1, #sections do
|
||||||
return a.y > b.y
|
local section = sections[j]
|
||||||
end
|
|
||||||
|
|
||||||
local function down(a, b)
|
if section.a and section.b and section.c and section.d then
|
||||||
return a.y < b.y
|
triangles[#triangles + 1] = mat(section.a, section.b, section.c)
|
||||||
end
|
triangles[#triangles + 1] = mat(section.b, section.c, section.d)
|
||||||
|
elseif section.a and section.b then
|
||||||
local function right(a, b)
|
triangles[#triangles + 1] = mat(section.a, section.b, section.c or section.d)
|
||||||
return a.x > b.x
|
elseif section.c and section.d then
|
||||||
end
|
triangles[#triangles + 1] = mat(section.a or section.b, section.c, section.d)
|
||||||
|
|
||||||
local function left(a, b)
|
|
||||||
return a.x < b.x
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, #sides do
|
|
||||||
local side = sides[i]
|
|
||||||
|
|
||||||
---@type number | function
|
|
||||||
local direction = side[1].y - side[2].y
|
|
||||||
direction = direction > 0 and up or down
|
|
||||||
table.sort(side, direction)
|
|
||||||
|
|
||||||
for j = 1, #side - 1 do
|
|
||||||
local a, b = side[j], side[j + 1]
|
|
||||||
local aData, bData = points[a], points[b]
|
|
||||||
local aPos, bPos
|
|
||||||
if aData.horizontal ~= bData.horizontal then
|
|
||||||
local aHorizontal, bHorizontal = horizontals[aData.horizontal], horizontals[bData.horizontal]
|
|
||||||
local c, d
|
|
||||||
|
|
||||||
if aHorizontal[2] then
|
|
||||||
---@type number | function
|
|
||||||
local direction = a.x - (a.x ~= aHorizontal[1].x and aHorizontal[1].x or aHorizontal[2].x)
|
|
||||||
direction = direction > 0 and right or left
|
|
||||||
table.sort(aHorizontal, direction)
|
|
||||||
|
|
||||||
for l = 1, #aHorizontal do
|
|
||||||
if a == aHorizontal[l] then
|
|
||||||
aPos = l
|
|
||||||
elseif c and aPos then
|
|
||||||
break
|
|
||||||
else
|
|
||||||
c = aHorizontal[l]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if bHorizontal[2] then
|
|
||||||
---@type number | function
|
|
||||||
local direction = b.x - (b.x ~= bHorizontal[1].x and bHorizontal[1].x or bHorizontal[2].x)
|
|
||||||
direction = direction > 0 and right or left
|
|
||||||
table.sort(bHorizontal, direction)
|
|
||||||
|
|
||||||
for l = 1, #bHorizontal do
|
|
||||||
if b == bHorizontal[l] then
|
|
||||||
bPos = l
|
|
||||||
elseif bPos and d then
|
|
||||||
break
|
|
||||||
else
|
|
||||||
d = bHorizontal[l]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if aData.uses < 2 then
|
|
||||||
if c and d then
|
|
||||||
if points[c].side ~= points[d].side then
|
|
||||||
local done
|
|
||||||
for l = aPos > 1 and aPos - 1 or 1, aPos > #aHorizontal and aPos + 1 or #aHorizontal do
|
|
||||||
c = aHorizontal[l]
|
|
||||||
if c ~= a then
|
|
||||||
for m = bPos > 1 and bPos - 1 or 1, bPos > #bHorizontal and bPos + 1 or #bHorizontal do
|
|
||||||
d = bHorizontal[m]
|
|
||||||
local sideDifference = points[c].side - points[d].side
|
|
||||||
if d ~= b and sideDifference >= -1 and sideDifference <= 1 then
|
|
||||||
done = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if done then break end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
c = polygon.contains(polygon, (a + c) / 2, 0.1) and c or nil
|
|
||||||
d = polygon.contains(polygon, (b + d) / 2, 0.1) and d or nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if c and not d then
|
|
||||||
for l = aPos > 1 and aPos - 1 or 1, aPos < #aHorizontal and aPos + 1 or #aHorizontal do
|
|
||||||
c = aHorizontal[l]
|
|
||||||
if c and c ~= a then
|
|
||||||
local sideDifference = bData.side - points[c].side
|
|
||||||
if sideDifference >= -1 and sideDifference <= 1 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif d and not c then
|
|
||||||
for l = bPos > 1 and bPos - 1 or 1, bPos < #bHorizontal and bPos + 1 or #bHorizontal do
|
|
||||||
d = aHorizontal[l]
|
|
||||||
if d and d ~= b then
|
|
||||||
local sideDifference = aData.side - points[d].side
|
|
||||||
if sideDifference >= -1 and sideDifference <= 1 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if c or d then
|
|
||||||
local t = { a, b, c, d }
|
|
||||||
nTriangles = #triangles
|
|
||||||
triangles[nTriangles + 1], triangles[nTriangles + 2] = makeTriangles(t)
|
|
||||||
if c and d then
|
|
||||||
for i = 1, #t do
|
|
||||||
points[t[i]].uses += 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for k, v in pairs(t) do
|
|
||||||
points[v].uses += 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
aData.uses += 1
|
|
||||||
bData.uses += 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return triangles
|
return triangles
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -414,7 +377,7 @@ lib.zones = {
|
|||||||
data.contains = contains
|
data.contains = contains
|
||||||
|
|
||||||
if data.debug then
|
if data.debug then
|
||||||
data.triangles = { makeTriangles({ data.polygon[1], data.polygon[2], data.polygon[4], data.polygon[3] }) }
|
data.triangles = { mat(data.polygon[1], data.polygon[2], data.polygon[3]), mat(data.polygon[1], data.polygon[3], data.polygon[4]) }
|
||||||
data.debug = debugPoly
|
data.debug = debugPoly
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user