area_poly1.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*!
  2. * \file gis/area_poly1.c
  3. *
  4. * \brief GIS Library - Polygon area calculation routines.
  5. *
  6. * (C) 2001-2009 by the GRASS Development Team
  7. *
  8. * This program is free software under the GNU General Public License
  9. * (>=v2). Read the file COPYING that comes with GRASS for details.
  10. *
  11. * \author Original author CERL
  12. */
  13. #include <math.h>
  14. #include <grass/gis.h>
  15. #include "pi.h"
  16. #define TWOPI M_PI + M_PI
  17. static struct state {
  18. double QA, QB, QC;
  19. double QbarA, QbarB, QbarC, QbarD;
  20. double AE; /** a^2(1-e^2) */
  21. double Qp; /** Q at the north pole */
  22. double E; /** Area of the earth */
  23. } state;
  24. static struct state *st = &state;
  25. static double Q(double x)
  26. {
  27. double sinx, sinx2;
  28. sinx = sin(x);
  29. sinx2 = sinx * sinx;
  30. return sinx * (1 + sinx2 * (st->QA + sinx2 * (st->QB + sinx2 * st->QC)));
  31. }
  32. static double Qbar(double x)
  33. {
  34. double cosx, cosx2;
  35. cosx = cos(x);
  36. cosx2 = cosx * cosx;
  37. return cosx * (st->QbarA + cosx2 * (st->QbarB + cosx2 * (st->QbarC + cosx2 * st->QbarD)));
  38. }
  39. /*!
  40. * \brief Begin area calculations.
  41. *
  42. * This initializes the polygon area calculations for the
  43. * ellipsoid with semi-major axis <i>a</i> (in meters) and ellipsoid
  44. * eccentricity squared <i>e2</i>.
  45. *
  46. * \param a semi-major axis
  47. * \param e2 ellipsoid eccentricity
  48. */
  49. void G_begin_ellipsoid_polygon_area(double a, double e2)
  50. {
  51. double e4, e6;
  52. e4 = e2 * e2;
  53. e6 = e4 * e2;
  54. st->AE = a * a * (1 - e2);
  55. st->QA = (2.0 / 3.0) * e2;
  56. st->QB = (3.0 / 5.0) * e4;
  57. st->QC = (4.0 / 7.0) * e6;
  58. st->QbarA = -1.0 - (2.0 / 3.0) * e2 - (3.0 / 5.0) * e4 - (4.0 / 7.0) * e6;
  59. st->QbarB = (2.0 / 9.0) * e2 + (2.0 / 5.0) * e4 + (4.0 / 7.0) * e6;
  60. st->QbarC = -(3.0 / 25.0) * e4 - (12.0 / 35.0) * e6;
  61. st->QbarD = (4.0 / 49.0) * e6;
  62. st->Qp = Q(M_PI_2);
  63. st->E = 4 * M_PI * st->Qp * st->AE;
  64. if (st->E < 0.0)
  65. st->E = -st->E;
  66. }
  67. /*!
  68. * \brief Area of lat-long polygon.
  69. *
  70. * Returns the area in square meters of the polygon described by the
  71. * <i>n</i> pairs of <i>lat,long</i> vertices for latitude-longitude
  72. * grids.
  73. *
  74. * <b>Note:</b> This routine assumes grid lines on the connecting the
  75. * vertices (as opposed to geodesics).
  76. *
  77. * \param lon array of longitudes
  78. * \param lat array of latitudes
  79. * \param n number of lat,lon pairs
  80. *
  81. * \return area in square meters
  82. */
  83. double G_ellipsoid_polygon_area(const double *lon, const double *lat, int n)
  84. {
  85. double x1, y1, x2, y2, dx, dy;
  86. double Qbar1, Qbar2;
  87. double area;
  88. x2 = Radians(lon[n - 1]);
  89. y2 = Radians(lat[n - 1]);
  90. Qbar2 = Qbar(y2);
  91. area = 0.0;
  92. while (--n >= 0) {
  93. x1 = x2;
  94. y1 = y2;
  95. Qbar1 = Qbar2;
  96. x2 = Radians(*lon++);
  97. y2 = Radians(*lat++);
  98. Qbar2 = Qbar(y2);
  99. if (x1 > x2)
  100. while (x1 - x2 > M_PI)
  101. x2 += TWOPI;
  102. else if (x2 > x1)
  103. while (x2 - x1 > M_PI)
  104. x1 += TWOPI;
  105. dx = x2 - x1;
  106. area += dx * (st->Qp - Q(y2));
  107. if ((dy = y2 - y1) != 0.0)
  108. area += dx * Q(y2) - (dx / dy) * (Qbar2 - Qbar1);
  109. }
  110. if ((area *= st->AE) < 0.0)
  111. area = -area;
  112. /* kludge - if polygon circles the south pole the area will be
  113. * computed as if it cirlced the north pole. The correction is
  114. * the difference between total surface area of the earth and
  115. * the "north pole" area.
  116. */
  117. if (area > st->E)
  118. area = st->E;
  119. if (area > st->E / 2)
  120. area = st->E - area;
  121. return area;
  122. }