如何使用Oracle Spatial Java API确定点是否在多边形内?

时间:2018-02-20 21:29:55

标签: java oracle-spatial

首先我尝试了:

public static boolean isInPolygon(java.awt.geom.Point2D point) {
        // ...
        // ... build prepared statement
        ResultSet rs = statement.executeQuery();
        STRUCT geoStruct = (STRUCT) rs.getObject("SDO_GEOMETRY_COLUMN");

        JGeometry geo = JGeometry.load(geoStruct);
        Shape shape = geo.createShape();
        return shape.contains(point);           
    }

这不起作用,因为JGeometry.createShape()返回一个java.awt.geom.GeneralPath对象,它没有双精度,因此shape.contains(...)在多边形边缘周围返回错误的结果。

然后我尝试使用JGeometry.createDoubleShape()代替oracle.spatial.util.SDODoubleGeneralPath对象:

// ...
JGeometry geo = JGeometry.load(geoStruct);
Shape shape = geo.createDoubleShape();
return shape.contains(point);

调用contains方法时,出现以下错误:

Exception in thread "main" java.lang.NoSuchMethodError: sun.awt.geom.Curve.crossingsForPath(Ljava/awt/geom/PathIterator;DD)I
    at oracle.spatial.util.SDODoubleGeneralPath.contains(SDODoubleGeneralPath.java:498)
    at igea_html.test.Test.handleGeo(Test.java:258)
    at igea_html.test.Test.jgeometryTest(Test.java:204)
    at igea_html.test.Main.main(Main.java:74)

如果SDODoubleGeneralPath方法出现错误,contains显然存在一些实现问题。

有替代方案吗?

我想避免自己实现一个算法来确定一个点是否在多边形内部,我宁愿相信已经从一个有信誉的来源实现的东西。 由于许可限制,我也无法直接在数据库中使用Oracle Spatial功能。

Obs。:我的isInPolygon方法使用Point2D作为参数,但如果我必须使用JGeometry对象形式的点,以防解决方案需要它。

按要求提供更多详情:
Oracle版本是11g,我正在开发一个应用程序来验证数据库中的几何数据。特别是,其中一个验证涉及检查某些点和多边形是否在其他多边形内。我引用的文档是:https://docs.oracle.com/cd/E18283_01/appdev.112/e11829/toc.htm
这些功能的体系结构仍然是一项正在进行中的工作,因此决定是应该由Web应用程序本身还是在数据库内部或其他方法做出决定仍然是开放的。由于许可限制,第二个选项被抛到了一边,所需的功能,即SDO_RELATE,在Oracle 11中独占Oracle Spatial,显然与Oracle 12相比,只有Oracle Locator可以使用它们。 编辑:这是不正确的,如下面的@Albert Godfrind所示。 Oracle Locator 11支持SDO_RELATE和其他空间操作员 ,如Oracle的文档中所示,版本1和版本2均为: https://docs.oracle.com/cd/B28359_01/appdev.111/b28400/sdo_locator.htm#CFACCEEG
https://docs.oracle.com/cd/E11882_01/appdev.112/e11830/sdo_locator.htm#CFACCEEG

此外,Java API for Oracle 11的JGeometry类不包含isInside()anyInteract()等方法,就像它在Oracle 12上一样。 Oracle 12 Java API文档:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/spajv/index.html?oracle/spatial/geometry/JGeometry.html

1 个答案:

答案 0 :(得分:1)

你说

  

由于许可限制,我也无法直接在数据库中使用Oracle Spatial功能。

这是不正确的。 2D的所有矢量处理功能都可以免费获得数据库许可证。它被称为 Oracle Locator 。有关定位器涵盖的详细信息(https://docs.oracle.com/en/database/oracle/oracle-database/18/spatl/oracle-locator.html#GUID-EC6DEA23-8FD7-4109-A0C1-93C0CE3D6FF2),请参阅用户指南的附录B.请注意,这是12.2。旧版本的限制性更强,但所有版本都具备进行所需几何过滤的基本功能。

Oracle Spatial&图形许可证补充了基本功能,支持3D,栅格,网络,地理编码,可视化以及语义和属性图等。

除此之外,您可以自由使用JAVA API(它随Oracle Locator一起提供)。但请注意,它仅适用于JGeometry个对象。特别是方法isInside()将告诉您一个JGeometry对象(您的点)是否完全包含在另一个JGeometry对象(您的多边形)中。如果您还希望返回落在多边形边界上的点,请改用anyInteract()方法。

但是,如果您的主要处理在数据库中,那么只需使用带有SDO_INSIDE(或SDO_ANYINTERACT谓词的纯SQL来查找多边形内的所有点。

您能详细说明您的实际用例吗?

修改

以下是使用SQL API的示例。这适用于所有数据库版本,一直回到11gR1,并且由Oracle Locator涵盖(即不需要任何Spatial许可证)。

在这个例子中,我使用以下两个表:

包含美国主要城市位置的表格:

Name                                     Null?    Type
---------------------------------------- -------- ----------------------------
ID                                       NOT NULL NUMBER
CITY                                              VARCHAR2(42 CHAR)
POP90                                             NUMBER
RANK90                                            NUMBER
LOCATION                                          MDSYS.SDO_GEOMETRY

包含美国州形状的表格:

Name                                     Null?    Type
---------------------------------------- -------- ----------------------------
ID                                       NOT NULL NUMBER
STATE                                             VARCHAR2(26 CHAR)
STATE_ABRV                                        VARCHAR2(2 CHAR)
FIPSST                                            VARCHAR2(2 CHAR)
LANDSQMI                                          NUMBER
POPPSQMI                                          NUMBER
GEOM                                              MDSYS.SDO_GEOMETRY

以下查询返回纽约州的所有城市:

select c.city, c.pop90
from us_cities c, us_states s
where s.state = 'New York'
and sdo_inside (c.location, s.geom) = 'TRUE';

返回:

CITY                                POP90
------------------------------ ----------
New York                          7322564
Buffalo                            328123
Rochester                          231636
Yonkers                            188082
Syracuse                           163860
Albany                             101082

6 rows selected.

您只需通过JDBC提交此语句并获取结果。如果您还想返回点的位置(在地图上突出显示它们),还要包含location列。您可以通过Spatial Java API在Java代码中进行解释。或者您也可以从点中提取坐标:

select c.city, c.pop90, c.location.sdo_point.x longitude, c.location.sdo_point.y latitude
from us_cities c, us_states s
where s.state = 'New York'
and sdo_inside (c.location, s.geom) = 'TRUE';

CITY                                POP90  LONGITUDE   LATITUDE
------------------------------ ---------- ---------- ----------
New York                          7322564 -73.943849    40.6698
Buffalo                            328123 -78.859684    42.8898
Rochester                          231636 -77.615838  43.168651
Yonkers                            188082 -73.867514  40.947033
Syracuse                           163860 -76.144067  43.041059
Albany                             101082 -73.799017   42.66575

6 rows selected.