geo_polygon_to_s2cells()
Beräknar S2-celltoken som täcker en polygon eller multipolygon på jorden. Den här funktionen är ett användbart geospatialt kopplingsverktyg.
Syntax
geo_polygon_to_s2cells(
polygon [,
nivå[,
radius]])
Läs mer om syntaxkonventioner.
Parametrar
Namn | Typ | Obligatorisk | Beskrivning |
---|---|---|---|
Polygon | dynamic |
✔️ | Polygon eller multipolygon i GeoJSON-format. |
Nivå | int |
Definierar den begärda cellnivån. Värden som stöds finns i intervallet [0, 30]. Om det är ospecificerat används standardvärdet 11 . |
|
Radie | real |
Buffertradie i meter. Om det är ospecificerat används standardvärdet 0 . |
Returer
Matris med S2-celltokensträngar som täcker en polygon eller en multipolygon. Om radien är inställd på ett positivt värde är täcket, förutom indataformen, av alla punkter inom indatageometrins radie. Om polygon, nivå, radie är ogiltigt eller om antalet celler överskrider gränsen genererar frågan ett null-resultat.
Anteckning
- Att täcka polygonen med S2-celltoken kan vara användbart för att matcha koordinater till polygoner som kan innehålla dessa koordinater och matcha polygoner med polygoner.
- Polygonen som täcker token har samma S2-cellnivå.
- Det maximala antalet token per polygon är 65536.
- Det geodetiska datum som används för mätningar på jorden är en sfär. Polygonkanter är geodesik på sfären.
- Om indatapolygonkanter är raka kartesiska linjer bör du överväga att använda geo_polygon_densify() för att konvertera planära kanter till geodesik.
Motivation för att täcka polygoner med S2-celltoken
Utan den här funktionen kan vi använda en metod för att klassificera koordinater i polygoner som innehåller dessa koordinater.
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
Resultat
Longitud | latitude | beskrivning |
---|---|---|
-73.95 | 40.75 | New York city |
-122.3 | 47.6 | Seattle |
-115.18 | 36.16 | Las Vegas |
Även om den här metoden fungerar i vissa fall är den ineffektiv. Den här metoden gör en korskoppling, vilket innebär att den försöker matcha varje polygon till varje punkt. Den här processen förbrukar en stor mängd minne och beräkningsresurser. I stället vill vi matcha varje polygon till en punkt med hög sannolikhet för att inneslutningen lyckas och filtrera bort andra punkter.
Den här matchningen kan uppnås genom följande process:
- Konvertera polygoner till S2-celler på nivå k,
- Konverterar punkter till samma S2-celler nivå k,
- Sammanfogning på S2-celler,
- Filtrera efter geo_point_in_polygon(). Den här fasen kan utelämnas om en viss mängd falska positiva identifieringar är ok. Det maximala felet är området för s2 celler på nivå k utanför polygonens gräns.
Välja S2-cellnivå
- Helst skulle vi vilja täcka varje polygon med en eller bara några unika celler så att inga två polygoner delar samma cell.
- Om polygonerna är nära varandra väljer du cellnivån S2 så att dess cellkant blir mindre (4, 8, 12 gånger mindre) än kanten på den genomsnittliga polygonen.
- Om polygonerna är långt ifrån varandra väljer du S2-cellnivån så att dess cellkant är liknande eller större än kanten på den genomsnittliga polygonen.
- Att täcka en polygon med fler än 10 000 celler kanske i praktiken inte ger bra prestanda.
- Exempel på användningsfall:
- S2-cellnivå 5 kan visa sig vara bra för att täcka länder/regioner.
- S2 cellnivå 16 kan täcka täta och relativt små Manhattan (New York) stadsdelar.
- S2 cellnivå 11 kan användas för att täcka australiens förorter.
- Frågekörningens tid och minnesförbrukning kan skilja sig mycket på grund av olika värden på S2-cellnivå.
Varning
Att täcka en stor polygon med små celler kan leda till en enorm mängd täckande celler. Därför kan frågan returnera null.
Anteckning
Förslag på prestandaförbättringar:
- Minska om möjligt tabellstorleken före koppling genom att gruppera koordinater som är mycket nära varandra med hjälp av geospatial klustring eller genom att filtrera bort icke-nesessära koordinater på grund av data eller affärsbehov.
- Om möjligt kan du minska antalet polygoner på grund av typen av data eller affärsbehov. Filtrera bort onödiga polygoner före koppling, omfång till intresseområde eller ena polygoner.
- Vid mycket stora polygoner minskar du deras storlek med hjälp av geo_polygon_simplify().
- Om du ändrar S2-cellnivå kan prestanda och minnesförbrukning förbättras.
- Ändring av kopplingstyp och tips kan förbättra prestanda och minnesförbrukning.
- Om en positiv radie har angetts kan du försöka förbättra prestanda genom att återgå till radie 0 på buffrad form med hjälp av geo_polygon_buffer().
Exempel
I följande exempel klassificeras koordinater i polygoner.
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
Resultat
Longitud | latitude | beskrivning |
---|---|---|
-73.9741 | 40.7914 | Övre västra sidan |
-73.995 | 40.734 | Greenwich by |
-73.9584 | 40.7688 | Övre östra sidan |
Här är ännu bättre på ovanstående fråga. Räkna stormhändelser per delstat i USA. Frågan nedan utför en mycket effektiv koppling eftersom den inte transporterar polygoner via kopplingen och använder uppslagsoperatorn
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
Resultat
StateName | StormEventsCountByState |
---|---|
Florida | 960 |
Georgia | 1085 |
... | ... |
I följande exempel filtreras polygoner som inte korsar området i polygonen av intresse. Det maximala felet är diagonalt med s2celllängd. Det här exemplet baseras på en polygoniserad jord på natten raster fil.
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
Resultat
Antal |
---|
83 |
Antal celler som behövs för att täcka en del polygoner med S2-celler på nivå 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));
Resultat
s2_cell_token_count |
---|
286 |
Om du täcker en polygon med stora områden med små celler returneras null.
let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print geo_polygon_to_s2cells(polygon, 30);
Resultat
print_0 |
---|
Om du täcker en polygon med stora områden med små celler returneras null.
let polygon = dynamic({"type":"Polygon","coordinates":[[[0,0],[0,50],[100,50],[0,0]]]});
print isnull(geo_polygon_to_s2cells(polygon, 30));
Resultat
print_0 |
---|
1 |
Feedback
https://aka.ms/ContentUserFeedback.
Kommer snart: Under hela 2024 kommer vi att fasa ut GitHub-problem som feedbackmekanism för innehåll och ersätta det med ett nytt feedbacksystem. Mer information finns i:Skicka och visa feedback för