feat(markarbejde): genbrug Courseplay-kurser — markform-signatur + kursus-register pr. maskine; genbrug/kopi i stedet for ny beregning, glemmes ved ændret mark (v1.34.0.0)
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
-- Kør: luajit tests/test_adCourseCache.lua (fra repo-roden)
|
||||
-- Kursus-registret: hvilken mark/bredde/markform/indstillinger en maskines nuværende Courseplay-kursus blev
|
||||
-- lavet til. Genbrug kun når ALT matcher; egen maskine først, ellers en anden maskines kursus (kopi).
|
||||
dofile("FS25_ADSmartPickup/adCourseCache.lua")
|
||||
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
|
||||
local function count(map)
|
||||
local n = 0
|
||||
for _ in pairs(map) do n = n + 1 end
|
||||
return n
|
||||
end
|
||||
|
||||
local C = ADCourseCache
|
||||
local SIG = "n=4;a=960000;c=800,300"
|
||||
|
||||
-- ---- indstillings-nøglen ----
|
||||
check("K1 standard", C.settingsKey({}), "off=0.0;lane=-;multi=1;vine=-;skip=-")
|
||||
check("K2 nil = standard", C.settingsKey(nil), C.settingsKey({}))
|
||||
check("K3 alt sat", C.settingsKey({toolOffset = 1.25, lane = -1, multiTools = 2, vineOffset = -1, vineSkip = 1}),
|
||||
"off=1.3;lane=-1;multi=2;vine=-1.0;skip=1")
|
||||
check("K4 -0.0 = 0.0", C.settingsKey({toolOffset = -0.0001}), C.settingsKey({toolOffset = 0}))
|
||||
check("K5 float-støj i forskydning tæller ikke", C.settingsKey({toolOffset = 1.2000001}), C.settingsKey({toolOffset = 1.2}))
|
||||
check("K6 anden bane = anden nøgle", C.settingsKey({multiTools = 2, lane = 1}) ~= C.settingsKey({multiTools = 2, lane = -1}), true)
|
||||
check("K7 vin-offset indgår", C.settingsKey({vineOffset = 0}) ~= C.settingsKey({vineOffset = -1}), true)
|
||||
check("K8 vin-skip indgår", C.settingsKey({vineOffset = -1, vineSkip = 0}) ~= C.settingsKey({vineOffset = -1, vineSkip = 1}), true)
|
||||
|
||||
local settings = C.settingsKey({})
|
||||
local request = {field = 22, width = 30, sig = SIG, settings = settings}
|
||||
local own = C.newRecord({vehicle = "v1", field = 22, width = 30.0, sig = SIG, settings = settings, waypoints = 812})
|
||||
|
||||
-- ---- key/matches ----
|
||||
check("M1 samme alt", C.matches(own, request), true)
|
||||
check("M2 bredde som float32 fra XML (30.0000001)", C.matches(C.newRecord({vehicle = "v1", field = 22, width = 30.0000001, sig = SIG, settings = settings}), request), true)
|
||||
check("M3 ny bredde", C.matches(own, {field = 22, width = 12, sig = SIG, settings = settings}), false)
|
||||
check("M4 anden mark", C.matches(own, {field = 23, width = 30, sig = SIG, settings = settings}), false)
|
||||
check("M5 form ændret", C.matches(own, {field = 22, width = 30, sig = "n=5;a=960000;c=800,300", settings = settings}), false)
|
||||
check("M6 andre indstillinger", C.matches(own, {field = 22, width = 30, sig = SIG, settings = C.settingsKey({toolOffset = 2})}), false)
|
||||
check("M7 ukendt form (nil) matcher aldrig", C.matches(C.newRecord({vehicle = "v1", field = 22, width = 30, settings = settings}), {field = 22, width = 30, settings = settings}), false)
|
||||
check("M8 intet register", C.matches(nil, request), false)
|
||||
check("M9 key", C.key(request), "22|30.0|" .. SIG .. "|" .. settings)
|
||||
check("M10 key uden form = nil", C.key({field = 22, width = 30, settings = settings}), nil)
|
||||
|
||||
-- ---- grund til ny beregning ----
|
||||
check("R1 intet gemt", C.mismatchReason(nil, request), "intet kursus gemt")
|
||||
check("R2 form ændret", C.mismatchReason(own, {field = 22, width = 30, sig = "x", settings = settings}), "markens form ændret")
|
||||
check("R3 ny bredde", C.mismatchReason(own, {field = 22, width = 12, sig = SIG, settings = settings}), "ny bredde")
|
||||
check("R4 anden mark", C.mismatchReason(own, {field = 9, width = 30, sig = SIG, settings = settings}), "kursus til en anden mark")
|
||||
check("R5 indstillinger", C.mismatchReason(own, {field = 22, width = 30, sig = SIG, settings = "x"}), "andre indstillinger")
|
||||
check("R6 ukendt form", C.mismatchReason(own, {field = 22, width = 30, settings = settings}), "markens form ukendt")
|
||||
|
||||
-- ---- register: immutabelt ----
|
||||
local records = C.withRecord({}, own)
|
||||
check("I1 tilføjet", records.v1 ~= nil, true)
|
||||
local other = C.newRecord({vehicle = "v2", field = 22, width = 30, sig = SIG, settings = settings, waypoints = 812})
|
||||
local both = C.withRecord(records, other)
|
||||
check("I2 original urørt", count(records), 1)
|
||||
check("I3 begge", count(both), 2)
|
||||
check("I4 without", count(C.without(both, "v1")), 1)
|
||||
check("I5 without urørt original", count(both), 2)
|
||||
check("I6 newRecord uden vehicle = nil", C.newRecord({field = 22}), nil)
|
||||
|
||||
-- ---- findReusable ----
|
||||
local rec, how = C.findReusable(both, request, "v1")
|
||||
check("F1 egen maskine først", rec and rec.vehicle, "v1")
|
||||
check("F2 egen = own", how, "own")
|
||||
rec, how = C.findReusable(both, request, "v3")
|
||||
check("F3 anden maskines kursus", rec and rec.vehicle, "v1")
|
||||
check("F4 = copy", how, "copy")
|
||||
-- egen maskines kursus er til en anden bredde -> kopi fra v2
|
||||
local mixed = C.withRecord(both, C.newRecord({vehicle = "v1", field = 22, width = 12, sig = SIG, settings = settings}))
|
||||
rec, how = C.findReusable(mixed, request, "v1")
|
||||
check("F5 egen passer ikke -> kopi fra v2", rec and rec.vehicle, "v2")
|
||||
check("F6 kopi", how, "copy")
|
||||
-- intet passer -> grunden fra egen post
|
||||
local changed = {field = 22, width = 30, sig = "n=6;a=1;c=0,0", settings = settings}
|
||||
rec, how = C.findReusable(both, changed, "v1")
|
||||
check("F7 intet passer", rec, nil)
|
||||
check("F8 grund: form ændret", how, "markens form ændret")
|
||||
rec, how = C.findReusable({}, request, "v1")
|
||||
check("F9 tomt register", how, "intet kursus gemt")
|
||||
-- gyldighedstjek: egen maskines kursus er væk/ændret -> kopi fra v2; alle ugyldige -> ny
|
||||
rec, how = C.findReusable(both, request, "v1", function(r) return r.vehicle ~= "v1" end)
|
||||
check("F10 egen ugyldig -> kopi", rec and rec.vehicle, "v2")
|
||||
rec, how = C.findReusable(both, request, "v1", function() return false end)
|
||||
check("F11 alle ugyldige", rec, nil)
|
||||
check("F12 grund: kurset på maskinen er ændret", how, "kurset på maskinen er ændret")
|
||||
-- multi-tool: lederens kursus (2 sæt, bane -1) genbruges ikke til et enkelt sæt
|
||||
local multi = C.newRecord({vehicle = "v1", field = 22, width = 30, sig = SIG, settings = C.settingsKey({multiTools = 2, lane = -1})})
|
||||
rec = C.findReusable(C.withRecord({}, multi), request, "v1")
|
||||
check("F13 multi-kursus != enkelt", rec, nil)
|
||||
rec, how = C.findReusable(C.withRecord({}, multi), {field = 22, width = 30, sig = SIG, settings = C.settingsKey({multiTools = 2, lane = -1})}, "v1")
|
||||
check("F14 multi samme bane genbruges", how, "own")
|
||||
-- deterministisk: flere kandidater -> laveste id
|
||||
local many = C.withRecord(C.withRecord({}, C.newRecord({vehicle = "v9", field = 22, width = 30, sig = SIG, settings = settings})),
|
||||
C.newRecord({vehicle = "v4", field = 22, width = 30, sig = SIG, settings = settings}))
|
||||
rec = C.findReusable(many, request, "v1")
|
||||
check("F15 deterministisk valg", rec and rec.vehicle, "v4")
|
||||
|
||||
-- ---- invalidateField ----
|
||||
local fieldRecords = C.withRecord(both, C.newRecord({vehicle = "v5", field = 7, width = 30, sig = "n=3;a=50;c=3,3", settings = settings}))
|
||||
local kept, removed = C.invalidateField(fieldRecords, 22, "n=5;a=1;c=0,0")
|
||||
check("V1 to poster for marken slettet", removed, 2)
|
||||
check("V2 anden mark bevaret", kept.v5 ~= nil, true)
|
||||
check("V3 original urørt", count(fieldRecords), 3)
|
||||
kept, removed = C.invalidateField(fieldRecords, 22, SIG)
|
||||
check("V4 samme form: intet slettes", removed, 0)
|
||||
check("V4b samme tabel tilbage", kept, fieldRecords)
|
||||
kept, removed = C.invalidateField(fieldRecords, 22, nil)
|
||||
check("V5 ukendt form: intet slettes", removed, 0)
|
||||
kept, removed = C.invalidateField(nil, 22, SIG)
|
||||
check("V6 nil-register", removed, 0)
|
||||
|
||||
-- ---- lim: prepare/afterStart/checkField med falske spil-objekter ----
|
||||
dofile("FS25_ADSmartPickup/adCpBridge.lua")
|
||||
local saves, logs = 0, {}
|
||||
ADFieldJobs = {state = {courseRecords = {}}, save = function() saves = saves + 1 end,
|
||||
log = function(_, fmt, ...) table.insert(logs, string.format(fmt, ...)) end}
|
||||
ADRuns = {vehicleLabel = function(v) return v.label end}
|
||||
Logging = {warning = function(...) print("WARN", ...) end}
|
||||
local function fakeCourse(n)
|
||||
return {getNumberOfWaypoints = function() return n end}
|
||||
end
|
||||
local function fakeVehicle(id, width, course)
|
||||
return {label = id, course = course,
|
||||
getFieldWorkCourse = function(self) return self.course end,
|
||||
getCourseGeneratorSettings = function() return {workWidth = {getValue = function() return width end}} end}
|
||||
end
|
||||
local tractorA = fakeVehicle("A", 30, nil)
|
||||
local tractorB = fakeVehicle("B", 30, nil)
|
||||
ADRunsController = {getFarmVehicles = function() return {tractorA, tractorB} end,
|
||||
getVehicleId = function(v) return v.label end}
|
||||
local fieldObj, info = {id = 22}, {shapeSig = SIG, fruitName = "WHEAT"}
|
||||
local assignA = {vehicle = tractorA, vehicleId = "A", role = "cultivator"}
|
||||
|
||||
-- G1: intet gemt -> ny beregning, opts urørt (ingen reuse/course)
|
||||
local opts, ctx = C.prepare({}, fieldObj, info, assignA, {})
|
||||
check("G1 ny beregning: ingen reuse", opts.reuse, nil)
|
||||
check("G1b ingen kursus", opts.course, nil)
|
||||
check("G1c log: nyt kursus (intet gemt)", logs[#logs]:find("nyt kursus beregnes", 1, true) ~= nil and logs[#logs]:find("intet kursus gemt", 1, true) ~= nil, true)
|
||||
-- CP har lavet kurset (812 punkter) -> registreres
|
||||
tractorA.course = fakeCourse(812)
|
||||
C.afterStart(tractorA, "A", ctx)
|
||||
check("G2 registreret", ADFieldJobs.state.courseRecords.A ~= nil and ADFieldJobs.state.courseRecords.A.waypoints, 812)
|
||||
check("G2b gemt til fil", saves, 1)
|
||||
-- G3: næste gang -> genbrug
|
||||
opts, ctx = C.prepare({}, fieldObj, info, assignA, {})
|
||||
check("G3 genbrug", opts.reuse, true)
|
||||
check("G3b log genbrugt", logs[#logs]:find("kursus genbrugt", 1, true) ~= nil, true)
|
||||
C.afterStart(tractorA, "A", ctx)
|
||||
check("G3c uændret register gemmes ikke igen", saves, 1)
|
||||
-- G4: B skal samme mark -> kopi fra A
|
||||
local assignB = {vehicle = tractorB, vehicleId = "B", role = "cultivator"}
|
||||
opts, ctx = C.prepare({}, fieldObj, info, assignB, {})
|
||||
check("G4 kopi fra A", opts.course, tractorA.course)
|
||||
check("G4b log kopieret", logs[#logs]:find("kopieret fra 'A'", 1, true) ~= nil, true)
|
||||
tractorB.course = fakeCourse(812)
|
||||
C.afterStart(tractorB, "B", ctx)
|
||||
check("G4c B registreret", ADFieldJobs.state.courseRecords.B ~= nil, true)
|
||||
-- G5: spilleren har lavet et nyt kursus på A i CP's HUD (andet antal punkter) -> kopi fra B
|
||||
tractorA.course = fakeCourse(400)
|
||||
opts = C.prepare({}, fieldObj, info, assignA, {})
|
||||
check("G5 A's kursus ændret -> kopi fra B", opts.course, tractorB.course)
|
||||
-- G6: kursus kopieret fra slåmaskinen (opts.course) -> registret bruges ikke, maskinens post glemmes
|
||||
local mowerCourse = fakeCourse(99)
|
||||
opts, ctx = C.prepare({}, fieldObj, info, assignB, {course = mowerCourse})
|
||||
check("G6 opts urørt", opts.course, mowerCourse)
|
||||
check("G6b ingen kontekst", ctx, nil)
|
||||
tractorB.course = fakeCourse(99)
|
||||
C.afterStart(tractorB, "B", ctx)
|
||||
check("G6c B glemt", ADFieldJobs.state.courseRecords.B, nil)
|
||||
-- G7: vinmark: vin-offset indgår i nøglen
|
||||
local vineReq = C.requestFor(tractorA, 22, {shapeSig = SIG, fruitName = "GRAPE"}, "fertilizer", {})
|
||||
check("G7 vin i nøglen", vineReq.settings, C.settingsKey({vineOffset = -1, vineSkip = 1}))
|
||||
-- G8: markens form ændret -> A's post glemmes, log
|
||||
local before = saves
|
||||
check("G8 checkField sletter", C.checkField(22, "n=9;a=1;c=0,0"), 1)
|
||||
check("G8b register tomt for marken", ADFieldJobs.state.courseRecords.A, nil)
|
||||
check("G8c gemt", saves, before + 1)
|
||||
check("G9 samme form: intet", C.checkField(22, "n=9;a=1;c=0,0"), 0)
|
||||
|
||||
-- G10: fejl i spil-API'et -> falder tilbage til ny beregning (opts urørt), ingen crash
|
||||
local brokenVehicle = {label = "X", getFieldWorkCourse = function() error("boom") end}
|
||||
local plainOpts = {lane = 1}
|
||||
local okPrep, gotOpts, gotCtx = pcall(C.prepare, {}, fieldObj, nil, {vehicle = brokenVehicle, vehicleId = "X", role = "x"}, plainOpts)
|
||||
check("G10 ingen crash", okPrep, true)
|
||||
check("G10b opts urørt", gotOpts, plainOpts)
|
||||
check("G10c ingen kontekst", gotCtx, nil)
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
@@ -115,5 +115,38 @@ check("PL tilladt", ADCpBridge.isPlantableIn(fruitPlant, 3), true)
|
||||
check("PL ikke nu", ADCpBridge.isPlantableIn(fruitPlant, 4), false)
|
||||
check("PL ukendt data = tilladt", ADCpBridge.isPlantableIn({}, 4), true)
|
||||
|
||||
-- CR: kursus-genbrug — start på maskinens eget kursus uden at CP beregner et nyt (opts.reuse)
|
||||
do
|
||||
local generated, started = 0, 0
|
||||
AIJobType = {FIELDWORK_CP = 1}
|
||||
function getWorldTranslation() return 0, 0, 0 end
|
||||
local job = {cpJobParameters = {}}
|
||||
function job.applyCurrentState() end
|
||||
function job.setValues() end
|
||||
function job.validate() return true end
|
||||
function job.registerFieldBoundaryDetectionCallback() end
|
||||
function job.detectFieldBoundary() return true, false, "" end
|
||||
function job.onClickGenerateFieldWorkCourse(_, callback) generated = generated + 1; callback(true) end
|
||||
g_currentMission = {aiJobTypeManager = {createJob = function() return job end},
|
||||
aiSystem = {startJob = function() started = started + 1 end}}
|
||||
local course = {}
|
||||
local vehicle = {rootNode = 1, getOwnerFarmId = function() return 1 end, getFieldWorkCourse = function() return course end}
|
||||
local reason = "?"
|
||||
ADCpBridge.start(vehicle, 0, 0, function(ok, r) reason = ok and (r or "generated") or "fail" end, {reuse = true})
|
||||
check("CR1 genbrug: ingen beregning", generated, 0)
|
||||
check("CR2 genbrug: CP startet", started, 1)
|
||||
check("CR3 genbrug: reason", reason, "reused")
|
||||
-- ingen kursus på maskinen -> beregnes alligevel
|
||||
vehicle.getFieldWorkCourse = function() return nil end
|
||||
ADCpBridge.start(vehicle, 0, 0, function(ok, r) reason = ok and (r or "generated") or "fail" end, {reuse = true})
|
||||
check("CR4 intet kursus -> beregnes", generated, 1)
|
||||
check("CR5 reason ny", reason, "generated")
|
||||
-- uden reuse: beregnes som før
|
||||
vehicle.getFieldWorkCourse = function() return course end
|
||||
ADCpBridge.start(vehicle, 0, 0, function(ok, r) reason = ok and (r or "generated") or "fail" end, {})
|
||||
check("CR6 uden reuse -> beregnes", generated, 2)
|
||||
AIJobType, g_currentMission = nil, nil
|
||||
end
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
@@ -38,5 +38,59 @@ for key, value in pairs(record) do
|
||||
check("ST2 rundtur: " .. key, tostring(again[key]), tostring(value))
|
||||
end
|
||||
|
||||
-- ST3-ST6: kursus-registret (genbrug af Courseplay-kurser) gemmes i samme fil, <courses><course .../></courses>
|
||||
dofile("FS25_ADSmartPickup/adCourseCache.lua")
|
||||
local course = ADCourseCache.newRecord({vehicle = "v7", field = 22, width = 30.0, sig = "n=4;a=960000;c=800,300",
|
||||
settings = ADCourseCache.settingsKey({multiTools = 2, lane = -1}), waypoints = 812})
|
||||
for key in pairs(course) do
|
||||
check("ST3 kursus-felt med i lagringen: " .. key, ADFieldStorage.COURSE_TYPES[key] ~= nil, true)
|
||||
end
|
||||
local cxml = fakeXml()
|
||||
ADFieldStorage.writeCourseRecord(cxml, "c", course)
|
||||
local cback = ADFieldStorage.readCourseRecord(cxml, "c")
|
||||
for key, value in pairs(course) do
|
||||
check("ST4 kursus-rundtur: " .. key, tostring(cback[key]), tostring(value))
|
||||
end
|
||||
check("ST4b matcher stadig efter rundtur", ADCourseCache.matches(cback, {field = 22, width = 30, sig = course.sig, settings = course.settings}), true)
|
||||
|
||||
-- hel fil: save -> load med falsk XMLFile (iterate over indekserede nøgler)
|
||||
local function fileXml(store)
|
||||
local xml = fakeXml()
|
||||
for _, kind in ipairs({"Int", "String", "Float"}) do
|
||||
xml["set" .. kind] = function(_, key, value) store[key] = value end
|
||||
xml["get" .. kind] = function(_, key) return store[key] end
|
||||
end
|
||||
function xml.iterate(_, base, fn)
|
||||
local index = 0
|
||||
while true do
|
||||
local prefix = string.format("%s(%d)", base, index)
|
||||
local found = false
|
||||
for key in pairs(store) do
|
||||
if key:sub(1, #prefix + 1) == prefix .. "#" or key:sub(1, #prefix + 1) == prefix .. "." then found = true break end
|
||||
end
|
||||
if not found then return end
|
||||
fn(index + 1, prefix)
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
function xml.save() end
|
||||
function xml.delete() end
|
||||
return xml
|
||||
end
|
||||
local disk = {}
|
||||
ADRunsStorage = {FILE_NAME = "runs.xml", getPath = function() return "/save/runs.xml" end}
|
||||
XMLFile = {create = function() return fileXml(disk) end, load = function() return fileXml(disk) end}
|
||||
function fileExists() return true end
|
||||
check("ST5 gem", ADFieldStorage.save({fields = {[77] = field}, fleet = {}, fleetMode = "all",
|
||||
courseRecords = ADCourseCache.withRecord({}, course)}), true)
|
||||
local loaded = ADFieldStorage.load()
|
||||
check("ST6 kursus indlæst", loaded.courseRecords.v7 ~= nil and loaded.courseRecords.v7.waypoints, 812)
|
||||
check("ST6b mark indlæst", loaded.fields[77] ~= nil, true)
|
||||
-- ST7: gammel fil uden <courses> -> tomt register (bagudkompatibelt)
|
||||
disk = {}
|
||||
ADFieldStorage.save({fields = {}, fleet = {}, fleetMode = "all"})
|
||||
local old = ADFieldStorage.load()
|
||||
check("ST7 gammel fil: tomt register", next(old.courseRecords), nil)
|
||||
|
||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||
os.exit(failures == 0 and 0 or 1)
|
||||
|
||||
@@ -56,6 +56,7 @@ check("PG3 majsen findes trods skiltet på bar stribe", info and info.fruitName,
|
||||
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)
|
||||
check("PG6b markens form-signatur (kursus-genbrug)", info and info.shapeSig, "n=4;a=960000;c=800,300")
|
||||
|
||||
-- PG7-9: field.fieldState er spillets sandhed (fields.xml: MAIZE growthState 2); jord-bits fra
|
||||
-- getFieldDataAtWorldPosition (2. værdi) er IKKE vækststadie. Høstet mark (cutState) = bar, vist som stub.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
-- Kør: luajit tests/test_adFieldsShape.lua (fra repo-roden)
|
||||
-- Markens form-fingeraftryk (genbrug af Courseplay-kurser): antal hjørner, areal og tyngdepunkt, afrundet så
|
||||
-- små float-forskelle ikke tæller — men en ændret mark (nyt hjørne, flyttet kant) giver en ny signatur.
|
||||
dofile("FS25_ADSmartPickup/adFields.lua")
|
||||
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
|
||||
|
||||
local function rect(x0, z0, w, h)
|
||||
return {{x = x0, z = z0}, {x = x0 + w, z = z0}, {x = x0 + w, z = z0 + h}, {x = x0, z = z0 + h}}
|
||||
end
|
||||
|
||||
-- S1: rektangel 1600 x 600 -> 4 hjørner, 960.000 m², tyngdepunkt (800, 300)
|
||||
check("S1 rektangel", ADFields.shapeSignature(rect(0, 0, 1600, 600)), "n=4;a=960000;c=800,300")
|
||||
-- S2: omløbsretning er ligegyldig (arealet er absolut)
|
||||
local reversed = {}
|
||||
for index = 4, 1, -1 do table.insert(reversed, rect(0, 0, 1600, 600)[index]) end
|
||||
check("S2 modsat omløb", ADFields.shapeSignature(reversed), "n=4;a=960000;c=800,300")
|
||||
-- S3: små float-forskelle (cm) tæller ikke
|
||||
local noisy = rect(0.0003, -0.0002, 1600.0004, 599.9997)
|
||||
check("S3 float-støj", ADFields.shapeSignature(noisy), "n=4;a=960000;c=800,300")
|
||||
-- S4: flyttet kant (1 m bredere) -> ny signatur
|
||||
check("S4 kant flyttet", ADFields.shapeSignature(rect(0, 0, 1601, 600)) ~= ADFields.shapeSignature(rect(0, 0, 1600, 600)), true)
|
||||
-- S5: ekstra hjørne på kanten (samme areal) -> ny signatur
|
||||
local extra = {{x = 0, z = 0}, {x = 800, z = 0}, {x = 1600, z = 0}, {x = 1600, z = 600}, {x = 0, z = 600}}
|
||||
check("S5 ekstra hjørne", ADFields.shapeSignature(extra), "n=5;a=960000;c=800,300")
|
||||
-- S6: samme form et andet sted på kortet -> anden signatur
|
||||
check("S6 flyttet mark", ADFields.shapeSignature(rect(100, 0, 1600, 600)), "n=4;a=960000;c=900,300")
|
||||
-- S7: tom/ingen polygon -> nil
|
||||
check("S7 tom", ADFields.shapeSignature({}), nil)
|
||||
check("S8 nil", ADFields.shapeSignature(nil), nil)
|
||||
-- S9: under 3 hjørner er ingen flade -> nil
|
||||
check("S9 to punkter", ADFields.shapeSignature({{x = 0, z = 0}, {x = 1, z = 1}}), nil)
|
||||
-- S10: trekant: areal 50, tyngdepunkt (10/3, 10/3) -> (3, 3)
|
||||
check("S10 trekant", ADFields.shapeSignature({{x = 0, z = 0}, {x = 10, z = 0}, {x = 0, z = 10}}), "n=3;a=50;c=3,3")
|
||||
-- S11: negative koordinater afrundes symmetrisk
|
||||
check("S11 negative", ADFields.shapeSignature(rect(-1000, -500, 200, 100)), "n=4;a=20000;c=-900,-450")
|
||||
|
||||
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