Freitag, 16. März 2012

Gebäudekonstruktion mit Oracle Spatial - Teil 1: LOD1

Vor nunmehr fast 5 Jahren wurde mit der Version 11 der Oracle Datenbank die Unterstützung für 3D Vektordaten sowie mit SDO_PC für Punktwolken und SDO_TIN für Dreiecksvermaschungen zusätzliche Datentypen zur Modellierung von Oberflächen und Körpern eingeführt.

Wie die 3D Funktionalität verwendet wird, möchte ich in mehreren Blog-Postings anhand des Aufbaus von 3D Stadtmodellen erläutern.

Im heutigen Posting soll es zunächst um die Konstruktion von LOD1 gehen. Die Abkürzung LOD steht für Level of Detail, Level 1 für die Konstruktion von Gebäudeblöcken aus in die Höhe gezogenen Grundflächen, auch Klötzchenmodell genannt.

Was wird benötigt?

Als Datengrundlage für die Konstruktion eines Klötzchenmodells steht eine Tabelle mit Gebäudeumrissen in 2D sowie 2 Höhenangaben für
  • Gebäudehöhe
  • Höhe über Grund
zur Verfügung. Dabei handelt es sich um Testdaten des British Ordnance Survey im Koordinatensystem OSGB 1936 (EPSG:27700).

Genausogut können Hausumringe z.B. aus ALK-Daten verwendet werden, sofern Höhenangaben beigegeben sind.

Wie geht man vor?

  1. Liegen die Daten nicht direkt als SDO_GEOMETRY vor, müssen sie mit einem Werkzeug zuvor konvertiert werden.
  2. Für die zu erzeugenden 3D-Geometrien wird eine neue Tabelle angelegt.
    create table buildings_lod1 (
      building_id         number primary key,
      gmlid               varchar2(30),
      height              number,
      ground_height       number,
      geom                sdo_geometry
    );
    
  3. Mit der Funktion SDO_UTIL.EXTRUDE werden aus den 2D-Geometrien (Flächen) unter Verwendung der Höhenangaben HEIGHT und GROUND_HEIGHT 3D-Geometrien (Körper) erzeugt.
    -- Vorgehen für Version 11.2
    insert into buildings_lod1 (
      building_id, 
      gmlid, 
      height, 
      ground_height, 
      geom)
    select 
      building_id,
      gmlid,
      height,
      ground_height,
      sdo_util.extrude (
        geom,
        sdo_number_array (ground_height),
        sdo_number_array (height),
        0.005,
        7405   -- Compound CRS aus EPSG:27700 + EPSG:5701
      )
    from building_footprints;
    commit;
    Für die 567 Gebäudesätze braucht es wenige Sekunden und die neue Tabelle ist befüllt.
    Neues Koordinatensystem ist jetzt EPSG:7405, also OSGB 1936 + ODN height.
  4. Zwecks Überprüfung werden die Daten nun noch nach KML konvertiert, in einem Ordner im XMLDB Repository als Resource abgelegt und mit Google Earth zur Anzeige gebracht.
    -- PL/SQL Prozedur: Export SDO_GEOMETRY als KML
     declare
      result boolean;
      kmldoc xmltype;
    begin
      SELECT 
      -- Anm.: Ein bisschen SQL/XML in der Datenbank kann nicht schaden
        xmlelement ( 
          "kml",
          xmlattributes ('http://www.opengis.net/kml/2.2' as "xmlns"),
          xmlelement (
            "Document",
            xmlelement (
              "Style",
              xmlattributes('BuildingStyle' as "id"),
              xmlelement ("LineStyle", xmlelement ("width", '1'), 
              xmlelement ("color", 'ffffffff')
            ),
            xmlelement (
              "PolyStyle", 
              xmlelement ("color", 'bfc0c0c0')
            ),
            xmlelement (
              "BalloonStyle", 
              xmlelement ("text", '$[name]')
            )
          ),
          xmlagg (
            xmlelement (
              "Placemark",
              xmlelement ("name", 'Building '|| gmlid),
              xmlelement ("styleUrl", '#BuildingStyle'),
              xmltype (
                sdo_util.to_kmlgeometry (
                  snap_to_ground (
                    sdo_cs.transform(geom,4327), 
                    0
                  )
                )
              )
            )
          )
        )
      )
      INTO kmldoc
      FROM buildings_lod1;
    
      -- Wenn KML-Datei schon in Repository vorhanden ist, dann löschen
      if dbms_xdb.existsresource ('/public/Buildings/buildings_lod1.kml') then
        dbms_xdb.deleteresource('/public/Buildings/buildings_lod1.kml');
      end if;
    
      -- KML-Datei ins Repository schreiben
      result := dbms_xdb.createResource ('/public/Buildings/buildings_lod1.kml', kmldoc);
      if not result then
        raise_application_error (-20000, 'Failed to create resource');
      end if;
    end;
    /
    commit;
    

    Die Hilfsfunktion SNAP_TO_GROUND ist übrigens wie folgt definiert:

    -- "Alles auf Grund"
    create or replace function snap_to_ground (
      geom sdo_geometry, 
      ground_height number)
    return sdo_geometry deterministic
    is
      i number;
      g sdo_geometry;
      current_ground_height number;
      offset number;
    begin
      g := geom;
      current_ground_height :=  sdo_geom.sdo_min_mbr_ordinate(g,3);
      offset := current_ground_height - ground_height;
      i := 0;
      while i < g.sdo_ordinates.count loop
        g.sdo_ordinates(i+3) := g.sdo_ordinates(i+3) - offset;
        i := i + 3;
      end loop;
      return g;
    end;
    /
    
    Die ausserdem verwendeten Funktionen SDO_UTIL.TO_KMLGEOMETRY und SDO_CS.TRANSFORM sind Bestandteil der Oracle DB Spatial Features.
    Alternativ kann der Export natürlich auch als GML (CityGML-konform) erfolgen. Dann läßt sich das Ergebnis, wie in der nachfolgenden Abbildung, z.B. mit dem LandExplorer CityGML Viewer darstellen.

