操作系统数据中心 - 网格参考中的邮政编码

Posted

技术标签:

【中文标题】操作系统数据中心 - 网格参考中的邮政编码【英文标题】:OS Data Hub - Postcode from Grid Reference 【发布时间】:2021-03-15 08:00:15 【问题描述】:

我负责管理英格兰西南部一家步行俱乐部的网站,该网站显示了即将举行的步行活动列表。每个步行条目都有一个用于步行开始的操作系统网格参考,以及一个步行者可以输入到他们的 SatNav 设备的英国邮政编码,以帮助他们开车到步行的起点。我目前使用 Nearby UK 的 API 获得每次步行的起点网格参考最近的邮政编码,这也为我提供了罗盘方位和从网格参考到邮政编码中心的距离,在一个国家地区可以是从步行开始一英里或更多。从这些我计算出邮政编码中心的网格参考,然后我可以将两个点都显示为 OS 地图上的标记 - 到目前为止,一切都很好。

最近完成了从 OS Open Space 到 OS Data Hub 的迁移,我想知道是否还可以使用 OS Data Hub 为我提供离网格参考最近的邮政编码,以及从一个到另一个的方位角和距离,或者邮政编码中心的网格参考,而不需要为此使用 Nearby API。

大约一个月前,我向 Ordnance Survey 的客户成功团队询问了这个问题,但他们还没有提供任何帮助。我还尝试了使用英国邮政编码数据库的各种方法,该数据库列出了每个英国邮政编码及其东和北坐标,但在整个列表中搜索寻找最近的坐标,使用毕达哥拉斯计算距离一个步行起点,需要几分钟。这可能是因为我必须使用我们的 walks 数据库进行搜索,该数据库是用 Visual Basic 编写的,但这是另一回事。

任何关于如何从 OS Data Hub 获取最近的邮政编码及其位置的指针,对于给定的网格参考,都将受到欢迎。

【问题讨论】:

【参考方案1】:

你可以找到最近的邮政编码,只要它的中心距离不超过1公里,例如

https://api.os.uk/search/names/v1/nearest?point=440200,458300&radius=1000&fq=LOCAL_TYPE:Postcode&key=yourkey

超过 1 公里,您需要在原点周围的外圈内进一步搜索

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Basic Map</title>
    <link rel="stylesheet" href="https://labs.os.uk/public/os-api-branding/v0.2.0/os-api-branding.css" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" />
    <style>
        body  margin:0; padding:0; 
        #map  position:absolute; top:0; bottom:0; width:100%; 
    </style>
</head>
<body>

<div id="map"></div>

