亲爱的stackoverflow读者,
我目前正在开发一个需要根据其坐标加载特定项目的应用程序。示例:我希望所有商店都来自坐标x或距其15公里。
我一直在Java EE 6中构建这个Web应用程序,并使用Hibernate 3.3将数据持久化到我的Postgres数据库。经过一番研究,我发现Hibernate-Spatial是实现目标的可能性。我安装了Postgis并运行了Hibernate-Spatial。
我正在使用Hibernate 3.3,Hibernate-Spatial 1.0,PostgreSQL 9.2和postgis-jdbc 1.3.3。
我创建了一个具有位置字段的实体:
@Column(columnDefinition = "Geometry", nullable = true)
@Type(type = "org.hibernatespatial.GeometryUserType")
private Point location;
最初我以为我可以创建一个Circle并基本上查询位于圆圈中的每个点。但这似乎比我想象的更难。我开始认为我选择使用Hibernate-Spatial是错误的。
我的问题是,是否可以通过使用Hibernate-Spatial查询特定边界内的每个点(从那里坐标x和y km)。
我也对解决我的要求的其他可能性感兴趣。我一直在考虑以下可能性:
任何人都可以提供一个例子,说明如何在Hibernate-Spatial中实现我的愿望,或者我如何以另一种方式实现我的要求。
答案 0 :(得分:6)
对于PostgreSQL / PostGIS方言,Hibernate Spatial支持dwithin
功能。
boolean dwithin(Geometry, Geometry, double)
- 如果是,则返回true 几何形状在彼此指定的距离内
解释Hibernate Spatial tutorial,查询看起来像这样:
String wktCenterPoint = "POINT(10 15)"
Geometry centerPoint = wktToGeometry(wktCenterPoint);
...
Query query = em.createQuery("select e from Event e where dwithin(e.location, :centerPoint, 15) = true", Event.class);
...
这将返回距离中心点15个单位内的所有事件。
但dwithin
中给出的距离与基础数据集的距离相同,不一定是千米。如果数据集单位为米,则距离将被视为米。
如果数据集在lat-lng中,则距离将为度。如果是这种情况,并且您的搜索距离很小(15 Km很小),并且您处于低纬度,那么您可以将Km近似为0.009。这将在赤道上为您提供一个完美的搜索圆,但是当您向北或向南移动时,这个圆将变成椭圆形,长轴指向北方和南方。在纬度+/- 60度时,椭圆的高度是宽度的两倍。显然不理想,但它可能适用于您的情况。
另一种方法是将数据集重新投影并存储在PostgreSQL中,作为投影数据集,单位为米。如果在地图上大规模显示,这会使您的数据失真,但您的搜索将按预期工作。
答案 1 :(得分:3)
上面的答案是不正确的,该参数描述的距离不是以公里为单位(如果你在足够高的纬度做工作,你可以将它转换成米或公里,任何准确度) 。请记住,如果在经度 - 纬度坐标上使用任何空间函数,那么您实际上将地图压缩为equirectangle projection,然后在那里进行计算。
DWITHIN能够在球体上进行计算,但只有在您提供地理数据时,它才会接受米作为其度量单位。
Hibernate Spatial 不支持地理类型(this bug 3年未解决,所以不要屏住呼吸)。
如果你正在使用多边形区域,那么取决于你所处的位置(越接近赤道越好)并且根据你正在检查的区域的大小,坐标计算方式的失真将是公平的最小的几何坐标。
因此,多边形区域或多或少会有一点失真。
长话短说,Hibernate Spatial不支持一种简单的方法来存储地理数据并对其执行操作。它支持将数据存储为投影的更高级和更困难的方法,并对此进行基本的笛卡尔数学运算。
编辑:请参阅@ lreeder的更新答案,该答案已经澄清。
答案 2 :(得分:0)
通过以下提及代码,您可以获得50至110米范围内的所有位置,因为我使用0.001,您可以根据需要使用距离。
GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326);
factory.createPoint(new Coordinate(longitude,latitude));
Point comparisonPoint = factory.createPoint(new Coordinate(longitude,latitude));
predicates.add(SpatialPredicates.distanceWithin(cb, geom from db), comparisonPoint, 0.001));
distanceWithin()函数以距离为单位进行距离转换,该距离必须转换为地理坐标,但是休眠Spatial不支持,因此还有另一种方法可以根据需要以十进制距离提供距离。小数点。
用于十进制转换 LINK :https://en.wikipedia.org/wiki/Decimal_degrees
用于创建geom并在数据库中添加扩展名 LINK :https://www.compose.com/articles/geofile-everything-in-the-radius-with-postgis/