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

How to determine if a point is inside a polygon using Oracle Spatial Java API?

首先我尝试了:

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() returns 一个 java.awt.geom.GeneralPath 对象,它没有双精度,因此 shape.contains(...) 在多边形。

然后我尝试使用 JGeometry.createDoubleShape() 代替 returns 一个 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)

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

有其他选择吗?

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

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

根据要求提供更多详细信息:
Oracle 版本是 11g,我正在开发一个应该验证数据库中的几何数据的 Web 应用程序。特别是,其中一项验证涉及检查某些点和多边形是否在其他多边形内部。我引用的文档是这样的: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 所指出的。 SDO_RELATE 和其他空间运算符 受 Oracle Locator 11 支持,如 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 class不包含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

你说

I also cannot use the Oracle Spatial functions directly in the database due to a license restriction.

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

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

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

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

你能多说说你的实际用例吗?

编辑

这里有一个使用SQLAPI的例子。这对所有数据库版本都有效,一直到 11gR1 并且包含在 Oracle Locator 中(即不需要任何 Spatial 许可)。

在此示例中,我使用了以下两个 table:

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

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

一个 table 包含美国各州的形状:

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

下面查询returns纽约州的所有城市:

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';

其中 return 个:

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

6 rows selected.

您只需通过 JDBC 提交此声明并获取结果。如果您还想 return 点的位置(以在地图上突出显示它们),则还包括 location 列。您可以通过空间 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.