最初的问题是,我试图找出集合中的点之一是否在给定的多边形内。我没有得到任何结果,因此将其简化为最简单的情况,但仍然没有得到结果。

多边形的几何形状看起来像这样(围绕坐标中心的小正方形):

geom1 := SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1),
SDO_ORDINATE_ARRAY(10,10, 10,-10, -10,-10, -10,10))


现在,我正在尝试使用SDO_RELATE找出点[0,0]是否在该多边形内。

sdo_relate(geom1,
        SDO_GEOMETRY('MULTIPOINT((0 0))',8307),
       'mask=anyinteract')


我使用anyinteract,因为根据Oracle documentation


ANYINTERACT:对象是不相交的。


多边形内的点显然与它不相交。因此,在尝试放置CONTAINS而不是ANYINTERACT并最终获得所需的输出之前,我花了大约一个小时尝试用不同的方式初始化点并检查坐标和所有内容。

所以我的问题是:


这是一个错误吗? contains参数显然比anyinteract更严格
检查集合中是否有点位于多边形中的最佳方法是什么?包含在这里无济于事,因为如果任何点在外面,则SDO_RELATE的结果为false。没有比anyinteract更合适的交点类型了,这不起作用。

最佳答案

首先,您的多边形格式错误:它不会关闭。对于多边形,最后一点必须与第一个点匹配。您可以通过执行以下操作来检测错误:

SQL> select sdo_geom.validate_geometry_with_context (SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(10,10, 10,-10, -10,-10, -10,10)), 0.05) from dual;

13348 [Element <1>] [Ring <1>]
1 row selected.

ORA-13348: polygon boundary is not closed


更正该错误后,您将得到另一个错误:

SQL> select sdo_geom.validate_geometry_with_context (SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(10,10, 10,-10, -10,-10, -10,10, 10,10)), 0.05) from dual;

13367 [Element <1>] [Ring <1>]
1 row selected.

ORA-13367: wrong orientation for interior/exterior rings


对于多边形,这些点必须处于逆时针方向。修正后,多边形就正确了:

SQL> select sdo_geom.validate_geometry_with_context (SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1),SDO_ORDINATE_ARRAY(10,10, -10,10, -10,-10, 10,-10, 10,10)), 0.05) from dual;

TRUE
1 row selected.


并且查询工作正常。这是一个例子:

create table t1 (id number, note varchar2(20), geom sdo_geometry);

insert into t1 (id, note, geom)
values (
 1,
 'Not closed',
 SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(10,10, 10,-10, -10,-10, -10,10))
);

insert into t1 (id, note, geom)
values (
 2,
 'Wrong orientation',
 SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(10,10, 10,-10, -10,-10, -10,10, 10,10))
);

insert into t1 (id, note, geom)
values (
 3,
 'Valid',
 SDO_GEOMETRY(2003, 8307, null, SDO_ELEM_INFO_ARRAY(1,1003,1), SDO_ORDINATE_ARRAY(10,10, -10,10, -10,-10, 10,-10, 10,10))
);

commit;

insert into user_sdo_geom_metadata (table_name, column_name, diminfo, srid)
values (
  'T1',
  'GEOM',
  sdo_dim_array (
    sdo_dim_element ('Long',-180,180,0.5),
    sdo_dim_element ('Lat',-90,90,0.5)
  ),
  8307
);
commit;

create index t1_sx on t1 (geom) indextype is mdsys.spatial_index;


测试表包含多边形的三个变体。让我们尝试一个查询:

select *
from t1
where sdo_relate(
  geom,
  SDO_GEOMETRY('MULTIPOINT((0 0))',8307),
  'mask=anyinteract'
) = 'TRUE';


返回正确的结果:只有有效的多边形被正确地标识为包含您的点:

        ID NOTE                 GEOM(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
---------- -------------------- -------------------------------------------------------------------------------
         3 Valid                SDO_GEOMETRY(2003, 8307, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1), SDO_ORDINATE_ARRAY(10, 10, -10, 10, -10, -10, 10, -10, 10, 10))

1 row selected.


至于ANYINTERACT和CONTAINS对于多边形中点的区别,可能会影响多边形边界上的那些点(或更准确地说,在边界的公差范围内)。 ANYINTERACT搜索将返回这些内容。没有CONTAINS / INSIDE搜索。

例如,当您想将点分布到多边形(例如销售区域中的客户点位置)并且某些客户位置点恰好落在相邻区域之间的边界上时,这可能很重要:ANYINTERACT搜索将报告这些位置在两个区域中。 INSIDE搜索将报告它们都不存在。

最后,对查询使用更简单的语法:

select *
from t1
where sdo_anyinteract(
  geom,
  SDO_GEOMETRY('MULTIPOINT((0 0))',8307)
) = 'TRUE';


有关如何获取与错误代码相对应的消息的一些信息(如13348)。我通常使用这种技术:

set serveroutput on
exec dbms_output.put_line(sqlerrm(-13348))


这将打印出完整的错误消息。请注意,您必须通过负号传递错误。

08-06 21:36