首先我尝试了:
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
答案 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.