Zmień „handedness” wielokąta dla SQL 2008 (odwrotna kolejność wierzchołków wielokątów)

11

Mam kilkaset kształty ( polygonS multipolygons) każda składająca się z dziesiątków tysięcy punktów, które staram się dostać do SQL 2008.

Niestety kształty, które próbowałem zaimportować, są „praworęczne” (obwód każdego z nich jest narysowany zgodnie z ruchem wskazówek zegara wokół zawartych w nim punktów). Serwer SQL przyjmuje kształty „leworęczne” (przeciwnie do ruchu wskazówek zegara wokół wnętrza), przynajmniej dla geographytypów. Oznacza to, że SQL zakłada, że ​​próbuję wybrać całą ziemię oprócz mojego kształtu. Niektórzy opisują to jako kształty „na lewą stronę”.

Z MSDN , który frustrująco nie mówi, której orientacji pierścienia należy użyć:

Jeśli używamy geographytypu danych do przechowywania instancji przestrzennej, musimy określić orientację pierścienia i dokładnie opisać lokalizację instancji.

Jeśli użyjesz niewłaściwej orientacji pierścienia w SQL 2008, ulega awarii z następującym błędem (wyróżnienie moje):

Wystąpił błąd programu .NET Framework podczas wykonywania procedury zdefiniowanej przez użytkownika lub agregacji „geografii”: Microsoft.SqlServer.Types.GLArgumentException: 24205: Podane dane wejściowe nie reprezentują prawidłowej instancji geograficznej, ponieważ przekraczają jedną półkulę. Każda instancja geograficzna musi mieścić się na jednej półkuli. Częstą przyczyną tego błędu jest niewłaściwa orientacja wielokąta.

Importowanie kształtów geometryzamiast geographydziała dobrze, ale chciałbym użyć, geographyjeśli mogę.

W SQL 2012 rozwiązanie tego problemu wydaje się dość trywialne , ale jestem przywiązany do 2008 roku.

Jak konwertować kształty?

Michael - Where's Clay Shirky
źródło
1
+1 świetne pytanie ... czy masz link, w którym mówi, że serwer Sql przyjmuje kształty dla leworęcznych?
Kirk Kuykendall
@Kirk Thanks. Mam problem ze znalezieniem oficjalnej dokumentacji, ale mogę połączyć się z MSDN, gdzie jest napisane, że „orientacja pierścienia” ma znaczenie (chociaż nie mówi, w jaki sposób użyć). Wprowadzę również błąd, który pojawia się, gdy ulega awarii.
Michael - Where's Clay Shirky

Odpowiedzi:

14

Blog Spatial Ed miał zwięzłe rozwiązanie. Oto trochę SQL demonstrujący transformację:

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

I fragment postu Eda:

Kluczem do tego zachowania jest STUnion()metoda. Ponieważ jest to metoda oparta na OGC, działająca na całą geometrię dla danej operacji, wymusza wielokąty do orientacji wymaganej dla tej metody - która akurat jest taka, jak dla tego Geographytypu [...]. Ta zilustrowana metoda jest dość wydajna, utrzymując małe koszty ogólne [...].

Michael - Where's Clay Shirky
źródło
2
Na SQL Server 2008 R2 musiałem również umieścić .MakeValid () wewnątrz STUnion (), aby to zadziałało: .STUnion (@ geom.MakeValid (). STStartPoint ())
Chris Smith
@Smitty Ma to sens w przypadkach, w których SQL nie może inaczej określić punktu początkowego. Może jeśli kształt podwaja się nad sobą lub w innych dziwnych okolicznościach?
Michael - Where's Clay Shirky
Tak, w moich okolicznościach kształt jest chropowaty i zachodzi na siebie.
Chris Smith,
0

W> = SQL Server 2012 metoda ReorientObject () powinna to osiągnąć. Dla <SQL Server 2012 poniżej znajduje się alternatywna metoda.

W przypadku istniejącej geografii SQL @g poniższy kod wyodrębni punkty i ponownie utworzy wielokąt z punktami (wierzchołkami) w odwrotnej kolejności:
(UWAGA 1: działa na proste wielokąty, a nie na wielokąty lub wielokąty z pierścieniami / centroidami)
(UWAGA 2: za pomocą układu współrzędnych 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); 
Baodad
źródło
0

Wygląda na to, że mogę użyć jakiejś bezbożnej hybrydy SQL i C # z SQL Server Spatial Tools , zgodnie z sugestią dotyczącą przepełnienia stosu .

Uwaga: w momencie opublikowania tej odpowiedzi nie było tam zbyt wielu informacji. Nie próbuj tej metody, chyba że potrzebujesz już SQL Server Spatial Tools do czegoś innego. Zamiast tego wypróbuj jedną z pozostałych odpowiedzi tutaj lub w sekcji Przepełnienie stosu .

Michael - Where's Clay Shirky
źródło