前面文章有shp 和kml 导入的方法,这篇文章是用来记录txt文件导入。txt文件中的坐标系2000国家大地坐标系,投影类型是高斯克吕格,转换的格式是WGS84,就是我们常见的坐标系。 需求是arcgis导出一个txt文件类型,要通过前端来进行类型转换变成geoJson 统一格式
效果图:
代码
1.先获取到txt文件 我用的是element 组件
const fileType = ['kml', 'shp', 'zip', 'txt']
// 处理文件
export const dealFile = async (file: UploadFile) => {
let geoJson = undefined
if (!file?.raw) return
try {
if (file?.name?.includes('.kml')) geoJson = await kmlToGeoJson(file.raw)
else if (file?.name?.includes('.shp') || file?.name?.includes('.zip')) geoJson = await readShp(file.raw)
else if (file?.name?.includes('.zip')) geoJson = await dealZip(file.raw)
else if (file?.name?.includes('.txt')) geoJson = await dealTxt(file.raw)
else ElMessage.warning(`本系统暂只支持${fileType}文件`)
} catch (err) {
}
return geoJson
}
2. 读取文件中的内容
// 处理txt 文件
const dealTxt = async (file: UploadRawFile) => {
let reader = new FileReader()
// 因为txt文件是gbk编码
reader.readAsText(file, 'GBK')
return new Promise((resolve, reject) => {
reader.onload = (e) => {
let fileString = e.target?.result
// 处理geoJson 格式
let geoJson = txtToGeoJson(fileString as string)
geoJson && resolve(geoJson)
}
reader.onerror = () => {
ElMessage.error('txt文件读取失败')
reject(reader.error)
}
})
}
最关键部分 文件转换
我们要用到proj4 这个库来实现坐标投影转换
数据大体样式:
如果需要数据的话可以私信我,我还可以给你数据和shp和txt互转工具 ,你就可以验证代码了。
我们在数据中得到了属性描述 ,当然我代码中的属性描述什么都是写死的,你也可以去进行字符匹配,变量赋值,更灵活些。里面有什么坐标系 2000国家大地坐标系,还有几度分带。几度分带可以确定中央经线 也是lat_0 值 后面再代码中我详细介绍了,地图坐标系转换 - 在线工具 这个网址有大地坐标中央经线参考表 带号也非常重要 带号不对 坐标系转换出来的肯定不对哦。我再下面代码中也详细介绍了。 带号是假东值,+x_0=计算是代号加上500千米 是字符串的加 不是数值的加,eg: 40带号是 40500000 单位是米 。剩下的参数代码中有介绍 。
代码解释:
1.先处理字符 把字符处理成数组 更好操作 ,选出我们地块坐标
2. 阅读数据发现 每一个@符号就是一个地块 所以我们解析数据的时候每到一个@符号就创建一个数组放到最大的数组里。
3.进行经纬度转换这里要注意,地块里有洞的 它的第二个参数会变,我们要进行标记。
4.进行geoJson转换 geojson ,最好看着正确的geojson格式进行代码处理。geojson 分为MultiPolygon和Polygon 两种,我们用MultiPolygon 就够了,单个套个数组就好。
// 先在 导入 改库
import proj4 from 'proj4';
const txtToGeoJson = async (fileString: string) => {
const blocks = fileString.split('[地块坐标]')[1].trim().split('\r\n');
// WGS84
const wgs84 = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ';
//+proj=tmerc: 使用 横轴墨卡托投影(Transverse Mercator),适用于长条状地区。几度分带=3:表示投影带宽为 3 度,用于确定 +proj=tmerc
// +lat_0=0: 投影的基准纬度,即赤道,纬度 0 度。
// +lon_0=120: 中央经线,定义为 120 度经线。 带号=40 几度分带=3 就为120 具体参考 https://tool.lu/coordinate
// +k=1: 比例因子,通常为 1,表示不缩放用于调整横轴墨卡托投影的缩放。
// +x_0=40500000:这是假东值,为 40500000 米, 代号加上500千米 单位是米 代号是40所以 405000000 偏移量,将投影坐标系的 X 轴(横坐标)原点偏移 40500000 米,以避免负坐标。
// +y_0=0: 偏移量,将投影坐标系的 Y 轴(纵坐标)原点设为 0 米。
// ellps=GRS80: 椭球模型,使用 GRS80(Geodetic Reference System 1980)大地测量参考系统。
// +towgs84=0,0,0,0,0,0,0: 椭球转换参数,指明从 GRS80 到 WGS84 椭球的转换,不进行任何移动或旋转。
// +units=m: 单位设置为 米,即投影坐标以米为单位。
// +no_defs: 禁止使用默认的定义,确保投影仅依据显式声明的参数进行。
const gaussKrugerCGCS2000 = "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs";
let coordinatesArr: { massif: string, latLon: number[] }[][] = []
blocks.forEach((item, index) => {
if (item.includes('@')) {
coordinatesArr.push([])
} else {
let coordinateParameter = item.split(',')
// 3298579.549, 40459970.552 但是 coordinates = [40459970.552, 3298579.549]
let coordinates = [parseFloat(coordinateParameter[3]), parseFloat(coordinateParameter[2])]
// 转换为经纬度 coordinates 输入的投影坐标 (X, Y)
const latLon = proj4(gaussKrugerCGCS2000, wgs84, coordinates);
// 将投影坐标转换为经纬度
isArray(coordinatesArr[coordinatesArr.length - 1]) && coordinatesArr[coordinatesArr.length - 1].push({
massif: coordinateParameter[1],
latLon: latLon
})
}
})
let features = coordinatesArr.map(item => {
let obj: any = {}
item.forEach((el) => {
if (!obj[el.massif]) {
obj[el.massif] = []
}
obj[el.massif].push(el.latLon)
})
return {
type: "Feature",
geometry: {
type: "MultiPolygon",
coordinates: [Object.values(obj)],
},
}
})
let geoJson = {
type: "FeatureCollection",
features: features
};
return geoJson
}