计算JSON多段线的中点(Python2.7.0,无库)

2024-10-03 04:33:29 发布

您现在位置:Python中文网/ 问答频道 /正文

场景:

我有一个system向web服务发出请求。你知道吗

  • web服务返回一个JSON对象。你知道吗
  • JSON对象包含数组中的多段线顶点。你知道吗

JSON对象的一个小片段是:

{
  "objectIdFieldName": "OBJECTID",
  "globalIdFieldName": "",
  "geometryType": "esriGeometryPolyline",
  "spatialReference": {
    "wkid": 476,
    "latestWkid": 476
  },
  "fields": [
    {
      "name": "OBJECTID",
      "alias": "OBJECTID",
      "type": "esriFieldTypeOID"
    }
  ],
  "features": [
    {
      "attributes": {
        "OBJECTID": 3311
      },
      "geometry": {
        "paths": [
          [
            [
              675844.1562959617,
              4861766.9811610579
            ],
            [
              675878.30397594348,
              4861792.5977392439
            ],
            [
              675891.38832408097,
              4861800.4024024364
            ],
            [
              675902.17710777745,
              4861804.9933949765
            ],
            [
              675912.27726199664,
              4861808.2070551421
            ],
            [
              675923.52513550781,
              4861810.2730065044
            ],
            [
              675934.77300901897,
              4861811.1911861338
            ],
            [
              675943.03676202707,
              4861811.1911861338
            ],
            [
              675951.07095439639,
              4861810.502546167
            ],
            [
              675961.17111910321,
              4861808.6661449578
            ],
            [
              675970.35304125212,
              4861806.1411667075
            ],
            [
              675981.51595173683,
              4861800.7007851209
            ],
            [
              675998.03647276573,
              4861792.2469376959
            ]
          ]
        ]
      }
    },

**The JSON object has been cut off.**

完整的JSON对象可以在这里找到:JSON Polylines


问题:

使用JSON顶点,我想计算多段线的中点(见下面的绿点):

  • 一些行(objectid3716和3385)是多部分的。在这种情况下,只能为直线的最长部分(而不是其他部分)生成中点。你知道吗
  • 为了解决这个问题,JSON文本可以保存为文本文件,并加载到python脚本中。在本例中,可以使用Python的JSON库——尽管下面提到了catch。你知道吗

enter image description here


输出如下(格式可能不同):

OBJECTID  MIDPOINT_X    MIDPOINT_Y
2165      676163.9343   4861476.373
2320      676142.0017   4861959.66
2375      676118.1226   4861730.258
2682      676060.3917   4861904.762
2683      675743.1666   4861724.081
2691      676137.4796   4861557.709
3311      675916.9815   4861809.071
3385      676208.669    4861536.555
3546      676262.2623   4861665.146
3547      676167.5738   4861612.699
3548      676021.3677   4861573.141
3549      675914.4334   4861669.87
3550      675866.6003   4861735.572
3551      675800.1232   4861827.482
3552      675681.9432   4861918.989
3716      675979.6493   4861724.323

捕获:

这需要在Python2.7.0中完成——因为我的系统使用Jython2.7.0。你知道吗

  • 需要注意的是,我不能将任何Python库导入到我使用的系统中的Jython实现中。因此,不幸的是,脚本不应该导入任何python库(除了用于测试的JSON库)。你知道吗

是否可以使用Python2.7.0(不导入库)计算JSON多段线的中点?你知道吗


Tags: 对象脚本webjson系统场景数组system
1条回答
网友
1楼 · 发布于 2024-10-03 04:33:29

是的,您可以只使用内置的Python函数/而不导入外部库来轻松计算多段线的中点。你知道吗

让我们打破你的要求:

  • 迭代对象的features字段中的功能
  • 能够计算多段线的长度
  • 如果有多条要素,请为每个要素拾取最长的多段线
  • 找到该多段线的中点(如注释中所建议的,您可以通过求其线段的长度的和来沿着多段线前进,直到您确定位于中点之间的两点,并使用vector math计算其值)

因此,我们需要一些辅助函数来计算两点之间的距离,然后是多段线的距离,依此类推:

# Euclidean distance between two points
def get_distance(p1, p2):
    return sum([(x-y)**2 for (x,y) in zip(p1, p2)]) ** (0.5)

# Length of a polyline by summing the length of its segments
def get_distance_line(line):
    total = 0
    for start_index in range(len(line) - 1):
        stop_index = start_index + 1
        total += get_distance(line[start_index], line[stop_index])
    return total

# Get the polyline with the longest distance
# within a list of polyline
def get_longest(li):
    return max(li, key=get_distance_line)

# Compute the target point at `_target_dist`
# of `p1` along the p1-p2 segment
def _get_pt_at_dist(p1, p2, _target_dist):
    # Define the vector from p1 to p2
    vx = p2[0] - p1[0]
    vy = p2[1] - p1[1]
    # Compute the length of the vector
    lv = (vx ** 2 + vy ** 2) ** 0.5
    # Compute the unit vector (the vector with length 1)
    nv = [vx / lv, vy / lv]
    # Compute the target point
    return [
        p1[0] + nv[0] * _target_dist,
        p1[1] + nv[1] * _target_dist,
    ]

# Get a point at a specific distance on a Polyline
# - 1st step to find the two points enclosing the `target_dist
# - 2nd step to calculate the midpoint along the 2 previously selected points
def get_point_at_distance(line, target_dist):
    sum_dist = 0
    for start_index in range(len(line) - 1):
        stop_index = start_index + 1
        n_dist = get_distance(line[start_index], line[stop_index])
        if sum_dist + n_dist > target_dist:
            # We have found the two enclosing points
            p1, p2 = line[start_index], line[stop_index]
            _target_dist = target_dist - sum_dist
            return _get_pt_at_dist(p1, p2, _target_dist)
        else:
            sum_dist += n_dist

    raise ValueError("target distance is greater than the length of the line")

让我们迭代您的数据(我将您的对象命名为dataset),并使用这些函数来计算中点:

result = {}

for ft in dataset['features']:
    paths = ft['geometry']['paths']

    # Pick the longest path of default to
    # the only existing one:
    if len(paths) == 1:
        p = paths[0]
    else:
        p = get_longest(paths)

    # Compute the distance
    # and the half of the distance
    # for this polyline
    distance_line = get_distance_line(p)
    middle_dist = distance_line / 2

    # Compute the midpoint and save it
    # into a `dict` using the `OBJECTID`
    # attribute as a key
    midpoint = get_point_at_distance(p, middle_dist)
    result[ft['attributes']['OBJECTID']] = midpoint

结果对象:

{3311: [675916.9814634613, 4861809.071098591],
 3385: [676208.6690235228, 4861536.554984818],
 2165: [676163.9343346333, 4861476.37263185],
 2682: [676060.391694662, 4861904.761846619],
 2683: [675743.1665799635, 4861724.081134027],
 2691: [676137.4796253176, 4861557.709372229],
 2375: [676118.1225925689, 4861730.258496471],
 2320: [676142.0016617056, 4861959.660392438],
 3716: [675979.6112380569, 4861724.356721315],
 3546: [676262.2623328466, 4861665.145686949],
 3547: [676167.5737531717, 4861612.6987658115],
 3548: [676021.3677275265, 4861573.140917723],
 3549: [675914.4334252588, 4861669.870444033],
 3550: [675866.6003329497, 4861735.571798388],
 3551: [675800.1231731868, 4861827.48182595],
 3552: [675681.9432478376, 4861918.988687315]}

请注意:首先,我选择了节点数最多的路径(而不是距离最长的路径-使用类似def get_longest(li): return max(li, key=len)的方法),结果(视觉)与提供的结果更接近,所以可能这就是为什么您在说the longest part of the line时想要的,但我不确定!

相关问题 更多 >