fix(markarbejde): markens omrids fra getDensityMapPolygon (FS25 har ingen polygonPoints) — flere prøvepunkter, markør-afstand til kanten; F108 majs sås som bar jord og F<nr>-markører 'manglede' på store marker (v1.28.6.0)
This commit is contained in:
@@ -151,13 +151,63 @@ local function isOnField(x, z)
|
||||
return FSDensityMapUtil.getFieldDataAtWorldPosition(x, y, z) and true or false
|
||||
end
|
||||
|
||||
local function findMarker(adEnv, fieldId, x, z)
|
||||
ADFields.SAMPLE_DIRECTIONS = 16
|
||||
|
||||
-- Markens omrids som {{x, z}, ...}. FS25: field:getDensityMapPolygon():getVerticesList() (flad liste
|
||||
-- x1, z1, x2, z2 ... — som Courseplay); ældre: polygonPoints (noder). Tom liste hvis intet findes.
|
||||
function ADFields.readPolygon(field)
|
||||
local verts = {}
|
||||
local okList, list = pcall(function()
|
||||
return field.getDensityMapPolygon ~= nil and field:getDensityMapPolygon():getVerticesList() or nil
|
||||
end)
|
||||
if okList and type(list) == "table" and #list >= 6 then
|
||||
for index = 1, #list - 1, 2 do
|
||||
table.insert(verts, {x = list[index], z = list[index + 1]})
|
||||
end
|
||||
return verts
|
||||
end
|
||||
for _, node in ipairs(field.polygonPoints or {}) do
|
||||
if type(node) == "number" then
|
||||
local x, _, z = getWorldTranslation(node)
|
||||
table.insert(verts, {x = x, z = z})
|
||||
end
|
||||
end
|
||||
return verts
|
||||
end
|
||||
|
||||
-- Hjørnernes gennemsnit (nil uden hjørner).
|
||||
function ADFields.polygonCenter(verts)
|
||||
if verts == nil or #verts == 0 then return nil end
|
||||
local cx, cz = 0, 0
|
||||
for _, v in ipairs(verts) do cx, cz = cx + v.x, cz + v.z end
|
||||
return cx / #verts, cz / #verts
|
||||
end
|
||||
|
||||
-- Afstand fra (x, z) til omridsets nærmeste kant; nil uden omrids.
|
||||
function ADFields.distanceToPolygon(verts, x, z)
|
||||
if verts == nil or #verts == 0 then return nil end
|
||||
local best = math.huge
|
||||
for index = 1, #verts do
|
||||
local a, b = verts[index], verts[index % #verts + 1]
|
||||
local dx, dz = b.x - a.x, b.z - a.z
|
||||
local len2 = dx * dx + dz * dz
|
||||
local t = len2 > 0 and math.max(0, math.min(1, ((x - a.x) * dx + (z - a.z) * dz) / len2)) or 0
|
||||
local d = math.sqrt((a.x + dx * t - x) ^ 2 + (a.z + dz * t - z) ^ 2)
|
||||
if d < best then best = d end
|
||||
end
|
||||
return best
|
||||
end
|
||||
|
||||
-- Markøren "F<nr>" nærmest marken: afstand til omridset (markører står ved kanten; midten kan
|
||||
-- ligge 900 m væk på store kort), ellers til midten.
|
||||
local function findMarker(adEnv, fieldId, x, z, verts)
|
||||
local best, bestDistance = nil, math.huge
|
||||
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
|
||||
if ADFields.parseMarkerName(marker.name) == fieldId then
|
||||
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
|
||||
if wayPoint ~= nil then
|
||||
local distance = math.sqrt((wayPoint.x - x) ^ 2 + (wayPoint.z - z) ^ 2)
|
||||
local distance = ADFields.distanceToPolygon(verts, wayPoint.x, wayPoint.z)
|
||||
or math.sqrt((wayPoint.x - x) ^ 2 + (wayPoint.z - z) ^ 2)
|
||||
if distance < bestDistance then best, bestDistance = marker, distance end
|
||||
end
|
||||
end
|
||||
@@ -199,24 +249,19 @@ local function newScan(adEnv, entry)
|
||||
scan.info = info
|
||||
-- 1) polygon og kandidatpunkter (centroid + halvvejs mod op til 8 hjørner)
|
||||
push(scan, function()
|
||||
local verts = {}
|
||||
for _, node in ipairs(field.polygonPoints or {}) do
|
||||
if type(node) == "number" then
|
||||
local x, _, z = getWorldTranslation(node)
|
||||
table.insert(verts, {x = x, z = z})
|
||||
end
|
||||
end
|
||||
local verts = ADFields.readPolygon(field)
|
||||
info.verts = verts
|
||||
local cx, cz = field.posX, field.posZ
|
||||
if (cx == nil or cz == nil) and #verts > 0 then
|
||||
cx, cz = 0, 0
|
||||
for _, v in ipairs(verts) do cx, cz = cx + v.x, cz + v.z end
|
||||
cx, cz = cx / #verts, cz / #verts
|
||||
end
|
||||
local cx, cz = ADFields.polygonCenter(verts)
|
||||
if cx == nil then cx, cz = field.posX, field.posZ end
|
||||
info.x, info.z = cx, cz
|
||||
if cx == nil then return end
|
||||
-- midten, markskiltet og halvvejs mod op til SAMPLE_DIRECTIONS hjørner: store marker (Dakota
|
||||
-- 16x: 1,7 km) har striber uden afgrøde, så ét punkt kan ramme forkert
|
||||
local candidates = {{x = cx, z = cz}}
|
||||
local step = math.max(1, math.floor(#verts / 8))
|
||||
if field.posX ~= nil and field.posZ ~= nil and (field.posX - cx) ^ 2 + (field.posZ - cz) ^ 2 > 1 then
|
||||
table.insert(candidates, {x = field.posX, z = field.posZ})
|
||||
end
|
||||
local step = math.max(1, math.floor(#verts / ADFields.SAMPLE_DIRECTIONS))
|
||||
for index = 1, #verts, step do
|
||||
table.insert(candidates, {x = (cx + verts[index].x) / 2, z = (cz + verts[index].z) / 2})
|
||||
end
|
||||
@@ -318,7 +363,7 @@ local function finishScan(adEnv, scan)
|
||||
if previous ~= nil and previous.markerCheckedAt ~= nil and ADFields.now - previous.markerCheckedAt < ADFields.MARKER_REFRESH_MS then
|
||||
info.markerId, info.markerName, info.markerDistance, info.markerCheckedAt = previous.markerId, previous.markerName, previous.markerDistance, previous.markerCheckedAt
|
||||
elseif info.x ~= nil then
|
||||
local marker, distance = findMarker(adEnv, info.id, info.x, info.z)
|
||||
local marker, distance = findMarker(adEnv, info.id, info.x, info.z, info.verts)
|
||||
info.markerId = marker ~= nil and marker.id or nil
|
||||
info.markerName = marker ~= nil and marker.name or nil
|
||||
info.markerDistance = distance
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<modDesc descVersion="107">
|
||||
<author>masterdraco</author>
|
||||
<version>1.28.5.0</version>
|
||||
<version>1.28.6.0</version>
|
||||
<title>
|
||||
<en>AD Smart Pickup</en>
|
||||
</title>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
-- Kør: luajit tests/test_adFieldsPolygon.lua (fra repo-roden)
|
||||
-- FS25-marker har ingen polygonPoints — omridset hentes med field:getDensityMapPolygon():getVerticesList().
|
||||
-- In-game 26/9 (Dakota 16x, marker på 1,7 x 0,6 km): uden omrids blev kun markskiltet (posX/posZ) prøvet;
|
||||
-- F108 med majs viste "bar jord" og "mangler markør" (markøren stod ved kanten, 890 m fra skiltet).
|
||||
local failures = 0
|
||||
local function check(name, actual, expected)
|
||||
if actual == expected then print("OK " .. name) else
|
||||
failures = failures + 1
|
||||
print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual)))
|
||||
end
|
||||
end
|
||||
Logging = {warning = function() end, info = function() end}
|
||||
|
||||
local MAIZE = 10
|
||||
function getWorldTranslation() return 0, 0, 0 end
|
||||
function getTerrainHeightAtWorldPos() return 0 end
|
||||
-- markskiltet står i marken, men ved en stribe uden afgrøde (x > 1400)
|
||||
local function cropAt(x) return x <= 1400 and MAIZE or nil end
|
||||
FSDensityMapUtil = {
|
||||
getFieldDataAtWorldPosition = function() return 1, 2 end,
|
||||
getFruitTypeIndexAtWorldPos = function(x, z) return cropAt(x) end,
|
||||
getFruitArea = function() return 0, 10 end,
|
||||
}
|
||||
FieldDensityMap = {SPRAY_LEVEL = 4, LIME_LEVEL = 5, PLOW_LEVEL = 6}
|
||||
DensityCoordType = {POINT_VECTOR_VECTOR = 1}
|
||||
DensityMapModifier = {new = function() return {setParallelogramWorldCoords = function() end, executeGet = function() return 1, 1 end} end}
|
||||
g_fruitTypeManager = {
|
||||
getFruitTypeByIndex = function() return {name = "MAIZE", fillType = {index = 60, title = "Majs"}, minHarvestingGrowthState = 7, maxHarvestingGrowthState = 7, cutState = 9} end,
|
||||
getConverterDataByName = function() return {} end,
|
||||
}
|
||||
g_fillTypeManager = {getConverterDataByName = function() return {} end, getFillTypeNameByIndex = function() return "X" end}
|
||||
g_farmlandManager = {getFarmlandOwner = function() return 1 end}
|
||||
local polygon = {getVerticesList = function() return {0, 0, 1600, 0, 1600, 600, 0, 600} end}
|
||||
local field = {getId = function() return 108 end, farmland = {id = 108}, posX = 1500, posZ = 50,
|
||||
getDensityMapPolygon = function() return polygon end}
|
||||
g_fieldManager = {getFields = function() return {field} end}
|
||||
g_currentMission = {terrainRootNode = 1, missionInfo = {}, fieldGroundSystem = {
|
||||
getDensityMapData = function() return 1, 0, 2 end, getMaxValue = function() return 2 end}}
|
||||
local adEnv = {ADGraphManager = {
|
||||
getMapMarkers = function() return {{id = 900, name = "F108"}} end,
|
||||
-- markøren står 5 m uden for marken ved den modsatte kant: 1505 m fra skiltet
|
||||
getWayPointById = function() return {x = -5, z = 300} end,
|
||||
}}
|
||||
|
||||
dofile("FS25_ADSmartPickup/adFields.lua")
|
||||
local now = 0
|
||||
for _ = 1, 1000 do
|
||||
if ADFields.getInfo(108) ~= nil then break end
|
||||
ADFields.scanStep(adEnv, 1, now)
|
||||
now = now + 16
|
||||
end
|
||||
local info = ADFields.getInfo(108)
|
||||
check("PG1 marken er scannet", info ~= nil, true)
|
||||
check("PG2 omrids fra getDensityMapPolygon", info and #info.verts, 4)
|
||||
check("PG3 majsen findes trods skiltet på bar stribe", info and info.fruitName, "MAIZE")
|
||||
check("PG4 ikke bar mark", info and info.kind, "harvest")
|
||||
check("PG5 markør ved kanten findes (afstand til omridset)", info and info.markerId, 900)
|
||||
check("PG6 afstand = til kanten", info and info.markerDistance, 5)
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
Reference in New Issue
Block a user