如何在Leaflet中绘制天梭的椭圆(Tissot's indicatrix)

How to draw Tissot's ellipse (Tissot's indicatrix) in Leaflet

OpenLayers supports tissot's ellipses natively by adding a sphere to the circular() method.

很遗憾 Leaflet L.circle() 不支持此功能。

如何使用 Leaflet 绘制天梭的椭圆?

编辑 3:

使用 leaflet-geodesy 的新命题似乎非常适合您的需要。它免除了 Turf 的错误(请参阅下面的编辑 2)。

API很简单:

LGeo.circle([51.441767, 5.470247], 500000).addTo(map);

(以 [latitude, longitude] 度为单位的中心位置,以米为单位的半径)

演示:http://jsfiddle.net/ve2huzxw/61/

与 nathansnider 的解决方案进行快速比较:http://fiddle.jshell.net/58ud0ttk/2/

(表明两个代码产生相同的结果面积,唯一的区别在于用于近似面积的段数)

编辑:一个很好的页面,将 Leaflet-geodesy 与标准 L.Circle 进行比较:https://www.mapbox.com/mapbox.js/example/v1.0.0/leaflet-geodesy/


编辑 2:

不幸的是 Turf 使用 JSTS Topology Suite 构建缓冲区。貌似JSTS中的这个操作不适合像地球表面这样的非平面几何。

错误已报告 here,截至今天,主要的 Turf 库还没有完整的解决方法。

所以下面的答案(编辑 1)产生了错误的结果

请参阅 了解围绕某个点构建缓冲区的解决方法。


编辑 1:

您可以使用 Turf 轻松构建所描述的多边形。它提供了 turf.buffer 方法,该方法在给定要素(可以是一个简单的点)周围创建具有指定距离的多边形。

所以你可以简单地做例如:

var pt = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Point",
    "coordinates": [5.470247, 51.441767]
  }
};

var buffered = turf.buffer(pt, 500, 'kilometers');

L.geoJson(pt).addTo(map);
L.geoJson(buffered).addTo(map);

演示:http://jsfiddle.net/ve2huzxw/41/


原回答:

不幸的是,目前似乎没有 Leaflet 插件可以这样做。

也不太清楚Tissot indicatrix应该代表什么:

  1. 表示无限小圆变形(即单点变形)的真椭圆,或
  2. 一个类似圆形的形状,代表地球表面上有限大小的圆的变形,就像您 link 到的 OpenLayers 演示一样?

在该演示中,EPSG:4326 中的形状不是椭圆,与形状的另一半相比,垂直轴的长度在较高纬度处减小。

如果您正在寻找第二个选项,那么您将不得不手动构建一个多边形来表示球体和地球表面的交点。如果我的理解是正确的,这就是OL demo所做的。如果这是你的选择,也许你可以在那里生成你的多边形并将它们作为 GeoJSON 特征导入 Leaflet? :-)

因为 turf.buffer 目前似乎有一个错误,这里有一个与 turf.js 不同的方法,这次使用 turf.destination 在一定范围内旋转来创建一个真实的圈子:

//creates a true circle from a center point using turf.destination
//arguments are the same as in turf.destination, except using number of steps 
//around the circle instead of fixed bearing. Returns a GeoJSON Polygon as output.

function tissotish(center, radius, steps, units) {
    var step_angle = 360/steps;
    var bearing = -180;
    var tissot = { "type": "Polygon",
    "coordinates": [[]]
    };
    for (var i = 0; i < steps + 1; ++i) {
        var target =  turf.destination(center, radius, bearing, units);
        var coords = target.geometry.coordinates;
        tissot.coordinates[0].push(coords);
        bearing = bearing + step_angle;
    }
    return tissot;
}

这不会产生真正的 Tissot 指示线(应该测量单个点的失真),但它确实会产生一个真正的圆,从您的其他评论来看,这似乎正是您要找的东西.这是一个例子 fiddle:

http://fiddle.jshell.net/nathansnider/58ud0ttk/

为了比较,我在此处添加了与上面 相同的测量线。 (点线的时候确实说高纬度的水平距离大于500km,但那是因为我画出来的线稍微延伸到圆圈外,懒得裁剪了他们。)