110 | static inline bool isLocationOnEdgeOrPath(const LatLng& point, const LatLngList& poly, bool closed, bool geodesic, double toleranceEarth) {
111 | size_t size = poly.size();
112 |
113 | if (size == 0U) {
114 | return false;
115 | }
116 |
117 | double tolerance = toleranceEarth / MathUtil::EARTH_RADIUS;
118 | double havTolerance = MathUtil::hav(tolerance);
119 | double lat3 = deg2rad(point.lat);
120 | double lng3 = deg2rad(point.lng);
121 | LatLng prev = poly[closed ? size - 1 : 0];
122 | double lat1 = deg2rad(prev.lat);
123 | double lng1 = deg2rad(prev.lng);
124 |
125 | if (geodesic) {
126 | for (auto val : poly) {
127 | double lat2 = deg2rad(val.lat);
128 | double lng2 = deg2rad(val.lng);
129 | if (PolyUtil::isOnSegmentGC(lat1, lng1, lat2, lng2, lat3, lng3, havTolerance)) {
130 | return true;
131 | }
132 | lat1 = lat2;
133 | lng1 = lng2;
134 | }
135 | }else {
136 | // We project the points to mercator space, where the Rhumb segment is a straight line,
137 | // and compute the geodesic distance between point3 and the closest point on the
138 | // segment. This method is an approximation, because it uses "closest" in mercator
139 | // space which is not "closest" on the sphere -- but the error is small because
140 | // "tolerance" is small.
141 | double minAcceptable = lat3 - tolerance;
142 | double maxAcceptable = lat3 + tolerance;
143 | double y1 = MathUtil::mercator(lat1);
144 | double y3 = MathUtil::mercator(lat3);
145 | double xTry[3];
146 | for (auto val : poly) {
147 | double lat2 = deg2rad(val.lat);
148 | double y2 = MathUtil::mercator(lat2);
149 | double lng2 = deg2rad(val.lng);
150 | if (std::max(lat1, lat2) >= minAcceptable && std::min(lat1, lat2) <= maxAcceptable) {
151 | // We offset longitudes by -lng1; the implicit x1 is 0.
152 | double x2 = MathUtil::wrap(lng2 - lng1, -M_PI, M_PI);
153 | double x3Base = MathUtil::wrap(lng3 - lng1, -M_PI, M_PI);
154 | xTry[0] = x3Base;
155 | // Also explore wrapping of x3Base around the world in both directions.
156 | xTry[1] = x3Base + 2 * M_PI;
157 | xTry[2] = x3Base - 2 * M_PI;
158 |
159 | for (auto x3 : xTry) {
160 | double dy = y2 - y1;
161 | double len2 = x2 * x2 + dy * dy;
162 | double t = len2 <= 0 ? 0 : MathUtil::clamp((x3 * x2 + (y3 - y1) * dy) / len2, 0, 1);
163 | double xClosest = t * x2;
164 | double yClosest = y1 + t * dy;
165 | double latClosest = MathUtil::inverseMercator(yClosest);
166 | double havDist = MathUtil::havDistance(lat3, latClosest, x3 - xClosest);
167 | if (havDist < havTolerance) {
168 | return true;
169 | }
170 | }
171 | }
172 | lat1 = lat2;
173 | lng1 = lng2;
174 | y1 = y2;
175 | }
176 | }
177 | return false;
178 | }
179 |
180 | /**
181 | * Computes the distance on the sphere between the point p and the line segment start to end.
182 | *
183 | * @param p the point to be measured
184 | * @param start the beginning of the line segment
185 | * @param end the end of the line segment
186 | * @return the distance in meters (assuming spherical earth)
187 | */
188 | static inline double distanceToLine(const LatLng& p, const LatLng& start, const LatLng& end) {
189 | if (start == end) {
190 | return SphericalUtil::computeDistanceBetween(end, p);
191 | }
192 | double s0lat = deg2rad(p.lat);
193 | double s0lng = deg2rad(p.lng);
194 | double s1lat = deg2rad(start.lat);
195 | double s1lng = deg2rad(start.lng);
196 | double s2lat = deg2rad(end.lat);
197 | double s2lng = deg2rad(end.lng);
198 | double s2s1lat = s2lat - s1lat;
199 | double s2s1lng = s2lng - s1lng;
200 | double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * s2s1lng)
201 | / (s2s1lat * s2s1lat + s2s1lng * s2s1lng);
202 | if (u <= 0) {
203 | return SphericalUtil::computeDistanceBetween(p, start);
204 | }
205 | if (u >= 1) {
206 | return SphericalUtil::computeDistanceBetween(p, end);
207 | }
208 | LatLng su(start.lat + u * (end.lat - start.lat), start.lng + u * (end.lng - start.lng));
209 | return SphericalUtil::computeDistanceBetween(p, su);
210 | }
211 |
212 |
213 | private:
214 | /**
215 | * Returns tan(latitude-at-lng3) on the great circle (lat1, lng1) to (lat2, lng2). lng1==0.
216 | * See http://williams.best.vwh.net/avform.htm .
217 | */
218 | static inline double tanLatGC(double lat1, double lat2, double lng2, double lng3) {
219 | return (tan(lat1) * sin(lng2 - lng3) + tan(lat2) * sin(lng3)) / sin(lng2);
220 | }
221 |
222 | /**
223 | * Returns mercator(latitude-at-lng3) on the Rhumb line (lat1, lng1) to (lat2, lng2). lng1==0.
224 | */
225 | static inline double mercatorLatRhumb(double lat1, double lat2, double lng2, double lng3) {
226 | return (MathUtil::mercator(lat1) * (lng2 - lng3) + MathUtil::mercator(lat2) * lng3) / lng2;
227 | }
228 |
229 | /**
230 | * Computes whether the vertical segment (lat3, lng3) to South Pole intersects the segment
231 | * (lat1, lng1) to (lat2, lng2).
232 | * Longitudes are offset by -lng1; the implicit lng1 becomes 0.
233 | */
234 | static inline double intersects(double lat1, double lat2, double lng2, double lat3, double lng3, bool geodesic) {
235 | // Both ends on the same side of lng3.
236 | if ((lng3 >= 0 && lng3 >= lng2) || (lng3 < 0 && lng3 < lng2)) {
237 | return false;
238 | }
239 | // Point is South Pole.
240 | if (lat3 <= -M_PI / 2) {
241 | return false;
242 | }
243 | // Any segment end is a pole.
244 | if (lat1 <= -M_PI / 2 || lat2 <= -M_PI / 2 || lat1 >= M_PI / 2 || lat2 >= M_PI / 2) {
245 | return false;
246 | }
247 | if (lng2 <= -M_PI) {
248 | return false;
249 | }
250 | double linearLat = (lat1 * (lng2 - lng3) + lat2 * lng3) / lng2;
251 | // Northern hemisphere and point under lat-lng line.
252 | if (lat1 >= 0 && lat2 >= 0 && lat3 < linearLat) {
253 | return false;
254 | }
255 | // Southern hemisphere and point above lat-lng line.
256 | if (lat1 <= 0 && lat2 <= 0 && lat3 >= linearLat) {
257 | return true;
258 | }
259 | // North Pole.
260 | if (lat3 >= M_PI / 2) {
261 | return true;
262 | }
263 | // Compare lat3 with latitude on the GC/Rhumb segment corresponding to lng3.
264 | // Compare through a strictly-increasing function (tan() or mercator()) as convenient.
265 | return geodesic ?
266 | tan(lat3) >= PolyUtil::tanLatGC(lat1, lat2, lng2, lng3) :
267 | MathUtil::mercator(lat3) >= PolyUtil::mercatorLatRhumb(lat1, lat2, lng2, lng3);
268 | }
269 |
270 | /**
271 | * Returns sin(initial bearing from (lat1,lng1) to (lat3,lng3) minus initial bearing
272 | * from (lat1, lng1) to (lat2,lng2)).
273 | */
274 | static inline double sinDeltaBearing(double lat1, double lng1, double lat2, double lng2, double lat3, double lng3) {
275 | double sinLat1 = sin(lat1);
276 | double cosLat2 = cos(lat2);
277 | double cosLat3 = cos(lat3);
278 | double lat31 = lat3 - lat1;
279 | double lng31 = lng3 - lng1;
280 | double lat21 = lat2 - lat1;
281 | double lng21 = lng2 - lng1;
282 | double a = sin(lng31) * cosLat3;
283 | double c = sin(lng21) * cosLat2;
284 | double b = sin(lat31) + 2 * sinLat1 * cosLat3 * MathUtil::hav(lng31);
285 | double d = sin(lat21) + 2 * sinLat1 * cosLat2 * MathUtil::hav(lng21);
286 | double denom = (a * a + b * b) * (c * c + d * d);
287 | return denom <= 0 ? 1 : (a * d - b * c) / sqrt(denom);
288 | }
289 |
290 | static inline bool isOnSegmentGC(double lat1, double lng1, double lat2, double lng2, double lat3, double lng3, double havTolerance) {
291 | double havDist13 = MathUtil::havDistance(lat1, lat3, lng1 - lng3);
292 | if (havDist13 <= havTolerance) {
293 | return true;
294 | }
295 | double havDist23 = MathUtil::havDistance(lat2, lat3, lng2 - lng3);
296 | if (havDist23 <= havTolerance) {
297 | return true;
298 | }
299 | double sinBearing = PolyUtil::sinDeltaBearing(lat1, lng1, lat2, lng2, lat3, lng3);
300 | double sinDist13 = MathUtil::sinFromHav(havDist13);
301 | double havCrossTrack = MathUtil::havFromSin(sinDist13 * sinBearing);
302 | if (havCrossTrack > havTolerance) {
303 | return false;
304 | }
305 | double havDist12 = MathUtil::havDistance(lat1, lat2, lng1 - lng2);
306 | double term = havDist12 + havCrossTrack * (1 - 2 * havDist12);
307 | if (havDist13 > term || havDist23 > term) {
308 | return false;
309 | }
310 | if (havDist12 < 0.74) {
311 | return true;
312 | }
313 | double cosCrossTrack = 1 - 2 * havCrossTrack;
314 | double havAlongTrack13 = (havDist13 - havCrossTrack) / cosCrossTrack;
315 | double havAlongTrack23 = (havDist23 - havCrossTrack) / cosCrossTrack;
316 | double sinSumAlongTrack = MathUtil::sinSumFromHav(havAlongTrack13, havAlongTrack23);
317 | return sinSumAlongTrack > 0; // Compare with half-circle == PI using sign of sin().
318 | }
319 | };
320 |
321 | #endif // GEOMETRY_LIBRARY_POLY_UTIL
322 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Geometry Library
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | C++ Geometry Library provides utility functions for the computation of geometric data on the surface of the Earth. Code ported from Google [Maps Android API](https://github.com/googlemaps/android-maps-utils/).
22 |
23 | ## Features
24 |
25 | * [Spherical](https://developers.google.com/maps/documentation/javascript/reference#spherical) contains spherical geometry utilities allowing you to compute angles, distances and areas from latitudes and longitudes.
26 | * [Poly](https://developers.google.com/maps/documentation/javascript/reference#poly) utility functions for computations involving polygons and polylines.
27 |
28 | ## Usage
29 |
30 | You just need to include `SphericalUtil.hpp` or `PolyUtil.hpp`
31 |
32 | Here is an example of using this library:
33 |
34 | ```c++
35 | #include
36 | #include
37 |
38 | #include "SphericalUtil.hpp"
39 |
40 | int main() {
41 | LatLng up = { 90.0, 0.0 };
42 | LatLng down = {-90.0, 0.0 };
43 | LatLng front = { 0.0, 0.0 };
44 | LatLng right = { 0.0, 90.0 };
45 |
46 | auto angle = SphericalUtil::computeAngleBetween(up, right); // 90
47 | std::cout << "The angle between up and right is " << rad2deg(angle) << " degrees" << std::endl;
48 |
49 | auto distance = SphericalUtil::computeDistanceBetween(up, down); // 2.00151e+07
50 | std::cout << "The distance between up and down is " << distance << " meters" << std::endl;
51 |
52 | std::vector points = { front, up, right };
53 |
54 | auto length = SphericalUtil::computeLength(points); // 2.00151e+07
55 | std::cout << "The length between front, up and right is " << length << " meters" << std::endl;
56 |
57 | auto area = SphericalUtil::computeArea(points); // 6.37582e+13
58 | std::cout << "The area between front, up and right is " << area << " square meters" << std::endl;
59 |
60 | return 0;
61 | }
62 | ```
63 |
64 | ## Available methods
65 |
66 | ### PolyUtil class
67 |
68 | * [`containsLocation(LatLng point, LatLngList polygon, bool geodesic)`](#containsLocation)
69 | * [`isLocationOnEdge(LatLng point, LatLngList polygon, double tolerance, bool geodesic)`](#isLocationOnEdge)
70 | * [`isLocationOnPath(LatLng point, LatLngList polyline, double tolerance, bool geodesic)`](#isLocationOnPath)
71 | * [`distanceToLine(LatLng point, LatLng start, LatLng end)`](#distanceToLine)
72 |
73 | ### SphericalUtil class
74 |
75 | * [`computeHeading(LatLng from, LatLng to)`](#computeHeading)
76 | * [`computeOffset(LatLng from, double distance, double heading)`](#computeOffset)
77 | * [`computeOffsetOrigin(LatLng to, double distance, double heading)`](#computeOffsetOrigin)
78 | * [`interpolate(LatLng from, LatLng to, double fraction)`](#interpolate)
79 | * [`computeDistanceBetween(LatLng from, LatLng to)`](#computeDistanceBetween)
80 | * [`computeLength(LatLngList path)`](#computeLength)
81 | * [`computeArea(LatLngList path)`](#computeArea)
82 | * [`computeSignedArea(LatLngList path)`](#computeSignedArea)
83 |
84 | ## Classes description
85 |
86 | `LatLng` - a point in geographical coordinates: latitude and longitude.
87 |
88 | * Latitude ranges between `-90` and `90` degrees, inclusive
89 | * Longitude ranges between `-180` and `180` degrees, inclusive
90 |
91 | Usage example:
92 |
93 | ```c++
94 | LatLng northPole = {90, 0};
95 |
96 | LatLng otherPoint = northPole;
97 | ```
98 |
99 | ---
100 |
101 | `LatLngList` - a series of connected coordinates in an ordered sequence. Any iterable containers.
102 |
103 | Usage example:
104 |
105 | ```c++
106 | std::vector aroundNorthPole = { {89, 0}, {89, 120}, {89, -120} };
107 |
108 | std::array northPole = { {90, 0} };
109 | ```
110 |
111 | ## Functions description
112 |
113 | ### PolyUtil functions
114 |
115 |
116 | **`PolyUtil::containsLocation(const LatLng& point, const LatLngList& polygon, bool geodesic = false)`** - Computes whether the given point lies inside the specified polygon
117 |
118 | * `point` - a point in geographical coordinates: latitude and longitude
119 | * `polygon` - a series of connected coordinates in an ordered sequence
120 | * `geodesic` - the polyline is composed of great circle segments if geodesic is true, and of Rhumb segments otherwise
121 |
122 | Return value: `bool` - whether the given point lies inside the specified polygon
123 |
124 | ```c++
125 | // Around the north pole.
126 | std::vector aroundNorthPole = { {89, 0}, {89, 120}, {89, -120} };
127 |
128 | std::cout << PolyUtil::containsLocation(LatLng(90, 0), aroundNorthPole); // true
129 | std::cout << PolyUtil::containsLocation(LatLng(-90, 0), aroundNorthPole); // false
130 | ```
131 |
132 | ---
133 |
134 |
135 | **`PolyUtil::isLocationOnEdge(const LatLng& point, const LatLngList& polygon, double tolerance = PolyUtil::DEFAULT_TOLERANCE, bool geodesic = true)`** - Computes whether the given point lies on or near to a polyline, or the edge of a polygon, within a specified tolerance. Returns true when the difference between the latitude and longitude of the supplied point, and the closest point on the edge, is less than the tolerance. The tolerance defaults to `0.1` meters.
136 |
137 | * `point` - a point in geographical coordinates: latitude and longitude
138 | * `polygon` - a series of connected coordinates in an ordered sequence
139 | * `tolerance` - tolerance value in meters
140 | * `geodesic` - the polyline is composed of great circle segments if geodesic is true, and of Rhumb segments otherwise
141 |
142 | Return value: `bool` - whether the given point lies on or near the edge of a polygon
143 |
144 | ```c++
145 | // On equator.
146 | std::vector equator = { {0, 90}, {0, 180} };
147 |
148 | double small = 5e-7; // Half the default tolerance.
149 | double big = 2e-6; // Double the default tolerance.
150 |
151 | std::cout << PolyUtil::isLocationOnEdge(LatLng(0, 90 - small), equator); // true
152 | std::cout << PolyUtil::isLocationOnEdge(LatLng(0, 90 - big), equator); // false
153 | ```
154 |
155 | ---
156 |
157 |
158 | **`PolyUtil::isLocationOnPath(const LatLng& point, const LatLngList& polyline, double tolerance = PolyUtil::DEFAULT_TOLERANCE, bool geodesic = true)`** - Computes whether the given point lies on or near a polyline, within a specified tolerance in meters. The polyline is composed of great circle segments if geodesic is true, and of Rhumb segments otherwise. The polyline is not closed -- the closing segment between the first point and the last point is not included.
159 |
160 | * `point` - a point in geographical coordinates: latitude and longitude
161 | * `polygon` - a series of connected coordinates in an ordered sequence
162 | * `tolerance` - tolerance value in meters
163 | * `geodesic` - the polyline is composed of great circle segments if geodesic is true, and of Rhumb segments otherwise
164 |
165 | Return value: `bool` - whether the point lies on or near a polyline
166 |
167 | ```c++
168 | // On equator.
169 | std::vector equator = { {0, 90}, {0, 180} };
170 |
171 | double small = 5e-7; // Half the default tolerance.
172 | double big = 2e-6; // Double the default tolerance.
173 |
174 | std::cout << PolyUtil::isLocationOnPath(LatLng(0, 90 - small), equator); // true
175 | std::cout << PolyUtil::isLocationOnPath(LatLng(0, 90 - big), equator); // false
176 | ```
177 |
178 | ---
179 |
180 |
181 | **`PolyUtil::distanceToLine(const LatLng& p, const LatLng& start, const LatLng& end)`** - Computes the distance on the sphere between the point p and the line segment start to end.
182 |
183 | * `point` - the point to be measured
184 | * `start` - the beginning of the line segment
185 | * `end` - the end of the line segment
186 |
187 | Return value: `double` - the distance in meters (assuming spherical earth)
188 |
189 | ```c++
190 | LatLng startLine(28.05359, -82.41632);
191 | LatLng endLine(28.05310, -82.41634);
192 | LatLng point(28.05342, -82.41594);
193 |
194 | std::cout << PolyUtil::distanceToLine(point, startLine, endLine); // 37.947946
195 | ```
196 |
197 | ### SphericalUtil functions
198 |
199 |
200 | **`SphericalUtil::computeHeading(const LatLng& from, const LatLng& to)`** - Returns the heading from one LatLng to another LatLng. Headings are expressed in degrees clockwise from North within the range [-180,180).
201 |
202 | * `from` - a point in geographical coordinates: latitude and longitude
203 | * `to` - a point in geographical coordinates: latitude and longitude
204 |
205 | Return value: `double` - the heading in degrees clockwise from north
206 |
207 | ```c++
208 | LatLng front(0, 0);
209 | LatLng right(0, 90);
210 |
211 | std::cout << SphericalUtil::computeHeading(right, front); // -90
212 | std::cout << SphericalUtil::computeHeading(front, right); // +90
213 | ```
214 |
215 | ---
216 |
217 |
218 | **`SphericalUtil::computeOffset(const LatLng& from, double distance, double heading)`** - Returns the LatLng resulting from moving a distance from an origin in the specified heading (expressed in degrees clockwise from north).
219 |
220 | * `from` - the LatLng from which to start.
221 | * `distance` - the distance to travel.
222 | * `heading` - the heading in degrees clockwise from north.
223 |
224 | Return value: `LatLng` - resulting from moving a distance from an origin in the specified heading (expressed in degrees clockwise from north)
225 |
226 | ```c++
227 | LatLng front(0, 0);
228 |
229 | auto up = SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, 0); // LatLng( 90, 0)
230 | auto down = SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, 180); // LatLng(-90, 0)
231 | auto left = SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, -90); // LatLng( 0, -90)
232 | auto right = SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS / 2, 90); // LatLng( 0, 90)
233 | auto back = SphericalUtil::computeOffset(front, M_PI * MathUtil::EARTH_RADIUS, 90); // LatLng( 0, -180)
234 | ```
235 |
236 | ---
237 |
238 |
239 | **`SphericalUtil::computeOffsetOrigin(const LatLng& to, double distance, double heading)`** - Returns the location of origin when provided with a LatLng destination, meters travelled and original heading. Headings are expressed in degrees clockwise from North.
240 |
241 | * `from` - the destination LatLng
242 | * `distance` - the distance travelled, in meters.
243 | * `heading` - the heading in degrees clockwise from north
244 |
245 | Return value: `LatLng` - the location of origin when provided with a LatLng destination, meters travelled and original heading. Headings are expressed in degrees clockwise from North
246 |
247 | ```c++
248 | LatLng front(0, 0);
249 |
250 | assert(front == SphericalUtil::computeOffsetOrigin(front, 0, 0));
251 |
252 | assert(front == SphericalUtil::computeOffsetOrigin(LatLng( 0, 45), M_PI * MathUtil::EARTH_RADIUS / 4, 90));
253 | assert(front == SphericalUtil::computeOffsetOrigin(LatLng( 0, -45), M_PI * MathUtil::EARTH_RADIUS / 4, -90));
254 | assert(front == SphericalUtil::computeOffsetOrigin(LatLng( 45, 0), M_PI * MathUtil::EARTH_RADIUS / 4, 0));
255 | assert(front == SphericalUtil::computeOffsetOrigin(LatLng(-45, 0), M_PI * MathUtil::EARTH_RADIUS / 4, 190));
256 | ```
257 |
258 | ---
259 |
260 |
261 | **`SphericalUtil::interpolate(const LatLng& from, const LatLng& to, double fraction)`** - Returns the LatLng which lies the given fraction of the way between the origin LatLng and the destination LatLng.
262 |
263 | * `from` - the LatLng from which to start.
264 | * `to` - the LatLng toward which to travel.
265 | * `fraction` - a fraction of the distance to travel.
266 |
267 | Return value: `LatLng` - point which lies the given fraction of the way between the origin LatLng and the destination LatLng
268 |
269 | ```c++
270 | LatLng up(90, 0);
271 | LatLng front(0, 0);
272 |
273 | assert(LatLng(1, 0) == SphericalUtil::interpolate(front, up, 1 / 90.0));
274 | assert(LatLng(1, 0) == SphericalUtil::interpolate(up, front, 89 / 90.0));
275 | assert(LatLng(89, 0) == SphericalUtil::interpolate(front, up, 89 / 90.0));
276 | assert(LatLng(89, 0) == SphericalUtil::interpolate(up, front, 1 / 90.0));
277 |
278 | ```
279 |
280 | ---
281 |
282 |
283 | **`SphericalUtil::computeDistanceBetween(const LatLng& from, const LatLng& to)`** - Returns the distance, in meters, between two LatLngs.
284 |
285 | * `from` - the first point
286 | * `to` - the second point
287 |
288 | Return value: `double` - the distance, in meters, between two LatLngs
289 |
290 | ```c++
291 | LatLng up(90, 0);
292 | LatLng down(-90, 0);
293 |
294 | std:cout << SphericalUtil::computeDistanceBetween(up, down); // MathUtil::EARTH_RADIUS
295 | ```
296 |
297 | ---
298 |
299 |
300 | **`SphericalUtil::computeLength(const LatLngList& path)`** - Returns the length of the given path, in meters, on Earth
301 |
302 | * `path` - a series of connected coordinates in an ordered sequence. Any iterable containers.
303 |
304 | Return valuse: `double` - the length of the given path, in meters, on Earth
305 |
306 | ```c++
307 | // List with three points
308 | std::vector latLngs2 = { {0, 0}, {90, 0}, {0, 90} };
309 |
310 | std::cout << SphericalUtil::computeLength(latLngs2); // M_PI * MathUtil::EARTH_RADIUS
311 | ```
312 |
313 | ---
314 |
315 |
316 | **`SphericalUtil::computeArea(const LatLngList& path)`** - Returns the area of a closed path on Earth.
317 |
318 | * `path` - a closed path. Any iterable containers.
319 |
320 | Return value: `double` - the area of a closed path on Earth
321 |
322 | ```c++
323 | LatLng up = { 90.0, 0.0 };
324 | LatLng down = {-90.0, 0.0 };
325 | LatLng front = { 0.0, 0.0 };
326 | LatLng right = { 0.0, 90.0 };
327 |
328 | std::vector path = { right, down, front, up, right };
329 |
330 | std::cout << SphericalUtil::computeArea(second); // M_PI * MathUtil::EARTH_RADIUS * MathUtil::EARTH_RADIUS
331 | ```
332 |
333 | ---
334 |
335 |
336 | **`SphericalUtil::computeSignedArea(const LatLngList& path)`** - Returns the signed area of a closed path on Earth. The sign of the area may be used to determine the orientation of the path. "inside" is the surface that does not contain the South Pole.
337 |
338 | * `path` - a closed path. Any iterable containers.
339 |
340 | Return value: `double` - the loop's area in square meters
341 |
342 | ```c++
343 | LatLng up = { 90.0, 0.0 };
344 | LatLng down = {-90.0, 0.0 };
345 | LatLng front = { 0.0, 0.0 };
346 | LatLng right = { 0.0, 90.0 };
347 |
348 | std::vector path = { right, up, front, down, right };
349 | std::vector pathReversed = { right, down, front, up, right };
350 |
351 | assert(SphericalUtil::computeSignedArea(path) == -SphericalUtil::computeSignedArea(pathReversed));
352 | ```
353 |
354 | ---
355 |
356 | ## Support
357 |
358 | [Please open an issue on GitHub](https://github.com/gistrec/cpp-geometry-library/issues)
359 |
360 | ## License
361 |
362 | Geometry Library Google Maps API V3 is released under the MIT License.
363 | See the bundled [LICENSE](https://github.com/alexpechkarev/geometry-library/blob/master/LICENSE) file for details.
--------------------------------------------------------------------------------