基于JS实现《国家基本比例尺地形图分幅和编号》标准

1、标准

GB T 13989-2012国家基本比例尺地形图分幅和编号

地址:【高清版】GB T 13989-2012国家基本比例尺地形图分幅和编号 - 道客巴巴

2、1:100万比例尺

2.1 说明

2.2 计算公式

2.3 计算代码

2.3.1 元素数据定义

由于中国只到N层,所以只定义到O.

/**
   * 100万比例尺下的行号对应的代码
   */
  static mateData100 = [
    {
      rowCode: "A",
      rowNumber: 1,
    },
    {
      rowCode: "B",
      rowNumber: 2,
    },
    {
      rowCode: "C",
      rowNumber: 3,
    },
    {
      rowCode: "D",
      rowNumber: 4,
    },
    {
      rowCode: "E",
      rowNumber: 5,
    },
    {
      rowCode: "F",
      rowNumber: 6,
    },
    {
      rowCode: "G",
      rowNumber: 7,
    },
    {
      rowCode: "H",
      rowNumber: 8,
    },
    {
      rowCode: "I",
      rowNumber: 9,
    },
    {
      rowCode: "J",
      rowNumber: 10,
    },
    {
      rowCode: "K",
      rowNumber: 11,
    },
    {
      rowCode: "L",
      rowNumber: 12,
    },
    {
      rowCode: "M",
      rowNumber: 13,
    },
    {
      rowCode: "N",
      rowNumber: 14,
    },
    {
      rowCode: "O",
      rowNumber: 15,
    },
  ];

2.3.2 代码实现

/**
   * 根据经纬度计算100万比例尺的行列号
   * @param lon
   * @param lat
   * @return {{col: number, row: number, code: string}}
   */
  static calcMapFrameNumber100 = (lon, lat) => {
    let a = Math.trunc(lat / 4.0) + 1;
    let b = Math.trunc(lon / 6.0) + 31;
    let mateInfo = MapFrameUtils.mateData100.find(
      (item) => item.rowNumber === a
    );
    return {
      row: a,
      col: b,
      code: mateInfo.rowCode,
    };
  };

3、非100万比例尺

3.1 说明

3.1.1 2000到50万比例尺格式

3.1.2 500到1000比例尺格式

3.2 计算公式

3.3 代码

3.3.1 元数据

/**
   * 100万比例尺下的行号对应的代码
   */
  static mateData100 = [
    {
      rowCode: "A",
      rowNumber: 1,
    },
    {
      rowCode: "B",
      rowNumber: 2,
    },
    {
      rowCode: "C",
      rowNumber: 3,
    },
    {
      rowCode: "D",
      rowNumber: 4,
    },
    {
      rowCode: "E",
      rowNumber: 5,
    },
    {
      rowCode: "F",
      rowNumber: 6,
    },
    {
      rowCode: "G",
      rowNumber: 7,
    },
    {
      rowCode: "H",
      rowNumber: 8,
    },
    {
      rowCode: "I",
      rowNumber: 9,
    },
    {
      rowCode: "J",
      rowNumber: 10,
    },
    {
      rowCode: "K",
      rowNumber: 11,
    },
    {
      rowCode: "L",
      rowNumber: 12,
    },
    {
      rowCode: "M",
      rowNumber: 13,
    },
    {
      rowCode: "N",
      rowNumber: 14,
    },
    {
      rowCode: "O",
      rowNumber: 15,
    },
  ];

3.3.2 实现代码

/**
   * 根据比例尺,经纬度计算地图的行列号
   * @param scale
   * @param lon
   * @param lat
   * @return {{col: number, code: *, row: number, digit: (number|*)}|null}
   */
  static calcMapFrameNumberNot100 = (scale, lon, lat) => {
    let mateData = MapFrameUtils.mateData.find((item) => item.scale === scale);
    if (mateData) {
      let cStep = ((lat % 4) / mateData.latD).toPrecision(4);
      let c = Math.round(4 / mateData.latD - Math.trunc(Number(cStep)));
      let dStep = ((lon % 6) / mateData.lonD).toPrecision(4);
      let d = Math.trunc(Number(dStep)) + 1;
      return {
        row: c,
        col: d,
        code: mateData.code,
        digit: mateData.digit,
      };
    } else {
      return null;
    }
  };

4、综合代码

/**
 * 采用标准:国家基本比例尺地形图分幅和编号《GB/T 13989-2012》
 * 1、根据经纬度计算图幅号
 * 2、根据图幅号图幅范围计算
 * 3、定义图幅信息
 */
