area.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*!
  2. \file lib/vector/Vlib/area.c
  3. \brief Vector library - area-related functions
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2009, 2011-2012 by the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Original author CERL, probably Dave Gerdes or Mike Higgins.
  9. \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
  10. */
  11. #include <stdlib.h>
  12. #include <grass/vector.h>
  13. #include <grass/glocale.h>
  14. /*!
  15. \brief Returns polygon array of points (outer ring) of given area
  16. \param Map pointer to Map_info structure
  17. \param area area id
  18. \param[out] BPoints points array
  19. \return number of points
  20. \return -1 on error
  21. */
  22. int Vect_get_area_points(const struct Map_info *Map,
  23. int area, struct line_pnts *BPoints)
  24. {
  25. int i, line, aline, dir;
  26. const struct Plus_head *Plus;
  27. struct P_area *Area;
  28. static int first_time = 1;
  29. static struct line_pnts *Points;
  30. G_debug(3, "Vect_get_area_points(): area = %d", area);
  31. BPoints->n_points = 0;
  32. Plus = &(Map->plus);
  33. Area = Plus->Area[area];
  34. if (Area == NULL) { /* dead area */
  35. G_warning(_("Attempt to read points of nonexistent area"));
  36. return -1; /* error , because we should not read dead areas */
  37. }
  38. if (first_time == 1) {
  39. Points = Vect_new_line_struct();
  40. first_time = 0;
  41. }
  42. G_debug(3, " n_lines = %d", Area->n_lines);
  43. for (i = 0; i < Area->n_lines; i++) {
  44. line = Area->lines[i];
  45. aline = abs(line);
  46. G_debug(3, " append line(%d) = %d", i, line);
  47. if (0 > Vect_read_line(Map, Points, NULL, aline)) {
  48. G_fatal_error(_("Unable to read read line %d"), aline);
  49. }
  50. G_debug(3, " line n_points = %d", Points->n_points);
  51. if (line > 0)
  52. dir = GV_FORWARD;
  53. else
  54. dir = GV_BACKWARD;
  55. Vect_append_points(BPoints, Points, dir);
  56. if (i != (Area->n_lines - 1)) /* all but not last */
  57. BPoints->n_points--;
  58. G_debug(3, " area n_points = %d", BPoints->n_points);
  59. }
  60. return BPoints->n_points;
  61. }
  62. /*!
  63. \brief Returns polygon array of points for given isle
  64. \param Map pointer to Map_info structure
  65. \param isle island id
  66. \param[out] BPoints points array
  67. \return number of points
  68. \return -1 on error
  69. */
  70. int Vect_get_isle_points(const struct Map_info *Map,
  71. int isle, struct line_pnts *BPoints)
  72. {
  73. int i, line, aline, dir;
  74. const struct Plus_head *Plus;
  75. struct P_isle *Isle;
  76. static int first_time = 1;
  77. static struct line_pnts *Points;
  78. G_debug(3, "Vect_get_isle_points(): isle = %d", isle);
  79. BPoints->n_points = 0;
  80. Plus = &(Map->plus);
  81. Isle = Plus->Isle[isle];
  82. if (first_time == 1) {
  83. Points = Vect_new_line_struct();
  84. first_time = 0;
  85. }
  86. G_debug(3, " n_lines = %d", Isle->n_lines);
  87. for (i = 0; i < Isle->n_lines; i++) {
  88. line = Isle->lines[i];
  89. aline = abs(line);
  90. G_debug(3, " append line(%d) = %d", i, line);
  91. if (0 > Vect_read_line(Map, Points, NULL, aline)) {
  92. G_fatal_error(_("Unable to read line %d"), aline);
  93. }
  94. G_debug(3, " line n_points = %d", Points->n_points);
  95. if (line > 0)
  96. dir = GV_FORWARD;
  97. else
  98. dir = GV_BACKWARD;
  99. Vect_append_points(BPoints, Points, dir);
  100. if (i != (Isle->n_lines - 1)) /* all but not last */
  101. BPoints->n_points--;
  102. G_debug(3, " isle n_points = %d", BPoints->n_points);
  103. }
  104. return (BPoints->n_points);
  105. }
  106. /*!
  107. \brief Returns centroid id for given area
  108. \param Map pointer to Map_info structure
  109. \param area area id
  110. \return centroid id of area
  111. \return 0 if no centroid found
  112. */
  113. int Vect_get_area_centroid(const struct Map_info *Map, int area)
  114. {
  115. const struct Plus_head *Plus;
  116. struct P_area *Area;
  117. G_debug(3, "Vect_get_area_centroid(): area = %d", area);
  118. Plus = &(Map->plus);
  119. Area = Plus->Area[area];
  120. if (Area == NULL)
  121. G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
  122. return (Area->centroid);
  123. }
  124. /*!
  125. \brief Creates list of boundaries for given area
  126. Note that ids in <b>List</b> can be negative. The sign indicates in
  127. which direction the boundary should be read (negative for
  128. backward).
  129. \param Map pointer to Map_info structure
  130. \param area area id
  131. \param[out] List pointer to list of boundaries
  132. \return number of boundaries
  133. */
  134. int Vect_get_area_boundaries(const struct Map_info *Map, int area, struct ilist *List)
  135. {
  136. int i, line;
  137. const struct Plus_head *Plus;
  138. struct P_area *Area;
  139. G_debug(3, "Vect_get_area_boundaries(): area = %d", area);
  140. Vect_reset_list(List);
  141. Plus = &(Map->plus);
  142. Area = Plus->Area[area];
  143. if (Area == NULL)
  144. G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
  145. for (i = 0; i < Area->n_lines; i++) {
  146. line = Area->lines[i];
  147. Vect_list_append(List, line);
  148. }
  149. return (List->n_values);
  150. }
  151. /*!
  152. \brief Creates list of boundaries for given isle
  153. Note that ids in <b>List</b> can be negative. The sign indicates in
  154. which direction the boundary should be read (negative for forward).
  155. \param Map pointer to Map_info structur
  156. \param isle island number
  157. \param[out] List pointer to list where boundaries are stored
  158. \return number of boundaries
  159. */
  160. int Vect_get_isle_boundaries(const struct Map_info *Map, int isle, struct ilist *List)
  161. {
  162. int i, line;
  163. const struct Plus_head *Plus;
  164. struct P_isle *Isle;
  165. G_debug(3, "Vect_get_isle_boundaries(): isle = %d", isle);
  166. Vect_reset_list(List);
  167. Plus = &(Map->plus);
  168. Isle = Plus->Isle[isle];
  169. if (Isle == NULL)
  170. G_fatal_error(_("Attempt to read topo for dead isle (%d)"), isle);
  171. for (i = 0; i < Isle->n_lines; i++) {
  172. line = Isle->lines[i];
  173. Vect_list_append(List, line);
  174. }
  175. return (List->n_values);
  176. }
  177. /*!
  178. \brief Returns number of isles for given area
  179. \param Map pointer to Map_info structure
  180. \param area area id
  181. \return number of isles for area
  182. \return 0 if area not found
  183. */
  184. int Vect_get_area_num_isles(const struct Map_info *Map, int area)
  185. {
  186. const struct Plus_head *Plus;
  187. struct P_area *Area;
  188. G_debug(3, "Vect_get_area_num_isles(): area = %d", area);
  189. Plus = &(Map->plus);
  190. Area = Plus->Area[area];
  191. if (Area == NULL)
  192. G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
  193. G_debug(3, " n_isles = %d", Area->n_isles);
  194. return (Area->n_isles);
  195. }
  196. /*!
  197. \brief Returns isle id for area
  198. \param Map pointer to Map_info structure
  199. \param area area id
  200. \param isle isle index (0 .. nisles - 1)
  201. \return isle id
  202. \return 0 if no isle found
  203. */
  204. int Vect_get_area_isle(const struct Map_info *Map, int area, int isle)
  205. {
  206. const struct Plus_head *Plus;
  207. struct P_area *Area;
  208. G_debug(3, "Vect_get_area_isle(): area = %d isle = %d", area, isle);
  209. Plus = &(Map->plus);
  210. Area = Plus->Area[area];
  211. if (Area == NULL)
  212. G_fatal_error(_("Attempt to read topo for dead area (%d)"), area);
  213. G_debug(3, " -> isle = %d", Area->isles[isle]);
  214. return (Area->isles[isle]);
  215. }
  216. /*!
  217. \brief Returns area id for isle
  218. \param Map vector
  219. \param isle isle number (0 .. nisles - 1)
  220. \return area id
  221. \return 0 area not found
  222. */
  223. int Vect_get_isle_area(const struct Map_info *Map, int isle)
  224. {
  225. const struct Plus_head *Plus;
  226. struct P_isle *Isle;
  227. G_debug(3, "Vect_get_isle_area(): isle = %d", isle);
  228. Plus = &(Map->plus);
  229. Isle = Plus->Isle[isle];
  230. if (Isle == NULL)
  231. G_fatal_error(_("Attempt to read topo for dead isle (%d)"), isle);
  232. G_debug(3, " -> area = %d", Isle->area);
  233. return (Isle->area);
  234. }
  235. /*!
  236. \brief Calculate area perimeter
  237. \param Points list of points defining area boundary
  238. \return area perimeter
  239. */
  240. double Vect_area_perimeter(const struct line_pnts *Points)
  241. {
  242. return Vect_line_length(Points);
  243. }
  244. /*!
  245. \brief Check if point is in area
  246. \param x,y point coordinates
  247. \param Map pointer to Map_info structure
  248. \param area area id
  249. \param box area bounding box
  250. \return 1 if point is in area
  251. \return 0 if not
  252. */
  253. int Vect_point_in_area(double x, double y, const struct Map_info *Map,
  254. int area, struct bound_box box)
  255. {
  256. int i, isle;
  257. const struct Plus_head *Plus;
  258. struct P_area *Area;
  259. struct bound_box ibox;
  260. int poly;
  261. Plus = &(Map->plus);
  262. Area = Plus->Area[area];
  263. if (Area == NULL)
  264. return 0;
  265. poly = Vect_point_in_area_outer_ring(x, y, Map, area, box);
  266. if (poly == 0)
  267. return 0; /* includes area boundary (poly == 2), OK? */
  268. /* check if in islands */
  269. for (i = 0; i < Area->n_isles; i++) {
  270. isle = Area->isles[i];
  271. Vect_get_isle_box(Map, isle, &ibox);
  272. poly = Vect_point_in_island(x, y, Map, isle, ibox);
  273. if (poly >= 1)
  274. return 0; /* excludes island boundary (poly == 2), OK? */
  275. }
  276. return 1;
  277. }
  278. /*!
  279. \brief Returns area of area without areas of isles
  280. \param Map pointer to Map_info structure
  281. \param area area id
  282. \return area of area without areas of isles
  283. */
  284. double Vect_get_area_area(const struct Map_info *Map, int area)
  285. {
  286. const struct Plus_head *Plus;
  287. struct P_area *Area;
  288. struct line_pnts *Points;
  289. double size;
  290. int i;
  291. static int first_time = 1;
  292. G_debug(3, "Vect_get_area_area(): area = %d", area);
  293. if (first_time == 1) {
  294. G_begin_polygon_area_calculations();
  295. first_time = 0;
  296. }
  297. Points = Vect_new_line_struct();
  298. Plus = &(Map->plus);
  299. Area = Plus->Area[area];
  300. Vect_get_area_points(Map, area, Points);
  301. size = G_area_of_polygon(Points->x, Points->y, Points->n_points);
  302. /* substructing island areas */
  303. for (i = 0; i < Area->n_isles; i++) {
  304. Vect_get_isle_points(Map, Area->isles[i], Points);
  305. size -= G_area_of_polygon(Points->x, Points->y, Points->n_points);
  306. }
  307. Vect_destroy_line_struct(Points);
  308. G_debug(3, " area = %f", size);
  309. return (size);
  310. }
  311. /*!
  312. \brief Get area categories
  313. \param Map pointer to Map_info structure
  314. \param area area id
  315. \param[out] Cats list of categories
  316. \return 0 centroid found (but may be without categories)
  317. \return 1 no centroid found
  318. */
  319. int Vect_get_area_cats(const struct Map_info *Map, int area, struct line_cats *Cats)
  320. {
  321. int centroid;
  322. Vect_reset_cats(Cats);
  323. centroid = Vect_get_area_centroid(Map, area);
  324. if (centroid > 0) {
  325. Vect_read_line(Map, NULL, Cats, centroid);
  326. }
  327. else {
  328. return 1; /* no centroid */
  329. }
  330. return 0;
  331. }
  332. /*!
  333. \brief Find FIRST category of given field and area
  334. \param Map pointer to Map_info structure
  335. \param area area id
  336. \param field layer number
  337. \return first found category of given field
  338. \return -1 no centroid or no category found
  339. */
  340. int Vect_get_area_cat(const struct Map_info *Map, int area, int field)
  341. {
  342. int i;
  343. static struct line_cats *Cats = NULL;
  344. if (!Cats)
  345. Cats = Vect_new_cats_struct();
  346. else
  347. Vect_reset_cats(Cats);
  348. if (Vect_get_area_cats(Map, area, Cats) == 1 || Cats->n_cats == 0) {
  349. return -1;
  350. }
  351. for (i = 0; i < Cats->n_cats; i++) {
  352. if (Cats->field[i] == field) {
  353. return Cats->cat[i];
  354. }
  355. }
  356. return -1;
  357. }