main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. /****************************************************************************
  2. *
  3. * MODULE: v.select - select features from one map by features in another map.
  4. * AUTHOR(S): Radim Blazek <radim.blazek gmail.com> (original contributor)
  5. * Glynn Clements <glynn gclements.plus.com>, Markus Neteler <neteler itc.it>
  6. * Martin Landa <landa.martin gmail.com> (GEOS support)
  7. * PURPOSE:
  8. * COPYRIGHT: (C) 2003-2009 by the GRASS Development Team
  9. *
  10. * This program is free software under the GNU General Public
  11. * License (>=v2). Read the file COPYING that comes with GRASS
  12. * for details.
  13. *
  14. *****************************************************************************/
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <grass/config.h>
  19. #include <grass/gis.h>
  20. #include <grass/dbmi.h>
  21. #include <grass/vector.h>
  22. #include <grass/glocale.h>
  23. #include "proto.h"
  24. int main(int argc, char *argv[])
  25. {
  26. int i, iopt;
  27. int operator;
  28. int aline, nalines, nskipped;
  29. int ltype, itype[2], ifield[2];
  30. int **cats, *ncats, nfields, *fields;
  31. char *pre[2];
  32. struct GModule *module;
  33. struct GParm parm;
  34. struct GFlag flag;
  35. struct Map_info In[2], Out;
  36. struct field_info *IFi, *OFi;
  37. struct line_pnts *APoints, *BPoints;
  38. struct line_cats *ACats, *BCats;
  39. int *ALines; /* List of lines: 0 do not output, 1 - write to output */
  40. struct ilist *List, *TmpList, *BoundList;
  41. G_gisinit(argv[0]);
  42. pre[0] = "a";
  43. pre[1] = "b";
  44. module = G_define_module();
  45. G_add_keyword(_("vector"));
  46. G_add_keyword(_("spatial query"));
  47. module->description =
  48. _("Selects features from vector map (A) by features from other vector map (B).");
  49. parse_options(&parm, &flag);
  50. if (G_parser(argc, argv))
  51. exit(EXIT_FAILURE);
  52. if (parm.operator->answer[0] == 'e')
  53. operator = OP_EQUALS;
  54. else if (parm.operator->answer[0] == 'd') {
  55. /* operator = OP_DISJOINT; */
  56. operator = OP_INTERSECTS;
  57. flag.reverse->answer = YES;
  58. }
  59. else if (parm.operator->answer[0] == 'i')
  60. operator = OP_INTERSECTS;
  61. else if (parm.operator->answer[0] == 't')
  62. operator = OP_TOUCHES;
  63. else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'r')
  64. operator = OP_CROSSES;
  65. else if (parm.operator->answer[0] == 'w')
  66. operator = OP_WITHIN;
  67. else if (parm.operator->answer[0] == 'c' && parm.operator->answer[1] == 'o')
  68. operator = OP_CONTAINS;
  69. else if (parm.operator->answer[0] == 'o')
  70. operator = OP_OVERLAPS;
  71. else if (parm.operator->answer[0] == 'r')
  72. operator = OP_RELATE;
  73. else
  74. G_fatal_error(_("Unknown operator"));
  75. if (operator != OP_OVERLAPS && flag.geos && !flag.geos->answer) {
  76. G_fatal_error(_("Enable GEOS operators (flag '%c') to use '%s'"),
  77. flag.geos->key, parm.operator->answer);
  78. }
  79. if (operator == OP_RELATE && !parm.relate->answer) {
  80. G_fatal_error(_("Required parameter <%s> not set"),
  81. parm.relate->key);
  82. }
  83. for (iopt = 0; iopt < 2; iopt++) {
  84. itype[iopt] = Vect_option_to_types(parm.type[iopt]);
  85. ifield[iopt] = atoi(parm.field[iopt]->answer);
  86. Vect_check_input_output_name(parm.input[iopt]->answer, parm.output->answer,
  87. GV_FATAL_EXIT);
  88. Vect_set_open_level(2);
  89. Vect_open_old(&(In[iopt]), parm.input[iopt]->answer, "");
  90. }
  91. /* Read field info */
  92. IFi = Vect_get_field(&(In[0]), ifield[0]);
  93. APoints = Vect_new_line_struct();
  94. BPoints = Vect_new_line_struct();
  95. ACats = Vect_new_cats_struct();
  96. BCats = Vect_new_cats_struct();
  97. List = Vect_new_list();
  98. TmpList = Vect_new_list();
  99. BoundList = Vect_new_list();
  100. /* Open output */
  101. Vect_open_new(&Out, parm.output->answer, Vect_is_3d(&(In[0])));
  102. Vect_set_map_name(&Out, _("Output from v.select"));
  103. Vect_set_person(&Out, G_whoami());
  104. Vect_copy_head_data(&(In[0]), &Out);
  105. Vect_hist_copy(&(In[0]), &Out);
  106. Vect_hist_command(&Out);
  107. nskipped = 0;
  108. nalines = Vect_get_num_lines(&(In[0]));
  109. #ifdef HAVE_GEOS
  110. initGEOS(G_message, G_fatal_error);
  111. GEOSGeometry *AGeom = NULL;
  112. #else
  113. void *AGeom = NULL;
  114. #endif
  115. /* Alloc space for input lines array */
  116. ALines = (int *)G_calloc(nalines + 1, sizeof(int));
  117. /* Lines in A. Go through all lines and mark those that meets condition */
  118. if (itype[0] & (GV_POINTS | GV_LINES)) {
  119. G_message(_("Processing features..."));
  120. for (aline = 1; aline <= nalines; aline++) {
  121. struct bound_box abox;
  122. G_debug(3, "aline = %d", aline);
  123. G_percent(aline, nalines, 2); /* must be before any continue */
  124. /* Check category */
  125. if (Vect_get_line_cat(&(In[0]), aline, ifield[0]) < 0) {
  126. nskipped++;
  127. continue;
  128. }
  129. /* Read line and check type */
  130. if (flag.geos && flag.geos->answer) {
  131. #ifdef HAVE_GEOS
  132. AGeom = Vect_read_line_geos(&(In[0]), aline, &ltype);
  133. #endif
  134. if (!(ltype & (GV_POINT | GV_LINE)))
  135. continue;
  136. if (!AGeom)
  137. G_fatal_error(_("Unable to read line id %d from vector map <%s>"),
  138. aline, Vect_get_full_name(&(In[0])));
  139. }
  140. else {
  141. ltype = Vect_read_line(&(In[0]), APoints, NULL, aline);
  142. }
  143. if (!(ltype & itype[0]))
  144. continue;
  145. Vect_get_line_box(&(In[0]), aline, &abox);
  146. abox.T = PORT_DOUBLE_MAX;
  147. abox.B = -PORT_DOUBLE_MAX;
  148. /* Check if this line overlaps any feature in B */
  149. /* x Lines in B */
  150. if (itype[1] & (GV_POINTS | GV_LINES)) {
  151. int i;
  152. int found = 0;
  153. /* Lines */
  154. Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List);
  155. for (i = 0; i < List->n_values; i++) {
  156. int bline;
  157. bline = List->value[i];
  158. G_debug(3, " bline = %d", bline);
  159. /* Check category */
  160. if (!Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) {
  161. nskipped++;
  162. continue;
  163. }
  164. if (flag.geos && flag.geos->answer) {
  165. #ifdef HAVE_GEOS
  166. if(line_relate_geos(&(In[1]), AGeom,
  167. bline, operator, parm.relate->answer)) {
  168. found = 1;
  169. break;
  170. }
  171. #endif
  172. }
  173. else {
  174. Vect_read_line(&(In[1]), BPoints, NULL, bline);
  175. if (Vect_line_check_intersection(APoints, BPoints, 0)) {
  176. found = 1;
  177. break;
  178. }
  179. }
  180. }
  181. if (found) {
  182. ALines[aline] = 1;
  183. continue; /* Go to next A line */
  184. }
  185. }
  186. /* x Areas in B. */
  187. if (itype[1] & GV_AREA) {
  188. int i;
  189. Vect_select_areas_by_box(&(In[1]), &abox, List);
  190. for (i = 0; i < List->n_values; i++) {
  191. int barea;
  192. barea = List->value[i];
  193. G_debug(3, " barea = %d", barea);
  194. if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) {
  195. nskipped++;
  196. continue;
  197. }
  198. if (flag.geos && flag.geos->answer) {
  199. #ifdef HAVE_GEOS
  200. if(area_relate_geos(&(In[1]), AGeom,
  201. barea, operator, parm.relate->answer)) {
  202. ALines[aline] = 1;
  203. break;
  204. }
  205. #endif
  206. }
  207. else {
  208. if (line_overlap_area(&(In[0]), aline, &(In[1]), barea)) {
  209. ALines[aline] = 1;
  210. break;
  211. }
  212. }
  213. }
  214. }
  215. if (flag.geos && flag.geos->answer) {
  216. #ifdef HAVE_GEOS
  217. GEOSGeom_destroy(AGeom);
  218. #endif
  219. AGeom = NULL;
  220. }
  221. }
  222. }
  223. /* Areas in A. */
  224. if (itype[0] & GV_AREA) {
  225. int aarea, naareas;
  226. G_message(_("Processing areas..."));
  227. naareas = Vect_get_num_areas(&(In[0]));
  228. for (aarea = 1; aarea <= naareas; aarea++) {
  229. struct bound_box abox;
  230. G_percent(aarea, naareas, 2); /* must be before any continue */
  231. if (Vect_get_area_cat(&(In[0]), aarea, ifield[0]) < 0) {
  232. nskipped++;
  233. continue;
  234. }
  235. Vect_get_area_box(&(In[0]), aarea, &abox);
  236. abox.T = PORT_DOUBLE_MAX;
  237. abox.B = -PORT_DOUBLE_MAX;
  238. if (flag.geos && flag.geos->answer) {
  239. #ifdef HAVE_GEOS
  240. AGeom = Vect_read_area_geos(&(In[0]), aarea);
  241. #endif
  242. if (!AGeom)
  243. G_fatal_error(_("Unable to read area id %d from vector map <%s>"),
  244. aline, Vect_get_full_name(&(In[0])));
  245. }
  246. /* x Lines in B */
  247. if (itype[1] & (GV_POINTS | GV_LINES)) {
  248. Vect_select_lines_by_box(&(In[1]), &abox, itype[1], List);
  249. for (i = 0; i < List->n_values; i++) {
  250. int bline;
  251. bline = List->value[i];
  252. if (Vect_get_line_cat(&(In[1]), bline, ifield[1]) < 0) {
  253. nskipped++;
  254. continue;
  255. }
  256. if (flag.geos && flag.geos->answer) {
  257. #ifdef HAVE_GEOS
  258. if(line_relate_geos(&(In[1]), AGeom,
  259. bline, operator, parm.relate->answer)) {
  260. add_aarea(&(In[0]), aarea, ALines);
  261. break;
  262. }
  263. #endif
  264. }
  265. else {
  266. if (line_overlap_area(&(In[1]), bline, &(In[0]), aarea)) {
  267. add_aarea(&(In[0]), aarea, ALines);
  268. continue;
  269. }
  270. }
  271. }
  272. }
  273. /* x Areas in B */
  274. if (itype[1] & GV_AREA) {
  275. int naisles;
  276. int found = 0;
  277. /* List of areas B */
  278. /* Make a list of features forming area A */
  279. Vect_reset_list(List);
  280. Vect_get_area_boundaries(&(In[0]), aarea, BoundList);
  281. for (i = 0; i < BoundList->n_values; i++) {
  282. Vect_list_append(List, abs(BoundList->value[i]));
  283. }
  284. naisles = Vect_get_area_num_isles(&(In[0]), aarea);
  285. for (i = 0; i < naisles; i++) {
  286. int j, aisle;
  287. aisle = Vect_get_area_isle(&(In[0]), aarea, i);
  288. Vect_get_isle_boundaries(&(In[0]), aisle, BoundList);
  289. for (j = 0; j < BoundList->n_values; j++) {
  290. Vect_list_append(List, BoundList->value[j]);
  291. }
  292. }
  293. Vect_select_areas_by_box(&(In[1]), &abox, TmpList);
  294. for (i = 0; i < List->n_values; i++) {
  295. int j, aline;
  296. aline = abs(List->value[i]);
  297. for (j = 0; j < TmpList->n_values; j++) {
  298. int barea, bcentroid;
  299. barea = TmpList->value[j];
  300. G_debug(3, " barea = %d", barea);
  301. if (Vect_get_area_cat(&(In[1]), barea, ifield[1]) < 0) {
  302. nskipped++;
  303. continue;
  304. }
  305. /* Check if any centroid of area B is in area A.
  306. * This test is important in if area B is completely within area A */
  307. bcentroid = Vect_get_area_centroid(&(In[1]), barea);
  308. Vect_read_line(&(In[1]), BPoints, NULL, bcentroid);
  309. if (flag.geos && flag.geos->answer) {
  310. #ifdef HAVE_GEOS
  311. if(area_relate_geos(&(In[1]), AGeom,
  312. barea, operator, parm.relate->answer)) {
  313. found = 1;
  314. break;
  315. }
  316. #endif
  317. }
  318. else {
  319. if (Vect_point_in_area(&(In[0]), aarea,
  320. BPoints->x[0], BPoints->y[0])) {
  321. found = 1;
  322. break;
  323. }
  324. /* Check intersectin of lines from List with area B */
  325. if (line_overlap_area(&(In[0]), aline,
  326. &(In[1]), barea)) {
  327. found = 1;
  328. break;
  329. }
  330. }
  331. }
  332. if (found) {
  333. add_aarea(&(In[0]), aarea, ALines);
  334. break;
  335. }
  336. }
  337. }
  338. if (flag.geos && flag.geos->answer) {
  339. #ifdef HAVE_GEOS
  340. GEOSGeom_destroy(AGeom);
  341. #endif
  342. AGeom = NULL;
  343. }
  344. }
  345. }
  346. Vect_close(&(In[1]));
  347. #ifdef HAVE_GEOS
  348. finishGEOS();
  349. #endif
  350. /* Write lines */
  351. nfields = Vect_cidx_get_num_fields(&(In[0]));
  352. cats = (int **)G_malloc(nfields * sizeof(int *));
  353. ncats = (int *)G_malloc(nfields * sizeof(int));
  354. fields = (int *)G_malloc(nfields * sizeof(int));
  355. for (i = 0; i < nfields; i++) {
  356. ncats[i] = 0;
  357. cats[i] =
  358. (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&(In[0]), i) *
  359. sizeof(int));
  360. fields[i] = Vect_cidx_get_field_number(&(In[0]), i);
  361. }
  362. G_message(_("Writing selected features..."));
  363. for (aline = 1; aline <= nalines; aline++) {
  364. int atype;
  365. G_debug(4, "aline = %d ALines[aline] = %d", aline, ALines[aline]);
  366. G_percent(aline, nalines, 2);
  367. if ((!flag.reverse->answer && !(ALines[aline])) ||
  368. (flag.reverse->answer && ALines[aline]))
  369. continue;
  370. atype = Vect_read_line(&(In[0]), APoints, ACats, aline);
  371. Vect_write_line(&Out, atype, APoints, ACats);
  372. if (!(flag.table->answer) && (IFi != NULL)) {
  373. for (i = 0; i < ACats->n_cats; i++) {
  374. int f, j;
  375. for (j = 0; j < nfields; j++) { /* find field */
  376. if (fields[j] == ACats->field[i]) {
  377. f = j;
  378. break;
  379. }
  380. }
  381. cats[f][ncats[f]] = ACats->cat[i];
  382. ncats[f]++;
  383. }
  384. }
  385. }
  386. /* Copy tables */
  387. if (!(flag.table->answer)) {
  388. int ttype, ntabs = 0;
  389. G_message(_("Writing attributes..."));
  390. /* Number of output tabs */
  391. for (i = 0; i < Vect_get_num_dblinks(&(In[0])); i++) {
  392. int f, j;
  393. IFi = Vect_get_dblink(&(In[0]), i);
  394. for (j = 0; j < nfields; j++) { /* find field */
  395. if (fields[j] == IFi->number) {
  396. f = j;
  397. break;
  398. }
  399. }
  400. if (ncats[f] > 0)
  401. ntabs++;
  402. }
  403. if (ntabs > 1)
  404. ttype = GV_MTABLE;
  405. else
  406. ttype = GV_1TABLE;
  407. for (i = 0; i < nfields; i++) {
  408. int ret;
  409. if (fields[i] == 0)
  410. continue;
  411. /* Make a list of categories */
  412. IFi = Vect_get_field(&(In[0]), fields[i]);
  413. if (!IFi) { /* no table */
  414. G_warning(_("Layer %d - no table"), fields[i]);
  415. continue;
  416. }
  417. OFi =
  418. Vect_default_field_info(&Out, IFi->number, IFi->name, ttype);
  419. ret =
  420. db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table,
  421. OFi->driver,
  422. Vect_subst_var(OFi->database, &Out),
  423. OFi->table, IFi->key, cats[i],
  424. ncats[i]);
  425. if (ret == DB_FAILED) {
  426. G_warning(_("Layer %d - unable to copy table"), fields[i]);
  427. }
  428. else {
  429. Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table,
  430. IFi->key, OFi->database, OFi->driver);
  431. }
  432. }
  433. }
  434. Vect_close(&(In[0]));
  435. Vect_build(&Out);
  436. Vect_close(&Out);
  437. if (nskipped > 0) {
  438. G_warning(_("%d features without category skipped"), nskipped);
  439. }
  440. G_done_msg(_("%d features written to output."), Vect_get_num_lines(&Out));
  441. exit(EXIT_SUCCESS);
  442. }