export default class MapFrameUtils {
  /**
   * 根据经纬度计算100万比例尺的行列号
   * @param lon
   * @param lat
   * @return {{col: number, row: number, code: string}}
   */
  static calcMapFrameNumber100 = (lon, lat) => {
    let a = Math.trunc(lat / 4.0) + 1;
    let b = Math.trunc(lon / 6.0) + 31;
    let mateInfo = MapFrameUtils.mateData100.find(
      (item) => item.rowNumber === a
    );
    return {
      row: a,
      col: b,
      code: mateInfo.rowCode,
    };
  };
  /**
   * 根据比例尺,经纬度计算地图的行列号
   * @param scale
   * @param lon
   * @param lat
   * @return {{col: number, code: *, row: number, digit: (number|*)}|null}
   */
  static calcMapFrameNumberNot100 = (scale, lon, lat) => {
    let mateData = MapFrameUtils.mateData.find((item) => item.scale === scale);
    if (mateData) {
      let cStep = ((lat % 4) / mateData.latD).toPrecision(4);
      let c = Math.round(4 / mateData.latD - Math.trunc(Number(cStep)));
      let dStep = ((lon % 6) / mateData.lonD).toPrecision(4);
      let d = Math.trunc(Number(dStep)) + 1;
      return {
        row: c,
        col: d,
        code: mateData.code,
        digit: mateData.digit,
      };
    } else {
      return null;
    }
  };
  /**
   * 根据计算出来的行列号,比例尺,计算该格网在地图商的范围
   * @param frame100
   * @param frameNot100
   * @param scale
   * @return {{minY: number, minX: number, maxY: number, maxX: number}}
   */
  static calcMapFrameExtent = (frame100, frameNot100, scale) => {
    let mateData = MapFrameUtils.mateData.find((item) => item.scale === scale);
    let lon = (frame100.col - 31) * 6 + (frameNot100.col - 1) * mateData.lonD;
    let lat =
      (frame100.row - 1) * 4 +
      (4 / mateData.latD - frameNot100.row) * mateData.latD;

    return {
      minX: lon,
      minY: lat,
      maxX: lon + mateData.lonD,
      maxY: lat + mateData.latD,
    };
  };
  /**
   * 根据比例尺和经纬度,获取所在图幅范围的编号、行列号以及范围
   * @param scale
   * @param lon
   * @param lat
   * @return {null|{extent: {minY: number, minX: number, maxY: number, maxX: number}, col: number, code: string, row: number}}
   */
  static calcMapFrameNumber = (scale, lon, lat) => {
    let mapFrameNumber100 = MapFrameUtils.calcMapFrameNumber100(lon, lat);
    let mapFrameNumberNot100 = MapFrameUtils.calcMapFrameNumberNot100(
      scale,
      lon,
      lat
    );
    if (mapFrameNumberNot100) {
      let code =
        mapFrameNumber100.code +
        "" +
        mapFrameNumber100.col +
        "" +
        mapFrameNumberNot100.code +
        "" +
        mapFrameNumberNot100.row
          .toString()
          .padStart(mapFrameNumberNot100.digit, "0") +
        "" +
        mapFrameNumberNot100.col
          .toString()
          .padStart(mapFrameNumberNot100.digit, "0");
      let extent = MapFrameUtils.calcMapFrameExtent(
        mapFrameNumber100,
        mapFrameNumberNot100,
        scale
      );
      return {
        code: code,
        extent: extent,
        row: mapFrameNumberNot100.row,
        col: mapFrameNumberNot100.col,
      };
    } else {
      return null;
    }
  };
  /**
   * 100万比例尺下的行号对应的代码
   */
  static mateData100 = [
    {
      rowCode: "A",
      rowNumber: 1,
    },
    {
      rowCode: "B",
      rowNumber: 2,
    },
    {
      rowCode: "C",
      rowNumber: 3,
    },
    {
      rowCode: "D",
      rowNumber: 4,
    },
    {
      rowCode: "E",
      rowNumber: 5,
    },
    {
      rowCode: "F",
      rowNumber: 6,
    },
    {
      rowCode: "G",
      rowNumber: 7,
    },
    {
      rowCode: "H",
      rowNumber: 8,
    },
    {
      rowCode: "I",
      rowNumber: 9,
    },
    {
      rowCode: "J",
      rowNumber: 10,
    },
    {
      rowCode: "K",
      rowNumber: 11,
    },
    {
      rowCode: "L",
      rowNumber: 12,
    },
    {
      rowCode: "M",
      rowNumber: 13,
    },
    {
      rowCode: "N",
      rowNumber: 14,
    },
    {
      rowCode: "O",
      rowNumber: 15,
    },
  ];
  /**
   * 非100万情况下,不同比例尺的原始数据
   */
  static mateData = [
    {
      scale: 500000,
      label: "1:50万",
      lonD: 3,
      latD: 2,
      code: "B",
      digit: 3,
    },
    {
      scale: 250000,
      label: "1:25万",
      lonD: 1.5,
      latD: 1,
      code: "C",
      digit: 3,
    },
    {
      scale: 100000,
      label: "1:10万",
      lonD: 0.5,
      latD: 0.33333333,
      code: "D",
      digit: 3,
    },
    {
      scale: 50000,
      label: "1:5万",
      lonD: 0.25,
      latD: 0.16666667,
      code: "E",
      digit: 3,
    },
    {
      scale: 25000,
      label: "1:2.5万",
      lonD: 0.125,
      latD: 0.08333333,
      code: "F",
      digit: 3,
    },
    {
      scale: 10000,
      label: "1:1万",
      lonD: 0.0625,
      latD: 0.04166667,
      code: "G",
      digit: 3,
    },
    {
      scale: 5000,
      label: "1:5000",
      lonD: 0.03125,
      latD: 0.02083333,
      code: "H",
      digit: 3,
    },
    {
      scale: 2000,
      label: "1:2000",
      lonD: 0.01041667,
      latD: 0.006944444,
      code: "I",
      digit: 3,
    },
    {
      scale: 1000,
      label: "1:1000",
      lonD: 0.005208333,
      latD: 0.003472222,
      code: "J",
      digit: 4,
    },
    {
      scale: 500,
      label: "1:500",
      lonD: 0.002603889,
      latD: 0.001736111,
      code: "K",
      digit: 4,
    },
  ];
}

5、测试结果

5.1 测试代码

MapFrameUtils.mateData.forEach((item) => {
  let mapFrame = MapFrameUtils.calcMapFrameNumber(item.scale, 114.5625, 39.375);
  console.log(item.scale, mapFrame);
});

5.2 测试结果

与标准中结果一致

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生活真难

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值