You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Maps Polyline提取与Buffer操作断言失败问题求助

解决Django+PostGIS项目中生成路线缓冲区时的Assertion Failed错误

嘿,我看你在开发Django项目时,遇到了Assertion failed: (0), function query, file AbstractSTRtree.cpp, line 287这个头疼的错误,结合你的代码和需求,我来帮你一步步梳理问题并解决:

首先,先修正模型里的明显错误

你的Route模型字段有几个低级错误,这可能会间接导致后续的问题:

  • startPoint_address和endPoint_address是用户输入的字符串地址,应该用CharField,不是PointField
  • Pointfield拼写错了,应该是PointField(注意大写的F)
  • 导入django.contrib.gis.db.models后就不需要再导入普通的models了,GIS模块已经包含了所有字段类型

修正后的模型代码:

from django.contrib.gis.db import models

class Route(models.Model):
    startPoint_address = models.CharField(max_length=255)
    startPoint_geolocation = models.PointField()
    endPoint_address = models.CharField(max_length=255)
    endPoint_geolocation = models.PointField()
    routeName = models.CharField(max_length=50, blank=True)
    deviationDistance = models.IntegerField(default=1000)  # 默认1km缓冲区

分析错误的核心原因

你遇到的这个断言错误,大概率是两个问题导致的:

  1. 缓冲区单位错误:Google返回的坐标是WGS84(EPSG:4326),单位是度,你用buffer(0.00001)相当于只缓冲了约1米的距离,这个值太小了,会让Shapely生成无效的多边形,触发底层的空间索引错误。
  2. 几何对象无效:解码后的polyline可能存在重复点、自相交的情况,也会导致缓冲区计算失败。

正确的缓冲区生成流程(转投影坐标系)

因为WGS84是地理坐标系,直接做缓冲区距离不准确(1度≈111km),所以必须先转换到投影坐标系(比如UTM,单位是米),生成1km缓冲区后再转回WGS84:

我帮你重写了核心逻辑,还去掉了没必要的自定义解码函数(Django GIS已经内置了这个功能):

import shapely.geometry
import shapely.ops
import googlemaps
from django.contrib.gis.geos import Point, Polygon, LineString

# 初始化Google Maps客户端
gmaps = googlemaps.Client(key='AIzaSyCetShZ10WQVBVPaIu9pdPEktRVQq78TF4')

# 获取路线数据
google_directions = gmaps.directions("Stellenbosch", "Cape Town")
encoded_polyline = google_directions[0]['overview_polyline']['points']

# 用Django GIS内置方法解码polyline,比自己写的可靠
decoded_line = LineString.from_encoded(encoded_polyline)

# 先修复可能无效的几何(比如自相交、重复点)
if not decoded_line.valid:
    decoded_line = decoded_line.buffer(0)

# 自动匹配合适的UTM投影带(根据路线中心点)
center = decoded_line.centroid
utm_zone = int((center.x + 180) / 6) + 1
# 南半球用327xx,北半球用326xx
utm_crs = f'EPSG:326{utm_zone}' if center.y >= 0 else f'EPSG:327{utm_zone}'

# 把路线转换到UTM坐标系(单位米)
projected_line = shapely.ops.transform(
    lambda x, y: Point(x, y).transform(utm_crs, clone=True).coords[0],
    decoded_line
)

# 生成1km缓冲区(这里的1000就是米)
buffered_line = projected_line.buffer(1000)

# 转换回WGS84坐标系,方便存入PostGIS
buffered_wgs84 = shapely.ops.transform(
    lambda x, y: Point(x, y).transform('EPSG:4326', clone=True).coords[0],
    buffered_line
)

# 转为Django GIS的Polygon对象,直接存数据库
django_polygon = Polygon(buffered_wgs84.exterior.coords)

额外的注意事项

  • 永远不要自己写polyline解码函数,Django GIS的LineString.from_encoded()已经经过测试,比自定义实现更稳定。
  • 确保你的PostGIS数据库已经正确配置,并且运行过makemigrations和migrate命令,创建了对应的GIS字段。
  • 如果还是遇到几何无效的问题,可以在生成缓冲区前强制修复几何:decoded_line = decoded_line.simplify(0.00001)(简化冗余点)。

完整的视图示例(处理用户输入)

假设你要在视图里处理用户提交的起点和终点,这里给你一个参考:

from django.shortcuts import render
from .models import Route

def create_route(request):
    if request.method == 'POST':
        start_addr = request.POST.get('start')
        end_addr = request.POST.get('end')
        
        gmaps = googlemaps.Client(key='AIzaSyCetShZ10WQVBVPaIu9pdPEktRVQq78TF4')
        
        # 获取起点和终点的经纬度
        start_geo = gmaps.geocode(start_addr)[0]['geometry']['location']
        end_geo = gmaps.geocode(end_addr)[0]['geometry']['location']
        
        # 获取路线polyline并处理缓冲区
        directions = gmaps.directions(start_addr, end_addr)
        encoded_polyline = directions[0]['overview_polyline']['points']
        decoded_line = LineString.from_encoded(encoded_polyline)
        
        if not decoded_line.valid:
            decoded_line = decoded_line.buffer(0)
        
        center = decoded_line.centroid
        utm_zone = int((center.x + 180) / 6) + 1
        utm_crs = f'EPSG:326{utm_zone}' if center.y >=0 else f'EPSG:327{utm_zone}'
        
        projected_line = shapely.ops.transform(
            lambda x, y: Point(x, y).transform(utm_crs, clone=True).coords[0],
            decoded_line
        )
        
        buffered_line = projected_line.buffer(1000)
        buffered_wgs84 = shapely.ops.transform(
            lambda x, y: Point(x, y).transform('EPSG:4326', clone=True).coords[0],
            buffered_line
        )
        
        django_polygon = Polygon(buffered_wgs84.exterior.coords)
        
        # 保存到数据库
        Route.objects.create(
            startPoint_address=start_addr,
            startPoint_geolocation=Point(start_geo['lng'], start_geo['lat']),
            endPoint_address=end_addr,
            endPoint_geolocation=Point(end_geo['lng'], end_geo['lat']),
            # 如果你的模型里有存储缓冲区的字段,比如:
            # route_buffer=django_polygon
        )
        
        return render(request, 'route_success.html')
    
    return render(request, 'route_form.html')

内容的提问来源于stack exchange,提问作者Petrus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:48:04