97 lines
2.7 KiB
JavaScript
97 lines
2.7 KiB
JavaScript
import fs from "node:fs/promises";
|
||
import path from "node:path";
|
||
|
||
const ROOT = process.cwd();
|
||
|
||
const ZONES = [
|
||
{ zoneId: "1", file: "특정어업수역Ⅰ.json", label: "Ⅰ", name: "수역I(동해)" },
|
||
{ zoneId: "2", file: "특정어업수역Ⅱ.json", label: "Ⅱ", name: "수역II(제주남방)" },
|
||
{ zoneId: "3", file: "특정어업수역Ⅲ.json", label: "Ⅲ", name: "수역III(서해남부)" },
|
||
{ zoneId: "4", file: "특정어업수역Ⅳ.json", label: "Ⅳ", name: "수역IV(서해중간)" },
|
||
];
|
||
|
||
// Inverse Web Mercator (EPSG:3857) -> WGS84 lon/lat
|
||
function mercatorToLonLat(x, y) {
|
||
const R = 6378137;
|
||
const lon = (x / R) * (180 / Math.PI);
|
||
const lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) * (180 / Math.PI);
|
||
return [lon, lat];
|
||
}
|
||
|
||
function looksLikeLonLat(x, y) {
|
||
return Math.abs(x) <= 180 && Math.abs(y) <= 90;
|
||
}
|
||
|
||
function convertPoint(pt) {
|
||
if (!Array.isArray(pt) || pt.length < 2) return pt;
|
||
const x = pt[0];
|
||
const y = pt[1];
|
||
if (typeof x !== "number" || typeof y !== "number") return pt;
|
||
if (looksLikeLonLat(x, y)) return [x, y];
|
||
return mercatorToLonLat(x, y);
|
||
}
|
||
|
||
function convertCoords(coords) {
|
||
if (!Array.isArray(coords)) return coords;
|
||
if (coords.length === 0) return coords;
|
||
|
||
// Point: [x, y]
|
||
if (typeof coords[0] === "number") return convertPoint(coords);
|
||
|
||
// Nested arrays
|
||
return coords.map(convertCoords);
|
||
}
|
||
|
||
async function main() {
|
||
const rawDir = path.join(ROOT, "data", "raw", "zones");
|
||
const outDir = path.join(ROOT, "apps", "web", "public", "data", "zones");
|
||
await fs.mkdir(outDir, { recursive: true });
|
||
|
||
const features = [];
|
||
for (const z of ZONES) {
|
||
const rawPath = path.join(rawDir, z.file);
|
||
const txt = await fs.readFile(rawPath, "utf-8");
|
||
const fc = JSON.parse(txt);
|
||
if (!fc || fc.type !== "FeatureCollection" || !Array.isArray(fc.features)) {
|
||
throw new Error(`Unexpected GeoJSON in ${rawPath}`);
|
||
}
|
||
|
||
for (const f of fc.features) {
|
||
if (!f?.geometry?.coordinates) continue;
|
||
const geometry = {
|
||
...f.geometry,
|
||
coordinates: convertCoords(f.geometry.coordinates),
|
||
};
|
||
|
||
features.push({
|
||
...f,
|
||
properties: {
|
||
...(f.properties || {}),
|
||
zoneId: z.zoneId,
|
||
zoneLabel: z.label,
|
||
zoneName: z.name,
|
||
},
|
||
geometry,
|
||
});
|
||
}
|
||
}
|
||
|
||
const out = {
|
||
type: "FeatureCollection",
|
||
name: "zones.wgs84",
|
||
features,
|
||
};
|
||
|
||
const outPath = path.join(outDir, "zones.wgs84.geojson");
|
||
await fs.writeFile(outPath, JSON.stringify(out), "utf-8");
|
||
// eslint-disable-next-line no-console
|
||
console.log(`Wrote ${features.length} features -> ${path.relative(ROOT, outPath)}`);
|
||
}
|
||
|
||
main().catch((err) => {
|
||
// eslint-disable-next-line no-console
|
||
console.error(err);
|
||
process.exit(1);
|
||
});
|
||
|