|
| 1 | +--- |
| 2 | +title: geo_closest_point_on_polygon() |
| 3 | +description: Learn how to use the geo_closest_point_on_polygon() function to calculate a point on a polygon or a multipolygon, which is closest to a given point on Earth. |
| 4 | +ms.reviewer: mbrichko |
| 5 | +ms.topic: reference |
| 6 | +ms.date: 04/09/2025 |
| 7 | +--- |
| 8 | +# geo_closest_point_on_polygon() |
| 9 | + |
| 10 | +> [!INCLUDE [applies](../includes/applies-to-version/applies.md)] [!INCLUDE [fabric](../includes/applies-to-version/fabric.md)] [!INCLUDE [azure-data-explorer](../includes/applies-to-version/azure-data-explorer.md)] [!INCLUDE [monitor](../includes/applies-to-version/monitor.md)] [!INCLUDE [sentinel](../includes/applies-to-version/sentinel.md)] |
| 11 | +
|
| 12 | +Calculates a point on a polygon or a multipolygon, which is closest to a given point on Earth. |
| 13 | + |
| 14 | +## Syntax |
| 15 | + |
| 16 | +`geo_closest_point_on_polygon(`*longitude*`,`*latitude*`,`*polygon*`)` |
| 17 | + |
| 18 | +[!INCLUDE [syntax-conventions-note](../includes/syntax-conventions-note.md)] |
| 19 | + |
| 20 | +## Parameters |
| 21 | + |
| 22 | +|Name|Type|Required|Description| |
| 23 | +|--|--|--|--| |
| 24 | +| *longitude* | `real` | :heavy_check_mark: | Geospatial coordinate, longitude value in degrees. Valid value is a real number and in the range [-180, +180].| |
| 25 | +| *latitude* | `real` | :heavy_check_mark: | Geospatial coordinate, latitude value in degrees. Valid value is a real number and in the range [-90, +90].| |
| 26 | +| *polygon* | `dynamic` | :heavy_check_mark: | Polygon or multipolygon in the [GeoJSON format](https://tools.ietf.org/html/rfc7946).| |
| 27 | + |
| 28 | +## Returns |
| 29 | + |
| 30 | +A point in [GeoJSON Format](https://tools.ietf.org/html/rfc7946) and of a [dynamic](scalar-data-types/dynamic.md) data type on a polygon or multipolygon which is the closest to a given point on Earth. If polygon contains input point, the result with be the same point. If the coordinates or polygons are invalid, the query produces a null result. |
| 31 | + |
| 32 | +> [!NOTE] |
| 33 | +> |
| 34 | +> * The geospatial coordinates are interpreted as represented by the [WGS-84](https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84) coordinate reference system. |
| 35 | +> * The [geodetic datum](https://en.wikipedia.org/wiki/Geodetic_datum) used for measurements on Earth is a sphere. Polygon edges are [geodesics](https://en.wikipedia.org/wiki/Geodesic) on the sphere. |
| 36 | +> * If input polygon edges are straight cartesian lines, consider using [geo_polygon_densify()](geo-polygon-densify-function.md) to convert planar edges to geodesics. |
| 37 | +> * In order to calculate a distance between the closest point on a polygon or multipolygon to a given point, use [geo_distance_point_to_polygon()](geo-distance-point-to-polygon-function.md) |
| 38 | +
|
| 39 | +**Polygon definition and constraints** |
| 40 | + |
| 41 | +dynamic({"type": "Polygon","coordinates": [LinearRingShell, LinearRingHole_1, ..., LinearRingHole_N]}) |
| 42 | + |
| 43 | +dynamic({"type": "MultiPolygon","coordinates": [[LinearRingShell, LinearRingHole_1,..., LinearRingHole_N],..., [LinearRingShell, LinearRingHole_1,..., LinearRingHole_M]]}) |
| 44 | + |
| 45 | +* LinearRingShell is required and defined as a `counterclockwise` ordered array of coordinates [[lng_1,lat_1],...,[lng_i,lat_i],...,[lng_j,lat_j],...,[lng_1,lat_1]]. There can be only one shell. |
| 46 | +* LinearRingHole is optional and defined as a `clockwise` ordered array of coordinates [[lng_1,lat_1],...,[lng_i,lat_i],...,[lng_j,lat_j],...,[lng_1,lat_1]]. There can be any number of interior rings and holes. |
| 47 | +* LinearRing vertices must be distinct with at least three coordinates. The first coordinate must be equal to the last. At least four entries are required. |
| 48 | +* Coordinates [longitude, latitude] must be valid. Longitude must be a real number in the range [-180, +180] and latitude must be a real number in the range [-90, +90]. |
| 49 | +* LinearRingShell encloses at most half of the sphere. LinearRing divides the sphere into two regions. The smaller of the two regions will be chosen. |
| 50 | +* LinearRing edge length must be less than 180 degrees. The shortest edge between the two vertices will be chosen. |
| 51 | +* LinearRings must not cross and must not share edges. LinearRings may share vertices. |
| 52 | +* Polygon doesn't necessarily contain its vertices. |
| 53 | + |
| 54 | +> [!TIP] |
| 55 | +> |
| 56 | +> * Using literal polygons may result in better performance. |
| 57 | +
|
| 58 | +## Examples |
| 59 | + |
| 60 | +The following example calculates a location in Central Park which is the closest to a given point. |
| 61 | + |
| 62 | +:::moniker range="azure-data-explorer" |
| 63 | +> [!div class="nextstepaction"] |
| 64 | +> <a href="https://dataexplorer.azure.com/clusters/help/databases/Samples?query=H4sIAAAAAAAAA1WQy2rDMBBF94X8g9AqASfoNQ%2Bl9B%2B6N8YYRwQTRzK2Nqb032vHGNLVDHfOXO5MH7JoQ8xj09dDMz7El7jNsXl27fFH5nkI8iq%2FUz%2FfU5SFbFMab11scpjktSzLM9mLdx4Kpy7k0VfFJgErMojGggWzDlkpZFQWUHujd4yN0t4Z5yw7fnkgG0AyVgER7RhZTcy4WIH1G%2BYAtEVQa9mx9xxV9Xv6PHwMYxezuIdUt32awpTrIS1KneLSvI46bkEWX7HukoLi3z9Of0WJZPIhAQAA" target="_blank">Run the query</a> |
| 65 | +::: moniker-end |
| 66 | + |
| 67 | +```kusto |
| 68 | +let central_park = dynamic({"type":"Polygon","coordinates":[[[-73.9495,40.7969],[-73.95807266235352,40.80068603561921],[-73.98201942443848,40.76825672305777],[-73.97317886352539,40.76455136505513],[-73.9495,40.7969]]]}); |
| 69 | +print geo_closest_point_on_polygon(-73.9839, 40.7705, central_park) |
| 70 | +``` |
| 71 | + |
| 72 | +**Output** |
| 73 | + |
| 74 | +|print_0| |
| 75 | +|---| |
| 76 | +|{"type": "Point","coordinates": [-73.981205580153926, 40.769359452843211] }| |
| 77 | + |
| 78 | + |
| 79 | +The following example returns a null result because of the invalid coordinate input. |
| 80 | + |
| 81 | +:::moniker range="azure-data-explorer" |
| 82 | +> [!div class="nextstepaction"] |
| 83 | +> <a href="https://dataexplorer.azure.com/clusters/help/databases/Samples?query=H4sIAAAAAAAAAzWLwQrDIBBEf0X2pODBHHoJ9B96F5FgJAjbXVFzkJJ%2F75aS0xvmzdRWaKiW%2B4lDPVXpdCLqI3NMyD33ESvLIjJJwHkw6YdzdrH7pO1dkv7AmDXDquD192AhMbe90DZyF%2BG9d9YF6xf53RT8yhAuY8wX36BVQYUAAAA%3D" target="_blank">Run the query</a> |
| 84 | +::: moniker-end |
| 85 | + |
| 86 | +```kusto |
| 87 | +print result = isnull(geo_closest_point_on_polygon(500,1,dynamic({"type": "Polygon","coordinates": [[[0,0],[10,10],[10,1],[0,0]]]}))) |
| 88 | +``` |
| 89 | + |
| 90 | +**Output** |
| 91 | + |
| 92 | +| result | |
| 93 | +|--------| |
| 94 | +| true | |
| 95 | + |
| 96 | +The following example returns a null result because of the invalid polygon input. |
| 97 | + |
| 98 | +:::moniker range="azure-data-explorer" |
| 99 | +> [!div class="nextstepaction"] |
| 100 | +> <a href="https://dataexplorer.azure.com/clusters/help/databases/Samples?query=H4sIAAAAAAAAA02KMQoDIRBFryJTKUyhbWDvkF5EFlcWwcyI4xYScvcY0mz1H%2B%2F91gsN1bNcdahNFaGrVn1mjqmyZBmx8XpEpgV1nkzaocNj0v4qSb9hzJbhoeD5r4CQmPtRaB9ZVvDeW7QBvbPo7vuzIXyMMV96app8hAAAAA%3D%3D" target="_blank">Run the query</a> |
| 101 | +::: moniker-end |
| 102 | + |
| 103 | +```kusto |
| 104 | +print result = isnull(geo_closest_point_on_polygon(1,1,dynamic({"type": "Polygon","coordinates": [[[0,0],[10,10],[10,10],[0,0]]]}))) |
| 105 | +``` |
| 106 | + |
| 107 | +**Output** |
| 108 | + |
| 109 | +| result | |
| 110 | +|--------| |
| 111 | +| true | |
0 commit comments