Damit ist der Teil "Konstruktion von LOD1 aus Gebäudeumrissen" abgeschlossen.

Fortsetzung folgt.

Donnerstag, 15. März 2012

Anzeige von Vektordaten (Geometrien) im SQL Developer Version 3.1

Seit Anfang Februar 2012 ist die Version 3.1 des kostenfreien Werkzeuges SQL Developer verfügbar.

Der SQL Developer enthält seit einiger Zeit Funktionalität für die Visualisierung von und den Umgang mit Daten des Typs SDO_GEOMETRY.
Mit Version 3.1 hat es nun eine Änderung gegeben, was die tabellarische Anzeige der Werte in den SDO_GEOMETRY-Spalten betrifft.

Diese werden jetzt als Platzhalter [MDSYS.SDO_GEOMETRY] angezeigt, statt wie bisher mit ihrem vollen Textinhalt.
Der eigentliche Wert wird mittels Doppelklick auf den Platzhalter eingeblendet.

Hintergrund dieser Änderung ist eine wesentliche bessere Performance in Bezug auf die Anzeige von Daten in Tabellen mit vielen Geometrien oder grossen Geometrien, die also sehr viele Stützpunkte aufweisen.

Kommentare und Informationen zum Werkzeug und seinen Features können im SQL Developer Forum ausgetauscht werden.
Für Änderungswünsche steht seitens des SQL Developer Product Management der Bereich SQL Developer Exchange zur Verfügung.

Webcast: Integration von Geodaten in ADF

Bernhard Fischer-Wasels gibt am 16. März in der Zeit von 8:30 bis 9:00 Uhr eine Überblick zur Intergration von Geodaten in das Oracle Application Development Framework (ADF).
Interessenten sind herzlich eingeladen, sich einzuwählen.

Einwahldaten für die Webkonferenz:

Einwahldaten für die parallele Telefonkonferenz:
  • Telefonnummern: 069 2222 16 106 oder 0800 66 485 15
  • Conference Code: 208 503 9
  • Security Passcode: 112233

Samstag, 10. März 2012

DOAG SIG Spatial am 18. April in Frankfurt a.M.

Die Special Interest Group der Deutschen Oracle Anwendergemeinschaft trifft sich wieder am 18. April in Franfurt a.M.
Die Vortragsliste umfasst folgende interessanten Beiträge:
  • Das Navi in der Datenbank: Oracle11g has NAVTEQ on Board
  • Das Netz: Der Umgang mit dem "Oracle Network Data Model" am Beispiel
  • Verwaltung von 3D Stadtmodellen
  • Koeexistenz zwischen Smallworld-GIS und Oracle Spatial
  • Oracle Apex IR und OpenLayers/OSM Karten gemeinsam nutzen - dank APEX Plug-In Technologie
  • Autodesk on Oracle: Erfassung und Bearbeitung raumbezogener Daten mit Oracle 11gR2 Spatial
Weitere Infos zur Veranstaltung gibt es hier.

Sonntag, 4. März 2012

Was tun, wenn die Datenbank ein Koordinatensystem nicht kennt?

Ein solcher Fall kann vorkommen. Dann liefert Ihnen die SQL-Abfrage wie im nachfolgenden Fall
select * 
  from cs_srs 
 where srid = 4647;
