Three iterations of the Daikoku PA ramps never read as a real
interchange. Measured why, rather than tuning further:
* the entry and exit decks INTERSECTED -- 2547 sample pairs within
30 studs horizontally at <12 studs dY, worst case 0.5 studs apart
at dY=0.0. On screen that is the bowtie tangle of white rails.
* both real Daikoku ramps turn the SAME way (clockwise; the guide
video says "right, right"). This build mirrored them into each
other.
* the real arc wraps OUTSIDE the lot and forms its north/east
boundary. This build cut across the apron interior.
Gated behind BUILD_PA_RAMPS=false rather than deleted -- the radius
was already correct (470 studs vs an OSM-measured mean of 469) and
the merge lands tangent at 0.1-0.2 deg divergence. Both worth keeping.
Also removed two leftovers that would have outlived the ramps:
* rampOpen punched holes in the mainline's outer parapet, railing
and kill wall for ramps that no longer exist -- a barrier gap with
a drop behind it. Sealed via RAMP_EDGE_OPENINGS=false. Verified:
Barrier/EdgeRail/KillWall = 1646 each = 823 samples x 2 edges,
0 road samples without a guard within 90 studs.
* gore zebra hatching painted 1024 bars + 64 boundary lines marking
a junction that is not there. Sealed via RAMP_GORE_MARKINGS=false.
Verified after a cache-busting fresh rebuild (Studio's require() cache
otherwise serves the previous map and reports a false pass):
parts 22628 -> 15988
all ramp part classes = 0
Road = 823 (unchanged), spawn pad + PASpawn intact
clip probe TRUSTWORTHY (control +11/-0), CLIPPING=0
Research and rebuild spec kept for when this is revisited:
reference/ramps/BUILD_SPEC.md, INDEX.md (10 CC-licensed Commons
photos), docs/daikoku-reference-spec.md (OSM circle fits).
105 lines
3.4 KiB
Luau
105 lines
3.4 KiB
Luau
-- FLYOVER PROBE. Two things the connectivity check cannot tell you:
|
|
--
|
|
-- 1. Does the crossing actually pass OVER the mainline deck, with real
|
|
-- vertical clearance? A "flyover" that intersects the deck is just a
|
|
-- wall. Measured as: for every Cross part, find mainline Road parts
|
|
-- directly beneath it in plan, and report the worst (smallest) gap
|
|
-- between the ramp underside and the road topside.
|
|
--
|
|
-- 2. Does the descent land tangent and flush on the FAR carriageway?
|
|
-- Reported as the dY at the last descent part vs the road beneath it.
|
|
--
|
|
-- Every metric carries a CONTROL that must come back non-zero, because a
|
|
-- silent 0 from a mis-scoped query is indistinguishable from a genuine pass
|
|
-- -- that exact trap produced two phantom "defects" earlier in this build.
|
|
|
|
local ws = game:GetService("Workspace")
|
|
local map = ws:FindFirstChild("Map")
|
|
if not map then
|
|
return "NO MAP"
|
|
end
|
|
|
|
local cross, descent, roads = {}, {}, {}
|
|
for _, d in ipairs(map:GetDescendants()) do
|
|
if d:IsA("BasePart") then
|
|
local nm = d.Name
|
|
if nm:find("RampCross_") then
|
|
table.insert(cross, d)
|
|
elseif nm:find("RampNear_") then
|
|
table.insert(descent, d)
|
|
elseif nm:sub(1, 5) == "Road_" then
|
|
table.insert(roads, d)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- plan-view overlap (ignores Y entirely)
|
|
local function planOverlap(a, b)
|
|
return math.abs(a.Position.X - b.Position.X) < (a.Size.X + b.Size.X) / 2
|
|
and math.abs(a.Position.Z - b.Position.Z) < (a.Size.Z + b.Size.Z) / 2
|
|
end
|
|
|
|
local out = {}
|
|
|
|
-- CONTROL 1: a road part must plan-overlap itself.
|
|
local ctlSelf = (#roads > 0 and planOverlap(roads[1], roads[1])) and 1 or 0
|
|
table.insert(out, ("CONTROL planOverlap-self=%d (want 1)"):format(ctlSelf))
|
|
|
|
-- CLEARANCE over the deck.
|
|
local worst, worstAt, nOver = 1e9, "none", 0
|
|
for _, cp in ipairs(cross) do
|
|
for _, rd in ipairs(roads) do
|
|
if planOverlap(cp, rd) then
|
|
nOver += 1
|
|
-- ramp underside minus road topside
|
|
local gap = (cp.Position.Y - cp.Size.Y / 2) - (rd.Position.Y + rd.Size.Y / 2)
|
|
if gap < worst then
|
|
worst, worstAt = gap, cp.Name .. " over " .. rd.Name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if nOver == 0 then
|
|
table.insert(out, "CROSSING: 0 road parts under any Cross part -- ramp does NOT span the deck")
|
|
else
|
|
table.insert(out, ("CROSSING: %d overlaps | worst vertical gap=%.1f at %s"):format(nOver, worst, worstAt))
|
|
end
|
|
|
|
-- LANDING: last descent part of each ramp vs the road under it.
|
|
local function tailOf(prefix)
|
|
local best, bestIdx = nil, -1
|
|
for _, p in ipairs(descent) do
|
|
if p.Name:sub(1, #prefix) == prefix then
|
|
local i = tonumber(p.Name:match("_(%d+)$")) or 0
|
|
if i > bestIdx then
|
|
best, bestIdx = p, i
|
|
end
|
|
end
|
|
end
|
|
return best
|
|
end
|
|
for _, pre in ipairs({ "PAEntryRampNear", "PAExitRampNear" }) do
|
|
local t = tailOf(pre)
|
|
if not t then
|
|
table.insert(out, pre .. ": no tail part")
|
|
else
|
|
local bestGap, bestNm = 1e9, "none"
|
|
for _, rd in ipairs(roads) do
|
|
if planOverlap(t, rd) then
|
|
local dy = (t.Position.Y - t.Size.Y / 2) - (rd.Position.Y + rd.Size.Y / 2)
|
|
if math.abs(dy) < math.abs(bestGap) then
|
|
bestGap, bestNm = dy, rd.Name
|
|
end
|
|
end
|
|
end
|
|
if bestNm == "none" then
|
|
table.insert(out, ("%s LANDING: tail is over NO road -- lands off the carriageway"):format(pre))
|
|
else
|
|
table.insert(out, ("%s LANDING: dY=%.1f onto %s"):format(pre, bestGap, bestNm))
|
|
end
|
|
end
|
|
end
|
|
|
|
table.insert(out, ("counts cross=%d descent=%d roads=%d"):format(#cross, #descent, #roads))
|
|
return table.concat(out, "\n")
|