计算JSON多段线的中点(Python 2.7.0,无库)
情景: 我有一个向web服务发出请求的服务器计算JSON多段线的中点(Python 2.7.0,无库),python,json,python-2.7,jython,polyline,Python,Json,Python 2.7,Jython,Polyline,情景: 我有一个向web服务发出请求的服务器 web服务返回一个JSON对象 JSON对象包含数组中的多段线顶点 JSON对象的一个小片段是: { "objectIdFieldName": "OBJECTID", "globalIdFieldName": "", "geometryType": "esriGeometryPolyline", "spatialReference": { "wkid": 476, "latestWkid": 476 },
- 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顶点,我想计算多段线的中点(见下面的绿点):
- 一些行(ObjectID 3716和3385)是多部分的。在这种情况下,只能为直线的最长部分(而不是其他部分)生成中点
- 为了解决这个问题,JSON文本可以保存为文本文件,并加载到python脚本中。在本例中,可以使用Python的JSON库——尽管下面提到了catch
输出如下所示(格式可能不同):
捕获物: 这需要在Python2.7.0中完成——因为我的系统使用2.7.0
- 需要注意的是,我无法将任何Python库导入到我正在使用的系统中的Jython实现中。因此,不幸的是,脚本不应该导入任何python库(用于测试的JSON库除外)
是否可以使用Python 2.7.0计算JSON多段线的中点(无需导入库)?是的,您可以仅使用内置Python函数/无需导入外部库轻松计算多段线的中点 让我们打破你的要求:
- 在对象的
字段中迭代该特征features
- 能够计算多段线的长度
- 如果有多条要素,请为每个要素拾取最长的多段线
- 找到此多段线的中点(如注释中所建议的,可以通过求和多段线线段的长度沿多段线前进,直到确定位于中点之间的两个点,并使用
# 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)
),我得到的(视觉)结果与提供的结果非常接近,所以,也许这就是为什么你想说行中最长的部分
,但我不确定 是的,您可以仅使用内置Python函数/轻松计算多段线的中点,而无需导入外部库
让我们打破你的要求:
- 在对象的
字段中迭代该特征features
- 能够计算多段线的长度
- 如果有多条要素,请为每个要素拾取最长的多段线
- 找到此多段线的中点(如注释中所建议的,可以通过求和多段线线段的长度沿多段线前进,直到确定位于中点之间的两个点,并使用
# 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)
),我得到的(视觉)结果与提供的结果非常接近,所以,也许这就是为什么你想说行中最长的部分
,但我不确定 总长度是每段(或弧,如果可以得到其半径)长度的总和。中点可以通过增加长度来计算,直到达到总长度的一半。你能给我上面的输入多段线的输出样本吗?@Bluespider我提供了一个输出样本(并对问题进行了总体更新)。谢谢。总长度是每段(或弧,如果你能得到它的半径)长度的总和。中点可以通过增加长度来计算,直到达到总长度的一半。你能给我上面的输入多段线的输出样本吗?@Bluespider我提供了一个输出样本(并对问题进行了总体更新)。谢谢,谢谢!关于你在答案末尾的注释:是的,我在寻找长度最长的部分,而不是顶点最多的部分。我最初在问题的建议结果集中包含了错误的部分(最短的部分,但更多的顶点)。对不起;我已经改正了,没问题!希望有帮助!非常感谢。关于你在答案末尾的注释:是的,我在寻找长度最长的部分,而不是顶点最多的部分。我最初在问题的建议结果集中包含了错误的部分(最短的部分,但更多的顶点)。对不起;我已经改正了,没问题!希望有帮助!