Delen via


geo_polygon_to_s2cells()

Berekent S2-celtokens die een veelhoek of multipolygon op aarde bedekken. Deze functie is een handig hulpprogramma voor georuimtelijke koppeling.

Syntax

geo_polygon_to_s2cells(veelhoek [,niveau[,radius]])

Meer informatie over syntaxisconventies.

Parameters

Naam Type Vereist Beschrijving
Veelhoek dynamic ✔️ Veelhoek of multipolygon in de GeoJSON-indeling.
Niveau int Hiermee definieert u het aangevraagde celniveau. Ondersteunde waarden bevinden zich in het bereik [0, 30]. Als u dit niet opgeeft, wordt de standaardwaarde 11 gebruikt.
Radius real Bufferradius in meters. Als u dit niet opgeeft, wordt de standaardwaarde 0 gebruikt.

Retouren

Matrix van S2-celtokenreeksen die een veelhoek of een multipolygon bedekken. Als radius is ingesteld op een positieve waarde, is de afdekking, naast de invoervorm, van alle punten binnen de radius van de invoergeometrie. Als veelhoek, niveau, radius ongeldig is of het aantal cellen de limiet overschrijdt, produceert de query een null-resultaat.

Notitie

  • Het afdekken van de veelhoek met S2-celtokens kan handig zijn bij het vergelijken van coördinaten met veelhoeken die deze coördinaten kunnen bevatten en overeenkomende veelhoeken met veelhoeken.
  • De veelhoek met tokens is van hetzelfde S2-celniveau.
  • Het maximum aantal tokens per veelhoek is 65536.
  • De geodetische datum die wordt gebruikt voor metingen op aarde is een bol. Polygoonranden zijn geodeën op de bol.
  • Als de randen van de invoer veelhoek rechte cartesische lijnen zijn, kunt u overwegen geo_polygon_densify() te gebruiken om planaire randen te converteren naar geodetische lijnen.

Motivatie voor het bedekken van veelhoeken met S2-celtokens

Zonder deze functie is er één benadering die we kunnen gebruiken om coördinaten te classificeren in veelhoeken die deze coördinaten bevatten.

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

Uitvoer

lengtegraad breedtegraad beschrijving
-73,95 40,75 New York
-122.3 47.6 Seattle
-115.18 36.16 Las Vegas

Hoewel deze methode in sommige gevallen werkt, is deze inefficiënt. Met deze methode wordt een cross-join uitgevoerd, wat betekent dat elke veelhoek wordt vergeleken met elk punt. Dit proces verbruikt een grote hoeveelheid geheugen en rekenresources. In plaats daarvan willen we elke veelhoek vergelijken met een punt met een hoge waarschijnlijkheid van insluitingssucces en andere punten eruit filteren.

Deze overeenkomst kan worden bereikt door het volgende proces:

  1. Veelhoeken converteren naar S2-cellen van niveau k,
  2. Punten converteren naar hetzelfde S2-celniveau k,
  3. Samenvoegen op S2-cellen,
  4. Filteren op geo_point_in_polygon(). Deze fase kan worden weggelaten als een aantal fout-positieven in orde is. De maximale fout is het gebied van s2-cellen op niveau k buiten de grens van de veelhoek.

Het celniveau S2 kiezen

  • Idealiter zouden we elke veelhoek willen bedekken met één of slechts enkele unieke cellen, zodat geen twee veelhoeken dezelfde cel delen.
  • Als de veelhoeken dicht bij elkaar liggen, kiest u het celniveau S2 zodat de celrand kleiner is (4, 8, 12 keer kleiner) dan de rand van de gemiddelde veelhoek.
  • Als de veelhoeken ver van elkaar liggen, kiest u het celniveau S2 zodat de celrand vergelijkbaar is met of groter is dan de rand van de gemiddelde veelhoek.
  • In de praktijk levert het afdekken van een veelhoek met meer dan 10.000 cellen mogelijk geen goede prestaties op.
  • Voorbeelden van gebruiksvoorbeelden:
  • S2 celniveau 5 kan goed zijn voor landen/regio's.
  • S2 celniveau 16 kan dichte en relatief kleine manhattanwijken (New York) omvatten.
  • S2 celniveau 11 kan worden gebruikt voor het afdekken van buitenwijken van Australië.
  • De uitvoeringstijd van query's en het geheugenverbruik kunnen sterk verschillen vanwege verschillende waarden op celniveau S2.

Waarschuwing

Het bedekken van een groot vlak veelhoek met cellen met kleine oppervlakten kan leiden tot een enorme hoeveelheid afdekkende cellen. Als gevolg hiervan kan de query null retourneren.

Notitie

Suggesties voor prestatieverbetering:

  • Verklein indien mogelijk de grootte van de coördinatentabellen voordat u de join uitvoert, door coördinaten die zeer dicht bij elkaar liggen te groeperen met behulp van georuimtelijke clustering of door niet-gekoppelde coördinaten uit te filteren vanwege de aard van de gegevens of zakelijke behoeften.
  • Verminder indien mogelijk het aantal veelhoeken vanwege de aard van de gegevens of zakelijke behoeften. Filter overbodige veelhoeken uit voordat u samenvoegt, bereik tot het interessegebied of veelhoeken samenvoegen.
  • In het geval van zeer grote veelhoeken verkleint u de grootte met behulp van geo_polygon_simplify().
  • Als u het niveau van de S2-cel wijzigt, kunnen de prestaties en het geheugenverbruik worden verbeterd.
  • Het wijzigen van de soort en hint voor joins kan de prestaties en het geheugenverbruik verbeteren.
  • Als een positieve radius is ingesteld, kunt u proberen de prestaties te verbeteren door terug te keren naar radius 0 op gebufferde shape met behulp van geo_polygon_buffer().

Voorbeelden

In het volgende voorbeeld worden coördinaten ingedeeld in veelhoeken.

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

Uitvoer

lengtegraad breedtegraad beschrijving
-73.9741 40.7914 Bovenzijde west
-73.995 40.734 Greenwich Village
-73.9584 40.7688 Upper East Side

Hier is nog meer verbetering ten opzichte van de bovenstaande query. Stormgebeurtenissen per Amerikaanse staat tellen. Met de onderstaande query wordt een zeer efficiënte join uitgevoerd omdat deze geen veelhoeken door de join voert en de opzoekoperator gebruikt

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

Uitvoer

StateName StormEventsCountByState
Florida 960
Georgië 1085
... ...

In het volgende voorbeeld worden veelhoeken gefilterd die elkaar niet snijden met het gebied van de gewenste veelhoek. De maximale fout is diagonaal van de lengte s2cell. Dit voorbeeld is gebaseerd op een rasterbestand met veelgeveelde aarde bij nacht.

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

Uitvoer

Count
83

Het aantal cellen dat nodig is om een bepaalde veelhoek te bedekken met S2-cellen van niveau 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));

Uitvoer

s2_cell_token_count
286

Als u een groot vlak veelhoek bedekt met cellen met kleine oppervlakten, wordt null geretourneerd.

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

Uitvoer

print_0

Als u een groot vlak veelhoek bedekt met cellen met kleine oppervlakten, wordt null geretourneerd.

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

Uitvoer

print_0
1