Freigeben über


geo_polygon_to_s2cells()

Berechnet S2-Zelltoken, die ein Polygon oder Multipolygon auf der Erde abdecken. Diese Funktion ist ein nützliches Geospatialbeitrittstool.

Weitere Informationen zur S2-Zellhierarchie.

Syntax

geo_polygon_to_s2cells(Polygon [, Level[, Radius]])

Erfahren Sie mehr über Syntaxkonventionen.

Parameter

Name Type Erforderlich Beschreibung
Vieleck dynamic ✔️ Polygon oder Multipolygon im GeoJSON-Format.
level int Definiert die angeforderte Zellenebene. Unterstützte Werte befinden sich im Bereich [0, 30]. Wenn nichts angegeben wird, wird der Standardwert 11 verwendet.
Radius real Pufferradius in Metern. Wenn nichts angegeben wird, wird der Standardwert 0 verwendet.

Gibt zurück

Array von S2-Zellentokenzeichenfolgen, die ein Polygon oder ein Multipolygon abdecken. Wenn der Radius auf einen positiven Wert festgelegt ist, ist die Abdeckung neben dem Eingabe-Shape alle Punkte innerhalb des Radius der Eingabegeometrie. Wenn Polygon, Ebene, Radius ungültig ist oder die Zellanzahl den Grenzwert überschreitet, erzeugt die Abfrage ein NULL-Ergebnis.

Hinweis

  • Die Abdeckung des Polygons mit S2-Zelltoken kann bei der Übereinstimmung von Koordinaten mit Polygonen hilfreich sein, die diese Koordinaten und übereinstimmende Polygone mit Polygonen enthalten können.
  • Das Polygon, das Token abdeckt, ist dieselbe S2-Zellebene.
  • Die maximale Anzahl von Token pro Polygon beträgt 65536.
  • Das geodetische Datum , das für Messungen auf der Erde verwendet wird, ist eine Kugel. Polygonränder sind Geodesik auf der Kugel.
  • Wenn eingabe polygonale Kanten gerade kartesische Linien sind, sollten Sie geo_polygon_densify() verwenden, um planare Kanten in Geodästik zu konvertieren.

Motivation für die Abdeckung von Polygonen mit S2-Zelltoken

Ohne diese Funktion können wir hier einen Ansatz verwenden, um Koordinaten in Polygone zu klassifizieren, die diese Koordinaten enthalten.

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

Output

longitude latitude Beschreibung
-73.95 40.75 New York City
-122.3 47.6 Seattle
-115.18 36.16 Las Vegas

Obwohl diese Methode in einigen Fällen funktioniert, ist sie ineffizient. Diese Methode führt eine Kreuzverknnung durch, d. h., sie versucht, jedes Polygon an jeden Punkt abzugleichen. Dieser Prozess verbraucht eine große Menge an Arbeitsspeicher und Rechenressourcen. Stattdessen möchten wir jedes Polygon an einen Punkt mit einer hohen Wahrscheinlichkeit des Eindämmungserfolgs abgleichen und andere Punkte herausfiltern.

Diese Übereinstimmung kann durch den folgenden Prozess erreicht werden:

  1. Konvertieren von Polygonen in S2-Zellen der Ebene k,
  2. Konvertieren von Punkten in die gleiche S2-Zellenebene k,
  3. Verknüpfen mit S2-Zellen,
  4. Filtern nach geo_point_in_polygon(). Diese Phase kann weggelassen werden, wenn eine Menge falsch positiver Ergebnisse in Ordnung ist. Der maximale Fehler ist der Bereich von s2 Zellen auf Ebene k über die Grenze des Polygons hinaus.