<script src="https://labs.os.uk/public/os-api-branding/v0.2.0/os-api-branding.js"></script>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
<script>

    var apiKey = 'ufArYa1UUPHJcOYbiJDaKkA7Fb4oCkEs';

    var serviceUrl = 'https://api.os.uk/maps/raster/v1/zxy';

    // Setup the EPSG:27700 (British National Grid) projection.
    proj4.defs("EPSG:27700", "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m +no_defs");
    ol.proj.proj4.register(proj4);

    var tilegrid = new ol.tilegrid.TileGrid(
        resolutions: [ 896.0, 448.0, 224.0, 112.0, 56.0, 28.0, 14.0, 7.0, 3.5, 1.75 ],
        origin: [ -238375.0, 1376256.0 ]
    );

    var gridReference = new ol.Feature();
    gridReference.setStyle(
        new ol.style.Style(
            image: new ol.style.Circle(
                radius: 6,
                fill: new ol.style.Fill(
                    color: 'red'
                )
            ),
            text: new ol.style.Text(
                font: 'bold 14px sans-serif',
                offsetY: -6,
                textBaseline: 'bottom'
            )
        )
    );

    var postcode = new ol.Feature();
    postcode.setStyle(
        new ol.style.Style(
            image: new ol.style.Circle(
                radius: 6,
                fill: new ol.style.Fill(
                    color: 'blue'
                )
            ),
            text: new ol.style.Text(
                font: 'bold 14px sans-serif',
                offsetY: -6,
                textBaseline: 'bottom'
            )
        )
    );

    // Initialize the map object.
    var map = new ol.Map(
        layers: [
            new ol.layer.Tile(
                source: new ol.source.XYZ(
                    url: serviceUrl + '/Road_27700/z/x/y.png?key=' + apiKey,
                    projection: 'EPSG:27700',
                    tileGrid: tilegrid
                )
            ),
            new ol.layer.Vector(
                source: new ol.source.Vector(
                    features: [gridReference, postcode]
                )
            )
        ],
        target: 'map',
        view: new ol.View(
            projection: 'EPSG:27700',
            extent: [ -238375.0, 0.0, 900000.0, 1376256.0 ],
            resolutions: tilegrid.getResolutions(),
            minZoom: 0,
            maxZoom: 9,
            center: [ 337297, 503695 ],
            zoom: 7
        )
    );

    map.on('singleclick', function(evt) 
        gridReference.setGeometry(new ol.geom.Point(evt.coordinate));
        postcode.setGeometry(undefined);

        var x = (Math.round(evt.coordinate[0]/10)/10) + 10000;
        var y = (Math.round(evt.coordinate[1]/10)/10) + 5000;

        var a1y = (4 - (Math.floor(y/5000)%5))*5;
        var a2y = (4 - (Math.floor(y/1000)%5))*5;
        var y1 = Math.floor(y/100)%10;
        var y2 = Math.floor(y/10)%10;
        var y3 = Math.floor(y)%10;
        a1y += (Math.floor(x/5000)%5);
        a2y += (Math.floor(x/1000)%5);
        var x1 = Math.floor(x/100)%10;
        var x2 = Math.floor(x/10)%10;
        var x3 = Math.floor(x)%10;

        var grid500km = String.fromCharCode(a1y + Math.floor((a1y+17)/25) + "A".charCodeAt(0));
        var grid100km = grid500km + String.fromCharCode(a2y + Math.floor((a2y+17)/25) + "A".charCodeAt(0));
        var gridText = grid100km + x1 + x2 + x3 + y1 + y2 + y3;

        gridReference.getStyle().getText().setText(gridText);

        var minDistSq = Infinity;
        var postcodeCoord, postcodeText;
        var radius = 0;
        tryPoints([evt.coordinate]);

        function tryPoints(coordinates) 

            var promises = [];

            coordinates.forEach(function(coordinate) 
                promises.push(
                    fetch(
                        'https://api.os.uk/search/names/v1/nearest?point=' +
                        coordinate[0].toFixed(2) + ',' + coordinate[1].toFixed(2) +
                        '&radius=1000&fq=LOCAL_TYPE:Postcode&key=' + apiKey
                    ).then(function(response) 
                        return response.json();
                    )
                );
            );

            Promise.all(promises).then(function(results) 
                results.forEach(function(result) 
                    if (result.results && result.results.length > 0) 
                        var entry = result.results[0]['GAZETTEER_ENTRY'];
                        var dx = entry['GEOMETRY_X'] - evt.coordinate[0];
                        var dy = entry['GEOMETRY_Y'] - evt.coordinate[1];
                        var distSq = dx * dx + dy * dy;
                        if (distSq < minDistSq) 
                            minDistSq = distSq;
                            postcodeCoord = [entry['GEOMETRY_X'], entry['GEOMETRY_Y']];
                            postcodeText = entry['NAME1'];
                        
                    
                );
                if (postcodeCoord) 
                    postcode.setGeometry(new ol.geom.Point(postcodeCoord));
                    postcode.getStyle().getText().setText(postcodeText);
                 else if (radius < 4) 
                    radius++;
                    var outerCircle = ol.geom.Polygon.fromCircle(new ol.geom.Circle(evt.coordinate, radius * 1000), 16 * radius);
                    tryPoints(outerCircle.getCoordinates()[0].slice(0, -1));
                
            );

        

    );

</script>

</body>
</html>

【讨论】:

这是一个很好的起点,非常感谢,但正如迈克所说,它只允许搜索半径为 1 公里。我们的许多步行都从达特穆尔的公共停车场开始,其中一些距离最近的邮政编码中心一英里或更多。到目前为止,我发现的最糟糕的情况是 Saddle Tor 在 1.36 英里 = 2.2 公里处,因此为了留出安全余量,我需要能够搜索到 3 公里。附近的英国很高兴返回 10 公里或更远的结果,所以可能没有使用 OS Data Hub。 您可以在原点周围的外圈进行进一步搜索,并且由于它是开放数据,您可以使用免费密钥。我在答案中添加了一个示例,从原始点延伸至 4 公里的 1 公里搜索环应该足以用于除苏格兰偏远地区以外的任何道路可到达的地方(单击地图以显示网格参考和最近的邮政编码) . Mike 的最新回答让我更进一步,我非常感激。从我已经完成的从 OS Open Space 迁移到 OS Data Hub 的工作中,我可以看到他的示例 javascript 代码的一般偏差,但鉴于我的专业知识有限,我可能需要几天时间才能更全面地理解它!我看到对于一些地图参考,例如 SX 930 704,Mike 的代码和 Nearby UK API 返回不同的邮政编码,这将是有趣的调查。再次,非常感谢。 我的代码在圆周上每 1 公里半径使用 16 个采样点,因此它们相距约 200 米。这不如使用直线,如果有两个候选邮政编码与起点的距离相差不到 200 米,则可能会选择错误的邮政编码。使用更多的样本点会提高准确性,但需要更多的 API 调用并花费更长的时间。 天哪 - 鸡蛋面时间!修改 Mike 的代码以显示邮政编码与原始网格参考的距离后,我现在发现对于我引用的示例 (SX 930 704),Mike 的代码返回的邮政编码实际上比 Nearby UK API 提供的邮政编码更接近。尽管如此,他对他的代码如何克服邮政编码搜索 1 公里限制的解释仍然受到欢迎。

以上是关于操作系统数据中心 - 网格参考中的邮政编码的主要内容,如果未能解决你的问题,请参考以下文章

在 onChange 事件中引用可操作的网格

DevExpress的gridControl怎么删除网格中的一行

刷新剑道网格,选择框

CUDA笔记(一)线程与数据量的关系

如何通过 Excel 中的展开和折叠操作将网格数据沿组标题/摘要记录导出到 Excel?

鸿蒙系统中的TableLayout网格布局