Geometry to wkt curve polygon

From WickyWiki
Revision as of 09:00, 14 February 2012 by Wilbert (talk | contribs)


In Oracle Spatial the conversion of arc's to WKT seems not supported as it is not part of the simple feature specification. On this page you will find:

  • a spatial function to stroke the arc's
  • a custom function to output polygons with arc's

SQL arc stroking with Oracle Spatial:

select SDO_UTIL.TO_WKTGEOMETRY( SDO_GEOM.SDO_ARC_DENSIFY(geom, 0.0005, 'arc_tolerance=0.01'))
  from (select MDSYS.SDO_GEOMETRY(2003, 90112, NULL, 
           MDSYS.SDO_ELEM_INFO_ARRAY(1,1005,3,1,2,1,3,2,2,7,2,1)
           , MDSYS.SDO_ORDINATE_ARRAY(161312.26, 383399.949, 161312.42, 383399.78
           , 161315.461, 383401.401, 161317.344, 383404.288, 161317.296, 383404.342
           , 161312.26, 383399.949)) as geom from dual)
  ;

Result:

POLYGON ((161312.26 383399.949, 161312.42 383399.78, 161313.087535512 383399.978123147
  , 161313.731792268 383400.242300498, 161314.346252635 383400.569859498
  , 161314.924700414 383400.957486391, 161315.461283728 383401.401259743
  , 161315.950574223 383401.896690114, 161316.387621984 383402.438765474
  , 161316.76800561 383403.022001908, 161317.087876943 383403.640499096
  , 161317.344 383404.288, 161317.296 383404.342, 161312.26 383399.949))

SQL curve WKT with custom function:

select GEOMETRY_TO_CURVEPOLYGON_WKT(geom)
  from (select MDSYS.SDO_GEOMETRY(2003, 90112, NULL, 
           MDSYS.SDO_ELEM_INFO_ARRAY(1,1005,3,1,2,1,3,2,2,7,2,1)
           , MDSYS.SDO_ORDINATE_ARRAY(161312.26, 383399.949, 161312.42, 383399.78
           , 161315.461, 383401.401, 161317.344, 383404.288, 161317.296, 383404.342
           , 161312.26, 383399.949)) as geom from dual)
  ;

Result:

CURVEPOLYGON(COMPOUNDCURVE((161312.26 383399.949,161312.42 383399.78)
  ,CIRCULARSTRING(161312.42 383399.78,161315.461 383401.401,161317.344 383404.288)
  ,(161317.344 383404.288,161317.296 383404.342,161312.26 383399.949)))

PL/SQL curve polygon function:

create or replace FUNCTION GEOMETRY_TO_CURVEPOLYGON_WKT( geom IN mdsys.Sdo_geometry ) RETURN CLOB is
    -- FUNCTION geometry --> curvepolygon wkt
    -- (c) 2012-01 Synaxion Urbidata
    -- exception voor foutieve of niet-ondersteunde geometrie, ondersteund zijn:
    -- - (curve)polygon, optioneel met 1 of meer gaten
    elem_info_i PLS_INTEGER;
    start_index PLS_INTEGER;
    until_index PLS_INTEGER;
    geometry_type VARCHAR2(12) := 'POLYGON';
    element_type PLS_INTEGER;
    element_interpretation PLS_INTEGER;
    subelements_num PLS_INTEGER;
    subelements_type PLS_INTEGER;
    ring CLOB;
    exterior CLOB;
    interiors CLOB;
    
    function num_to_char(n number) return varchar2 is
    begin
      if trunc(n)=n then
        return trim(to_char(n,'9999999999.0'));
      else
        return to_char(n);
      end if;
    end;
    
    function read_elem_info(i PLS_INTEGER) return PLS_INTEGER is
    begin
      IF i+2 > geom.sdo_elem_info.COUNT THEN
        raise_application_error(-20002, 'The elemtinfo count ('||to_char(geom.sdo_elem_info.COUNT)||') is not a multitude of 3');
      END IF;
      start_index:=geom.sdo_elem_info( i );
      element_type := geom.sdo_elem_info( i+1 );
      element_interpretation:=geom.sdo_elem_info( i+2 );
      -- next start index: 'until_index'
      IF i+3 <= geom.sdo_elem_info.COUNT THEN
        until_index:=geom.sdo_elem_info(i+3);
      ELSE
        until_index:=geom.Sdo_ordinates.COUNT+1;
      END IF;
      RETURN i+3;
    end;
    
    function read_ring(start_index PLS_INTEGER, until_index PLS_INTEGER) return clob is
    begin
      declare
        j PLS_INTEGER;
        r clob;
      begin
        r:=null;
        -- check index, create ring
        IF start_index<=geom.Sdo_ordinates.COUNT
        and start_index > 0
        and until_index+1-2<=geom.Sdo_ordinates.COUNT
        and until_index-2>0
        and start_index<until_index-1
        THEN
          j:=start_index;
          WHILE j < until_index LOOP
            IF not r is NULL THEN
              r := r||',';
            END IF;
            r := r || num_to_char( geom.sdo_ordinates(j+0) ) || ' ' || num_to_char( geom.sdo_ordinates(j+1) );
            j:=j+2;
          END LOOP;
        ELSE
          raise_application_error(-20003, 'GEOMETRY_TO_CURVEPOLYGON_WKT: the offset does not point to any coordinates');
        END IF;
        return r;
      end;      
    end;
