area.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*!
  2. * \file lib/gis/area.c
  3. *
  4. * \brief GIS Library - Area calculation functions.
  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 <grass/gis.h>
  14. static struct state {
  15. struct Cell_head window;
  16. double square_meters;
  17. int projection;
  18. double units_to_meters_squared;
  19. /* these next are for lat-long only */
  20. int next_row;
  21. double north_value;
  22. double north;
  23. double (*darea0) (double);
  24. } state;
  25. static struct state *st = &state;
  26. /*!
  27. * \brief Begin cell area calculations.
  28. *
  29. * This routine must be called once before any call to
  30. * G_area_of_cell_at_row(). It perform all inititalizations needed to
  31. * do area calculations for grid cells, based on the current window
  32. * "projection" field. It can be used in either planimetric
  33. * projections or the latitude-longitude projection.
  34. *
  35. * \return 0 if the projection is not measurable (ie. imagery or xy)
  36. * \return 1 if the projection is planimetric (ie. UTM or SP)
  37. * \return 2 if the projection is non-planimetric (ie. latitude-longitude)
  38. */
  39. int G_begin_cell_area_calculations(void)
  40. {
  41. double a, e2;
  42. double factor;
  43. G_get_set_window(&st->window);
  44. switch (st->projection = st->window.proj) {
  45. case PROJECTION_LL:
  46. G_get_ellipsoid_parameters(&a, &e2);
  47. if (e2) {
  48. G_begin_zone_area_on_ellipsoid(a, e2, st->window.ew_res / 360.0);
  49. st->darea0 = G_darea0_on_ellipsoid;
  50. }
  51. else {
  52. G_begin_zone_area_on_sphere(a, st->window.ew_res / 360.0);
  53. st->darea0 = G_darea0_on_sphere;
  54. }
  55. st->next_row = 0;
  56. st->north = st->window.north;
  57. st->north_value = st->darea0(st->north);
  58. return 2;
  59. default:
  60. st->square_meters = st->window.ns_res * st->window.ew_res;
  61. factor = G_database_units_to_meters_factor();
  62. if (factor > 0.0)
  63. st->square_meters *= (factor * factor);
  64. return (factor > 0.0);
  65. }
  66. }
  67. /*!
  68. * \brief Cell area in specified row.
  69. *
  70. * This routine returns the area in square meters of a cell in the
  71. * specified <i>row</i>. This value is constant for planimetric grids
  72. * and varies with the row if the projection is latitude-longitude.
  73. *
  74. * \param row row number
  75. *
  76. * \return cell area
  77. */
  78. double G_area_of_cell_at_row(int row)
  79. {
  80. double south_value;
  81. double cell_area;
  82. if (st->projection != PROJECTION_LL)
  83. return st->square_meters;
  84. if (row != st->next_row) {
  85. st->north = st->window.north - row * st->window.ns_res;
  86. st->north_value = st->darea0(st->north);
  87. }
  88. st->north -= st->window.ns_res;
  89. south_value = st->darea0(st->north);
  90. cell_area = st->north_value - south_value;
  91. st->next_row = row + 1;
  92. st->north_value = south_value;
  93. return cell_area;
  94. }
  95. /*!
  96. * \brief Begin polygon area calculations.
  97. *
  98. * This initializes the polygon area calculation routines. It is used
  99. * both for planimetric and latitude-longitude projections.
  100. *
  101. * \return 0 if the projection is not measurable (ie. imagery or xy)
  102. * \return 1 if the projection is planimetric (ie. UTM or SP)
  103. * \return 2 if the projection is non-planimetric (ie. latitude-longitude)
  104. */
  105. int G_begin_polygon_area_calculations(void)
  106. {
  107. double a, e2;
  108. double factor;
  109. if ((st->projection = G_projection()) == PROJECTION_LL) {
  110. G_get_ellipsoid_parameters(&a, &e2);
  111. G_begin_ellipsoid_polygon_area(a, e2);
  112. return 2;
  113. }
  114. factor = G_database_units_to_meters_factor();
  115. if (factor > 0.0) {
  116. st->units_to_meters_squared = factor * factor;
  117. return 1;
  118. }
  119. st->units_to_meters_squared = 1.0;
  120. return 0;
  121. }
  122. /*!
  123. * \brief Area in square meters of polygon.
  124. *
  125. * Returns the area in square meters of the polygon described by the
  126. * <i>n</i> pairs of <i>x,y</i> coordinate vertices. It is used both for
  127. * planimetric and latitude-longitude projections.
  128. *
  129. * You should call G_begin_polygon_area_calculations() function before
  130. * calling this function.
  131. *
  132. * <b>Note:</b> If the database is planimetric with the non-meter grid,
  133. * this routine performs the required unit conversion to produce square
  134. * meters.
  135. *
  136. * \param x array of x coordinates
  137. * \param y array of y coordinates
  138. * \param n number of x,y coordinate pairs
  139. *
  140. * \return area in square meters of the polygon
  141. */
  142. double G_area_of_polygon(const double *x, const double *y, int n)
  143. {
  144. double area;
  145. if (st->projection == PROJECTION_LL)
  146. area = G_ellipsoid_polygon_area(x, y, n);
  147. else
  148. area = G_planimetric_polygon_area(x, y, n) * st->units_to_meters_squared;
  149. return area;
  150. }