fix(great-circle): fix antimeridian splitting by upgrading arc to v1.0.0#3048
fix(great-circle): fix antimeridian splitting by upgrading arc to v1.0.0#3048thomas-hervey wants to merge 4 commits intoTurfjs:masterfrom
Conversation
Fixes Turfjs#3030 Routes crossing the international dateline (e.g. Tokyo-LAX, Auckland-LAX, Shanghai-SFO) were returning a malformed MultiLineString with a gap at the +/-180 boundary. This was caused by a bug in the GDAL-ported linear heuristic in arc.js v0.1.x/v0.2.x. arc v1.0.0 replaces the heuristic with analytical bisection, producing exact +/-180 boundary coordinates and a correctly closed MultiLineString. Changes: - Bump arc dependency from ^0.2.0 to ^1.0.0 - Remove offset from Arc() call - antimeridian splitting is now automatic - Mark options.offset as deprecated in JSDoc (kept for backward compat) - Remove unused offset destructuring - Add three antimeridian test fixtures: Tokyo-LAX, Auckland-LAX, Shanghai-SFO - Add tape tests asserting MultiLineString output and exact +/-180 boundary coords - Fix fixture-dependent tests to use named getFixture() lookup instead of fixtures[0] - Regenerate basic.geojson snapshot (arc@1.0.0 defaults to 100 points)
|
@smallsaucepan @rowanwins I see that you've contributed more recently and was wondering if I could get your review on this PR. In short, it's a bump of the Thanks! |
|
Thanks for this. While checking to see if this might fix the sourcemap issue #2721 as well noticed that arc as of 1.0.0 is ESM only? |
|
@smallsaucepan Yes, arc@1.0.0 is ESM-only. I believe that this is safe for turf because tsup/esbuild bundles arc into turf's output at build time (all node versions passed CI build above). Is there a reason we'd still want to support CommonJS? Regarding #2721, arc@1.0.0 also adds |
|
We do currently support CJS and dropping it would mean a breaking change. Going ESM only is being touted for v8, though that's a little way off. There might be some nuances that make it ok. However we got caught out with this recently (see #3018) so will want to be very sure. Would you mind init-ing a simple CJS client project and |
|
Right, that makes sense. I will discuss with the other arc.js contributors on a plan forward. |
|
hi y'all 👋 arc.js co-maintainer here. i'm not opposed to exporting CJS from arc.js directly if there's no other path forward, but i'm curious to investigate whether there's a viable way for this library to support ESM only dependencies and CJS consumers simultaneously if that would be welcome. |
|
i poked at this a little and it looks like one option would be to include export default [
defineConfig({
...baseOptions,
outDir: "dist/bundled",
// since 'arc' is a ESM only dep, bundle its transpiled code in the CJS build
noExternal: ["arc"],
format: "cjs",
}),
// ...
];given that arc doesn't make use of a global cache or any singletons, this seems like a reasonable trade-off to me for legacy users, but i'm curious to hear what others think. |
|
@jgravois I think your idea is the best approach so I started working on a solution locally but ran into an issue with a custom per-package config, so it's getting a bit messy. To elaborate, I implemented a per-package However, turf's monorepolint rule enforces that every package's build script must be specifically "tsup --config ../../tsup.config.ts", so a per-package config is blocked by the pre-commit hook. I think that the alternative is to add noExternal: ['arc'] directly to the CJS format in the root Since only @turf/great-circle imports arc, this would be a no-op for all other packages. That said, it feels like a package-specific concern in a shared config. I suspect @smallsaucepan would not want this top-level config change for just one package. |
|
i think it makes sense to open this PR for review tweaking the shared tsup config file and let the maintainers share their opinion. personally I wouldn't bother trying to override the lint rule until/unless we receive feedback indicating that the overall approach is something they're interested in pursuing and that they do indeed want to sequester the override in a unique single package config. |
|
@smallsaucepan following commit 762db6c to add Per @jgravois's suggestion, the root CJS client test: // plain CJS
const { greatCircle } = require("@turf/great-circle");
const cases = [
{ name: "Tokyo → LAX", start: [139.7798, 35.5494], end: [-118.4085, 33.9416] },
{ name: "Auckland → LAX", start: [174.79, -36.85], end: [-118.41, 33.94] },
{ name: "Shanghai → SFO", start: [121.81, 31.14], end: [-122.38, 37.62] },
];
for (const { name, start, end } of cases) {
const result = greatCircle(
{ type: "Feature", geometry: { type: "Point", coordinates: start }, properties: {} },
{ type: "Feature", geometry: { type: "Point", coordinates: end }, properties: {} },
{ npoints: 10 }
);
const geom = result.geometry;
const lastOfFirst = geom.coordinates[0].at(-1);
const firstOfSecond = geom.coordinates[1][0];
console.log(`${geom.type === "MultiLineString" ? "PASS" : "FAIL"} ${name}: ${geom.type}, split at ±180° (lat=${lastOfFirst[1].toFixed(4)})`);
}Output against this PR's built The built CJS file no longer contains |
|
That's a neat fix for the ESM-only code using |
Summary
Fixes #3030
Details
Routes crossing the international dateline (e.g. Tokyo-LAX, Auckland-LAX, Shanghai-SFO) were returning a malformed MultiLineString with a gap at the +/-180 boundary. This was caused by a bug in the GDAL-ported linear heuristic in arc.js v0.1.x/v0.2.x.
Fix
arc v1.0.0 replaces the heuristic with analytical bisection, producing exact +/-180 boundary coordinates and a correctly closed MultiLineString.
Changes:
offsetfrom Arc() call. Antimeridian splitting is now automaticoptions.offsetas deprecated in JSDoc (kept for backward compat)offsetdestructuringTest
When testing locally, arc@0.2.0 fails, but passes at arc@1.0.0
... and the visual results were verified in geojson.io (see screenshot below)

Please provide the following when creating a PR:
contributorsfield ofpackage.json- you've earned it! 👏