{"id":18579522,"url":"https://github.com/artoria2e5/prcoords","last_synced_at":"2025-07-28T08:07:52.479Z","repository":{"id":50661194,"uuid":"77301298","full_name":"Artoria2e5/PRCoords","owner":"Artoria2e5","description":"Public Domain library for rectifying Chinese coordinates","archived":false,"fork":false,"pushed_at":"2024-05-21T05:12:32.000Z","size":340,"stargazers_count":164,"open_issues_count":4,"forks_count":28,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-06-30T20:15:30.429Z","etag":null,"topics":["bd-09","bd09","china","cross-language","eviltransform","gcj-02","gcj02","gis"],"latest_commit_sha":null,"homepage":"https://artoria2e5.github.io/PRCoords/demo.html","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Artoria2e5.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.gplv3","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-24T21:51:41.000Z","updated_at":"2025-06-22T10:01:21.000Z","dependencies_parsed_at":"2024-05-07T12:30:41.609Z","dependency_job_id":"becf4770-86ff-45a8-9afb-67f0500a0b2c","html_url":"https://github.com/Artoria2e5/PRCoords","commit_stats":{"total_commits":164,"total_committers":5,"mean_commits":32.8,"dds":"0.12804878048780488","last_synced_commit":"09c8cc0cc0f87f32bb1fe617a6a728f4cbb10f75"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Artoria2e5/PRCoords","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Artoria2e5%2FPRCoords","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Artoria2e5%2FPRCoords/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Artoria2e5%2FPRCoords/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Artoria2e5%2FPRCoords/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Artoria2e5","download_url":"https://codeload.github.com/Artoria2e5/PRCoords/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Artoria2e5%2FPRCoords/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267482004,"owners_count":24094508,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bd-09","bd09","china","cross-language","eviltransform","gcj-02","gcj02","gis"],"created_at":"2024-11-06T23:41:08.374Z","updated_at":"2025-07-28T08:07:52.458Z","avatar_url":"https://github.com/Artoria2e5.png","language":"C++","funding_links":["https://www.patreon.com/artoria2e5"],"categories":[],"sub_categories":[],"readme":"PRCoords\n========\n\nPeople's Rectified Coordinates (PRCoords) is a cross-language implementation of \"public secret\" Chinese coordinate obfuscation methods including GCJ-02 and BD-09, along with general deobfuscation methods previously established in [ChinaMapShift][], [eviltransform][], and [geoChina][]. (Referring to the process of replacing straight lines with wavy ones as a \"transform\" is euphemism overdone.)\n\nFor a background on China's geographic obfuscation, see [Restrictions on geographic data in China](https://en.wikipedia.org/wiki/Restrictions_on_geographic_data_in_China#Coordinate_systems) and [中华人民共和国测绘限制](https://zh.wikipedia.org/wiki/中华人民共和国测绘限制) on Wikipedia.\n\n[ChinaMapShift]: https://gist.github.com/anonymous/e7c6f67555099180ce1ae8da4ba2c513\n[geoChina]: https://github.com/caijun/geoChina/blob/master/R/cst.R\n[eviltransform]: https://github.com/googollee/eviltransform\n\nLanguages\n---------\n\n- [x] JavaScript ([`npm install prcoords`](https://www.npmjs.com/package/prcoords)) [![](https://data.jsdelivr.com/v1/package/npm/prcoords/badge)](https://www.jsdelivr.com/package/npm/prcoords)\n  * Web demo: https://artoria2e5.github.io/PRCoords/demo\n  * Now with AMD support and faux `__esModule` interop for Babel and TypeScript!\n- [x] Python ([`pip install prcoords`](https://pypi.org/project/prcoords/))\n- [x] \\(Obj-\\)C/C++ (C ABI)\n  * [x] Makefile with `install`\n- [ ] Ruby\n- [ ] Swift\n- [ ] C#\n- [x] Haskell (GCJ only; data structure incomplete)\n  * need to move googollee/eviltransform#54 here sometime.\n- [ ] Java\n- [ ] Matlab/Octave\n  * too lazy to split the files. also expand \"caijun\"\n- [x] PGSQL\n- [ ] Typed Racket\n  * is it done?\n\n(should I split them into submodules?)\n\nFor languages not yet supported, we recommend you to check for [eviltransform][] (MIT) or [geoChina][] (GPLv3, R) instead.\n\nAPI\n---\n\nPRCoord's APIs operate on, and returns, dedicated structures for coordinates. In API names, we generally refer to WGS-84 as `wgs`, GCJ-02 as `gcj`, and BD-09 (lat-lon) as `bd`. \n\n### Inverse functions\n\nThe obfuscations generally have these properties to maintain basic usefulness:\n\n1. `obfs(coord)` is sort of close to `coord`.\n2. `obfs(a) - obfs(b)` is usually close to `a - b`. (The closer `a` and `b` are\n   to each other, the better it works.)\n\nIn general two approaches of inverting the \"forward\" obfuscations, or working from\n`obfs(coord)` to `coord`, are implemented:\n\n* _Run it backwards_: `obfs(coord)` is never too far from `coord`, so just use\n  `obfs(obfs(coord)) - obfs(coord)` to estimate `obfs(coord) - coord`.\n* _Iterate a bit_: Get a rough `guess` somehow, and just use property 2 to estimate\n  the remaining error as `obfs(guess) - obfs(coord)` and correct the `guess`.\n\nYou can read on the demo page about how well these methods work from the `ΔRoundtrip`\nentry. Unless you are doing archival work, you generally don't have to iterate.\n\n### The \"in China\" sanity check\n\nTypically PRCoords is only supposed to be ran on obfuscated input data, which\nare primarily Chinese coordinates. For this reason, initial implementations\ninclude this [very very rough](https://news.ycombinator.com/item?id=10965506)\nsanity check that spans a rectangular region on a mercator-projected map.\nThis check can be overridden by passing a boolean value, or may be not at all\nimplemented in certain languages if I am not in the right mood for doing\nsilly things.\n\nThere is an \"insane\" sanity check intended to approximate the range of Google\nand Baidu's distortion, intended for use by [IITC](https://iitc.me):\n[`js/insane_is_in_china.js`](https://github.com/Artoria2e5/PRCoords/blob/master/js/insane_is_in_china.js).\nIt is basically a ray-casting polygon check with 70 vertices. You, as the\ncaller, should still be responsible for telling whether a point is part of the\ngov-screwed Chinese data.\n\nFAQ\n---\n\n### Why another wheel?\n\n* Correctness\n* Public Domain\n* Clean API based on pairs of coordinates\n* Need to find a place for this sarcastic name\n\n### Can the systems be described as WKT or proj-strings?\n\nNot directly as a datum, because in both representations a datum is either\n\"sane\" (no non-linearity in 3D, Helmert possible) or a big table of grids.\n\nIt should be possible to describe the two CS with a `PROJECTION` entry as\na `PROJCS`. Since a `PROJCS` cannot be nested in another, the BD\ntransformation must be described using WGS84 and a fuzed GCJ-BD projection.\nThe situation is similar with [Baidu \"Meractor\"](https://github.com/gumblex/cntms/commit/bbde4006adeb92f48da1ff7d1f88da393d382f8a).\n\n\u003cdetails\u003e\n\u003csummary\u003eSpeculative WKT/PROJ4\u003c/summary\u003e\n\n```js\nPROJCS[\"Baidu 2009, Pseudo-Mercator\",\n    GEOGCS[\"WGS 84\",\n        DATUM[\"WGS_1984\",\n            SPHEROID[\"WGS 84\",6378137,298.257223563,\n                AUTHORITY[\"EPSG\",\"7030\"]],\n            AUTHORITY[\"EPSG\",\"6326\"]],\n        PRIMEM[\"Greenwich\",0,\n            AUTHORITY[\"EPSG\",\"8901\"]],\n        UNIT[\"degree\",0.0174532925199433,\n            AUTHORITY[\"EPSG\",\"9122\"]],\n        AUTHORITY[\"EPSG\",\"4326\"]],\n    PROJECTION[\"CN_Obfs_Baidu_2009_Mercator\"],\n    AXIS[\"x\",east],\n    AXIS[\"y\",north],\n    UNIT[\"metre\",1,\n      AUTHORITY[\"EPSG\",\"9001\"]],\n    EXTENSION[\"PROJ4\",\"+proj=baidumerc +units=m +nadgrids=@null +wktext +no_defs\"],\n    AUTHORITY[\"EPSG\",\"888002\"]]\n\nPROJCS[\"Chinese BSM 2002, Pseudo-Ellipsoidal\",\n    GEOGCS[\"WGS 84\", AUTHORITY[\"EPSG\",\"4326\"]],\n    PROJECTION[\"CN_Obfs_GCJ_2002_Ellipsoidal\"],\n    AXIS[\"longitude\",east],\n    AXIS[\"latitude\",north],\n    UNIT[\"degree\",0.0174532925199433,\n      AUTHORITY[\"EPSG\",\"9122\"]],\n    EXTENSION[\"PROJ4\",\"+proj=gcjlonglat +units=deg +nadgrids=@null +wktext +no_defs\"],\n    AUTHORITY[\"EPSG\",\"888000\"]]\n```\n\u003c/details\u003e\n\nThe good people at proj4js has made their stuff [very easy to extend](https://github.com/proj4js/proj4js/issues/358). Here is [an example](https://runkit.com/artoria2e5/proj4-plugin-prcoords).\n\n### Should I use fast fp math?\n\nYes. Nobody knows what the original looks like anyways, so what's wrong with letting the compiler recombine a bit more? You can't be more off\nthan the one-meter random error (in \"EMQ\") anyways.\n\nOr tinker with 32-bit floats and fixed-point numbers. Or try approximation tools like [Sollya](http://sollya.gforge.inria.fr/) or [MC++](https://omega-icl.github.io/mcpp/). Really, just search on the Internet for \"\\\u003clanguage\\\u003e Taylor Chebyshev Model\". You only need less than 1e-6 error on a [not-very-large slice](https://github.com/Artoria2e5/PRCoords/blob/a3a8bb8/js/PRCoords.js#L91) of the Earth anyways.\n\nI threw TaylorModels.jl at GCJ-02, and got ~~decent~~ results out of it. Still too lazy to put it in code though. Check out [approx/approx.ipynb](https://github.com/Artoria2e5/PRCoords/blob/master/approx/approx.ipynb). (Nope, not decent. Gotta do it properly some day, just don't use the notebook and expect it to work!)\n\nI tried another route with the C++ version using a devmaster user Nick's `sinpi()` approximation. It seems to be good enough for 1e-6: check out [cpp/bench_out](https://github.com/Artoria2e5/PRCoords/tree/master/cpp/bench_out) and [cpp/badmath.hh](https://github.com/Artoria2e5/PRCoords/blob/master/cpp/badmath.hh).\n\nPhysical PRCoords\n-----------------\n\nYou can print out a minimal copy of PRCoords with [this PDF file](https://commons.wikimedia.org/wiki/File:PRcoords_Cheatsheet.pdf). I am working on some better options [in issue #2](https://github.com/Artoria2e5/PRCoords/issues/2). A fairly simple tote bag with an older version of the PDF is [available from Teespring](https://teespring.com/miniprcoords-tote-v1).\n\nFeel free to print and sell t-shirts with the PDF file! It is put in the Public Domain, so you don't have to pay me for that. You can always fund my subversive activities on [Patreon](https://www.patreon.com/artoria2e5) though.\n\nLicense\n-------\n\nUnless otherwise mentioned, all files in this package, including this README file,\nare dual-licensed under:\n\n* [CC0 1.0 Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/)\n* [GNU General Public License (version 3 or up)](https://gnu.org/licenses/gpl.html)\n\nGPL is only included for fun here.\n\nSources\n-------\n\n* [Algorithm.Coords.Converter](https://archive.is/20130815104734/emq.googlecode.com/svn/emq/src/Algorithm/Coords/Converter.java) from [EMQ](https://code.google.com/archive/p/emq/) ([GitHub mirror](https://github.com/richardyu-au/emq)) is probably *the* GCJ leak. It is a JSP project \"for demonstrating GIS systems\", probably done by some government contractor.\n  * There is some randomness in the GCJ deltas on both axes: one `sin` invocation and one LCG. Each add a maximum of 1 meter of error.\n* [on4wp7](https://archive.is/20150702191259/https://on4wp7.codeplex.com/SourceControl/changeset/view/21483%23353936) (2013) is the earliest rationalized GCJ (forward) implementation. No randomness is attempted.\n* [ChinaMapShift][] (2014) figured out the quick iterative inverse for GCJ. I learned about it via geoChina first and generalized it here.\n* BD-09 is not very well sourced, but [pycoordtrans](https://github.com/zxteloiv/pycoordtrans) (2014) seems to have it.\n\nSee also\n--------\n\n* [eviltransform][] is among the most popular cross-language soltions to the problem. It borrows its name directly from [EvilTransform.cs](https://github.com/Leask/EvilTransform/blob/master/EvilTransform.cs), an early refactored version of a raw-flesh Java implementation found in \"[emq](https://code.google.com/archive/p/emq/)\", some sort of government contractor GIS demo project.\n  * Since June 2016, eviltransform contains numerous parameter errors that compromise its output, especially for BD-09. See googollee/eviltransform[#43](https://github.com/googollee/eviltransform/issues/43), [#53](https://github.com/googollee/eviltransform/pull/53) and [#44](https://github.com/googollee/eviltransform/issues/44) for corrections. As of June 2019 these problems are not fixed.\n* [geoChina][] by caijun is a clear, concise implementation written in R. It features the iterative method from ChinaMapShift.\n* I am planning on moving some of the comments on the algorithm found in [my initial JavaScript implementation](https://zh.wikipedia.org/wiki/User:Artoria2e5/PRCoords.js) to the [GitHub Wiki](https://github.com/Artoria2e5/PRCoords/wiki). I don't think anyone is going to be interested in copying comments on these idiocy when translating my implementation to other languages.\n  * If you are doing a translation, consider only using the comments from the PDF.\n* [Ishisashi's writeup](https://chaoli.club/index.php/4777/0) on this subject. They wrote a super enhanced version of the demo too.\n\nOh, and finally, here is an official [news report](https://archive.fo/20110804185923/http://cxzy.people.com.cn/GB/196034/14908095.html) on that particular *\\[bleep\\]* who came up with GCJ-02.\n\n\n\u003ca href=\"https://artoria2e5.github.io/PRCoords/demo\"\u003e\n  \u003cimg src=\"https://Artoria2e5.github.io/PRCoords/Globe%2C_distorted_China.svg\" width=\"100%\" height=\"100\"\u003e\n\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartoria2e5%2Fprcoords","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartoria2e5%2Fprcoords","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartoria2e5%2Fprcoords/lists"}