Donnerstag, 23. April 2015

PolygonToLine: Geht das auch umgekehrt?

Im PL/SQL Package SDO_UTIL findet sich die Funktion POLYGONTOLINE, welche ein Polygon in eine Linie konvertiert.
Für den umgekehrten Vorgang, eine Linie in ein Polygon umzuwandeln, gibt es (noch) keine solche Funktion im Package. Allerdings kann ich die gerade ganz gut brauchen. Denn für ein Set an Isolinien (SDO_GEOMETRY mit GTYPE=2002) sollen die abgedeckten Flächen berechnet werden. Flächenberechnungen mit SDO_GEOM.AREA sind aber nur für Polygone (inklusive Polygone mit Löchern) erlaubt.
Also schreiben wir uns selbst eine Funktion. Das ist auch nicht weiter schwierig, wie Ihr weiter unten sehen könnt.
Der besseren Lesbarkeit halber habe ich die wichtigsten Erläuterungen als Kommentar in den Code eingefügt.

Viel Spass beim Ausprobieren !

create or replace function line_to_polygon (
  p_line_geom sdo_geometry)
return sdo_geometry deterministic
is 
  p_polygon_geom sdo_geometry;
  k number;
begin
  /* 
   * Geometrietyp prüfen: Muss gleich 2002 für einfache 2D Linien-Geometrie sein.
   * Doku: http://docs.oracle.com/cd/B28359_01/appdev.111/b28400/sdo_objrelschema.htm#g1013735 
   */
  if p_line_geom.sdo_gtype <> 2002 then
    raise_application_error (-20001, 'Geometrie ist keine einfache 2D Linie.  GTYPE <> 2002.');
  end if;

  p_polygon_geom := p_line_geom;

  -- GTYPE neu setzen für einfache 2D Polygon-Geometrie.
  p_polygon_geom.sdo_gtype := 2003;

  /* 
   * ELEMENT_INFO_ARRAY neu setzen.
   * Doku: http://docs.oracle.com/cd/B28359_01/appdev.111/b28400/sdo_objrelschema.htm#SPATL494 
   */
  
  p_polygon_geom.sdo_elem_info := sdo_elem_info_array (1, 1003, 1);

  -- Anzahl der Stützpunkte bestimmen
  k := p_polygon_geom.sdo_ordinates.count;

  /* 
   * Polygon muss geschlossen werden. 
   * Daher prüfen, ob letzter Stützpunkt der Linie gleich dem 1. Stützpunkt ist. 
   * Wenn nicht, neuen Stützpunkt einfügen (SDO_ORDINATE_ARRAY wird erweitert um 2 Werte). 
   */

  if (p_polygon_geom.sdo_ordinates(k-1) <> p_polygon_geom.sdo_ordinates(1)
    or p_polygon_geom.sdo_ordinates(k) <> p_polygon_geom.sdo_ordinates(2))
  then
    p_polygon_geom.sdo_ordinates.extend(2);
    p_polygon_geom.sdo_ordinates(k+1) := p_polygon_geom.sdo_ordinates(1);
    p_polygon_geom.sdo_ordinates(k+2) := p_polygon_geom.sdo_ordinates(2);
  end if;
  
  -- Jetzt nur noch die Polygon-Geometrie zurückgeben
  return p_polygon_geom;
end line_to_polygon;
/
sho err
Diejenigen unter Euch, welche Anfang des Jahres im Oracle Spatial Workshop mit Albert Godfrind waren, finden die Funktion auch im Labs/07-processing-Ordner.

1 Kommentar:

  1. Weil ich gerade ein Anfrage in diesem Zusammenhang bekommen habe, möchte ich noch Folgendes ergänzen:
    WEnn SDO_UTIL.POLYGONTOLINE auf Polygone mit Löchern angwandt wird oder auch zusammengesetzte Polygone, dann wird als Ergebnis eine Geometrie vom Typ 2006 (Multiline) zurückgegeben.

    Wer es ausprobieren möchte, kann Tabelle T1 im Spatial Handbuch (http://docs.oracle.com/database/121/SPATL/sdo_objrelschema.htm#SPATL516) dafür nutzen.
    Und dann einfach mal diese Query absetzen:

    with test as (
    select i, d, g polygon, sdo_util.polygontoline(g) line
    from t1 p
    where p.g.sdo_gtype = 2003 )
    select t.i, t.d, t.polygon.sdo_gtype polygon_type,
    t.line.sdo_gtype line_type,
    sdo_util.getnumelem(polygon) no_of_elems_in_polygon,
    sdo_util.getnumelem(line) no_of_elems_in_line,
    sdo_util.getnumvertices(polygon) no_of_verts_in_polygon,
    sdo_util.getnumvertices(line) no_of_verts_in_line
    from test t
    order by 3,4

    AntwortenLöschen