是否有用于查找自相交线串的 oracle 空间函数?

Is there an oracle spatial function for finding self-intersecting linestrings?

我需要在 table 中找到所有自相交的线串。 SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT 仅查找自相交多边形,因为允许自相交线串。有什么想法吗?

这需要一些工作,但它是可行的。
由于 Oracle(11.2) 未能提供,我们唯一的选择是将线分成段并在段对上使用 RELATE
以下是我自己的实现(在生产代码中使用超过 3 年,超过数百万个几何图形)。我选择了流水线方法来覆盖过大或复杂的几何图形。

先决条件 1,数据库类型:

CREATE OR REPLACE TYPE ElemGeom as object
(eid integer, egeom mdsys.sdo_geometry, egtype integer, eelemnum integer, evertnum integer, earea number, elength number);  
CREATE OR REPLACE TYPE ElemGeomTbl as table of ElemGeom;

前提2,拆分函数:

    create or replace FUNCTION LineSegments (igeom in mdsys.sdo_geometry)  
RETURN ElemGeomTbl pipelined 
    is
    seg      ElemGeom := ElemGeom(null,null,null,null,null,null,null);      
    cursor c  is  select T.id, T.X ,T.Y  from table(SDO_UTIL.GETVERTICES(iGEOM)) T  order by 1;
    type ctbl is table of c%rowtype;
    carr      ctbl;
    seg_geom  mdsys.sdo_geometry;
    cnt       integer:=0;
    segid integer; x1 number; y1 number; x2 number; y2 number; 
    begin
      --if igeom.sdo_gtype not in (2002,2006) 
      --then... if you need to catch non-linears here...
      --end if;

       open c;
       loop
          fetch c
          bulk collect into carr ;
          for i in carr.first .. carr.last -1
          loop cnt:=cnt+1;
          segid := cnt;
             x1 := carr(i).X;   y1 := carr(i).Y;
             x2 := carr(i+1).X; y2 := carr(i+1).Y;

          seg_geom:= (mdsys.sdo_geometry(2002,2100,null 
                                                  ,mdsys.sdo_elem_info_array(1,2,1)
                                                  ,mdsys.sdo_ordinate_array(x1,y1, x2,y2)));
          seg.eid:=segid;
          seg.egeom:=seg_geom;
          seg.egtype:=seg_geom.sdo_gtype;
          pipe row(seg);
          end loop;

       exit when c%notfound;
       end loop;
       close c;

    end LineSegments;

你可以用类似的东西测试它的输出(我的 GEOM 是 SRID 2100):

with t1 as (
select 
SDO_GEOMETRY(2002,2100,NULL,
SDO_ELEM_INFO_ARRAY(1,2,1),
SDO_ORDINATE_ARRAY(290161.697,4206385.413, 290161.901,4206388.095, 290162.684,4206385.188, 290163.188,4206388.041,
 290163.51,4206385.22, 290164.357,4206388.159, 290166.879,4206387.108, 290161.397,4206387.366,
 290166.331,4206386.067, 290165.763,4206388.052))
as G from DUAL
)
select * from t1,table(LineSegments(g));

主要功能:

    create or replace FUNCTION validate_Line  
    (igeom in mdsys.sdo_geometry, itol in number default null)  
    RETURN varchar2 
    is
    vtol  number:= nvl(itol, 1/power(10,6));
    verd1 varchar2(256); verd2 varchar2(256); v varchar2(256); 
    begin

    verd1:= sdo_geom.validate_geometry_with_context(igeom,vtol);

      for r1 in ( select a.eid seg1, a.egeom geom1, b.eid seg2, b.egeom geom2
                    from table(LineSegments(igeom)) a, table(LineSegments(igeom)) b 
                   where a.eid < b.eid
                   order by a.eid, b.eid )
      loop
      --I hate outputting long words, so:
v:= replace(replace(sdo_geom.relate(r1.geom1,'determine',r1.geom2, vtol)
                         ,'OVERLAPBDYDISJOINT','OVR-BDIS'),'OVERLAPBDYINTERSECT','OVR-BINT');

        if instr('EQUAL,TOUCH,DISJOINT',v) = 0 then
           verd2:= verd2|| case when verd2 is not null 
                                then ', '||r1.seg1||'-'||r1.seg2||'='||v 
                                else       r1.seg1||'-'||r1.seg2||'='||v end;
        end if;

      end loop;

      verd1:= nvl(verd1,'NULL') 
           || case when verd1  ='TRUE' and verd2 is     null then null
                   when verd1  ='TRUE' and verd2 is not null then ' *+: '||verd2
                   end;

      return verd1;
    end validate_Line;  

及其测试:

with t1 as (
select 
SDO_GEOMETRY(2002,2100,NULL,
SDO_ELEM_INFO_ARRAY(1,2,1),
SDO_ORDINATE_ARRAY(290161.697,4206385.413, 290161.901,4206388.095, 290162.684,4206385.188, 290163.188,4206388.041,
 290163.51,4206385.22, 290164.357,4206388.159, 290166.879,4206387.108, 290161.397,4206387.366,
 290166.331,4206386.067, 290165.763,4206388.052))
as G from DUAL
)
select t1.*,validate_Line(g) from t1;

这个returns:

*TRUE *+: 1-7=OVR-BDIS, 1-8=OVR-BDIS, 2-7=OVR-BDIS, 2-8=OVR-BDIS, 3-7=OVR-BDIS, 3-8=OVR-BDIS, 4-7=OVR-BDIS, 4-8=OVR-BDIS, 5-7=OVR-BDIS, 5-8=OVR-BDIS, 6-9=OVR-BDIS, 7-9=OVR-BDIS*

当然,您可以将输出修改为只是一个标志或其他任何东西 - 这正是适合我自己的需要。
HTH