From f4871a76258ef872b59c59944b9485091757bb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Mu=C3=B1oz?= Date: Wed, 25 Sep 2024 15:27:16 +0200 Subject: [PATCH] Add quadbinToBoundary utility --- CONTRIBUTING.md | 26 +++++++++++++ README.md | 8 +++- package.json | 8 ++-- src/index.ts | 34 ++++++++++++++++ test/index.spec.js | 10 +---- yarn.lock | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5655bd2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,26 @@ +## Quickstart + +To install and build `quadbin-js` locally from source: + +```bash +# install dependencies +yarn + +# build package once +yarn build +``` + +To run tests, coverage, or a linter, you should execute `yarn build`, and afterward: + +```bash +# run tests once +yarn test +``` + +## Releases + +1. Create a new version: `yarn version [ major | minor | patch | prerelease ]` + +2. Commit, tag, and push to GitHub: `yarn postversion` + +3. Execute `yarn publish` \ No newline at end of file diff --git a/README.md b/README.md index 988dc78..fd2f4ab 100644 --- a/README.md +++ b/README.md @@ -79,4 +79,10 @@ Converts quadbin cell into a xyz tile. function geometryToCells(geometry: GeoJSONGeometry, resolution: bigint): bigint ``` -Returns a list of cells covering a GeoJSON geometry at a given resolution +## quadbinToBoundary + +```javascript +function quadbinToBoundary(quadbin: bigint): GeoJSONGeometry +``` + +Converts a Quadbin cell identifier into a geographical boundary represented as a polygon diff --git a/package.json b/package.json index 0efca43..071640a 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,9 @@ "build:esm": "tsc -p tsconfig/tsconfig.esm.json", "build:types": "tsc -p tsconfig/tsconfig.types.json", "build:umd": "webpack --config tsconfig/webpack.config.cjs", - "lint": "npx prettier --check src", + "lint": "prettier --check src", "test": "yarn lint && yarn test-fast", - "test-fast": "npx ts-node node_modules/tape/bin/tape test/**/*.spec.js" + "test-fast": "ts-node node_modules/tape/bin/tape test/**/*.spec.js" }, "browser": { "jsdom": false @@ -46,6 +46,7 @@ "prettier": "^2.4.1", "tape": "^5.3.0", "ts-loader": "^9.2.5", + "ts-node": "^10.9.2", "typescript": "^4.4.4", "webpack": "^5.52.1", "webpack-cli": "^4.8.0" @@ -55,5 +56,6 @@ }, "dependencies": { "@mapbox/tile-cover": "3.0.1" - } + }, + "packageManager": "yarn@1.22.22" } diff --git a/src/index.ts b/src/index.ts index a7caf40..e399888 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,27 @@ const S = [0n, 1n, 2n, 4n, 8n, 16n]; type Quadbin = bigint; type Tile = {x: number; y: number; z: number}; +function cellToBoundingBox(cell: bigint) { + const tile = cellToTile(cell); + const xmin = tileToLongitude(tile, 0); + const xmax = tileToLongitude(tile, 1); + const ymin = tileToLatitude(tile, 1); + const ymax = tileToLatitude(tile, 0); + + return [xmin, ymin, xmax, ymax]; +} + +function tileToLongitude(tile: ReturnType, offset: number) { + const {x, z} = tile; + return 180 * ((2.0 * (x + offset)) / (1 << z) - 1.0); +} + +function tileToLatitude(tile: ReturnType, offset: number) { + const {y, z} = tile; + const expy = Math.exp(-((2.0 * (y + offset)) / (1 << z) - 1) * Math.PI); + return 360 * (Math.atan(expy) / Math.PI - 0.25); +} + export function hexToBigInt(hex: string): bigint { return BigInt(`0x${hex}`); } @@ -89,3 +110,16 @@ export function geometryToCells(geometry, resolution: bigint): Quadbin[] { max_zoom: zoom }).map(([x, y, z]) => tileToCell({x, y, z})); } + +export function quadbinToBoundary(cell: bigint) { + const bbox = cellToBoundingBox(cell); + const boundary = [ + [bbox[0], bbox[3]], + [bbox[0], bbox[1]], + [bbox[2], bbox[1]], + [bbox[2], bbox[3]], + [bbox[0], bbox[3]] + ]; + + return {type: 'Polygon', coordinates: [boundary]}; +} diff --git a/test/index.spec.js b/test/index.spec.js index c722c12..3d542a8 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,12 +1,5 @@ import test from 'tape'; -import { - tileToCell, - cellToTile, - cellToParent, - geometryToCells, - getResolution, - hexToBigInt -} from 'quadbin'; +import {tileToCell, cellToTile, cellToParent, geometryToCells, getResolution} from 'quadbin'; import {tileToQuadkey} from './quadkey-utils.js'; @@ -51,7 +44,6 @@ test('Quadbin getParent', async t => { import PointGeometry from './data/PointGeometry.json' assert {type: 'json'}; import MultiPointGeometry from './data/MultiPointGeometry.json' assert {type: 'json'}; import LineStringGeometry from './data/LineStringGeometry.json' assert {type: 'json'}; -import MultiLineStringGeometry from './data/MultiLineStringGeometry.json' assert {type: 'json'}; import PolygonGeometry from './data/PolygonGeometry.json' assert {type: 'json'}; import PolygonAntimeridianGeometry from './data/PolygonAntimeridianGeometry.json' assert {type: 'json'}; import MultiPolygonGeometry from './data/MultiPolygonGeometry.json' assert {type: 'json'}; diff --git a/yarn.lock b/yarn.lock index df90cda..817b403 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13,6 +13,13 @@ pirates "^4.0.5" source-map-support "^0.5.16" +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" @@ -50,6 +57,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": version "0.3.15" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" @@ -79,6 +94,26 @@ dependencies: tilebelt "^1.0.1" +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@types/eslint-scope@^3.7.3": version "3.7.4" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" @@ -268,6 +303,18 @@ acorn-import-assertions@^1.7.6: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + acorn@^8.5.0, acorn@^8.7.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" @@ -295,6 +342,11 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + array-buffer-byte-length@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" @@ -661,6 +713,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -725,6 +782,11 @@ defined@^1.0.1: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + dotignore@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" @@ -1389,6 +1451,11 @@ make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -1892,6 +1959,25 @@ ts-loader@^9.2.5: micromatch "^4.0.0" semver "^7.3.4" +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -1961,6 +2047,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" @@ -2083,3 +2174,8 @@ yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==