Ubah "kidal" poligon untuk SQL 2008 (urutan vertex terbalik poligon)

11

Saya memiliki beberapa ratus bentuk ( polygons dan multipolygons) masing-masing terdiri dari puluhan ribu poin yang saya coba masuk ke SQL 2008.

Sayangnya, bentuk yang saya coba impor adalah "tangan kanan" (perimeter masing-masing ditarik searah jarum jam di sekitar titik-titik di dalamnya). SQL server mengasumsikan bentuk "kidal" (anti-searah jarum jam di sekitar interior), setidaknya untuk geographyjenis. Ini berarti bahwa SQL mengasumsikan bahwa saya mencoba untuk memilih seluruh bumi kecuali untuk bentuk saya. Beberapa orang menggambarkan ini sebagai bentuk "luar-dalam".

Dari MSDN , yang dengan putus asa tidak mengatakan orientasi dering mana yang harus digunakan:

Jika kita menggunakan geographytipe data untuk menyimpan instance spasial, kita harus menentukan orientasi cincin dan secara akurat menggambarkan lokasi instance.

Jika Anda menggunakan orientasi dering yang salah di SQL 2008, itu macet dengan kesalahan berikut (penekanan tambang):

Kesalahan .NET Framework terjadi selama eksekusi rutin yang ditentukan pengguna atau "geografi" agregat: Microsoft.SqlServer.Types.GLArgumentException: 24205: Input yang ditentukan tidak mewakili instance geografi yang valid karena melebihi satu belahan bumi. Setiap instance geografi harus masuk dalam satu belahan bumi. Alasan umum untuk kesalahan ini adalah poligon memiliki orientasi dering yang salah.

Mengimpor bentuk sebagai geometryganti geographyberfungsi dengan baik, tapi saya ingin menggunakannya geographyjika saya bisa.

Di SQL 2012, tampaknya cukup sepele untuk memperbaiki masalah ini, tapi saya terikat pada 2008.

Bagaimana saya harus mengubah bentuk?

Michael - Dimana Clay Shirky
sumber
1
+1 pertanyaan bagus ... apakah Anda memiliki tautan di mana dikatakan Sql server mengasumsikan bentuk kidal?
Kirk Kuykendall
@ Sir Terima kasih. Saya mengalami masalah dalam menemukan dokumentasi resmi, tetapi saya dapat menautkan ke MSDN di mana dikatakan "orientasi cincin" penting (meskipun tidak disebutkan cara penggunaannya). Saya juga akan memasukkan kesalahan yang didapat saat crash.
Michael - Di mana Clay Shirky

Jawaban:

14

Blog Spatial Ed punya solusi ringkas. Berikut adalah beberapa SQL yang menunjukkan transformasi:

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

Dan kutipan dari posting Ed:

Kunci dari perilaku ini adalah STUnion()metodenya. Karena ini adalah metode berbasis OGC, bekerja pada seluruh geometri untuk fitur yang diberikan, itu memaksa poligon ke dalam orientasi yang diperlukan untuk metode ini — yang kebetulan merupakan yang digunakan untuk Geographytipe [...]. Metode ini diilustrasikan cukup efisien, menjaga overhead kecil [...].

Michael - Dimana Clay Shirky
sumber
2
Pada SQL Server 2008 r2, saya harus meletakkan .MakeValid () di bagian dalam STUnion () juga agar ini berfungsi: .STUnion (@ geom.MakeValid (). STStartPoint ())
Chris Smith
@Smitty Itu masuk akal untuk kasus-kasus di mana SQL tidak bisa menentukan titik awal. Mungkin jika bentuknya menggandakan diri atau keadaan aneh lainnya?
Michael - Di mana Clay Shirky
Ya, dalam keadaan saya, bentuknya aneh dan tumpang tindih.
Chris Smith
0

Dalam> = SQL Server 2012, metode ReorientObject () harus menyelesaikan ini. Untuk <SQL Server 2012, di bawah ini adalah metode alternatif.

Untuk SQL geografi @g yang ada, kode di bawah ini akan mengekstrak poin dan membuat kembali poligon dengan poin (simpul) dalam urutan terbalik:
(CATATAN 1: berfungsi untuk poligon sederhana, bukan untuk multipoligon atau poligon dengan cincin / centroid)
(CATATAN 2: menggunakan sistem koordinat 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
sumber
0

Sepertinya saya dapat menggunakan beberapa hybrid SQL dan C # yang tidak suci dari SQL Server Spatial Tools , seperti yang disarankan pada Stack Overflow .

Catatan: Pada saat jawaban ini diposting, tidak ada banyak informasi di luar sana. Tolong jangan coba metode ini kecuali Anda sudah membutuhkan SQL Server Spatial Tools untuk hal lain. Alih-alih, coba salah satu jawaban lain di sini atau di Stack Overflow .

Michael - Dimana Clay Shirky
sumber