eine leere Ergebnismenge. Aber das ist kein Grund zur Panik.

Denn das Problem ist mit wenigen INSERT-Befehlen behoben, sofern man nicht bis zum nächsten DB-Release warten möchte.

Was wird benötigt?
  • Die Informationen zum fehlenden Koordinatensystem.
    Für unser Beispiel 4647 sind die über die Suchfunktion auf den EPSG-Seiten zu finden.
  • Dazu braucht es noch die Angaben zur Transformation.
    Die sind im Bereich Conversion zu finden, wenn man auf den Link View öffnet.
    Wie man dort sieht, ist der dazugehörige EPSG-Code 4648. Und auch dafür gibt es einen Eintrag auf den EPSG-Seiten.
So. nun kann es auch schon losgehen.
Zuerst wird die Transformation eingetragen, da später beim INSERT des Koordinatensystems auf diese referenziert wird.
insert into sdo_coord_ops (
  COORD_OP_ID,
  COORD_OP_NAME,
  COORD_OP_TYPE,
  SOURCE_SRID,
  TARGET_SRID,
  COORD_TFM_VERSION,
  COORD_OP_VARIANT,
  COORD_OP_METHOD_ID,
  UOM_ID_SOURCE_OFFSETS,
  UOM_ID_TARGET_OFFSETS,
  INFORMATION_SOURCE,
  DATA_SOURCE,
  SHOW_OPERATION,
  IS_LEGACY,
  LEGACY_CODE,
  REVERSE_OP,
  IS_IMPLEMENTED_FORWARD,
  IS_IMPLEMENTED_REVERSE)
values (
  4648,                                        -- Code
  'UTM zone 32N with prefix',                  -- Name
  'CONVERSION',                                -- Operation
  NULL,
  NULL,
  NULL,
  NULL,
  9807,                                        -- Transverse Mercator (= Operation Method Name)
  NULL,
  NULL,
  'Landesvermessungsamt Schleswig-Holstein.',  -- Information Source
  'OGP',                                       -- Data Source
  1,                                           -- 
  'FALSE',                                     -- Not legacy  
  NULL,
  1,                                           -- Operation is reversible
  1,                                           -- Forward
  1);                                          -- and reverse
Als Wert für die Spalte COORD_OP_TYPE ist CONVERSION einzutragen. Informationen zu möglichen anderen Werten sind im Oracle Spatial Developer's Guide zu finden.
Der Wert für die Spalte COORD_OP_METHOD_ID wurde mit der nachfolgenden Abfrage ermittelt.
-- Operation Method
select * 
  from sdo_coord_op_methods 
 where coord_op_method_name = 'Transverse Mercator';  
-- COORD_OP_METHOD_ID = 9807
Nun sind noch die Parameterwerte wie in der Abbildung angegeben einzufügen.
Dazu braucht es ein paar IDs aus den Tabellen SDO_COORD_OP_PARAMS und SDO_UNIT_OF_MEASURE.
-- Conversion parameters
select parameter_id 
  from sdo_coord_op_params 
 where parameter_name = 'Latitude of natural origin';     -- 8801
select parameter_id 
  from sdo_coord_op_params 
 where parameter_name = 'Longitude of natural origin';    -- 8802
select parameter_id 
  from sdo_coord_op_params 
 where parameter_name = 'Scale factor at natural origin'; -- 8805
select parameter_id 
  from sdo_coord_op_params 
 where parameter_name = 'False easting';                  -- 8806
select parameter_id 
  from sdo_coord_op_params 
 where parameter_name = 'False northing';                 -- 8807

 -- Units of measure
select uom_id 
  from sdo_units_of_measure 
 where unit_of_meas_name = 'degree';                      -- 9102
select uom_id 
  from sdo_units_of_measure 
 where unit_of_meas_name = 'unity';                       -- 9201
select uom_id 
  from sdo_units_of_measure 
 where unit_of_meas_name = 'metre';                       -- 9001
Die 5 Parameter Latitude of natural origin, Longitude of natural origin, Scale factor at natural origin, False easting und False northing werden jetzt nacheinander in die Tabelle SDO_COORD_OP_PARAM_VALS eingetragen.
insert into sdo_coord_op_param_vals (
  COORD_OP_ID,
  COORD_OP_METHOD_ID,
  PARAMETER_ID,
  PARAMETER_VALUE,
  PARAM_VALUE_FILE_REF,
  PARAM_VALUE_FILE,
  PARAM_VALUE_XML,
  UOM_ID)
values (
  4648,
  9807,
  8801,             -- Latitude of natural origin
  0,
  NULL,
  NULL,
  NULL,
  9102);            -- degree

insert into sdo_coord_op_param_vals (
  COORD_OP_ID,
  COORD_OP_METHOD_ID,
  PARAMETER_ID,
  PARAMETER_VALUE,
  PARAM_VALUE_FILE_REF,
  PARAM_VALUE_FILE,
  PARAM_VALUE_XML,
  UOM_ID)
values (
  4648,
  9807,
  8802,             -- Longitude of natural origin
  9,
  NULL,
  NULL,
  NULL,
  9102);            -- degree

insert into sdo_coord_op_param_vals (
  COORD_OP_ID,
  COORD_OP_METHOD_ID,
  PARAMETER_ID,
  PARAMETER_VALUE,
  PARAM_VALUE_FILE_REF,
  PARAM_VALUE_FILE,
  PARAM_VALUE_XML,
  UOM_ID)
values (
  4648,
  9807,
  8805,             -- Scale factor at natural origin
  .9996,
  NULL,
  NULL,
  NULL,
  9201);            -- unity

insert into sdo_coord_op_param_vals (
  COORD_OP_ID,
  COORD_OP_METHOD_ID,
  PARAMETER_ID,
  PARAMETER_VALUE,
  PARAM_VALUE_FILE_REF,
  PARAM_VALUE_FILE,
  PARAM_VALUE_XML,
  UOM_ID)
values (
  4648,
  9807,
  8806,             -- False easting
  32500000,
  NULL,
  NULL,
  NULL,
  9001);            -- metre

insert into sdo_coord_op_param_vals (
  COORD_OP_ID,
  COORD_OP_METHOD_ID,
  PARAMETER_ID,
  PARAMETER_VALUE,
  PARAM_VALUE_FILE_REF,
  PARAM_VALUE_FILE,
  PARAM_VALUE_XML,
  UOM_ID
values (
  4648,
  9807,
  8807,             -- False northing
  0,
  NULL,
  NULL,
  NULL,
  9001);            -- metre
Abschliessend ist dann nur noch das Koordinatensystem 4647 einzutragen in den dafür vorgesehenen View SDO_COORD_REF_SYSTEM.
insert into sdo_coord_ref_system (
  SRID,
  COORD_REF_SYS_NAME,
  COORD_REF_SYS_KIND,
  COORD_SYS_ID,
  DATUM_ID,
  GEOG_CRS_DATUM_ID,
  SOURCE_GEOG_SRID,
  PROJECTION_CONV_ID,
  CMPD_HORIZ_SRID,
  CMPD_VERT_SRID,
  INFORMATION_SOURCE,
  DATA_SOURCE,
  IS_LEGACY,
  LEGACY_CODE,
  LEGACY_WKTEXT,
  LEGACY_CS_BOUNDS,
  IS_VALID,
  SUPPORTS_SDO_GEOMETRY)
values (
  4647,                                       -- Code
  'ETRS89 / UTM zone N32',                    -- Name
  'PROJECTED',                                -- Projected CRS
  4400,                                       -- Erläuterung nachfolgend
  NULL, 
  6258,                                       -- Erläuterung nachfolgend
  4258,                                       -- Erläuterung nachfolgend
  4648,                                       -- Zuvor registrierte Operation
  NULL,
  NULL,
  'Landesvermessungsamt Schleswig-Holstein',  -- Information Source
  'OGP',                                      -- Data Source
  'FALSE',                                    -- Not legacy
  NULL,
  NULL,
  NULL,
  'TRUE',                                     -- Is valid
  'TRUE');

commit;
Um den Wert 4400 für COORD_SYS_ID zu ermitteln, muss man ein bisschen genauer in die Tabelle SDO_COORD_SYS schauen. Und findet dann:
-- Coordinate axes: Easting, Northing. UoM = m
select * 
  from sdo_coord_sys 
 where coord_sys_name like 
       '%2D%Axes: easting, northing (E,N)%Orientations: east, north%UoM: m.';  
-- COORD_SYS_ID = 4400
GEOG_CRS_DATUM_ID und SOURCE_GEOG_SRID sind auch wieder mit den entsprechenden Abfragen zu ermitteln.
-- Geodetic Datum = European Terrestrial Reference System (ETRS) 1989
select * 
  from sdo_datums 
 where datum_name = 'European Terrestrial Reference System 1989';  
-- DATUM_ID = 6258

select * 
  from sdo_coord_ref_sys 
 where coord_ref_sys_name = 'ETRS89'
   and coord_ref_sys_kind like '%2D%';   
-- SRID = 4258                             
Das Ergebnis kann nun begutachtet werden:
select *
  from cs_srs 
 where srid = 4647;
Mehr Infos sind natürlich im Oracle Spatial Developer's Guide zu finden.