2

我目前在“星搜索和排序”数据库中使用 GeoDjango,该数据库提供有关恒星和行星系统的信息并将模拟关于恒星和行星系统的信息。

我正在使用 GeoDjango 1)因为我喜欢它并在其他地方使用它,以及 2)因为我最终想使用各种“地理”搜索功能,如距离/线/多边形变换,以进行我找不到的复杂而酷的体积查询别处。

我已经启动并运行了系统(https://github.com/jaycrossler/procyon),它目前使用恒星银河坐标(已经从赤经/赤纬转换)。目前数据库中有 15 万颗星,我正在考虑增加到几百万。

一颗星在数据库中后,我构建了一个包含 GeoDjango PointField 的新表,然后用银河 X、Y、Z 坐标(以秒为单位,主要在 -500 到 500 的范围内)填充它. 现在,我已将 SRID 设置为 900913(这样我就有一个不会在世界线上滚动的良好坐标范围)......但是当我搜索附近的星星并按距离排序时,我只得到在一条线上的回报,而不是基于 X、Y、Z 距离真正接近的回报。

location = models.PointField(dim=3, blank=True, null=True, srid=900913)
objects = models.GeoManager()

我认为这是因为我所做的每一次搜索最终都会被包裹在一个球体的表面上,这既低效又令人费解(尽管如果它使搜索只需要一行代码,我对此很满意)。

我在 Django 中使用的当前搜索是:

    origin = self.location

    distance = 1000
    close_by_stars = StarModel.objects.filter(location__distance_lte=(origin, D(m=distance))).distance(origin).order_by('distance')
    for s in close_by_stars[:200]:
      #export results

但是返回的结果不是我所期望的(我认为它们会聚集在一颗星周围,而不是在一条线上),可视化: 从搜索中可视化的星星

所以,最大的问题是:1)我应该使用 SRID,例如 900913(球形墨卡托)还是 2)是否有没有映射到行星表面的 SRID,这样我就可以在 X、Y 上搜索, Z 距离而不会将 -180 滚动到 +180(或基于投影系统的任何等效值)?我尝试使用 SRID=0,但 geodjango 比 pukes 和不允许这样做。

4

1 回答 1

1

我有一个修复程序,我在这里分享它可能会帮助其他人。

我认为问题在于'location__distance_lte ='函数在POSTGIS中转换为地理函数':ST_DWithin

通过查看 pg_log/latest,我看到了 SQL 命令:

SELECT (ST_Distance("modelname"."location",
ST_GeomFromEWKB('\x01010000a031bf0d0021e527d53e2963409f3c2cd49ab2404081b22957787d5540'::bytea))) AS "distance",
"modelname"."info", "modelname"."location" 
FROM "modelname" WHERE ST_Distance("modelname"."location",
ST_GeomFromEWKB('\x01010000a031bf0d0021e527d53e2963409f3c2cd49ab2404081b22957787d5540'::bytea))
<= 10.0 ORDER BY "distance" ASC

因此,当按 X、Y、Z 搜索并寻找最近的点时,它只在 2D 空间内搜索 - 并寻找 X、Y 距离内的点……而不是 Z 内的点。

有一个 ST_3DDWithin ( http://postgis.net/docs/ST_3DDWithin.html ) 但不幸的是 Django 不知道它:https://github.com/django/django/blob/master/django/contrib/gis /db/backends/postgis/operations.py#L154

我可以使用原始 sql 方法,而不是覆盖 django 源代码:https ://docs.djangoproject.com/en/dev/topics/db/sql/#django.db.models.Manager.raw 。但是,那么 orm 将失去很多它的好处。

但相反,我决定变得更简单/更复杂。我保留了相同的搜索(它基本上返回一个“圆柱体”而不是一个结果球体)。然后,在函数中,我遍历结果并解析出不在球形结果中的结果:

origin = item.location
origin_array = numpy.array((origin.x, origin.y, origin.z))

close_by_stars = star_model.objects.filter(location__distance_lte=(origin, D(m=distance))).distance(origin).order_by('distance')

star_list = []
for s in close_by_stars:
    location_array = numpy.array((s.location.x, s.location.y, s.location.z))

    dist = numpy.linalg.norm(origin_array - location_array)
    if dist > distance:
        continue

    star_handle = dict()
    star_handle['data'] = s.data ...
于 2013-12-09T03:31:16.057 回答