wkt.build.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. 'use strict';
  2. var NEUTRAL = 1;
  3. var KEYWORD = 2;
  4. var NUMBER = 3;
  5. var QUOTED = 4;
  6. var AFTERQUOTE = 5;
  7. var ENDED = -1;
  8. var whitespace = /\s/;
  9. var latin = /[A-Za-z]/;
  10. var keyword = /[A-Za-z84_]/;
  11. var endThings = /[,\]]/;
  12. var digets = /[\d\.E\-\+]/;
  13. // const ignoredChar = /[\s_\-\/\(\)]/g;
  14. function Parser(text) {
  15. if (typeof text !== 'string') {
  16. throw new Error('not a string');
  17. }
  18. this.text = text.trim();
  19. this.level = 0;
  20. this.place = 0;
  21. this.root = null;
  22. this.stack = [];
  23. this.currentObject = null;
  24. this.state = NEUTRAL;
  25. }
  26. Parser.prototype.readCharicter = function() {
  27. var char = this.text[this.place++];
  28. if (this.state !== QUOTED) {
  29. while (whitespace.test(char)) {
  30. if (this.place >= this.text.length) {
  31. return;
  32. }
  33. char = this.text[this.place++];
  34. }
  35. }
  36. switch (this.state) {
  37. case NEUTRAL:
  38. return this.neutral(char);
  39. case KEYWORD:
  40. return this.keyword(char)
  41. case QUOTED:
  42. return this.quoted(char);
  43. case AFTERQUOTE:
  44. return this.afterquote(char);
  45. case NUMBER:
  46. return this.number(char);
  47. case ENDED:
  48. return;
  49. }
  50. };
  51. Parser.prototype.afterquote = function(char) {
  52. if (char === '"') {
  53. this.word += '"';
  54. this.state = QUOTED;
  55. return;
  56. }
  57. if (endThings.test(char)) {
  58. this.word = this.word.trim();
  59. this.afterItem(char);
  60. return;
  61. }
  62. throw new Error('havn\'t handled "' +char + '" in afterquote yet, index ' + this.place);
  63. };
  64. Parser.prototype.afterItem = function(char) {
  65. if (char === ',') {
  66. if (this.word !== null) {
  67. this.currentObject.push(this.word);
  68. }
  69. this.word = null;
  70. this.state = NEUTRAL;
  71. return;
  72. }
  73. if (char === ']') {
  74. this.level--;
  75. if (this.word !== null) {
  76. this.currentObject.push(this.word);
  77. this.word = null;
  78. }
  79. this.state = NEUTRAL;
  80. this.currentObject = this.stack.pop();
  81. if (!this.currentObject) {
  82. this.state = ENDED;
  83. }
  84. return;
  85. }
  86. };
  87. Parser.prototype.number = function(char) {
  88. if (digets.test(char)) {
  89. this.word += char;
  90. return;
  91. }
  92. if (endThings.test(char)) {
  93. this.word = parseFloat(this.word);
  94. this.afterItem(char);
  95. return;
  96. }
  97. throw new Error('havn\'t handled "' +char + '" in number yet, index ' + this.place);
  98. };
  99. Parser.prototype.quoted = function(char) {
  100. if (char === '"') {
  101. this.state = AFTERQUOTE;
  102. return;
  103. }
  104. this.word += char;
  105. return;
  106. };
  107. Parser.prototype.keyword = function(char) {
  108. if (keyword.test(char)) {
  109. this.word += char;
  110. return;
  111. }
  112. if (char === '[') {
  113. var newObjects = [];
  114. newObjects.push(this.word);
  115. this.level++;
  116. if (this.root === null) {
  117. this.root = newObjects;
  118. } else {
  119. this.currentObject.push(newObjects);
  120. }
  121. this.stack.push(this.currentObject);
  122. this.currentObject = newObjects;
  123. this.state = NEUTRAL;
  124. return;
  125. }
  126. if (endThings.test(char)) {
  127. this.afterItem(char);
  128. return;
  129. }
  130. throw new Error('havn\'t handled "' +char + '" in keyword yet, index ' + this.place);
  131. };
  132. Parser.prototype.neutral = function(char) {
  133. if (latin.test(char)) {
  134. this.word = char;
  135. this.state = KEYWORD;
  136. return;
  137. }
  138. if (char === '"') {
  139. this.word = '';
  140. this.state = QUOTED;
  141. return;
  142. }
  143. if (digets.test(char)) {
  144. this.word = char;
  145. this.state = NUMBER;
  146. return;
  147. }
  148. if (endThings.test(char)) {
  149. this.afterItem(char);
  150. return;
  151. }
  152. throw new Error('havn\'t handled "' +char + '" in neutral yet, index ' + this.place);
  153. };
  154. Parser.prototype.output = function() {
  155. while (this.place < this.text.length) {
  156. this.readCharicter();
  157. }
  158. if (this.state === ENDED) {
  159. return this.root;
  160. }
  161. throw new Error('unable to parse string "' +this.text + '". State is ' + this.state);
  162. };
  163. function parseString(txt) {
  164. var parser = new Parser(txt);
  165. return parser.output();
  166. }
  167. function mapit(obj, key, value) {
  168. if (Array.isArray(key)) {
  169. value.unshift(key);
  170. key = null;
  171. }
  172. var thing = key ? {} : obj;
  173. var out = value.reduce(function(newObj, item) {
  174. sExpr(item, newObj);
  175. return newObj
  176. }, thing);
  177. if (key) {
  178. obj[key] = out;
  179. }
  180. }
  181. function sExpr(v, obj) {
  182. if (!Array.isArray(v)) {
  183. obj[v] = true;
  184. return;
  185. }
  186. var key = v.shift();
  187. if (key === 'PARAMETER') {
  188. key = v.shift();
  189. }
  190. if (v.length === 1) {
  191. if (Array.isArray(v[0])) {
  192. obj[key] = {};
  193. sExpr(v[0], obj[key]);
  194. return;
  195. }
  196. obj[key] = v[0];
  197. return;
  198. }
  199. if (!v.length) {
  200. obj[key] = true;
  201. return;
  202. }
  203. if (key === 'TOWGS84') {
  204. obj[key] = v;
  205. return;
  206. }
  207. if (key === 'AXIS') {
  208. if (!(key in obj)) {
  209. obj[key] = [];
  210. }
  211. obj[key].push(v);
  212. return;
  213. }
  214. if (!Array.isArray(key)) {
  215. obj[key] = {};
  216. }
  217. var i;
  218. switch (key) {
  219. case 'UNIT':
  220. case 'PRIMEM':
  221. case 'VERT_DATUM':
  222. obj[key] = {
  223. name: v[0].toLowerCase(),
  224. convert: v[1]
  225. };
  226. if (v.length === 3) {
  227. sExpr(v[2], obj[key]);
  228. }
  229. return;
  230. case 'SPHEROID':
  231. case 'ELLIPSOID':
  232. obj[key] = {
  233. name: v[0],
  234. a: v[1],
  235. rf: v[2]
  236. };
  237. if (v.length === 4) {
  238. sExpr(v[3], obj[key]);
  239. }
  240. return;
  241. case 'PROJECTEDCRS':
  242. case 'PROJCRS':
  243. case 'GEOGCS':
  244. case 'GEOCCS':
  245. case 'PROJCS':
  246. case 'LOCAL_CS':
  247. case 'GEODCRS':
  248. case 'GEODETICCRS':
  249. case 'GEODETICDATUM':
  250. case 'EDATUM':
  251. case 'ENGINEERINGDATUM':
  252. case 'VERT_CS':
  253. case 'VERTCRS':
  254. case 'VERTICALCRS':
  255. case 'COMPD_CS':
  256. case 'COMPOUNDCRS':
  257. case 'ENGINEERINGCRS':
  258. case 'ENGCRS':
  259. case 'FITTED_CS':
  260. case 'LOCAL_DATUM':
  261. case 'DATUM':
  262. v[0] = ['name', v[0]];
  263. mapit(obj, key, v);
  264. return;
  265. default:
  266. i = -1;
  267. while (++i < v.length) {
  268. if (!Array.isArray(v[i])) {
  269. return sExpr(v, obj[key]);
  270. }
  271. }
  272. return mapit(obj, key, v);
  273. }
  274. }
  275. var D2R = 0.01745329251994329577;
  276. function rename(obj, params) {
  277. var outName = params[0];
  278. var inName = params[1];
  279. if (!(outName in obj) && (inName in obj)) {
  280. obj[outName] = obj[inName];
  281. if (params.length === 3) {
  282. obj[outName] = params[2](obj[outName]);
  283. }
  284. }
  285. }
  286. function d2r(input) {
  287. return input * D2R;
  288. }
  289. function cleanWKT(wkt) {
  290. if (wkt.type === 'GEOGCS') {
  291. wkt.projName = 'longlat';
  292. } else if (wkt.type === 'LOCAL_CS') {
  293. wkt.projName = 'identity';
  294. wkt.local = true;
  295. } else {
  296. if (typeof wkt.PROJECTION === 'object') {
  297. wkt.projName = Object.keys(wkt.PROJECTION)[0];
  298. } else {
  299. wkt.projName = wkt.PROJECTION;
  300. }
  301. }
  302. if (wkt.AXIS) {
  303. var axisOrder = '';
  304. for (var i = 0, ii = wkt.AXIS.length; i < ii; ++i) {
  305. var axis = [wkt.AXIS[i][0].toLowerCase(), wkt.AXIS[i][1].toLowerCase()];
  306. if (axis[0].indexOf('north') !== -1 || ((axis[0] === 'y' || axis[0] === 'lat') && axis[1] === 'north')) {
  307. axisOrder += 'n';
  308. } else if (axis[0].indexOf('south') !== -1 || ((axis[0] === 'y' || axis[0] === 'lat') && axis[1] === 'south')) {
  309. axisOrder += 's';
  310. } else if (axis[0].indexOf('east') !== -1 || ((axis[0] === 'x' || axis[0] === 'lon') && axis[1] === 'east')) {
  311. axisOrder += 'e';
  312. } else if (axis[0].indexOf('west') !== -1 || ((axis[0] === 'x' || axis[0] === 'lon') && axis[1] === 'west')) {
  313. axisOrder += 'w';
  314. }
  315. }
  316. if (axisOrder.length === 2) {
  317. axisOrder += 'u';
  318. }
  319. if (axisOrder.length === 3) {
  320. wkt.axis = axisOrder;
  321. }
  322. }
  323. if (wkt.UNIT) {
  324. wkt.units = wkt.UNIT.name.toLowerCase();
  325. if (wkt.units === 'metre') {
  326. wkt.units = 'meter';
  327. }
  328. if (wkt.UNIT.convert) {
  329. if (wkt.type === 'GEOGCS') {
  330. if (wkt.DATUM && wkt.DATUM.SPHEROID) {
  331. wkt.to_meter = wkt.UNIT.convert*wkt.DATUM.SPHEROID.a;
  332. }
  333. } else {
  334. wkt.to_meter = wkt.UNIT.convert;
  335. }
  336. }
  337. }
  338. var geogcs = wkt.GEOGCS;
  339. if (wkt.type === 'GEOGCS') {
  340. geogcs = wkt;
  341. }
  342. if (geogcs) {
  343. //if(wkt.GEOGCS.PRIMEM&&wkt.GEOGCS.PRIMEM.convert){
  344. // wkt.from_greenwich=wkt.GEOGCS.PRIMEM.convert*D2R;
  345. //}
  346. if (geogcs.DATUM) {
  347. wkt.datumCode = geogcs.DATUM.name.toLowerCase();
  348. } else {
  349. wkt.datumCode = geogcs.name.toLowerCase();
  350. }
  351. if (wkt.datumCode.slice(0, 2) === 'd_') {
  352. wkt.datumCode = wkt.datumCode.slice(2);
  353. }
  354. if (wkt.datumCode === 'new_zealand_geodetic_datum_1949' || wkt.datumCode === 'new_zealand_1949') {
  355. wkt.datumCode = 'nzgd49';
  356. }
  357. if (wkt.datumCode === 'wgs_1984' || wkt.datumCode === 'world_geodetic_system_1984') {
  358. if (wkt.PROJECTION === 'Mercator_Auxiliary_Sphere') {
  359. wkt.sphere = true;
  360. }
  361. wkt.datumCode = 'wgs84';
  362. }
  363. if (wkt.datumCode.slice(-6) === '_ferro') {
  364. wkt.datumCode = wkt.datumCode.slice(0, - 6);
  365. }
  366. if (wkt.datumCode.slice(-8) === '_jakarta') {
  367. wkt.datumCode = wkt.datumCode.slice(0, - 8);
  368. }
  369. if (~wkt.datumCode.indexOf('belge')) {
  370. wkt.datumCode = 'rnb72';
  371. }
  372. if (geogcs.DATUM && geogcs.DATUM.SPHEROID) {
  373. wkt.ellps = geogcs.DATUM.SPHEROID.name.replace('_19', '').replace(/[Cc]larke\_18/, 'clrk');
  374. if (wkt.ellps.toLowerCase().slice(0, 13) === 'international') {
  375. wkt.ellps = 'intl';
  376. }
  377. wkt.a = geogcs.DATUM.SPHEROID.a;
  378. wkt.rf = parseFloat(geogcs.DATUM.SPHEROID.rf, 10);
  379. }
  380. if (geogcs.DATUM && geogcs.DATUM.TOWGS84) {
  381. wkt.datum_params = geogcs.DATUM.TOWGS84;
  382. }
  383. if (~wkt.datumCode.indexOf('osgb_1936')) {
  384. wkt.datumCode = 'osgb36';
  385. }
  386. if (~wkt.datumCode.indexOf('osni_1952')) {
  387. wkt.datumCode = 'osni52';
  388. }
  389. if (~wkt.datumCode.indexOf('tm65')
  390. || ~wkt.datumCode.indexOf('geodetic_datum_of_1965')) {
  391. wkt.datumCode = 'ire65';
  392. }
  393. if (wkt.datumCode === 'ch1903+') {
  394. wkt.datumCode = 'ch1903';
  395. }
  396. if (~wkt.datumCode.indexOf('israel')) {
  397. wkt.datumCode = 'isr93';
  398. }
  399. }
  400. if (wkt.b && !isFinite(wkt.b)) {
  401. wkt.b = wkt.a;
  402. }
  403. function toMeter(input) {
  404. var ratio = wkt.to_meter || 1;
  405. return input * ratio;
  406. }
  407. var renamer = function(a) {
  408. return rename(wkt, a);
  409. };
  410. var list = [
  411. ['standard_parallel_1', 'Standard_Parallel_1'],
  412. ['standard_parallel_1', 'Latitude of 1st standard parallel'],
  413. ['standard_parallel_2', 'Standard_Parallel_2'],
  414. ['standard_parallel_2', 'Latitude of 2nd standard parallel'],
  415. ['false_easting', 'False_Easting'],
  416. ['false_easting', 'False easting'],
  417. ['false-easting', 'Easting at false origin'],
  418. ['false_northing', 'False_Northing'],
  419. ['false_northing', 'False northing'],
  420. ['false_northing', 'Northing at false origin'],
  421. ['central_meridian', 'Central_Meridian'],
  422. ['central_meridian', 'Longitude of natural origin'],
  423. ['central_meridian', 'Longitude of false origin'],
  424. ['latitude_of_origin', 'Latitude_Of_Origin'],
  425. ['latitude_of_origin', 'Central_Parallel'],
  426. ['latitude_of_origin', 'Latitude of natural origin'],
  427. ['latitude_of_origin', 'Latitude of false origin'],
  428. ['scale_factor', 'Scale_Factor'],
  429. ['k0', 'scale_factor'],
  430. ['latitude_of_center', 'Latitude_Of_Center'],
  431. ['latitude_of_center', 'Latitude_of_center'],
  432. ['lat0', 'latitude_of_center', d2r],
  433. ['longitude_of_center', 'Longitude_Of_Center'],
  434. ['longitude_of_center', 'Longitude_of_center'],
  435. ['longc', 'longitude_of_center', d2r],
  436. ['x0', 'false_easting', toMeter],
  437. ['y0', 'false_northing', toMeter],
  438. ['long0', 'central_meridian', d2r],
  439. ['lat0', 'latitude_of_origin', d2r],
  440. ['lat0', 'standard_parallel_1', d2r],
  441. ['lat1', 'standard_parallel_1', d2r],
  442. ['lat2', 'standard_parallel_2', d2r],
  443. ['azimuth', 'Azimuth'],
  444. ['alpha', 'azimuth', d2r],
  445. ['srsCode', 'name']
  446. ];
  447. list.forEach(renamer);
  448. if (!wkt.long0 && wkt.longc && (wkt.projName === 'Albers_Conic_Equal_Area' || wkt.projName === 'Lambert_Azimuthal_Equal_Area')) {
  449. wkt.long0 = wkt.longc;
  450. }
  451. if (!wkt.lat_ts && wkt.lat1 && (wkt.projName === 'Stereographic_South_Pole' || wkt.projName === 'Polar Stereographic (variant B)')) {
  452. wkt.lat0 = d2r(wkt.lat1 > 0 ? 90 : -90);
  453. wkt.lat_ts = wkt.lat1;
  454. } else if (!wkt.lat_ts && wkt.lat0 && wkt.projName === 'Polar_Stereographic') {
  455. wkt.lat_ts = wkt.lat0;
  456. wkt.lat0 = d2r(wkt.lat0 > 0 ? 90 : -90);
  457. }
  458. }
  459. var index = function(wkt) {
  460. var lisp = parseString(wkt);
  461. var type = lisp.shift();
  462. var name = lisp.shift();
  463. lisp.unshift(['name', name]);
  464. lisp.unshift(['type', type]);
  465. var obj = {};
  466. sExpr(lisp, obj);
  467. cleanWKT(obj);
  468. return obj;
  469. };
  470. module.exports = index;