geojson lat lon 多边形绘制较小的内部多边形

问题描述 投票:0回答:1

我需要编写一个函数,它采用基于

lat
lon
值的 GeoJSON 并将多边形绘制到 2d 画布上。

除此之外,我还需要添加一些距离并绘制内部多边形,其中多边形的 4 个边(北、东、西、南)与外多边形的距离不同。我有一个问题,边缘坐标仅在一维中输出,在绘制多边形时,某些点/线需要通过单边(北或南等)偏移......或者在某些情况下,两侧需要偏移都要考虑在内。

有人能指出我解决问题的方向吗?到目前为止,除了绿色圆圈中的边缘情况外,大多数线条都已正确绘制。

不正确 not correct

正确的图片应该是这样的

正确

enter image description here

当前实现的codepen

https://codepen.io/Zlatko-Memisevic/pen/qBGNVgj

const exampleGeoJson = {
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature",
    "geometry": {
      "type": "Polygon",
      "coordinates": [
        [
          [9.409277330768161, 47.330294996637527],
          [9.40929555711242, 47.330394995087424],
          [9.409449188016863, 47.330385694636568],
          [9.409441872135783, 47.330340644668418],
          [9.409432145964761, 47.330341377653177],
          [9.409430621953572, 47.330332010609965],
          [9.409383287787568, 47.330335311475089],
          [9.409376169945089, 47.330288098791449],
          [9.409349057871147, 47.330289992509627],
          [9.409347814140572, 47.330283553765319],
          [9.409279252163072, 47.330288260899749],
          [9.409281541354549, 47.330294699779891],
          [9.409277330768161, 47.330294996637527]
        ]
      ]
    }
  }]
};

function drawGeoJsonOnCanvas(geoJson, canvasId, offsets) {
  const canvas = document.getElementById(canvasId);
  const ctx = canvas.getContext('2d');

  if (!canvas) {
    console.error(`Canvas element with id "${canvasId}" not found.`);
    return;
  }

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const bbox = turf.bbox(geoJson);
  const scaleX = canvas.width / (bbox[2] - bbox[0]);
  const scaleY = canvas.height / (bbox[3] - bbox[1]);

  function drawPolygon(coordinates, dotted, labelSides = false) {
    ctx.beginPath();
    coordinates.forEach((coord, index) => {
      const x = (coord[0] - bbox[0]) * scaleX;
      const y = (bbox[3] - coord[1]) * scaleY;

      if (index === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    });
    ctx.closePath();
    if (dotted) {
      ctx.setLineDash([5, 5]);
    } else {
      ctx.setLineDash([]);
    }
    ctx.stroke();

    if (labelSides) {
      for (let i = 0; i < coordinates.length - 1; i++) {
        const start = coordinates[i];
        const end = coordinates[i + 1];
        const mid = turf.midpoint(start, end);

        const midX = (mid.geometry.coordinates[0] - bbox[0]) * scaleX;
        const midY = (bbox[3] - mid.geometry.coordinates[1]) * scaleY;

        const length = turf.distance(start, end, {
          units: 'meters'
        }).toFixed(2);

        ctx.fillText(`${length}m`, midX, midY);
      }
    }
  }

  function getOffsetDistance(direction, offsets) {
    if (direction >= -45 && direction < 45) {
      return offsets.east;
    } else if (direction >= 45 && direction < 135) {
      return offsets.north;
    } else if (direction >= -135 && direction < -45) {
      return offsets.south;
    } else {
      return offsets.west;
    }
  }

  const features = geoJson.features;

  features.forEach(feature => {
    const coordinates = feature.geometry.coordinates[0];
    drawPolygon(coordinates, false, true);

    const offsettedCoordinates = [];
    for (let i = 0; i < coordinates.length - 1; i++) {
      const start = coordinates[i];
      const end = coordinates[(i + 1) % coordinates.length];

      const line = turf.lineString([start, end]);
      const direction = turf.bearing(start, end);

      const offsetDistance = getOffsetDistance(direction, offsets);
      const offsettedLine = turf.transformTranslate(line, offsetDistance, direction + 90, {
        units: 'centimeters'
      });

      offsettedCoordinates.push(offsettedLine.geometry.coordinates[0]);
      offsettedCoordinates.push(offsettedLine.geometry.coordinates[1]);
    }

    const uniqueOffsettedCoordinates = Array.from(new Set(offsettedCoordinates.map(JSON.stringify))).map(JSON.parse);
    uniqueOffsettedCoordinates.push(uniqueOffsettedCoordinates[0]); // Close the polygon

    const innerPolygon = turf.polygon([uniqueOffsettedCoordinates]);

    if (innerPolygon.geometry.type === 'Polygon') {
      const innerCoordinates = innerPolygon.geometry.coordinates[0];
      drawPolygon(innerCoordinates, true);
    }
  });
}

// Example usage
document.addEventListener('DOMContentLoaded', () => {
  const offsets = {
    north: 50, // in centimeters
    south: 50, // in centimeters
    east: 50, // in centimeters
    west: 50 // in centimeters
  };
  drawGeoJsonOnCanvas(exampleGeoJson, 'geoCanvas', offsets);
});
#geoCanvas {
  border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/6.5.0/turf.min.js"></script>
<canvas id="geoCanvas" width="800" height="600"></canvas>

javascript canvas gis geojson turfjs
1个回答
0
投票

从未见过针对您想要做的事情的开箱即用的解决方案。

一个新颖的解决方案是:

  1. 依次走各个角落
  2. 计算从该角到两条偏移线交点的方位角和距离
  3. 将所有这些点连接在一起形成一个新的多边形

这会很繁琐并且涉及一些数学,但应该相当稳健,至少对于像你所展示的那样复杂的形状是这样。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.