main.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /****************************************************************************
  2. *
  3. * MODULE: v.overlay
  4. * AUTHOR(S): Radim Blazek <radim.blazek gmail.com> (original contributor)
  5. * Glynn Clements <glynn gclements.plus.com>,
  6. * Hamish Bowman <hamish_b yahoo.com>,
  7. * Jachym Cepicky <jachym les-ejk.cz>,
  8. * Markus Neteler <neteler itc.it>,
  9. * Paul Kelly <paul-grass stjohnspoint.co.uk>
  10. * OGR support by Martin Landa <landa.martin gmail.com>
  11. * Markus Metz
  12. * PURPOSE:
  13. * COPYRIGHT: (C) 2003-2016 by the GRASS Development Team
  14. *
  15. * This program is free software under the GNU General
  16. * Public License (>=v2). Read the file COPYING that
  17. * comes with GRASS for details.
  18. *
  19. *****************************************************************************/
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <unistd.h>
  25. #include <grass/gis.h>
  26. #include <grass/dbmi.h>
  27. #include <grass/vector.h>
  28. #include <grass/glocale.h>
  29. #include "local.h"
  30. void copy_table(struct Map_info *, struct Map_info *, int, int, int);
  31. int main(int argc, char *argv[])
  32. {
  33. int i, j, input, line, nlines, operator;
  34. int type[2], field[2], ofield[3];
  35. double snap_thresh;
  36. struct GModule *module;
  37. struct Option *in_opt[2], *out_opt, *type_opt[2], *field_opt[2],
  38. *ofield_opt, *operator_opt, *snap_opt;
  39. struct Flag *table_flag;
  40. struct Map_info In[2], Out, Tmp;
  41. struct line_pnts *Points, *Points2;
  42. struct line_cats *Cats;
  43. struct ilist *BList;
  44. char *desc;
  45. int verbose;
  46. struct field_info *Fi = NULL;
  47. int table_type;
  48. char buf[DB_SQL_MAX];
  49. dbString stmt;
  50. dbString sql, value_string, col_defs;
  51. dbDriver *driver;
  52. ATTRIBUTES attr[2];
  53. G_gisinit(argv[0]);
  54. module = G_define_module();
  55. G_add_keyword(_("vector"));
  56. G_add_keyword(_("geometry"));
  57. G_add_keyword(_("spatial query"));
  58. G_add_keyword(_("clip"));
  59. G_add_keyword(_("difference"));
  60. G_add_keyword(_("intersection"));
  61. G_add_keyword(_("union"));
  62. module->description = _("Overlays two vector maps offering clip, intersection, difference, symmetrical difference, union operators.");
  63. in_opt[0] = G_define_standard_option(G_OPT_V_INPUT);
  64. in_opt[0]->label = _("Name of input vector map (A)");
  65. in_opt[0]->key = "ainput";
  66. field_opt[0] = G_define_standard_option(G_OPT_V_FIELD);
  67. field_opt[0]->label = _("Layer number or name (vector map A)");
  68. field_opt[0]->key = "alayer";
  69. type_opt[0] = G_define_standard_option(G_OPT_V_TYPE);
  70. type_opt[0]->label = _("Feature type (vector map A)");
  71. type_opt[0]->key = "atype";
  72. type_opt[0]->options = "line,area,auto";
  73. type_opt[0]->answer = "auto";
  74. in_opt[1] = G_define_standard_option(G_OPT_V_INPUT);
  75. in_opt[1]->label = _("Name of input vector map (B)");
  76. in_opt[1]->key = "binput";
  77. field_opt[1] = G_define_standard_option(G_OPT_V_FIELD);
  78. field_opt[1]->label = _("Layer number or name (vector map B)");
  79. field_opt[1]->key = "blayer";
  80. type_opt[1] = G_define_standard_option(G_OPT_V_TYPE);
  81. type_opt[1]->label = _("Feature type (vector map B)");
  82. type_opt[1]->key = "btype";
  83. type_opt[1]->options = "area";
  84. type_opt[1]->answer = "area";
  85. operator_opt = G_define_option();
  86. operator_opt->key = "operator";
  87. operator_opt->type = TYPE_STRING;
  88. operator_opt->required = YES;
  89. operator_opt->multiple = NO;
  90. operator_opt->options = "and,or,not,xor";
  91. operator_opt->label = _("Operator defines features written to "
  92. "output vector map");
  93. operator_opt->description =
  94. _("Feature is written to output if the result "
  95. "of operation 'ainput operator binput' is true. "
  96. "Input feature is considered to be true, if "
  97. "category of given layer is defined.");
  98. desc = NULL;
  99. G_asprintf(&desc,
  100. "and;%s;or;%s;not;%s;xor;%s",
  101. _("also known as 'intersection' in GIS"),
  102. _("also known as 'union' in GIS (only for atype=area)"),
  103. _("also known as 'difference' (features from ainput not "
  104. "overlaid by features from binput)"),
  105. _("also known as 'symmetrical difference' (features from either ainput or binput but "
  106. "not those from ainput overlaid by binput (only "
  107. "for atype=area)"));
  108. operator_opt->descriptions = desc;
  109. out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
  110. ofield_opt = G_define_standard_option(G_OPT_V_FIELD);
  111. ofield_opt->key = "olayer";
  112. ofield_opt->multiple = YES;
  113. ofield_opt->answer = "1,0,0";
  114. ofield_opt->label = _("Output layer for new category, ainput and binput");
  115. ofield_opt->description = _("If 0 or not given, "
  116. "the category is not written");
  117. ofield_opt->required = NO;
  118. ofield_opt->guisection = _("Attributes");
  119. snap_opt = G_define_option();
  120. snap_opt->key = "snap";
  121. snap_opt->label = _("Snapping threshold for boundaries");
  122. snap_opt->description = _("Disable snapping with snap <= 0");
  123. snap_opt->type = TYPE_DOUBLE;
  124. snap_opt->answer = "1e-8";
  125. table_flag = G_define_standard_flag(G_FLG_V_TABLE);
  126. table_flag->guisection = _("Attributes");
  127. if (G_parser(argc, argv))
  128. exit(EXIT_FAILURE);
  129. for (input = 0; input < 2; input++) {
  130. type[input] = Vect_option_to_types(type_opt[input]);
  131. }
  132. /* not needed
  133. if (type[0] & GV_AREA)
  134. type[0] = GV_AREA;
  135. */
  136. ofield[0] = ofield[1] = ofield[2] = 0;
  137. i = 0;
  138. while (ofield_opt->answers[i] && i < 3) {
  139. ofield[i] = atoi(ofield_opt->answers[i]);
  140. i++;
  141. }
  142. table_type = GV_1TABLE;
  143. if ((ofield[0] > 0) + (ofield[1] > 0) + (ofield[2] > 0) > 1)
  144. table_type = GV_MTABLE;
  145. if (operator_opt->answer[0] == 'a')
  146. operator = OP_AND;
  147. else if (operator_opt->answer[0] == 'o')
  148. operator = OP_OR;
  149. else if (operator_opt->answer[0] == 'n')
  150. operator = OP_NOT;
  151. else if (operator_opt->answer[0] == 'x')
  152. operator = OP_XOR;
  153. else
  154. G_fatal_error(_("Unknown operator '%s'"), operator_opt->answer);
  155. Vect_check_input_output_name(in_opt[0]->answer, out_opt->answer,
  156. G_FATAL_EXIT);
  157. Vect_check_input_output_name(in_opt[1]->answer, out_opt->answer,
  158. G_FATAL_EXIT);
  159. for (input = 0; input < 2; input++) {
  160. Vect_set_open_level(2);
  161. if (Vect_open_old2(&(In[input]), in_opt[input]->answer, "", field_opt[input]->answer) < 0)
  162. G_fatal_error(_("Unable to open vector map <%s>"),
  163. in_opt[input]->answer);
  164. field[input] = Vect_get_field_number(&(In[input]), field_opt[input]->answer);
  165. }
  166. if (type[0] == 0) { /* atype=auto */
  167. type[0] = Vect_read_next_line(&(In[0]), NULL, NULL);
  168. if (type[0] == -1)
  169. G_fatal_error(_("Unable to determine feature type for <%s>"),
  170. in_opt[0]->key);
  171. if (type[0] & (GV_BOUNDARY | GV_CENTROID))
  172. type[0] = GV_AREA;
  173. if (!(type[0] & (GV_LINE | GV_AREA)))
  174. G_fatal_error(_("Invalid feature type (%d) for <%s>. Only '%s' or '%s' supported."),
  175. type[0], in_opt[0]->key, "line", "area");
  176. G_debug(1, "auto -> atype=%d", type[0]);
  177. }
  178. /* OP_OR, OP_XOR is not supported for lines,
  179. mostly because I'am not sure if they make enouhg sense */
  180. if (type[0] == GV_LINE && (operator == OP_OR || operator == OP_XOR))
  181. G_fatal_error(_("Operator '%s' is not supported for type line"),
  182. operator_opt->answer);
  183. snap_thresh = atof(snap_opt->answer);
  184. Points = Vect_new_line_struct();
  185. Points2 = Vect_new_line_struct();
  186. Cats = Vect_new_cats_struct();
  187. /* Open output */
  188. if (Vect_open_new(&Out, out_opt->answer, WITHOUT_Z) < 0)
  189. G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer);
  190. Vect_set_map_name(&Out, "Output from v.overlay");
  191. Vect_set_person(&Out, G_whoami());
  192. Vect_hist_command(&Out);
  193. if (Vect_open_tmp_new(&Tmp, NULL, WITHOUT_Z) < 0)
  194. G_fatal_error(_("Unable to create temporary vector map"));
  195. /* Create dblinks */
  196. if (ofield[0] > 0) {
  197. Fi = Vect_default_field_info(&Out, ofield[0], NULL, table_type);
  198. }
  199. db_init_string(&sql);
  200. db_init_string(&value_string);
  201. db_init_string(&col_defs);
  202. /* Open database */
  203. if (ofield[0] > 0 && !(table_flag->answer)) {
  204. db_init_string(&stmt);
  205. driver =
  206. db_start_driver_open_database(Fi->driver,
  207. Vect_subst_var(Fi->database, &Out));
  208. if (driver == NULL) {
  209. Vect_close(&Out);
  210. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  211. Fi->database, Fi->driver);
  212. }
  213. db_set_error_handler_driver(driver);
  214. }
  215. else {
  216. driver = NULL;
  217. }
  218. /* Copy lines to output */
  219. BList = Vect_new_list();
  220. verbose = G_verbose();
  221. G_set_verbose(0);
  222. Vect_build_partial(&Tmp, GV_BUILD_BASE);
  223. G_set_verbose(verbose);
  224. for (input = 0; input < 2; input++) {
  225. int ncats, index, nlines_out, newline;
  226. G_message(_("Copying vector features from <%s>..."),
  227. Vect_get_full_name(&(In[input])));
  228. nlines = Vect_get_num_lines(&(In[input]));
  229. nlines_out = 0;
  230. for (line = 1; line <= nlines; line++) {
  231. int ltype;
  232. int vertices = 100; /* max number of vertices per line */
  233. G_percent(line, nlines, 1); /* must be before any continue */
  234. ltype = Vect_read_line(&(In[input]), Points, Cats, line);
  235. if (type[input] == GV_AREA) {
  236. if (!(ltype & GV_BOUNDARY))
  237. continue;
  238. }
  239. else { /* GV_LINE */
  240. if (!(ltype & type[input]))
  241. continue;
  242. }
  243. /* lines and boundaries must have at least 2 distinct vertices */
  244. /* Vect_line_prune(Points); */
  245. if (Points->n_points > 0) {
  246. j = 1;
  247. for (i = 1; i < Points->n_points; i++) {
  248. Points->z[i] = 0; /* Tmp, Out are 2D */
  249. if (Points->x[i] != Points->x[j - 1] ||
  250. Points->y[i] != Points->y[j - 1]) {
  251. Points->x[j] = Points->x[i];
  252. Points->y[j] = Points->y[i];
  253. j++;
  254. }
  255. }
  256. Points->n_points = j;
  257. }
  258. if (Points->n_points < 2)
  259. continue;
  260. /* TODO: figure out a reasonable threshold */
  261. if (Points->n_points > vertices) {
  262. int start = 0; /* number of coordinates written */
  263. vertices = Points->n_points / (Points->n_points / vertices + 1);
  264. /* split */
  265. while (start < Points->n_points - 1) {
  266. int v = 0;
  267. Vect_reset_line(Points2);
  268. for (i = 0; i < vertices; i++) {
  269. v = start + i;
  270. if (v == Points->n_points)
  271. break;
  272. Vect_append_point(Points2, Points->x[v], Points->y[v],
  273. Points->z[v]);
  274. }
  275. newline = Vect_write_line(&Tmp, ltype, Points2, Cats);
  276. if (input == 1)
  277. G_ilist_add(BList, newline);
  278. start = v;
  279. }
  280. }
  281. else {
  282. newline = Vect_write_line(&Tmp, ltype, Points, Cats);
  283. if (input == 1)
  284. G_ilist_add(BList, newline);
  285. }
  286. nlines_out++;
  287. }
  288. if (nlines_out == 0) {
  289. Vect_close(&Tmp);
  290. Vect_close(&Out);
  291. Vect_delete(out_opt->answer);
  292. G_fatal_error(_("No %s features found in vector map <%s>. Verify '%s' parameter."),
  293. type_opt[input]->answer, Vect_get_full_name(&(In[input])),
  294. type_opt[input]->key);
  295. }
  296. /* Allocate attributes */
  297. attr[input].n = 0;
  298. /* this may be more than necessary */
  299. attr[input].attr =
  300. (ATTR *)
  301. G_calloc(Vect_cidx_get_type_count
  302. (&(In[input]), field[input], type[input]), sizeof(ATTR));
  303. index = Vect_cidx_get_field_index(&(In[input]), field[input]);
  304. if (index >= 0) {
  305. ncats = Vect_cidx_get_num_cats_by_index(&(In[input]), index);
  306. for (i = 0; i < ncats; i++) {
  307. int cat, ctype, id;
  308. Vect_cidx_get_cat_by_index(&(In[input]), index, i, &cat,
  309. &ctype, &id);
  310. if (!(ctype & type[input]))
  311. continue;
  312. if (attr[input].n == 0 ||
  313. cat != attr[input].attr[attr[input].n - 1].cat) {
  314. attr[input].attr[attr[input].n].cat = cat;
  315. attr[input].n++;
  316. }
  317. }
  318. }
  319. G_debug(3, "%d cats read from index", attr[input].n);
  320. attr[input].null_values = NULL;
  321. attr[input].columns = NULL;
  322. /* Attributes */
  323. if (driver) {
  324. int ncol, more;
  325. struct field_info *inFi;
  326. dbDriver *in_driver;
  327. dbCursor cursor;
  328. dbTable *Table;
  329. dbColumn *Column;
  330. dbValue *Value;
  331. int sqltype, ctype;
  332. G_verbose_message(_("Collecting input attributes..."));
  333. inFi = Vect_get_field(&(In[input]), field[input]);
  334. if (!inFi) {
  335. G_warning(_("Database connection not defined for layer %d"),
  336. field[input]);
  337. continue;
  338. }
  339. /* Open input driver and database */
  340. if (strcmp(inFi->driver, Fi->driver) == 0
  341. && strcmp(inFi->database, Vect_subst_var(Fi->database, &Out)) == 0) {
  342. G_debug(3, "Use the same driver");
  343. in_driver = driver;
  344. }
  345. else {
  346. in_driver =
  347. db_start_driver_open_database(inFi->driver, inFi->database);
  348. if (in_driver == NULL) {
  349. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  350. inFi->database, inFi->driver);
  351. }
  352. }
  353. sprintf(buf, "select * from %s", inFi->table);
  354. db_set_string(&sql, buf);
  355. if (db_open_select_cursor(in_driver, &sql, &cursor, DB_SEQUENTIAL)
  356. != DB_OK)
  357. G_fatal_error(_("Unable to select attributes"));
  358. Table = db_get_cursor_table(&cursor);
  359. ncol = db_get_table_number_of_columns(Table);
  360. G_debug(3, "ncol = %d", ncol);
  361. db_set_string(&sql, "");
  362. db_set_string(&col_defs, "");
  363. for (i = 0; i < ncol; i++) {
  364. db_append_string(&sql, ", null");
  365. Column = db_get_table_column(Table, i);
  366. sqltype = db_get_column_sqltype(Column);
  367. ctype = db_sqltype_to_Ctype(sqltype);
  368. if (input == 0)
  369. db_append_string(&col_defs, ", a_");
  370. else
  371. db_append_string(&col_defs, ", b_");
  372. db_append_string(&col_defs, db_get_column_name(Column));
  373. db_append_string(&col_defs, " ");
  374. switch (sqltype) {
  375. case DB_SQL_TYPE_CHARACTER:
  376. sprintf(buf, "varchar(%d)", db_get_column_length(Column));
  377. db_append_string(&col_defs, buf);
  378. break;
  379. case DB_SQL_TYPE_TEXT:
  380. db_append_string(&col_defs, "varchar(250)");
  381. break;
  382. case DB_SQL_TYPE_SMALLINT:
  383. case DB_SQL_TYPE_INTEGER:
  384. db_append_string(&col_defs, "integer");
  385. break;
  386. case DB_SQL_TYPE_REAL:
  387. case DB_SQL_TYPE_DOUBLE_PRECISION:
  388. case DB_SQL_TYPE_DECIMAL:
  389. case DB_SQL_TYPE_NUMERIC:
  390. case DB_SQL_TYPE_INTERVAL:
  391. db_append_string(&col_defs, "double precision");
  392. break;
  393. case DB_SQL_TYPE_DATE:
  394. db_append_string(&col_defs, "date");
  395. break;
  396. case DB_SQL_TYPE_TIME:
  397. db_append_string(&col_defs, "time");
  398. break;
  399. case DB_SQL_TYPE_TIMESTAMP:
  400. db_append_string(&col_defs, "datetime");
  401. break;
  402. default:
  403. G_warning(_("Unknown column type '%s' of column '%s'"),
  404. db_sqltype_name(sqltype), db_get_column_name(Column));
  405. sprintf(buf, "varchar(250)");
  406. }
  407. }
  408. attr[input].null_values = G_store(db_get_string(&sql));
  409. attr[input].columns = G_store(db_get_string(&col_defs));
  410. while (1) {
  411. int cat = -1;
  412. ATTR *at;
  413. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  414. G_fatal_error(_("Unable to fetch data from table"));
  415. if (!more)
  416. break;
  417. db_set_string(&sql, "");
  418. for (i = 0; i < ncol; i++) {
  419. Column = db_get_table_column(Table, i);
  420. sqltype = db_get_column_sqltype(Column);
  421. ctype = db_sqltype_to_Ctype(sqltype);
  422. Value = db_get_column_value(Column);
  423. if (G_strcasecmp(db_get_column_name(Column), inFi->key) ==
  424. 0) {
  425. cat = db_get_value_int(Value);
  426. G_debug(3, "cat = %d", cat);
  427. }
  428. db_append_string(&sql, ", ");
  429. db_convert_value_to_string(Value, sqltype, &value_string);
  430. G_debug(3, "%d: %s : %s", i, db_get_column_name(Column),
  431. db_get_string(&value_string));
  432. switch (ctype) {
  433. case DB_C_TYPE_STRING:
  434. case DB_C_TYPE_DATETIME:
  435. if (db_test_value_isnull(Value)) {
  436. db_append_string(&sql, "null");
  437. }
  438. else {
  439. db_double_quote_string(&value_string);
  440. sprintf(buf, "'%s'",
  441. db_get_string(&value_string));
  442. db_append_string(&sql, buf);
  443. }
  444. break;
  445. case DB_C_TYPE_INT:
  446. case DB_C_TYPE_DOUBLE:
  447. if (db_test_value_isnull(Value)) {
  448. db_append_string(&sql, "null");
  449. }
  450. else {
  451. db_append_string(&sql,
  452. db_get_string(&value_string));
  453. }
  454. break;
  455. default:
  456. G_warning(_("Unknown column type '%s' of column '%s', values lost"),
  457. db_sqltype_name(sqltype), db_get_column_name(Column));
  458. db_append_string(&sql, "null");
  459. }
  460. }
  461. at = find_attr(&(attr[input]), cat);
  462. if (!at)
  463. continue;
  464. /* if ( !at->used ) continue; *//* We don't know yet */
  465. at->values = G_store(db_get_string(&sql));
  466. G_debug(3, "values: %s", at->values);
  467. }
  468. db_table_to_sql(Table, &sql);
  469. if (in_driver != driver)
  470. db_close_database_shutdown_driver(in_driver);
  471. }
  472. }
  473. if (driver) {
  474. sprintf(buf, "create table %s (cat integer ", Fi->table);
  475. db_set_string(&stmt, buf);
  476. if (attr[0].columns)
  477. db_append_string(&stmt, attr[0].columns);
  478. else {
  479. sprintf(buf, ", a_cat integer");
  480. db_append_string(&stmt, buf);
  481. }
  482. if (attr[1].columns)
  483. db_append_string(&stmt, attr[1].columns);
  484. else {
  485. sprintf(buf, ", b_cat integer");
  486. db_append_string(&stmt, buf);
  487. }
  488. db_append_string(&stmt, " )");
  489. G_debug(3, "%s", db_get_string(&stmt));
  490. if (db_execute_immediate(driver, &stmt) != DB_OK) {
  491. Vect_close(&Out);
  492. db_close_database_shutdown_driver(driver);
  493. G_fatal_error(_("Unable to create table: '%s'"),
  494. db_get_string(&stmt));
  495. }
  496. if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
  497. G_warning(_("Unable to create index"));
  498. if (db_grant_on_table
  499. (driver, Fi->table, DB_PRIV_SELECT,
  500. DB_GROUP | DB_PUBLIC) != DB_OK)
  501. G_fatal_error(_("Unable to grant privileges on table <%s>"),
  502. Fi->table);
  503. /* Table created, now we can write dblink */
  504. Vect_map_add_dblink(&Out, ofield[0], NULL, Fi->table, GV_KEY_COLUMN,
  505. Fi->database, Fi->driver);
  506. db_begin_transaction(driver);
  507. }
  508. /* AREA x AREA */
  509. if (type[0] == GV_AREA) {
  510. area_area(In, field, &Tmp, &Out, Fi, driver, operator, ofield, attr, BList, snap_thresh);
  511. }
  512. else { /* LINE x AREA */
  513. line_area(In, field, &Tmp, &Out, Fi, driver, operator, ofield, attr, BList);
  514. }
  515. Vect_close(&Tmp);
  516. /* Build topology to show the final result and prepare for Vect_close() */
  517. Vect_build(&Out);
  518. if (driver) {
  519. /* Close table */
  520. db_commit_transaction(driver);
  521. db_close_database_shutdown_driver(driver);
  522. }
  523. if (ofield[0] < 1 && !table_flag->answer) {
  524. /* TODO: copy only valid attributes */
  525. /* copy attributes from ainput */
  526. if (ofield[1] > 0 && field[0] > 0) {
  527. copy_table(&In[0], &Out, field[0], ofield[1], table_type);
  528. }
  529. /* copy attributes from binput */
  530. if (ofield[2] > 0 && field[1] > 0 && ofield[1] != ofield[2]) {
  531. copy_table(&In[1], &Out, field[1], ofield[2], table_type);
  532. }
  533. }
  534. Vect_close(&(In[0]));
  535. Vect_close(&(In[1]));
  536. Vect_close(&Out);
  537. G_done_msg(" ");
  538. exit(EXIT_SUCCESS);
  539. }
  540. void copy_table(struct Map_info *In, struct Map_info *Out, int infield,
  541. int outfield, int table_type)
  542. {
  543. struct ilist *list;
  544. int findex;
  545. findex = Vect_cidx_get_field_index(Out, outfield);
  546. if (findex < 0)
  547. return;
  548. list = Vect_new_list();
  549. Vect_cidx_get_unique_cats_by_index(Out, findex, list);
  550. Vect_copy_table_by_cats(In, Out, infield, outfield, NULL,
  551. table_type, list->value, list->n_values);
  552. Vect_destroy_list(list);
  553. }