Created
May 24, 2022 10:17
-
-
Save wewindy/2185a33f0d9691b264e4a897093c6fff to your computer and use it in GitHub Desktop.
WKTString-Geojson Transformer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export interface IGeoJson { | |
| type: 'Feature' | 'Point' | 'LineString' | 'Polygon' | 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' | 'GeometryCollection'; | |
| coordinates?: any[]; | |
| geometry?: IGeoJson; | |
| geometries?: IGeoJson[]; | |
| crs?: string | { | |
| type: string; | |
| properties: { | |
| name: string; | |
| }; | |
| }; | |
| } | |
| export interface IWKTCoord extends Array<number> { | |
| } | |
| export interface IWKTRing extends Array<IWKTCoord> { | |
| } | |
| export interface IWKTRings extends Array<IWKTRing> { | |
| } | |
| export interface IWKTMultiRings extends Array<any> { | |
| } | |
| /** | |
| * Stringifies a GeoJSON object into WKT | |
| */ | |
| export declare const stringify: (geojson: IGeoJson) => any; | |
| /** | |
| * Parse WKT and return GeoJSON. | |
| * | |
| * @param input A EWKT/WKT geometry | |
| */ | |
| export declare const parse: (wktString: string) => IGeoJson; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 数字格式,含可选的正号或负号,支持小数点、e或E表示的科学计数法 | |
| const numberRegexp = /[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/; | |
| // 至少 1 个以上的数字格式,且由空格连接,例如 “1 -2.98 5e-2” atLeastOneNumberConnectWithSpace | |
| const atLeastOneNumberConnectWithSpace = new RegExp(`^${numberRegexp.source}(\\s${numberRegexp.source}){1,}`); | |
| /** | |
| * @param coords | |
| * @example | |
| * ``` | |
| * [112.5, 22.3] => "112.5 22.3" | |
| * ``` | |
| */ | |
| const pairWKT = (coords) => coords.join(' '); | |
| /** | |
| * @param ring | |
| * @example | |
| * ``` | |
| * [[112.52 22.30], [114.31 21.92]] => "112.52 22.30,114.31 21.92" | |
| * ``` | |
| */ | |
| const ringWKT = (ring) => ring.map(pairWKT).join(','); | |
| /** | |
| * @param rings Polygon 或 MultiLineString | |
| * @example | |
| * ``` | |
| * [ | |
| * [[310, 30], [40, 30], [50, 20]], // ring0 | |
| * [[10, 10], [20, 20]] // ring1 | |
| * ] | |
| * => | |
| * "(310 30, 40 30, 50 20),(10 10, 20 20)" | |
| * ``` | |
| */ | |
| const ringsWKT = (rings) => rings.map(ringWKT).map(addOutsideBrackets).join(','); | |
| /** | |
| * @param multiRings MULTIPOLYGON | |
| * @example | |
| * ``` | |
| * [ | |
| * [ // singlePolygon0 | |
| * [[0, 1], [3, 0], [4, 3], [0, 4], [0, 1]], | |
| * ], | |
| * [ // singlePolygon1 | |
| * [[3, 4], [6, 3], [5, 5], [3, 4]], | |
| * ], | |
| * ] | |
| * => | |
| * "((0 1,3 0,4 3,0 4,0 1)),((3 4,6 3,5 5,3 4))" | |
| * ``` | |
| */ | |
| const multiRingsWKT = (multiRings) => multiRings.map(ringsWKT).map(addOutsideBrackets).join(','); | |
| const addOutsideBrackets = (s) => `(${s})`; | |
| /** | |
| * Stringifies a GeoJSON object into WKT | |
| */ | |
| export const stringify = (geojson) => { | |
| const target = geojson.type === 'Feature' ? geojson.geometry : geojson; | |
| switch (target.type) { | |
| case 'Point': | |
| return `POINT (${pairWKT(target.coordinates)})`; | |
| case 'LineString': | |
| return `LINESTRING (${ringWKT(target.coordinates)})`; | |
| case 'Polygon': | |
| return `POLYGON (${ringsWKT(target.coordinates)})`; | |
| case 'MultiPoint': | |
| return `MULTIPOINT (${ringWKT(target.coordinates)})`; | |
| case 'MultiPolygon': | |
| return `MULTIPOLYGON (${multiRingsWKT(target.coordinates)})`; | |
| case 'MultiLineString': | |
| return `'MULTILINESTRING (${ringsWKT(target.coordinates)})`; | |
| case 'GeometryCollection': | |
| return `GEOMETRYCOLLECTION (${target.geometries.map(stringify).join(',')})`; | |
| default: | |
| throw new Error('stringify requires a valid GeoJSON Feature or geometry object as input'); | |
| } | |
| }; | |
| /** | |
| * Parse WKT and return GeoJSON. | |
| * | |
| * @param input A EWKT/WKT geometry | |
| */ | |
| export const parse = (wktString) => { | |
| // DEMO: SRID=4269;LINESTRING(-71.160281 42.258729,-71.160837 42.259113,-71.161144 42.25932) | |
| const parts = wktString.split(';'); | |
| let wktGeometryPart = parts.pop(); // 取表示几何的最后一部分 | |
| const srid = (parts.shift() || '').split('=').pop(); // 取表示坐标系的第一部分 | |
| let charOffset = 0; | |
| /** | |
| * 使用正则表达式选择 WKT 文本 | |
| * @param reg 正则选择器 | |
| * @returns 匹配到的字符串 | |
| * @private | |
| */ | |
| const $ = (reg) => { | |
| const match = wktGeometryPart.substring(charOffset).match(reg); | |
| if (!match) | |
| return null; | |
| else { | |
| charOffset += match[0].length; | |
| return match[0]; | |
| } | |
| }; | |
| /** | |
| * 为最终的 GeoJson 附加参考坐标系信息 | |
| * @private | |
| */ | |
| const appendCrs = (obj) => { | |
| if (obj && srid.match(/\d+/)) { | |
| obj.crs = { | |
| type: 'name', | |
| properties: { | |
| name: `urn:ogc:def:crs:EPSG::${srid}` | |
| } | |
| }; | |
| } | |
| return obj; | |
| }; | |
| /** | |
| * 移除开头的空格(*号表示0~N个) | |
| * @private | |
| */ | |
| const white = () => { $(/^\s*/); }; | |
| const multicoords = () => { | |
| white(); | |
| let depth = 0; | |
| const rings = []; | |
| const stack = [rings]; | |
| let pointer = rings; | |
| let elem; | |
| while (elem = | |
| $(/^(\()/) || | |
| $(/^(\))/) || | |
| $(/^(,)/) || | |
| $(atLeastOneNumberConnectWithSpace)) { | |
| if (elem === '(') { | |
| stack.push(pointer); | |
| pointer = []; | |
| stack[stack.length - 1].push(pointer); | |
| depth++; | |
| } | |
| else if (elem === ')') { | |
| // For the case: Polygon(), ... | |
| if (pointer.length === 0) | |
| return null; | |
| pointer = stack.pop(); | |
| // the stack was empty, input was malformed | |
| if (!pointer) | |
| return null; | |
| depth--; | |
| if (depth === 0) | |
| break; | |
| } | |
| else if (elem === ',') { | |
| pointer = []; | |
| stack[stack.length - 1].push(pointer); | |
| } | |
| else if (!elem.split(/\s/g).some(v => isNaN(+v))) { | |
| Array.prototype.push.apply(pointer, elem.split(/\s/g).map(parseFloat)); | |
| } | |
| else { | |
| return null; | |
| } | |
| white(); | |
| } | |
| if (depth !== 0) | |
| return null; | |
| return rings; | |
| }; | |
| const coords = () => { | |
| let list = []; | |
| let item; | |
| let pt; | |
| while (pt = $(atLeastOneNumberConnectWithSpace) || $(/^(,)/)) { | |
| if (pt === ',') { | |
| list.push(item); | |
| item = []; | |
| } | |
| else if (!pt.split(/\s/g).some(v => isNaN(+v))) { | |
| if (!item) | |
| item = []; | |
| Array.prototype.push.apply(item, pt.split(/\s/g).map(parseFloat)); | |
| } | |
| white(); | |
| } | |
| if (item) | |
| list.push(item); | |
| else | |
| return null; | |
| return list.length ? list : null; | |
| }; | |
| const point = () => { | |
| // 选择 WKT 中的 'point' 或 'point z'(不区分大小写) | |
| if (!$(/^(point(\sz)?)/i)) | |
| return null; | |
| white(); | |
| // 选择 WKT 中的 '(' | |
| if (!$(/^(\()/)) | |
| return null; | |
| // 选择坐标 | |
| const c = coords(); | |
| if (!c) | |
| return null; | |
| white(); | |
| if (!$(/^(\))/)) | |
| return null; | |
| return { | |
| type: 'Point', | |
| coordinates: c[0] | |
| }; | |
| }; | |
| const multipoint = () => { | |
| // 选择 WKT 中的 'multipoint'(不区分大小写) | |
| if (!$(/^(multipoint)/i)) | |
| return null; | |
| white(); | |
| // 重组成新的 MULTIPOINT WKT | |
| const newCoordsFormat = wktGeometryPart | |
| .substring(wktGeometryPart.indexOf('(') + 1, wktGeometryPart.length - 1) | |
| .replace(/\(/g, '') | |
| .replace(/\)/g, ''); | |
| wktGeometryPart = `MULTIPOINT (${newCoordsFormat})`; | |
| const c = multicoords(); | |
| if (!c) | |
| return null; | |
| white(); | |
| return { | |
| type: 'MultiPoint', | |
| coordinates: c | |
| }; | |
| }; | |
| const multilinestring = () => { | |
| if (!$(/^(multilinestring)/i)) | |
| return null; | |
| white(); | |
| var c = multicoords(); | |
| if (!c) | |
| return null; | |
| white(); | |
| return { | |
| type: 'MultiLineString', | |
| coordinates: c | |
| }; | |
| }; | |
| const linestring = () => { | |
| // 选择 WKT 中的 'linestring' 或 'linestring z'(不区分大小写) | |
| if (!$(/^(linestring(\sz)?)/i)) | |
| return null; | |
| white(); | |
| if (!$(/^(\()/)) | |
| return null; | |
| const c = coords(); | |
| if (!c) | |
| return null; | |
| if (!$(/^(\))/)) | |
| return null; | |
| return { | |
| type: 'LineString', | |
| coordinates: c | |
| }; | |
| }; | |
| const polygon = () => { | |
| // 选择 WKT 中的 'polygon' 或 'polygon z'(不区分大小写) | |
| if (!$(/^(polygon(\sz)?)/i)) | |
| return null; | |
| white(); | |
| const c = multicoords(); | |
| if (!c) | |
| return null; | |
| return { | |
| type: 'Polygon', | |
| coordinates: c | |
| }; | |
| }; | |
| const multipolygon = () => { | |
| // 选择 WKT 中的 'multipolygon'(不区分大小写) | |
| if (!$(/^(multipolygon)/i)) | |
| return null; | |
| white(); | |
| const c = multicoords(); | |
| if (!c) | |
| return null; | |
| return { | |
| type: 'MultiPolygon', | |
| coordinates: c | |
| }; | |
| }; | |
| const geometrycollection = () => { | |
| const geometries = []; | |
| let geometry; | |
| // 选择 WKT 中的 'geometrycollection'(不区分大小写) | |
| if (!$(/^(geometrycollection)/i)) | |
| return null; | |
| white(); | |
| if (!$(/^(\()/)) | |
| return null; | |
| while (geometry = root()) { | |
| geometries.push(geometry); | |
| white(); | |
| $(/^(,)/); | |
| white(); | |
| } | |
| if (!$(/^(\))/)) | |
| return null; | |
| return { | |
| type: 'GeometryCollection', | |
| geometries: geometries | |
| }; | |
| }; | |
| /** | |
| * 获取整个 GeoJson | |
| * @private | |
| */ | |
| const root = () => { | |
| return point() || | |
| linestring() || | |
| polygon() || | |
| multipoint() || | |
| multilinestring() || | |
| multipolygon() || | |
| geometrycollection(); | |
| }; | |
| return appendCrs(root()); | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const numberRegexp=/[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/,atLeastOneNumberConnectWithSpace=new RegExp(`^${numberRegexp.source}(\\s${numberRegexp.source}){1,}`),pairWKT=coords=>coords.join(" "),ringWKT=ring=>ring.map(pairWKT).join(","),ringsWKT=rings=>rings.map(ringWKT).map(addOutsideBrackets).join(","),multiRingsWKT=multiRings=>multiRings.map(ringsWKT).map(addOutsideBrackets).join(","),addOutsideBrackets=s=>`(${s})`;export const stringify=geojson=>{const target="Feature"===geojson.type?geojson.geometry:geojson;switch(target.type){case"Point":return`POINT (${pairWKT(target.coordinates)})`;case"LineString":return`LINESTRING (${ringWKT(target.coordinates)})`;case"Polygon":return`POLYGON (${ringsWKT(target.coordinates)})`;case"MultiPoint":return`MULTIPOINT (${ringWKT(target.coordinates)})`;case"MultiPolygon":return`MULTIPOLYGON (${multiRings=target.coordinates,multiRings.map(ringsWKT).map(addOutsideBrackets).join(",")})`;case"MultiLineString":return`'MULTILINESTRING (${ringsWKT(target.coordinates)})`;case"GeometryCollection":return`GEOMETRYCOLLECTION (${target.geometries.map(stringify).join(",")})`;default:throw new Error("stringify requires a valid GeoJSON Feature or geometry object as input")}var multiRings};export const parse=wktString=>{const parts=wktString.split(";");let wktGeometryPart=parts.pop();const srid=(parts.shift()||"").split("=").pop();let charOffset=0;const $=reg=>{const match=wktGeometryPart.substring(charOffset).match(reg);return match?(charOffset+=match[0].length,match[0]):null},white=()=>{$(/^\s*/)},multicoords=()=>{white();let depth=0;const rings=[],stack=[rings];let elem,pointer=rings;for(;elem=$(/^(\()/)||$(/^(\))/)||$(/^(,)/)||$(atLeastOneNumberConnectWithSpace);){if("("===elem)stack.push(pointer),pointer=[],stack[stack.length-1].push(pointer),depth++;else if(")"===elem){if(0===pointer.length)return null;if(pointer=stack.pop(),!pointer)return null;if(depth--,0===depth)break}else if(","===elem)pointer=[],stack[stack.length-1].push(pointer);else{if(elem.split(/\s/g).some((v=>isNaN(+v))))return null;Array.prototype.push.apply(pointer,elem.split(/\s/g).map(parseFloat))}white()}return 0!==depth?null:rings},coords=()=>{let item,pt,list=[];for(;pt=$(atLeastOneNumberConnectWithSpace)||$(/^(,)/);)","===pt?(list.push(item),item=[]):pt.split(/\s/g).some((v=>isNaN(+v)))||(item||(item=[]),Array.prototype.push.apply(item,pt.split(/\s/g).map(parseFloat))),white();return item?(list.push(item),list.length?list:null):null},root=()=>(()=>{if(!$(/^(point(\sz)?)/i))return null;if(white(),!$(/^(\()/))return null;const c=coords();return c?(white(),$(/^(\))/)?{type:"Point",coordinates:c[0]}:null):null})()||(()=>{if(!$(/^(linestring(\sz)?)/i))return null;if(white(),!$(/^(\()/))return null;const c=coords();return c&&$(/^(\))/)?{type:"LineString",coordinates:c}:null})()||(()=>{if(!$(/^(polygon(\sz)?)/i))return null;white();const c=multicoords();return c?{type:"Polygon",coordinates:c}:null})()||(()=>{if(!$(/^(multipoint)/i))return null;white();const newCoordsFormat=wktGeometryPart.substring(wktGeometryPart.indexOf("(")+1,wktGeometryPart.length-1).replace(/\(/g,"").replace(/\)/g,"");wktGeometryPart=`MULTIPOINT (${newCoordsFormat})`;const c=multicoords();return c?(white(),{type:"MultiPoint",coordinates:c}):null})()||(()=>{if(!$(/^(multilinestring)/i))return null;white();var c=multicoords();return c?(white(),{type:"MultiLineString",coordinates:c}):null})()||(()=>{if(!$(/^(multipolygon)/i))return null;white();const c=multicoords();return c?{type:"MultiPolygon",coordinates:c}:null})()||(()=>{const geometries=[];let geometry;if(!$(/^(geometrycollection)/i))return null;if(white(),!$(/^(\()/))return null;for(;geometry=root();)geometries.push(geometry),white(),$(/^(,)/),white();return $(/^(\))/)?{type:"GeometryCollection",geometries:geometries}:null})();return(obj=root())&&srid.match(/\d+/)&&(obj.crs={type:"name",properties:{name:`urn:ogc:def:crs:EPSG::${srid}`}}),obj;var obj}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 数字格式,含可选的正号或负号,支持小数点、e或E表示的科学计数法 | |
| const numberRegexp = /[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/ | |
| // 至少 1 个以上的数字格式,且由空格连接,例如 “1 -2.98 5e-2” atLeastOneNumberConnectWithSpace | |
| const atLeastOneNumberConnectWithSpace = new RegExp(`^${numberRegexp.source}(\\s${numberRegexp.source}){1,}`) | |
| export interface IGeoJson { | |
| type: 'Feature' | 'Point' | 'LineString' | 'Polygon' | 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' | 'GeometryCollection', | |
| coordinates?: any[], | |
| geometry?: IGeoJson, | |
| geometries?: IGeoJson[], | |
| crs?: string | { | |
| type: string, | |
| properties: { | |
| name: string | |
| } | |
| }, | |
| } | |
| export interface IWKTCoord extends Array<number> { } | |
| export interface IWKTRing extends Array<IWKTCoord> { } | |
| export interface IWKTRings extends Array<IWKTRing> { } | |
| export interface IWKTMultiRings extends Array<any> { } | |
| /** | |
| * @param coords | |
| * @example | |
| * ``` | |
| * [112.5, 22.3] => "112.5 22.3" | |
| * ``` | |
| */ | |
| const pairWKT = (coords: IWKTCoord) => coords.join(' ') | |
| /** | |
| * @param ring | |
| * @example | |
| * ``` | |
| * [[112.52 22.30], [114.31 21.92]] => "112.52 22.30,114.31 21.92" | |
| * ``` | |
| */ | |
| const ringWKT = (ring: IWKTRing) => ring.map(pairWKT).join(',') | |
| /** | |
| * @param rings Polygon 或 MultiLineString | |
| * @example | |
| * ``` | |
| * [ | |
| * [[310, 30], [40, 30], [50, 20]], // ring0 | |
| * [[10, 10], [20, 20]] // ring1 | |
| * ] | |
| * => | |
| * "(310 30, 40 30, 50 20),(10 10, 20 20)" | |
| * ``` | |
| */ | |
| const ringsWKT = (rings: IWKTRings) => rings.map(ringWKT).map(addOutsideBrackets).join(',') | |
| /** | |
| * @param multiRings MULTIPOLYGON | |
| * @example | |
| * ``` | |
| * [ | |
| * [ // singlePolygon0 | |
| * [[0, 1], [3, 0], [4, 3], [0, 4], [0, 1]], | |
| * ], | |
| * [ // singlePolygon1 | |
| * [[3, 4], [6, 3], [5, 5], [3, 4]], | |
| * ], | |
| * ] | |
| * => | |
| * "((0 1,3 0,4 3,0 4,0 1)),((3 4,6 3,5 5,3 4))" | |
| * ``` | |
| */ | |
| const multiRingsWKT = (multiRings: IWKTMultiRings) => multiRings.map(ringsWKT).map(addOutsideBrackets).join(',') | |
| const addOutsideBrackets = (s: string) => `(${s})` | |
| /** | |
| * Stringifies a GeoJSON object into WKT | |
| */ | |
| export const stringify = (geojson: IGeoJson) => { | |
| const target = geojson.type === 'Feature' ? geojson.geometry : geojson | |
| switch (target.type) { | |
| case 'Point': | |
| return `POINT (${pairWKT(target.coordinates as IWKTCoord)})` | |
| case 'LineString': | |
| return `LINESTRING (${ringWKT(target.coordinates)})` | |
| case 'Polygon': | |
| return `POLYGON (${ringsWKT(target.coordinates)})` | |
| case 'MultiPoint': | |
| return `MULTIPOINT (${ringWKT(target.coordinates)})` | |
| case 'MultiPolygon': | |
| return `MULTIPOLYGON (${multiRingsWKT(target.coordinates)})` | |
| case 'MultiLineString': | |
| return `'MULTILINESTRING (${ringsWKT(target.coordinates)})` | |
| case 'GeometryCollection': | |
| return `GEOMETRYCOLLECTION (${target.geometries.map(stringify).join(',')})` | |
| default: | |
| throw new Error('stringify requires a valid GeoJSON Feature or geometry object as input') | |
| } | |
| } | |
| /** | |
| * Parse WKT and return GeoJSON. | |
| * | |
| * @param input A EWKT/WKT geometry | |
| */ | |
| export const parse = (wktString: string) => { | |
| // DEMO: SRID=4269;LINESTRING(-71.160281 42.258729,-71.160837 42.259113,-71.161144 42.25932) | |
| const parts = wktString.split(';') | |
| let wktGeometryPart = parts.pop() // 取表示几何的最后一部分 | |
| const srid = (parts.shift() || '').split('=').pop() // 取表示坐标系的第一部分 | |
| let charOffset = 0 | |
| /** | |
| * 使用正则表达式选择 WKT 文本 | |
| * @param reg 正则选择器 | |
| * @returns 匹配到的字符串 | |
| * @private | |
| */ | |
| const $ = (reg: RegExp) => { | |
| const match = wktGeometryPart.substring(charOffset).match(reg) | |
| if (!match) return null | |
| else { | |
| charOffset += match[0].length | |
| return match[0] | |
| } | |
| } | |
| /** | |
| * 为最终的 GeoJson 附加参考坐标系信息 | |
| * @private | |
| */ | |
| const appendCrs = (obj: IGeoJson) => { | |
| if (obj && srid.match(/\d+/)) { | |
| obj.crs = { | |
| type: 'name', | |
| properties: { | |
| name: `urn:ogc:def:crs:EPSG::${srid}` | |
| } | |
| } | |
| } | |
| return obj | |
| } | |
| /** | |
| * 移除开头的空格(*号表示0~N个) | |
| * @private | |
| */ | |
| const white = () => { $(/^\s*/) } | |
| const multicoords = () => { | |
| white() | |
| let depth = 0 | |
| const rings = [] | |
| const stack = [rings] | |
| let pointer = rings | |
| let elem: string | |
| while (elem = | |
| $(/^(\()/) || | |
| $(/^(\))/) || | |
| $(/^(,)/) || | |
| $(atLeastOneNumberConnectWithSpace) | |
| ) { | |
| if (elem === '(') { | |
| stack.push(pointer) | |
| pointer = [] | |
| stack[stack.length - 1].push(pointer) | |
| depth++ | |
| } else if (elem === ')') { | |
| // For the case: Polygon(), ... | |
| if (pointer.length === 0) return null | |
| pointer = stack.pop() | |
| // the stack was empty, input was malformed | |
| if (!pointer) return null | |
| depth-- | |
| if (depth === 0) break | |
| } else if (elem === ',') { | |
| pointer = [] | |
| stack[stack.length - 1].push(pointer) | |
| } else if (!elem.split(/\s/g).some(v => isNaN(+v))) { | |
| Array.prototype.push.apply(pointer, elem.split(/\s/g).map(parseFloat)) | |
| } else { | |
| return null | |
| } | |
| white() | |
| } | |
| if (depth !== 0) return null | |
| return rings | |
| } | |
| const coords = () => { | |
| let list: IWKTCoord[] = [] | |
| let item: IWKTCoord | |
| let pt: string | |
| while (pt = $(atLeastOneNumberConnectWithSpace) || $(/^(,)/)) { | |
| if (pt === ',') { | |
| list.push(item) | |
| item = [] | |
| } else if (!pt.split(/\s/g).some(v => isNaN(+v))) { | |
| if (!item) item = [] | |
| Array.prototype.push.apply(item, pt.split(/\s/g).map(parseFloat)) | |
| } | |
| white() | |
| } | |
| if (item) list.push(item) | |
| else return null | |
| return list.length ? list : null | |
| } | |
| const point = (): IGeoJson => { | |
| // 选择 WKT 中的 'point' 或 'point z'(不区分大小写) | |
| if (!$(/^(point(\sz)?)/i)) return null | |
| white() | |
| // 选择 WKT 中的 '(' | |
| if (!$(/^(\()/)) return null | |
| // 选择坐标 | |
| const c = coords() | |
| if (!c) return null | |
| white() | |
| if (!$(/^(\))/)) return null | |
| return { | |
| type: 'Point', | |
| coordinates: c[0] as [] | |
| } | |
| } | |
| const multipoint = (): IGeoJson => { | |
| // 选择 WKT 中的 'multipoint'(不区分大小写) | |
| if (!$(/^(multipoint)/i)) return null | |
| white() | |
| // 重组成新的 MULTIPOINT WKT | |
| const newCoordsFormat = wktGeometryPart | |
| .substring(wktGeometryPart.indexOf('(') + 1, wktGeometryPart.length - 1) | |
| .replace(/\(/g, '') | |
| .replace(/\)/g, '') | |
| wktGeometryPart = `MULTIPOINT (${newCoordsFormat})` | |
| const c = multicoords() | |
| if (!c) return null | |
| white() | |
| return { | |
| type: 'MultiPoint', | |
| coordinates: c | |
| } | |
| } | |
| const multilinestring = (): IGeoJson | null => { | |
| if (!$(/^(multilinestring)/i)) return null | |
| white() | |
| var c = multicoords() | |
| if (!c) return null | |
| white() | |
| return { | |
| type: 'MultiLineString', | |
| coordinates: c | |
| } | |
| } | |
| const linestring = (): IGeoJson => { | |
| // 选择 WKT 中的 'linestring' 或 'linestring z'(不区分大小写) | |
| if (!$(/^(linestring(\sz)?)/i)) return null | |
| white() | |
| if (!$(/^(\()/)) return null | |
| const c = coords() | |
| if (!c) return null | |
| if (!$(/^(\))/)) return null | |
| return { | |
| type: 'LineString', | |
| coordinates: c | |
| } | |
| } | |
| const polygon = (): IGeoJson => { | |
| // 选择 WKT 中的 'polygon' 或 'polygon z'(不区分大小写) | |
| if (!$(/^(polygon(\sz)?)/i)) return null | |
| white() | |
| const c = multicoords() | |
| if (!c) return null | |
| return { | |
| type: 'Polygon', | |
| coordinates: c | |
| } | |
| } | |
| const multipolygon = (): IGeoJson => { | |
| // 选择 WKT 中的 'multipolygon'(不区分大小写) | |
| if (!$(/^(multipolygon)/i)) return null | |
| white() | |
| const c = multicoords() | |
| if (!c) return null | |
| return { | |
| type: 'MultiPolygon', | |
| coordinates: c | |
| } | |
| } | |
| const geometrycollection = (): IGeoJson => { | |
| const geometries: IGeoJson[] = [] | |
| let geometry: IGeoJson | |
| // 选择 WKT 中的 'geometrycollection'(不区分大小写) | |
| if (!$(/^(geometrycollection)/i)) return null | |
| white() | |
| if (!$(/^(\()/)) return null | |
| while (geometry = root()) { | |
| geometries.push(geometry) | |
| white() | |
| $(/^(,)/) | |
| white() | |
| } | |
| if (!$(/^(\))/)) return null | |
| return { | |
| type: 'GeometryCollection', | |
| geometries: geometries | |
| } | |
| } | |
| /** | |
| * 获取整个 GeoJson | |
| * @private | |
| */ | |
| const root = () => { | |
| return point() || | |
| linestring() || | |
| polygon() || | |
| multipoint() || | |
| multilinestring() || | |
| multipolygon() || | |
| geometrycollection() | |
| } | |
| return appendCrs(root()) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment