Ändern Sie die Polygon-Händigkeit für SQL 2008 (umgekehrte Polygon-Scheitelpunktreihenfolge).


11

Ich habe ein paar hundert Formen ( polygons und multipolygons), die jeweils aus Zehntausenden von Punkten bestehen, die ich in SQL 2008 einführen möchte.

Leider sind die Formen, die ich zu importieren versucht habe, "rechtshändig" (der Umfang jeder Form wird im Uhrzeigersinn um die darin enthaltenen Punkte gezogen). SQL Server nimmt zumindest für geographyTypen "linkshändige" Formen an (gegen den Uhrzeigersinn im Inneren) . Dies bedeutet, dass SQL davon ausgeht, dass ich versuche, die gesamte Erde mit Ausnahme meiner Form auszuwählen . Einige Leute beschreiben dies als "Inside-Out" -Formen.

Von MSDN , das frustrierend nicht sagt, welche Ringorientierung man verwenden soll:

Wenn wir den geographyDatentyp zum Speichern der räumlichen Instanz verwenden, müssen wir die Ausrichtung des Rings angeben und den Ort der Instanz genau beschreiben.

Wenn Sie in SQL 2008 die falsche Ringausrichtung verwenden, stürzt der folgende Fehler ab (Hervorhebung von mir):

Während der Ausführung einer benutzerdefinierten Routine oder einer aggregierten "Geografie" ist ein .NET Framework-Fehler aufgetreten: Microsoft.SqlServer.Types.GLArgumentException: 24205: Die angegebene Eingabe stellt keine gültige Geografieinstanz dar, da sie eine einzelne Hemisphäre überschreitet. Jede Geografieinstanz muss in eine einzelne Hemisphäre passen. Ein häufiger Grund für diesen Fehler ist, dass ein Polygon die falsche Ringausrichtung hat.

Das Importieren der Formen als geometrystatt geographyfunktioniert einwandfrei, aber ich würde es gerne verwenden, geographywenn ich kann.

In SQL 2012 scheint es ziemlich trivial zu sein, dieses Problem zu beheben, aber ich bin an 2008 gebunden.

Wie soll ich die Formen konvertieren?


1
+1 große Frage ... haben Sie einen Link, auf dem steht, dass der SQL Server linkshändige Formen annimmt?
Kirk Kuykendall

@ Kirk Danke. Ich habe Probleme beim Auffinden der offiziellen Dokumentation, kann jedoch einen Link zum MSDN erstellen, in dem angegeben ist, dass die "Ringorientierung" wichtig ist (obwohl nicht angegeben ist, welche Verwendung verwendet werden soll). Ich werde auch den Fehler eingeben, den man bekommt, wenn es abstürzt.
Michael - Wo ist Clay Shirky

Antworten:


14

Spatial Eds Blog hatte eine prägnante Lösung. Hier ist etwas SQL, das die Transformation demonstriert:

DECLARE @geom GEOMETRY = 'POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))';
DECLARE @geog GEOGRAPHY = @geom.MakeValid().STUnion(@geom.STStartPoint()).STAsText()

Und ein Auszug aus Eds Post:

Der Schlüssel zu diesem Verhalten ist die STUnion()Methode. Da es sich um eine OGC-basierte Methode handelt, bei der die gesamte Geometrie für ein bestimmtes Feature bearbeitet wird, werden Polygone in die für die Methode erforderliche Ausrichtung gezwungen - die zufällig für den GeographyTyp [...] verwendet wird. Diese dargestellte Methode ist sehr effizient und hält den Overhead klein [...].


2
Unter SQL Server 2008 r2 musste ich .MakeValid () auch in die STUnion () einfügen, damit dies funktioniert: .STUnion (@ geom.MakeValid (). STStartPoint ())
Chris Smith

@Smitty Das ist sinnvoll in Fällen, in denen SQL den Startpunkt sonst nicht bestimmen kann. Vielleicht, wenn sich die Form über sich selbst oder andere seltsame Umstände verdoppelt?
Michael - Wo ist Clay Shirky

Ja, unter meinen Umständen ist die Form verrückt und überlappt sich.
Chris Smith

0

In> = SQL Server 2012 sollte die ReorientObject () -Methode dies erreichen. Für <SQL Server 2012 ist unten eine alternative Methode.

Für eine vorhandene SQL-Geografie @g extrahiert der folgende Code die Punkte und erstellt ein Polygon mit Punkten (Scheitelpunkten) in umgekehrter Reihenfolge neu:
(HINWEIS 1: Funktioniert für einfache Polygone, nicht für Multipolygone oder Polygone mit Ringen / Zentroiden)
(HINWEIS 2: Verwenden des Koordinatensystems SRID 4326 (WGS 84)

--For existing geography @g
DECLARE @GeometryText varchar(max), @ReversedPolygon geography
DECLARE @GeometryType varchar(20) = 'POLYGON', @Count int
SET @Count = @g.STNumPoints()
WHILE @Count > 0
BEGIN
    SET @GeometryText = @GeometryText + CONVERT(varchar(30),CONVERT(decimal(12,8),@g.STPointN(@Count).Long)) + ' ' + CONVERT(varchar(30),CONVERT(decimal(12,8),@g.STPointN(@Count).Lat))
    SET @Count = @Count - 1
    IF @Count > 0 SET @GeometryText = @GeometryText + ','
END
SET @GeometryText = @GeometryType +'((' + @GeometryText + '))'
SET @ReversedPolygon = geography::STGeomFromText(@GeometryText, 4326); 

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.