BEGIN
    IF geom is NULL THEN
      RETURN NULL;    
    ELSIF NOT geom.sdo_elem_info IS NULL THEN
      IF geom.sdo_gtype = 2003 THEN          
        exterior:=NULL;
        interiors:=NULL;
        elem_info_i:=1;
        WHILE elem_info_i <= geom.sdo_elem_info.COUNT LOOP

          elem_info_i:=read_elem_info(elem_info_i);
          
          -- curve polygons
          IF element_type in (1005,2005) THEN 
            geometry_type:='CURVEPOLYGON';
            subelements_num:=element_interpretation;
            subelements_type:=element_type;
            ring:=NULL;
            WHILE subelements_num>0 LOOP
              subelements_num:=subelements_num-1;
              elem_info_i:=read_elem_info(elem_info_i);
              IF NOT ring is NULL THEN
                ring:=ring||',';
              END IF;

              -- if not last segment then add first point of next segment
              IF subelements_num>0 AND until_index<geom.sdo_ordinates.COUNT+1 THEN
                until_index:=until_index+2;
              END IF;
              
              IF element_interpretation=1 THEN
                ring:=ring||'('||read_ring(start_index,until_index)||')';
              ELSIF element_interpretation=2 THEN
                 ring:=ring||'CIRCULARSTRING('||read_ring(start_index,until_index)||')';
              ELSE
                raise_application_error(-20003, 'GEOMETRY_TO_CURVEPOLYGON_WKT: the interpretation of subelement ('||to_char(element_interpretation)||') should be 1 (straight) or 2 (curve)');
              END IF;                
            END LOOP;
            IF subelements_type=1005 AND exterior is NULL THEN
              exterior:='COMPOUNDCURVE('||ring||')';
            ELSIF subelements_type=2005 THEN
              interiors:=interiors || ',' || 'COMPOUNDCURVE('||ring||')';
            ELSE
              raise_application_error(-20004, 'GEOMETRY_TO_CURVEPOLYGON_WKT: unsupported coumpound geometry');
            END IF;
          ELSIF element_type=1003 AND exterior is NULL THEN
            exterior:='(' || read_ring(start_index,until_index) || ')';
          ELSIF element_type=2003 THEN
            interiors:=interiors || ',' || '(' || read_ring(start_index,until_index) || ')';
          ELSE
            raise_application_error(-20005, 'GEOMETRY_TO_CURVEPOLYGON_WKT: unsupported geometry');
          END IF;
          
        END LOOP;
        RETURN geometry_type || '(' || exterior || interiors || ')';
      ELSE
        raise_application_error(-20006, 'GEOMETRY_TO_CURVEPOLYGON_WKT: unsupported geometry');
      END IF; -- geom.sdo_gtype = 2003
    ELSE
      raise_application_error(-20006, 'GEOMETRY_TO_CURVEPOLYGON_WKT: unsupported geometry');
    END IF; -- NOT geom.sdo_elem_info IS NULL    
    
    EXCEPTION WHEN OTHERS THEN
      --RETURN NULL;
      RETURN DBMS_UTILITY.FORMAT_ERROR_BACKTRACE || SQLERRM;
END;
/