-- Geometry facts needed to re-cut the ramps so they (a) merge at the highway -- EDGE instead of landing on top of it, (b) run a corridor that misses the PA -- shops, and (c) get pole/beam supports instead of whatever's there now. -- -- Outputs: -- 1. Mainline cross-section at the PA: per-carriageway edge X/Z + width, so -- a merge can target the OUTER edge rather than the deck centreline. -- 2. Plan-footprint of every shop model near the PA, as an X/Z box, so a -- clear corridor can be computed instead of guessed. -- 3. Current support part sizes/shapes, to see what needs replacing. local ws = game:GetService("Workspace") local map = ws:FindFirstChild("Map") local out = {} -- 1. mainline cross-section near the PA (sample by Z band) local band = {} for _, d in ipairs(map:GetDescendants()) do if d:IsA("BasePart") and d.Name:match("^Road_") then local p = d.Position if p.Z > -7250 and p.Z < -7050 and p.X > -4700 and p.X < -3400 then table.insert(band, d) end end end table.sort(band, function(a, b) return a.Position.Z < b.Position.Z end) table.insert(out, ("mainline sample parts in band=%d"):format(#band)) -- cluster by Z to find the two carriageways local zmin, zmax = 1e9, -1e9 for _, d in ipairs(band) do zmin = math.min(zmin, d.Position.Z - d.Size.Z / 2) zmax = math.max(zmax, d.Position.Z + d.Size.Z / 2) end table.insert(out, ("mainline Z extent %.1f .. %.1f (total %.1f)"):format(zmin, zmax, zmax - zmin)) for i = 1, math.min(#band, 6) do local d = band[i] table.insert( out, (" %s pos %.0f,%.1f,%.1f size %.1fx%.1f rotY=%.0f"):format( d.Name, d.Position.X, d.Position.Y, d.Position.Z, d.Size.X, d.Size.Z, math.deg(select(2, d.CFrame:ToEulerAnglesYXZ())) ) ) end -- 2. shop model footprints near the PA table.insert(out, "--- shop model footprints (plan boxes) ---") for _, top in ipairs(ws:GetChildren()) do if top ~= map and not top:IsA("Terrain") and not top:IsA("Camera") and not top:IsA("BasePart") then local x0, x1, z0, z1, y0, y1, n = 1e9, -1e9, 1e9, -1e9, 1e9, -1e9, 0 for _, d in ipairs(top:GetDescendants()) do if d:IsA("BasePart") then n += 1 x0 = math.min(x0, d.Position.X - d.Size.X / 2) x1 = math.max(x1, d.Position.X + d.Size.X / 2) z0 = math.min(z0, d.Position.Z - d.Size.Z / 2) z1 = math.max(z1, d.Position.Z + d.Size.Z / 2) y0 = math.min(y0, d.Position.Y - d.Size.Y / 2) y1 = math.max(y1, d.Position.Y + d.Size.Y / 2) end end if n > 0 and x0 > -6000 and x1 < -2500 and z0 > -9000 and z1 < -6000 then table.insert( out, (" %-42s n=%-5d X[%.0f..%.0f] Z[%.0f..%.0f] Y[%.0f..%.0f]"):format(top.Name, n, x0, x1, z0, z1, y0, y1) ) end end end -- 3. what the current supports look like table.insert(out, "--- current ramp supports ---") local sup = {} for _, d in ipairs(ws:GetDescendants()) do if d:IsA("BasePart") and (d.Name:find("RampPillar") or d.Name:find("PierColumn") or d.Name:find("PierCap")) then local k = ("%s shape=%s size=%.1fx%.1fx%.1f"):format( d.Name, d.Shape and d.Shape.Name or "n/a", d.Size.X, d.Size.Y, d.Size.Z ) sup[k] = (sup[k] or 0) + 1 end end local sl = {} for k, v in pairs(sup) do table.insert(sl, ("%s x%d"):format(k, v)) end table.sort(sl) for i = 1, math.min(#sl, 12) do table.insert(out, " " .. sl[i]) end return table.concat(out, "\n")