前端使用shapefile生成智慧城市白模

229 阅读3分钟

什么是shapefile?

arcgis关于shapefile的介绍,下面的文字就是从里面摘录出来的

desktop.arcgis.com/zh-cn/arcma…

Shapefile 是一种用于存储地理要素的几何位置和属性信息的非拓扑简单格式。 shapefile 中的地理要素可表示为点、线或面(区域)。 包含 shapefile 的工作空间还可以包含 dBASE 表,它们用于存储可连接到 shapefile 的要素的附加属性。

默认情况下,具有文件扩展名 .txt、.asc、.csv 或 .tab 的所有文件将以文本文件的形式显示在 ArcCatalog 中。

组成 shapefile 的每个文件均被限制为 2 GB。 因此,.dbf 文件不能超过 2 GB,.shp 文件也不能超过 2 GB(只有这两个文件的容量会很大)。 所有组成文件的总大小可以超过 2 GB。

shapefile 格式在应存储在同一项目工作空间且使用特定文件扩展名的三个或更多文件中定义地理配准要素的几何和属性。这些文件是:

  • .shp - 用于存储要素几何的主文件;必需文件。
  • .shx - 用于存储要素几何索引的索引文件;必需文件。
  • .dbf - 用于存储要素属性信息的 dBASE 表;必需文件。几何与属性是一对一关系,这种关系基于记录编号。dBASE 文件中的属性记录必须与主文件中的记录采用相同的顺序。
  • .sbn.sbx - 用于存储要素空间索引的文件。
  • .fbn.fbx - 用于存储只读 shapefile 的要素空间索引的文件。
  • .ain.aih - 用于存储某个表中或专题属性表中活动字段属性索引的文件。
  • .atx - .atx 文件针对在 ArcCatalog 中创建的各个 Shapefile 或 dBASE 属性索引而创建。ArcGIS 不使用 shapefile 和 dBASE 文件的 ArcView GIS 3.x 属性索引。已为 shapefile 和 dBASE 文件开发出新的属性索引建立模型。
  • .ixs - 读/写 shapefile 的地理编码索引。
  • .mxs - 读/写 shapefile(ODB 格式)的地理编码索引。
  • .prj - 用于存储坐标系信息的文件;由 ArcGIS 使用。
  • .xml - ArcGIS 的元数据 - 用于存储 shapefile 的相关信息。
  • .cpg - 可选文件,指定用于标识要使用的字符集的代码页。

解析获取数据

通过转换,可以转换的数据可以是geojson,可以直接在前端使用

使用qgis解析

导入shp文件后,直接保存为geojson

前端解析

目前可用的前端库

在研究其中代码之后发现,解析shapefile需要关注三个文件.shp, .prj, .dbf

  • 前两个文件保存的是 生成geojson的经纬度的数据,.shp是二进制文件,可以通过buffer数据进行解析, .prj坐标系信息,使用之前用npm:proj4计算后获取转换经纬度的函数
  • .dbf保存的是城市的信息,我们的数据中保存了一个Height字段

转换的结果如下:

前端使用

解析数据

fetch('/static/objects/shp/example.zip')
  .then((res) => res.arrayBuffer())
  .then(buffer=>{
    return parseShpToGeoJson.zip(buffer, { isBuffer: true })
  })
  .then(geojson=>{
    console.log("geojson",geojson);
  })

在three中使用

const map = new THREE.Group();
turf.featureEach(geoJson, (feature) => {
  const coordinates = turf.getCoords(feature);
  const color = 0x666666;
  coordinates.forEach((polygon: any) => {
    const shape = new THREE.Shape();
    polygon.forEach((coord: any, index: number) => {
      let [x, y] = this.#projection(coord) as any;
      if (!isNaN(x) && !isNaN(y)) {
        if (index === 0) {
          shape.moveTo(x, -y);
        }
        shape.lineTo(x, -y);
      }
    });

    const geometry = new THREE.ExtrudeGeometry(shape, {
      depth: feature.properties.Height,
      bevelEnabled: false,
    });
    const material = new THREE.MeshBasicMaterial({ color });
    // const texture = new THREE.CanvasTexture(gradientImage);
    // texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
    // texture.repeat.set(10, 10);
    // const material2 = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide });
    const mesh = new THREE.Mesh(geometry, material);
    map.add(mesh);
  });
});

utils.fitToViewport(this.object3d, map);
this.addObject(map);

在cesium中使用

const geojson = await fetch(URL_GEOJSON).then((res) => res.json());
const dataSource = await Cesium.GeoJsonDataSource.load(geojson, {});
await app.viewer.dataSources.add(dataSource);

dataSource.entities.values.forEach((entity, index) => {
  // @ts-ignore
  entity.polygon.extrudedHeight = geojson.features[index].properties.Height;
  // @ts-ignore
  entity.polygon.material = Cesium.Color.fromCssColorString('rgb(5, 101, 190)');
  // @ts-ignore
  entity.polygon.outlineColor = Cesium.Color.fromCssColorString('rgb(5, 101, 190)').withAlpha(0.8);
});

// 定位到
// app.viewer.scene.mode = Cesium.SceneMode.COLUMBUS_VIEW;
app.viewer.flyTo(dataSource);

渲染结果