geo_polygon_to_s2cells()
Dotyczy: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Oblicza tokeny komórek S2, które obejmują wielokąt lub wielopolygon na Ziemi. Ta funkcja jest przydatnym narzędziem sprzężenia geoprzestrzennego.
Przeczytaj więcej na temat hierarchii komórek S2.
Składnia
geo_polygon_to_s2cells(
wielokąt [,
poziom[,
promień]])
Dowiedz się więcej na temat konwencji składni.
Parametry
Nazwisko | Type | Wymagania | opis |
---|---|---|---|
wielokąt | dynamic |
✔️ | Wielokąt lub multipolygon w formacie GeoJSON. |
poziom | int |
Definiuje żądany poziom komórki. Obsługiwane wartości znajdują się w zakresie [0, 30]. Jeśli nie określono, zostanie użyta wartość 11 domyślna. |
|
promień | real |
Promień buforu w metrach. Jeśli nie określono, zostanie użyta wartość 0 domyślna. |
Zwraca
Tablica ciągów tokenu komórki S2, które obejmują wielokąt lub wielokąt. Jeśli promień jest ustawiony na wartość dodatnią, pokrycie będzie, oprócz kształtu wejściowego, wszystkich punktów w promieniu geometrii wejściowej. Jeśli wielokąt, poziom, promień jest nieprawidłowy lub liczba komórek przekracza limit, zapytanie spowoduje wygenerowanie wyniku null.
Uwaga
- Pokrycie wielokąta za pomocą tokenów komórek S2 może być przydatne w dopasowywaniu współrzędnych do wielokątów, które mogą obejmować te współrzędne i pasujące wielokąty do wielokątów.
- Wielokąt obejmujący tokeny są na tym samym poziomie komórki S2.
- Maksymalna liczba tokenów na wielokąt wynosi 65536.
- Geodetyczne datum używane do pomiarów na Ziemi jest sferą. Krawędzie wielokątne są geodesykami na sferze.
- Jeśli krawędzie wielokąta wejściowe są liniami kartezjańskimi, rozważ użycie geo_polygon_densify() w celu przekonwertowania krawędzi planarnych na geodesyki.
Motywacja do pokrycia wielokątów za pomocą tokenów komórek S2
Bez tej funkcji możemy użyć jednego podejścia w celu sklasyfikowania współrzędnych na wielokąty zawierające te współrzędne.
let Polygons =
datatable(description:string, polygon:dynamic)
[
"New York", dynamic({"type":"Polygon","coordinates":[[[-73.85009765625,40.85744791303121],[-74.16046142578125,40.84290487729676],[-74.190673828125,40.59935608796518],[-73.83087158203125,40.61812224225511],[-73.85009765625,40.85744791303121]]]}),
"Seattle", dynamic({"type":"Polygon","coordinates":[[[-122.200927734375,47.68573021131587],[-122.4591064453125,47.68573021131587],[-122.4755859375,47.468949677672484],[-122.17620849609374,47.47266286861342],[-122.200927734375,47.68573021131587]]]}),
"Las Vegas", dynamic({"type":"Polygon","coordinates":[[[-114.9,36.36],[-115.4498291015625,36.33282808737917],[-115.4498291015625,35.84453450421662],[-114.949951171875,35.902399875143615],[-114.9,36.36]]]}),
];
let Coordinates =
datatable(longitude:real, latitude:real)
[
real(-73.95), real(40.75), // New York
real(-122.3), real(47.6), // Seattle
real(-115.18), real(36.16) // Las Vegas
];
Polygons | extend dummy=1
| join kind=inner (Coordinates | extend dummy=1) on dummy
| where geo_point_in_polygon(longitude, latitude, polygon)
| project longitude, latitude, description
Wyjście
długość geograficzna | latitude | opis |
---|---|---|
-73.95 | 40.75 | Nowy Jork |
-122.3 | 47.6 | Seattle |
-115.18 | 36.16 | Las Vegas |
Chociaż ta metoda działa w niektórych przypadkach, jest nieefektywna. Ta metoda wykonuje sprzężenie krzyżowe, co oznacza, że próbuje dopasować każdy wielokąt do każdego punktu. Ten proces zużywa dużą ilość pamięci i zasobów obliczeniowych. Zamiast tego chcemy dopasować każdy wielokąt do punktu z wysokim prawdopodobieństwem powodzenia powstrzymania i odfiltrować inne punkty.
To dopasowanie można osiągnąć przez następujący proces:
- Konwertowanie wielokątów na komórki S2 poziomu k,
- Konwertowanie punktów na ten sam poziom komórek S2 k,
- Łączenie na komórkach S2,
- Filtrowanie według geo_point_in_polygon(). Tę fazę można pominąć, jeśli pewna ilość wyników fałszywie dodatnich jest w porządku. Maksymalny błąd będzie obszarem komórek s2 na poziomie k poza granicą wielokąta.
Wybieranie poziomu komórki S2
- W idealnym przypadku chcemy pokryć każdy wielokąt jednym lub tylko kilkoma unikatowymi komórkami, tak aby żadne dwa wielokąty miały tę samą komórkę.
- Jeśli wielokąty są blisko siebie, wybierz poziom komórki S2, tak aby jego krawędź komórki będzie mniejsza (4, 8, 12 razy mniejsza) niż krawędź średniego wielokąta.
- Jeśli wielokąty są dalekie od siebie, wybierz poziom komórki S2, tak aby jego krawędź komórki będzie podobna lub większa niż krawędź średniego wielokąta.
- W praktyce pokrycie wielokąta z ponad 10 000 komórek może nie przynieść dobrej wydajności.
- Przykładowe przypadki użycia:
- Poziom S2 komórki 5 może okazać się dobry dla krajów/regionów.
- Poziom komórki S2 16 może obejmować gęste i stosunkowo małe dzielnice Manhattan (Nowy Jork).
- Poziom S2 komórki 11 może służyć do pokrycia przedmieściach Australii.
- Użycie czasu wykonywania zapytań i pamięci może się znacznie różnić ze względu na różne wartości na poziomie komórki S2.
Ostrzeżenie
Pokrycie wielokąta dużego obszaru z komórkami o małym obszarze może prowadzić do ogromnej ilości komórek pokrywających. W związku z tym zapytanie może zwrócić wartość null.
Uwaga
Sugestie dotyczące poprawy wydajności:
- Jeśli to możliwe, zmniejsz rozmiar tabeli współrzędnych przed sprzężenie, grupując współrzędne, które są bardzo blisko siebie przy użyciu klastrowania geoprzestrzennego lub przez filtrowanie współrzędnych niezrejeźnych ze względu na charakter danych lub potrzeb biznesowych.
- Jeśli to możliwe, zmniejsz liczbę wielokątów ze względu na charakter danych lub potrzeb biznesowych. Odfiltruj niepotrzebne wielokąty przed sprzężeniami, zakres do obszaru zainteresowania lub ujednolicenie wielokątów.
- W przypadku bardzo dużych wielokątów zmniejsz ich rozmiar przy użyciu geo_polygon_simplify().
- Zmiana poziomu komórki S2 może zwiększyć wydajność i zużycie pamięci.
- Zmiana rodzaju sprzężenia i wskazówka może poprawić wydajność i zużycie pamięci.
- Jeśli ustawiono promień dodatni, możesz spróbować poprawić wydajność, przywracając promień 0 dla kształtu buforowanego przy użyciu geo_polygon_buffer ().
Przykłady
Poniższy przykład klasyfikuje współrzędne na wielokąty.
let Polygons =
datatable(description:string, polygon:dynamic)
[
'Greenwich Village', dynamic({"type":"Polygon","coordinates":[[[-73.991460000000131,40.731738000000206],[-73.992854491775518,40.730082566051351],[-73.996772,40.725432000000154],[-73.997634685522883,40.725786309886963],[-74.002855946639244,40.728346630056791],[-74.001413,40.731065000000207],[-73.996796995070824,40.73736378205173],[-73.991724524037934,40.735245208931886],[-73.990703782359589,40.734781896080477],[-73.991460000000131,40.731738000000206]]]}),
'Upper West Side', dynamic({"type":"Polygon","coordinates":[[[-73.958357552055688,40.800369095633819],[-73.98143901556422,40.768762584141953],[-73.981548752788598,40.7685590292784],[-73.981565335901905,40.768307084720796],[-73.981754418060945,40.768399727738668],[-73.982038573548124,40.768387823012056],[-73.982268248204349,40.768298621883247],[-73.982384797518051,40.768097213086911],[-73.982320919746599,40.767894461792181],[-73.982155532845766,40.767756204474757],[-73.98238873834039,40.767411004834273],[-73.993650353659021,40.772145571634361],[-73.99415893763998,40.772493009137818],[-73.993831082030937,40.772931787850908],[-73.993891252437052,40.772955194876722],[-73.993962585514595,40.772944653908901],[-73.99401262480508,40.772882846631894],[-73.994122058082397,40.77292405902601],[-73.994136652588594,40.772901870174394],[-73.994301342391154,40.772970028663913],[-73.994281535134448,40.77299380206933],[-73.994376552751078,40.77303955110149],[-73.994294029824005,40.773156243992048],[-73.995023275860802,40.773481196576356],[-73.99508939189289,40.773388475039134],[-73.995013963716758,40.773358035426909],[-73.995050284699261,40.773297153189958],[-73.996240651898916,40.773789791397689],[-73.996195837470992,40.773852356184044],[-73.996098807369748,40.773951805299085],[-73.996179459973888,40.773986954351571],[-73.996095245226442,40.774086186437756],[-73.995572265161172,40.773870731394297],[-73.994017424135961,40.77321375261053],[-73.993935876811335,40.773179512586211],[-73.993861942928888,40.773269531698837],[-73.993822393527211,40.773381758622882],[-73.993767019318497,40.773483981224835],[-73.993698463744295,40.773562141052594],[-73.993358326468751,40.773926888327956],[-73.992622663865575,40.774974056037109],[-73.992577842766124,40.774956016359418],[-73.992527743951555,40.775002110439829],[-73.992469745815342,40.775024159551755],[-73.992403837191887,40.775018140390664],[-73.99226708903538,40.775116033858794],[-73.99217809026365,40.775279293897171],[-73.992059084937338,40.775497598192516],[-73.992125372394938,40.775509075053385],[-73.992226867797001,40.775482211026116],[-73.992329346608813,40.775468900958522],[-73.992361756801131,40.775501899766638],[-73.992386042960277,40.775557180424634],[-73.992087684712729,40.775983970821372],[-73.990927174149746,40.777566878763238],[-73.99039616003671,40.777585065679204],[-73.989461267506471,40.778875124584417],[-73.989175778438053,40.779287524015778],[-73.988868617400072,40.779692922911607],[-73.988871874499793,40.779713738253008],[-73.989219022880576,40.779697895209402],[-73.98927785904425,40.779723439271038],[-73.989409054180143,40.779737706471963],[-73.989498614927044,40.779725044389757],[-73.989596493388234,40.779698146683387],[-73.989679812902509,40.779677568658038],[-73.989752702937935,40.779671244211556],[-73.989842247806507,40.779680752670664],[-73.990040102120489,40.779707677698219],[-73.990137977524839,40.779699769704784],[-73.99033584033225,40.779661794394983],[-73.990430598697046,40.779664973055503],[-73.990622199396725,40.779676064914298],[-73.990745069505479,40.779671328184051],[-73.990872114282197,40.779646007643876],[-73.990961672224358,40.779639683751753],[-73.991057472829539,40.779652352625774],[-73.991157429497036,40.779669775606465],[-73.991242817404469,40.779671367084504],[-73.991255318289745,40.779650782516491],[-73.991294887120119,40.779630209208889],[-73.991321967649895,40.779631796041372],[-73.991359455569423,40.779585883337383],[-73.991551059227476,40.779574821437407],[-73.99141982585985,40.779755280287233],[-73.988886144117032,40.779878898532999],[-73.988939656706265,40.779956178440393],[-73.988926103530844,40.780059292013632],[-73.988911680264692,40.780096037146606],[-73.988919261468567,40.780226094343945],[-73.988381050202634,40.780981074045783],[-73.988232413846987,40.781233144215555],[-73.988210420831663,40.781225482542055],[-73.988140000000143,40.781409000000224],[-73.988041288067166,40.781585961353777],[-73.98810029382463,40.781602878305286],[-73.988076449145055,40.781650935001608],[-73.988018059972219,40.781634188810422],[-73.987960792842145,40.781770987031535],[-73.985465811970457,40.785360700575431],[-73.986172704965611,40.786068452258647],[-73.986455862401996,40.785919219081421],[-73.987072345615601,40.785189638820121],[-73.98711901394276,40.785210319004058],[-73.986497781023601,40.785951202887254],[-73.986164628806279,40.786121882448327],[-73.986128422486075,40.786239001331111],[-73.986071135219746,40.786240706026611],[-73.986027274789123,40.786228964236727],[-73.986097637849426,40.78605822569795],[-73.985429321269592,40.785413942184597],[-73.985081137732209,40.785921935110366],[-73.985198833254501,40.785966552197777],[-73.985170502389906,40.78601333415817],[-73.985216218673656,40.786030501816427],[-73.98525509797993,40.785976205511588],[-73.98524273937646,40.785972572653328],[-73.98524962933017,40.785963139855845],[-73.985281779186749,40.785978620950075],[-73.985240032884533,40.786035858136792],[-73.985683885242182,40.786222123919686],[-73.985717529004575,40.786175994668795],[-73.985765660297687,40.786196274858618],[-73.985682871922691,40.786309786213067],[-73.985636270930442,40.786290150649279],[-73.985670722564691,40.786242911993817],[-73.98520511880038,40.786047669212785],[-73.985211035607492,40.786039554883686],[-73.985162639946992,40.786020999769754],[-73.985131636312062,40.786060297019972],[-73.985016964065125,40.78601423719563],[-73.984655078830457,40.786534741807841],[-73.985743787901043,40.786570082854738],[-73.98589227228328,40.786426529019593],[-73.985942854994988,40.786452847880334],[-73.985949561556794,40.78648711396653],[-73.985812373526713,40.786616865357047],[-73.985135209703174,40.78658761889551],[-73.984619428584324,40.786586016349787],[-73.981952458164173,40.790393724337193],[-73.972823037363767,40.803428052816756],[-73.971036786332192,40.805918478839672],[-73.966701,40.804169000000186],[-73.959647,40.801156000000113],[-73.958508540159471,40.800682279767472],[-73.95853274080838,40.800491362464697],[-73.958357552055688,40.800369095633819]]]}),
'Upper East Side', dynamic({"type":"Polygon","coordinates":[[[-73.943592454622546,40.782747908206574],[-73.943648235390199,40.782656161333449],[-73.943870759887162,40.781273026571704],[-73.94345932494096,40.780048275653243],[-73.943213862652243,40.779317588660199],[-73.943004239504688,40.779639495474292],[-73.942716005450905,40.779544169476175],[-73.942712374762181,40.779214856940001],[-73.942535563208608,40.779090956062532],[-73.942893408188027,40.778614093246276],[-73.942438481745029,40.777315235766039],[-73.942244919522594,40.777104088947254],[-73.942074188038887,40.776917846977142],[-73.942002667222781,40.776185317382648],[-73.942620205199006,40.775180871576474],[-73.94285645694552,40.774796600349191],[-73.94293043781397,40.774676268036011],[-73.945870899588215,40.771692257932997],[-73.946618690150586,40.77093339256956],[-73.948664164778933,40.768857624399587],[-73.950069793030679,40.767025088383498],[-73.954418260786071,40.762184104951245],[-73.95650786241211,40.760285256574043],[-73.958787773424007,40.758213471309809],[-73.973015157270069,40.764278692864671],[-73.955760332998182,40.787906554459667],[-73.944023,40.782960000000301],[-73.943592454622546,40.782747908206574]]]}),
];
let Coordinates =
datatable(longitude:real, latitude:real)
[
real(-73.9741), 40.7914, // Upper West Side
real(-73.9950), 40.7340, // Greenwich Village
real(-73.9584), 40.7688, // Upper East Side
];
let Level = 16;
Polygons
| extend covering = geo_polygon_to_s2cells(polygon, Level) // cover every polygon with s2 cell token array
| mv-expand covering to typeof(string) // expand cells array such that every row will have one cell mapped to its polygon
| join kind=inner hint.strategy=broadcast // assume that Polygons count is small (In some specific case)
(
Coordinates
| extend covering = geo_point_to_s2cell(longitude, latitude, Level) // cover point with cell
) on covering // join on the cell, this filters out rows of point and polygons where the point definitely does not belong to the polygon
| where geo_point_in_polygon(longitude, latitude, polygon) // final filtering for exact result
| project longitude, latitude, description
Wyjście
długość geograficzna | latitude | opis |
---|---|---|
-73.9741 | 40.7914 | Górna strona zachodnia |
-73.995 | 40.734 | Greenwich Village |
-73.9584 | 40.7688 | Górna strona wschodnia |
Oto jeszcze więcej ulepszeń dla powyższego zapytania. Liczba zdarzeń burzy na stan USA. Poniższe zapytanie wykonuje bardzo wydajne sprzężenia, ponieważ nie przenosi wielokątów za pośrednictwem sprzężenia i używa operatora odnośnika
let Level = 6;
let polygons = materialize(
US_States
| project StateName = tostring(features.properties.NAME), polygon = features.geometry, id = new_guid());
let tmp =
polygons
| project id, covering = geo_polygon_to_s2cells(polygon, Level)
| mv-expand covering to typeof(string)
| join kind=inner hint.strategy=broadcast
(
StormEvents
| project lng = BeginLon, lat = BeginLat
| project lng, lat, covering = geo_point_to_s2cell(lng, lat, Level)
) on covering
| project-away covering, covering1;
tmp | lookup polygons on id
| project-away id
| where geo_point_in_polygon(lng, lat, polygon)
| summarize StormEventsCountByState = count() by StateName
Wyjście
StateName | StormEventsCountByState |
---|---|
Floryda | 960 |
Gruzja | 1085 |
... | ... |
Poniższy przykład filtruje wielokąty, które nie przecinają się z obszarem wielokąta zainteresowania. Maksymalny błąd to przekątna długości s2cell. Ten przykład jest oparty na wielokątnej ziemi w nocnym pliku rasterowym.
let intersection_level_hint = 7;
let area_of_interest = dynamic({"type": "Polygon","coordinates": [[[-73.94966125488281,40.79698248639272],[-73.95841598510742,40.800426144169315],[-73.98124694824219,40.76806170936614],[-73.97283554077148,40.7645513650551],[-73.94966125488281,40.79698248639272]]]});
let area_of_interest_covering = geo_polygon_to_s2cells(area_of_interest, intersection_level_hint);
EarthAtNight
| project value = features.properties.DN, polygon = features.geometry
| extend covering = geo_polygon_to_s2cells(polygon, intersection_level_hint)
| mv-apply c = covering to typeof(string) on
(
summarize is_intersects = take_anyif(1, array_index_of(area_of_interest_covering, c) != -1)
)
| where is_intersects == 1
| count
Wyjście
Count |
---|
83 |
Liczba komórek, które będą potrzebne do pokrycia części wielokąta z komórkami S2 poziomu 5.
let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print s2_cell_token_count = array_length(geo_polygon_to_s2cells(polygon, 5));
Wyjście
s2_cell_token_count |
---|
286 |
Pokrycie wielokąta dużego obszaru z komórkami o małym obszarze zwraca wartość null.
let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print geo_polygon_to_s2cells(polygon, 30);
Wyjście
print_0 |
---|
Pokrycie wielokąta dużego obszaru z komórkami o małym obszarze zwraca wartość null.
let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print isnull(geo_polygon_to_s2cells(polygon, 30));
Wyjście
print_0 |
---|
1 |