Auswählen der S2-Zellenebene

  • Im Idealfall möchten wir jedes Polygon mit einer oder nur wenigen eindeutigen Zellen abdecken, sodass keine zwei Polygone dieselbe Zelle gemeinsam nutzen.
  • Wenn sich die Polygone nahe beieinander befinden, wählen Sie die S2-Zellenebene so aus, dass der Zellrand kleiner (4, 8, 12 mal kleiner) als der Rand des durchschnittlichen Polygons ist.
  • Wenn sich die Polygone weit voneinander befinden, wählen Sie die S2-Zellenebene aus, sodass derEn Zellrand ähnlich oder größer als der Rand des durchschnittlichen Polygons ist.
  • In der Praxis führt die Abdeckung eines Polygons mit mehr als 10.000 Zellen möglicherweise nicht zu einer guten Leistung.
  • Beispielanwendungsfälle:
  • S2 Zelle Ebene 5 kann sich als gut für die Abdeckung von Ländern/Regionen erweisen.
  • S2 Cell Level 16 kann dichte und relativ kleine Manhattan (New York) Viertel abdecken.
  • S2 Cell Level 11 kann für die Abdeckung von Vororten australiens verwendet werden.
  • Die Laufzeit der Abfrage und der Arbeitsspeicherverbrauch können sich aufgrund unterschiedlicher Werte auf S2-Zellebene erheblich unterscheiden.

Warnung

Die Abdeckung eines großflächigen Polygons mit Zellen mit kleinen Flächen kann zu einer großen Menge an überdeckten Zellen führen. Daher gibt die Abfrage möglicherweise NULL zurück.

Hinweis

Vorschläge zur Leistungsverbesserung:

  • Verringern Sie nach Möglichkeit die Tabellengröße der Koordinaten vor der Verknüpfung, indem Sie Koordinaten gruppieren, die sich sehr nah beieinander befinden, indem Sie geospatiale Clustering verwenden oder nicht ensessäre Koordinaten aufgrund der Art der Daten- oder Geschäftsanforderungen herausfiltern.
  • Reduzieren Sie die Anzahl der Polygone nach Möglichkeit aufgrund der Art der Daten- oder Geschäftsanforderungen. Filtern Sie unnötige Polygone vor dem Verbinden, bereichsbezogene Bereiche auf den Bereich von Interesse oder vereinheitlichen Polygone.
  • Reduzieren Sie bei sehr großen Polygonen ihre Größe mithilfe von geo_polygon_simplify().
  • Das Ändern der S2-Zellebene kann die Leistung und den Arbeitsspeicherverbrauch verbessern.
  • Das Ändern der Verknüpfungsart und hinweise kann die Leistung und den Arbeitsspeicherverbrauch verbessern.
  • Wenn ein positiver Radius festgelegt ist, können Sie versuchen, die Leistung zu verbessern, indem Sie den Radius 0 für gepufferte Form mithilfe von geo_polygon_buffer() wiederherstellen.

Beispiele

Im folgenden Beispiel werden Koordinaten in Polygone klassifiziert.

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

Output

longitude latitude Beschreibung
-73.9741 40.7914 Obere Westseite
-73.995 40.734 Greenwich Village
-73.9584 40.7688 Obere Ostseite

Hier ist noch mehr Verbesserung bei der obigen Abfrage. Zählen Sie Sturmereignisse pro US-Bundesstaat. Die folgende Abfrage führt eine sehr effiziente Verknüpfung durch, da sie keine Polygone durch die Verknüpfung führt und den Nachschlageoperator verwendet .

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

Output

StateName StormEventsCountByState
Florida 960
Georgien 1085
... ...

Im folgenden Beispiel werden Polygone herausfiltert, die sich nicht mit dem Bereich des interessanten Polygons überschneiden. Der maximale Fehler ist diagonal von der Länge der s2cell. Dieses Beispiel basiert auf einer polygonisierten Erde in der Nachtrasterdatei.

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

Output

Anzahl
83

Anzahl der Zellen, die benötigt werden, um einige Polygone mit S2-Zellen der Ebene 5 abzudecken.

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));

Output

s2_cell_token_count
286

Wenn sie ein polygon großes Gebiet mit Zellen mit kleinen Flächen abdecken, wird null zurückgegeben.

let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print geo_polygon_to_s2cells(polygon, 30);

Output

print_0

Wenn sie ein polygon großes Gebiet mit Zellen mit kleinen Flächen abdecken, wird null zurückgegeben.

let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print isnull(geo_polygon_to_s2cells(polygon, 30));

Output

print_0
1