ascii.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. /*!
  2. \file lib/vector/Vlib/ascii.c
  3. \brief Vector library - GRASS ASCII vector format
  4. Higher level functions for reading/writing/manipulating vectors.
  5. (C) 2001-2015 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
  9. \author Updated for GRASS 7 (SF support) by Martin Landa <landa.martin gmail.com>
  10. */
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <grass/vector.h>
  15. #include <grass/dbmi.h>
  16. #include <grass/glocale.h>
  17. #define BUFFSIZE 128
  18. static int srch(const void *, const void *);
  19. static int get_cat(const struct line_cats *, const struct cat_list *,
  20. const int *, int, int, int *);
  21. static void free_col_arrays(int *, char *, char **);
  22. /*!
  23. \brief Read data in GRASS ASCII vector format
  24. \param ascii pointer to the input ASCII file
  25. \param[out] Map pointer to the output Map_info structure
  26. \return number of read features
  27. \return -1 on error
  28. */
  29. int Vect_read_ascii(FILE *ascii, struct Map_info *Map)
  30. {
  31. char ctype;
  32. char buff[BUFFSIZE];
  33. char east_str[256], north_str[256];
  34. double *xarray;
  35. double *yarray;
  36. double *zarray;
  37. double *x, *y, *z;
  38. int i, n_points, n_coors, n_cats, n_lines;
  39. int type, with_z, skip_feat, nskipped_3d;
  40. int alloc_points;
  41. struct line_pnts *Points;
  42. struct line_cats *Cats;
  43. int catn, cat;
  44. /* Must always use this to create an initialized line_pnts structure */
  45. Points = Vect_new_line_struct();
  46. Cats = Vect_new_cats_struct();
  47. /*alloc_points = 1000 ; */
  48. alloc_points = 1;
  49. xarray = (double *)G_calloc(alloc_points, sizeof(double));
  50. yarray = (double *)G_calloc(alloc_points, sizeof(double));
  51. zarray = (double *)G_calloc(alloc_points, sizeof(double));
  52. n_lines = nskipped_3d = 0;
  53. with_z = Vect_is_3d(Map);
  54. while (G_getl2(buff, BUFFSIZE - 1, ascii) != 0) {
  55. n_cats = 0;
  56. skip_feat = FALSE;
  57. if (buff[0] == '\0') {
  58. G_debug(3, "a2b: skipping blank line");
  59. continue;
  60. }
  61. if (sscanf(buff, "%1c%d%d", &ctype, &n_coors, &n_cats) < 2 ||
  62. n_coors < 0 || n_cats < 0) {
  63. if (ctype == '#') {
  64. G_debug(2, "a2b: skipping commented line");
  65. continue;
  66. }
  67. G_warning(_("Error reading ASCII file: (bad type) [%s]"),
  68. buff);
  69. return -1;
  70. }
  71. if (ctype == '#') {
  72. G_debug(2, "a2b: Skipping commented line");
  73. continue;
  74. }
  75. switch (ctype) {
  76. case 'A':
  77. type = GV_BOUNDARY;
  78. break;
  79. case 'B':
  80. type = GV_BOUNDARY;
  81. break;
  82. case 'C':
  83. type = GV_CENTROID;
  84. break;
  85. case 'L':
  86. type = GV_LINE;
  87. break;
  88. case 'P':
  89. type = GV_POINT;
  90. break;
  91. case 'F':
  92. type = GV_FACE;
  93. break;
  94. case 'K':
  95. type = GV_KERNEL;
  96. break;
  97. case 'a':
  98. case 'b':
  99. case 'c':
  100. case 'l':
  101. case 'p':
  102. type = 0; /* dead -> ignore */
  103. break;
  104. default: {
  105. G_warning(_("Error reading ASCII file: (unknown type) [%s]"),
  106. buff);
  107. return -1;
  108. }
  109. }
  110. G_debug(5, "feature type = %d", type);
  111. if ((type & (GV_FACE | GV_KERNEL)) && !with_z) {
  112. skip_feat = TRUE;
  113. nskipped_3d++;
  114. }
  115. n_points = 0;
  116. x = xarray;
  117. y = yarray;
  118. z = zarray;
  119. /* Collect the points */
  120. for (i = 0; i < n_coors; i++) {
  121. if (G_getl2(buff, BUFFSIZE - 1, ascii) == 0) {
  122. G_warning(_("End of ASCII file reached before end of coordinates"));
  123. return -1;
  124. }
  125. if (buff[0] == '\0') {
  126. G_debug(3, "a2b: skipping blank line while reading vertices");
  127. i--;
  128. continue;
  129. }
  130. *z = 0;
  131. if (sscanf(buff, "%lf%lf%lf", x, y, z) < 2) {
  132. if (sscanf(buff, " %s %s %lf", east_str, north_str, z) < 2) {
  133. G_warning(_("Error reading ASCII file: (bad point) [%s]"),
  134. buff);
  135. return -1;
  136. } else {
  137. if (!G_scan_easting(east_str, x, G_projection())) {
  138. G_warning(_("Unparsable longitude value: [%s]"),
  139. east_str);
  140. return -1;
  141. }
  142. if (!G_scan_northing(north_str, y, G_projection())) {
  143. G_warning(_("Unparsable latitude value: [%s]"),
  144. north_str);
  145. return -1;
  146. }
  147. }
  148. }
  149. G_debug(5, "coor in: %s -> x = %f y = %f z = %f", G_chop(buff),
  150. *x, *y, *z);
  151. n_points++;
  152. x++;
  153. y++;
  154. z++;
  155. if (n_points >= alloc_points) {
  156. alloc_points = n_points + 1000;
  157. xarray =
  158. (double *)G_realloc((void *)xarray,
  159. alloc_points * sizeof(double));
  160. yarray =
  161. (double *)G_realloc((void *)yarray,
  162. alloc_points * sizeof(double));
  163. zarray =
  164. (double *)G_realloc((void *)zarray,
  165. alloc_points * sizeof(double));
  166. x = xarray + n_points;
  167. y = yarray + n_points;
  168. z = zarray + n_points;
  169. }
  170. }
  171. /* Collect the cats */
  172. Vect_reset_cats(Cats);
  173. for (i = 0; i < n_cats; i++) {
  174. if (G_getl2(buff, BUFFSIZE - 1, ascii) == 0) {
  175. G_warning(_("End of ASCII file reached before end of categories"));
  176. return -1;
  177. }
  178. if (buff[0] == '\0') {
  179. G_debug(3,
  180. "a2b: skipping blank line while reading category info");
  181. i--;
  182. continue;
  183. }
  184. if (sscanf(buff, "%u%u", &catn, &cat) != 2) {
  185. G_warning(_("Error reading categories: [%s]"), buff);
  186. return -1;
  187. }
  188. Vect_cat_set(Cats, catn, cat);
  189. }
  190. if (skip_feat)
  191. continue;
  192. /* Allocation is handled for line_pnts */
  193. if (0 >
  194. Vect_copy_xyz_to_pnts(Points, xarray, yarray, zarray, n_points)) {
  195. G_warning(_("Unable to copy points"));
  196. return -1;
  197. }
  198. if (type > 0) {
  199. if (-1 == Vect_write_line(Map, type, Points, Cats)) {
  200. return -1;
  201. }
  202. n_lines++;
  203. }
  204. }
  205. if (nskipped_3d > 0)
  206. G_warning(_("Vector map <%s> is 2D. %d 3D features (faces or kernels) skipped."),
  207. Vect_get_name(Map), nskipped_3d);
  208. Vect_destroy_line_struct(Points);
  209. Vect_destroy_cats_struct(Cats);
  210. return n_lines;
  211. }
  212. /*!
  213. \brief Read header of GRASS ASCII vector format
  214. \param dascii pointer to the ASCII file
  215. \param Map pointer to Map_info structure
  216. \return 0 on success
  217. \return -1 on error
  218. */
  219. int Vect_read_ascii_head(FILE *dascii, struct Map_info *Map)
  220. {
  221. char buff[1024];
  222. char *ptr;
  223. for (;;) {
  224. if (0 == G_getl2(buff, sizeof(buff) - 1, dascii))
  225. return (0);
  226. /* Last line of header */
  227. if (strncmp(buff, "VERTI:", 6) == 0)
  228. return (0);
  229. if (!(ptr = strchr(buff, ':'))) {
  230. G_warning(_("Unexpected data in vector header:\n[%s]"), buff);
  231. return -1;
  232. }
  233. ptr++; /* Search for the start of text */
  234. while (*ptr == ' ')
  235. ptr++;
  236. if (strncmp(buff, "ORGANIZATION:", 13) == 0)
  237. Vect_set_organization(Map, ptr);
  238. else if (strncmp(buff, "DIGIT DATE:", 11) == 0)
  239. Vect_set_date(Map, ptr);
  240. else if (strncmp(buff, "DIGIT NAME:", 11) == 0)
  241. Vect_set_person(Map, ptr);
  242. else if (strncmp(buff, "MAP NAME:", 9) == 0)
  243. Vect_set_map_name(Map, ptr);
  244. else if (strncmp(buff, "MAP DATE:", 9) == 0)
  245. Vect_set_map_date(Map, ptr);
  246. else if (strncmp(buff, "MAP SCALE:", 10) == 0)
  247. Vect_set_scale(Map, atoi(ptr));
  248. else if (strncmp(buff, "OTHER INFO:", 11) == 0)
  249. Vect_set_comment(Map, ptr);
  250. else if (strncmp(buff, "ZONE:", 5) == 0 ||
  251. strncmp(buff, "UTM ZONE:", 9) == 0)
  252. Vect_set_zone(Map, atoi(ptr));
  253. else if (strncmp(buff, "WEST EDGE:", 10) == 0) {
  254. }
  255. else if (strncmp(buff, "EAST EDGE:", 10) == 0) {
  256. }
  257. else if (strncmp(buff, "SOUTH EDGE:", 11) == 0) {
  258. }
  259. else if (strncmp(buff, "NORTH EDGE:", 11) == 0) {
  260. }
  261. else if (strncmp(buff, "MAP THRESH:", 11) == 0)
  262. Vect_set_thresh(Map, atof(ptr));
  263. else {
  264. G_warning(_("Unknown keyword <%s> in vector head"), buff);
  265. }
  266. }
  267. /* NOTREACHED */
  268. }
  269. /*!
  270. \brief Write data to GRASS ASCII vector format
  271. Prints message if some features without category are skipped.
  272. \param[out] ascii pointer to the output ASCII file
  273. \param[out] att att file (< version 5 only)
  274. \param Map pointer to Map_info structure
  275. \param ver version number 4 or 5
  276. \param format format GV_ASCII_FORMAT_POINT or GV_ASCII_FORMAT_STD
  277. \param dp number of significant digits
  278. \param fs field separator
  279. \param region_flag check region
  280. \param type feature type filter
  281. \param field field number
  282. \param Clist list of categories to filter features or NULL
  283. \param where SQL select where statement to filter features or NULL
  284. \param column_names array of columns to be included to the output or NULL
  285. "*" as the first item in the array indicates all columns
  286. \param header TRUE to print also header
  287. \return number of written features
  288. \return -1 on error
  289. */
  290. int Vect_write_ascii(FILE *ascii,
  291. FILE *att, struct Map_info *Map, int ver,
  292. int format, int dp, char *fs, int region_flag, int type,
  293. int field, const struct cat_list *Clist, const char* where,
  294. const char **column_names, int header)
  295. {
  296. int ltype, ctype, i, cat, line, left, right, found;
  297. double *xptr, *yptr, *zptr, x, y;
  298. static struct line_pnts *Points;
  299. struct line_cats *Cats, *ACats;
  300. char *xstring, *ystring, *zstring;
  301. size_t xsize, ysize, zsize;
  302. struct Cell_head window;
  303. struct ilist *fcats;
  304. int count, n_skipped;
  305. /* where || columns */
  306. struct field_info *Fi;
  307. dbDriver *driver;
  308. dbValue value;
  309. dbHandle handle;
  310. int *cats, ncats, more;
  311. dbTable *Table;
  312. dbString dbstring;
  313. dbColumn *Column;
  314. dbValue *Value;
  315. char *buf;
  316. size_t bufsize;
  317. dbCursor cursor;
  318. /* columns */
  319. char **columns;
  320. int *coltypes;
  321. char *all_columns;
  322. Fi = NULL;
  323. driver = NULL;
  324. columns = NULL;
  325. coltypes = NULL;
  326. all_columns = NULL;
  327. G_zero(&value, sizeof(dbValue));
  328. db_init_string(&dbstring);
  329. xstring = NULL;
  330. ystring = NULL;
  331. zstring = NULL;
  332. xsize = 0;
  333. ysize = 0;
  334. zsize = 0;
  335. buf = NULL;
  336. bufsize = 0;
  337. /* get the region */
  338. G_get_window(&window);
  339. count = ncats = 0;
  340. xstring = ystring = zstring = NULL;
  341. cats = NULL;
  342. if (field > 0 && (where || column_names)) {
  343. Fi = Vect_get_field(Map, field);
  344. if (!Fi) {
  345. G_fatal_error(_("Database connection not defined for layer %d"),
  346. field);
  347. }
  348. driver = db_start_driver(Fi->driver);
  349. if (!driver)
  350. G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);
  351. db_init_handle(&handle);
  352. db_set_handle(&handle, Fi->database, NULL);
  353. if (db_open_database(driver, &handle) != DB_OK)
  354. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  355. Fi->database, Fi->driver);
  356. /* select cats (sorted array) */
  357. ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats);
  358. G_debug(3, "%d categories selected from table <%s>", ncats, Fi->table);
  359. if (!column_names) {
  360. db_close_database(driver);
  361. db_shutdown_driver(driver);
  362. }
  363. else {
  364. int icol, ncols;
  365. const char *col_name;
  366. int len_all = 0;
  367. db_set_string(&dbstring, Fi->table);
  368. if (db_describe_table(driver, &dbstring, &Table) != DB_OK) {
  369. G_warning(_("Unable to describe table <%s>"), Fi->table);
  370. return -1;
  371. }
  372. ncols = db_get_table_number_of_columns(Table);
  373. columns = (char **) G_malloc((ncols + 1) * sizeof(char *));
  374. if (column_names[0] && strcmp(column_names[0], "*") == 0) {
  375. /* all columns */
  376. icol = 0;
  377. for (i = 0; i < ncols; i++) {
  378. col_name = db_get_column_name(db_get_table_column(Table, i));
  379. /* key column skipped */
  380. if (strcmp(Fi->key, col_name) != 0)
  381. columns[icol++] = G_store(col_name);
  382. }
  383. columns[icol] = NULL;
  384. }
  385. else {
  386. int j;
  387. icol = 0;
  388. i = 0;
  389. while (column_names[i]) {
  390. /* key column skipped */
  391. if (strcmp(Fi->key, column_names[i]) != 0) {
  392. found = 0;
  393. for (j = 0; j < ncols; j++) {
  394. col_name = db_get_column_name(db_get_table_column(Table, j));
  395. if (strcmp(col_name, column_names[i]) == 0) {
  396. columns[icol++] = G_store(col_name);
  397. found = 1;
  398. break;
  399. }
  400. }
  401. if (!found) {
  402. G_warning(_("Column <%s> does not exist"),
  403. column_names[i]);
  404. G_important_message(_("Available columns:"));
  405. for (j = 0; j < ncols; j++) {
  406. col_name = db_get_column_name(db_get_table_column(Table, j));
  407. G_important_message("%s", col_name);
  408. }
  409. G_warning(_("Export cancelled"));
  410. db_close_database(driver);
  411. db_shutdown_driver(driver);
  412. return -1;
  413. }
  414. }
  415. i++;
  416. }
  417. columns[icol] = NULL;
  418. }
  419. db_zero_string(&dbstring);
  420. db_free_table(Table);
  421. Table = NULL;
  422. if (columns[0]) {
  423. /* selected columns only */
  424. i = 0;
  425. while (columns[i])
  426. len_all += strlen(columns[i++]);
  427. coltypes = G_malloc(i * sizeof(int));
  428. all_columns = G_malloc(len_all + i + 2);
  429. i = 0;
  430. strcpy(all_columns, columns[0]);
  431. while (columns[i]) {
  432. /* get column types */
  433. coltypes[i] = db_column_Ctype(driver, Fi->table, columns[i]);
  434. if (coltypes[i] < 0) {
  435. db_close_database(driver);
  436. db_shutdown_driver(driver);
  437. G_warning(_("Unknown type of column <%s>, export cancelled"),
  438. columns[i]);
  439. return -1;
  440. }
  441. if (i > 0) {
  442. strcat(all_columns, ",");
  443. strcat(all_columns, columns[i]);
  444. }
  445. i++;
  446. }
  447. }
  448. else {
  449. /* no column or only key column selected */
  450. G_free(columns);
  451. columns = NULL;
  452. db_close_database(driver);
  453. db_shutdown_driver(driver);
  454. }
  455. }
  456. }
  457. if (format == GV_ASCII_FORMAT_POINT && header) {
  458. /* print header */
  459. if (Map->head.with_z)
  460. fprintf(ascii, "east%snorth%sheight%scat", fs, fs, fs);
  461. else
  462. fprintf(ascii, "east%snorth%scat", fs, fs);
  463. if (columns) {
  464. for (i = 0; columns[i]; i++) {
  465. if (db_select_value
  466. (driver, Fi->table, Fi->key, cat,
  467. columns[i], &value) < 0)
  468. G_fatal_error(_("Unable to select record from table <%s> (key %s, column %s)"),
  469. Fi->table, Fi->key, columns[i]);
  470. if (columns[i])
  471. fprintf(ascii, "%s%s", fs, columns[i]);
  472. else
  473. fprintf(ascii, "%s", columns[i]); /* can not happen */
  474. }
  475. }
  476. fprintf(ascii, "%s", HOST_NEWLINE);
  477. }
  478. Points = Vect_new_line_struct();
  479. Cats = Vect_new_cats_struct();
  480. ACats = Vect_new_cats_struct();
  481. fcats = Vect_new_list();
  482. /* by default, read_next_line will NOT read Dead lines */
  483. /* but we can override that (in Level I only) by specifying */
  484. /* the type -1, which means match all line types */
  485. Vect_rewind(Map);
  486. count = n_skipped = line = 0;
  487. while (TRUE) {
  488. ltype = Vect_read_next_line(Map, Points, Cats);
  489. if (ltype == -1 ) { /* failure */
  490. if (columns) {
  491. db_close_database(driver);
  492. db_shutdown_driver(driver);
  493. free_col_arrays(coltypes, all_columns,
  494. column_names && strcmp(column_names[0], "*") == 0 ? columns : NULL);
  495. }
  496. return -1;
  497. }
  498. if (ltype == -2) { /* EOF */
  499. if (columns) {
  500. db_close_database(driver);
  501. db_shutdown_driver(driver);
  502. free_col_arrays(coltypes, all_columns,
  503. column_names && strcmp(column_names[0], "*") == 0 ? columns : NULL);
  504. }
  505. break;
  506. }
  507. line++;
  508. if (!(ltype & type))
  509. continue;
  510. if (format == GV_ASCII_FORMAT_POINT && !(ltype & GV_POINTS))
  511. continue;
  512. found = get_cat(Cats, Clist, cats, ncats, field, &cat);
  513. if (!found && field > 0 && ltype == GV_BOUNDARY &&
  514. type & GV_AREA && Vect_level(Map) > 1) {
  515. Vect_get_line_areas(Map, line, &left, &right);
  516. if (left < 0)
  517. left = Vect_get_isle_area(Map, abs(left));
  518. if (left > 0) {
  519. Vect_get_area_cats(Map, left, ACats);
  520. found = get_cat(ACats, Clist, cats, ncats, field, &cat);
  521. }
  522. if (right < 0)
  523. right = Vect_get_isle_area(Map, abs(right));
  524. if (!found && right > 0) {
  525. Vect_get_area_cats(Map, right, ACats);
  526. found = get_cat(ACats, Clist, cats, ncats, field, &cat);
  527. }
  528. }
  529. if (!found) {
  530. if (Cats->n_cats < 1)
  531. n_skipped++;
  532. continue;
  533. }
  534. if (ver < 5) {
  535. Vect_cat_get(Cats, 1, &cat);
  536. }
  537. switch (ltype) {
  538. case GV_BOUNDARY:
  539. if (ver == 5)
  540. ctype = 'B';
  541. else
  542. ctype = 'A';
  543. break;
  544. case GV_CENTROID:
  545. if (ver < 5) {
  546. if (att != NULL) {
  547. if (cat > 0) {
  548. G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]);
  549. G_trim_decimal(xstring);
  550. G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]);
  551. G_trim_decimal(ystring);
  552. fprintf(att, "A %s %s %d%s", xstring, ystring, cat, HOST_NEWLINE);
  553. }
  554. }
  555. continue;
  556. }
  557. ctype = 'C';
  558. break;
  559. case GV_LINE:
  560. ctype = 'L';
  561. break;
  562. case GV_POINT:
  563. ctype = 'P';
  564. break;
  565. case GV_FACE:
  566. ctype = 'F';
  567. break;
  568. case GV_KERNEL:
  569. ctype = 'K';
  570. break;
  571. default:
  572. ctype = 'X';
  573. G_warning(_("Unknown feature type %d"), (int)ltype);
  574. break;
  575. }
  576. if (format == GV_ASCII_FORMAT_POINT) {
  577. if (region_flag) {
  578. if ((window.east < Points->x[0]) ||
  579. (window.west > Points->x[0]))
  580. continue;
  581. }
  582. G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]);
  583. G_trim_decimal(xstring);
  584. if (region_flag) {
  585. if ((window.north < Points->y[0]) ||
  586. (window.south > Points->y[0]))
  587. continue;
  588. }
  589. G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]);
  590. G_trim_decimal(ystring);
  591. Vect_field_cat_get(Cats, field, fcats);
  592. if (Map->head.with_z && ver == 5) {
  593. if (region_flag) {
  594. if ((window.top < Points->z[0]) ||
  595. (window.bottom > Points->z[0]))
  596. continue;
  597. }
  598. G_rasprintf(&zstring, &zsize, "%.*f", dp, Points->z[0]);
  599. G_trim_decimal(zstring);
  600. fprintf(ascii, "%s%s%s%s%s", xstring, fs, ystring, fs,
  601. zstring);
  602. }
  603. else {
  604. fprintf(ascii, "%s%s%s", xstring, fs, ystring);
  605. }
  606. if (fcats->n_values > 0 && cat > -1) {
  607. if (fcats->n_values > 1) {
  608. G_warning(_("Feature has more categories. Only one category (%d) "
  609. "is exported."), cat);
  610. }
  611. fprintf(ascii, "%s%d", fs, cat);
  612. /* print attributes */
  613. if (columns) {
  614. G_rasprintf(&buf, &bufsize, "SELECT %s FROM %s WHERE %s = %d",
  615. all_columns, Fi->table, Fi->key, cat);
  616. G_debug(2, "SQL: %s", buf);
  617. db_set_string(&dbstring, buf);
  618. if (db_open_select_cursor
  619. (driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
  620. db_close_database(driver);
  621. db_shutdown_driver(driver);
  622. G_fatal_error(_("Cannot select attributes for cat = %d"),
  623. cat);
  624. }
  625. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
  626. db_close_database(driver);
  627. db_shutdown_driver(driver);
  628. G_fatal_error(_("Unable to fetch data from table"));
  629. }
  630. Table = db_get_cursor_table(&cursor);
  631. for (i = 0; columns[i]; i++) {
  632. Column = db_get_table_column(Table, i);
  633. Value = db_get_column_value(Column);
  634. if (db_test_value_isnull(Value)) {
  635. fprintf(ascii, "%s", fs);
  636. }
  637. else {
  638. switch(coltypes[i])
  639. {
  640. case DB_C_TYPE_INT: {
  641. fprintf(ascii, "%s%d", fs, db_get_value_int(Value));
  642. break;
  643. }
  644. case DB_C_TYPE_DOUBLE: {
  645. fprintf(ascii, "%s%.*f", fs, dp, db_get_value_double(Value));
  646. break;
  647. }
  648. case DB_C_TYPE_STRING: {
  649. fprintf(ascii, "%s%s", fs, db_get_value_string(Value));
  650. break;
  651. }
  652. case DB_C_TYPE_DATETIME: {
  653. break;
  654. }
  655. case -1:
  656. G_fatal_error(_("Column <%s> not found in table <%s>"),
  657. columns[i], Fi->table);
  658. default: G_fatal_error(_("Column <%s>: unsupported data type"),
  659. columns[i]);
  660. }
  661. }
  662. }
  663. db_close_cursor(&cursor);
  664. }
  665. }
  666. fprintf(ascii, "%s", HOST_NEWLINE);
  667. }
  668. else if (format == GV_ASCII_FORMAT_STD) {
  669. /* FORMAT_STANDARD */
  670. if (ver == 5 && Cats->n_cats > 0)
  671. fprintf(ascii, "%c %d %d%s", ctype, Points->n_points,
  672. Cats->n_cats, HOST_NEWLINE);
  673. else
  674. fprintf(ascii, "%c %d%s", ctype, Points->n_points, HOST_NEWLINE);
  675. xptr = Points->x;
  676. yptr = Points->y;
  677. zptr = Points->z;
  678. while (Points->n_points--) {
  679. G_rasprintf(&xstring, &xsize, "%.*f", dp, *xptr++);
  680. G_trim_decimal(xstring);
  681. G_rasprintf(&ystring, &ysize, "%.*f", dp, *yptr++);
  682. G_trim_decimal(ystring);
  683. if (ver == 5) {
  684. if (Map->head.with_z) {
  685. G_rasprintf(&zstring, &zsize, "%.*f", dp, *zptr++);
  686. G_trim_decimal(zstring);
  687. fprintf(ascii, " %-12s %-12s %-12s%s", xstring,
  688. ystring, zstring, HOST_NEWLINE);
  689. }
  690. else {
  691. fprintf(ascii, " %-12s %-12s%s", xstring, ystring, HOST_NEWLINE);
  692. }
  693. } /*Version 4 */
  694. else {
  695. fprintf(ascii, " %-12s %-12s%s", ystring, xstring, HOST_NEWLINE);
  696. }
  697. }
  698. if (ver == 5) {
  699. for (i = 0; i < Cats->n_cats; i++) {
  700. fprintf(ascii, " %-5d %-10d%s", Cats->field[i],
  701. Cats->cat[i], HOST_NEWLINE);
  702. }
  703. }
  704. else {
  705. if (cat > -1) {
  706. if (ltype == GV_POINT) {
  707. G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]);
  708. G_trim_decimal(xstring);
  709. G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]);
  710. G_trim_decimal(ystring);
  711. fprintf(att, "P %s %s %d%s", xstring, ystring, cat, HOST_NEWLINE);
  712. }
  713. else {
  714. x = (Points->x[1] + Points->x[0]) / 2;
  715. y = (Points->y[1] + Points->y[0]) / 2;
  716. G_rasprintf(&xstring, &xsize, "%.*f", dp, x);
  717. G_trim_decimal(xstring);
  718. G_rasprintf(&ystring, &ysize, "%.*f", dp, y);
  719. G_trim_decimal(ystring);
  720. fprintf(att, "L %s %s %d%s", xstring, ystring, cat, HOST_NEWLINE);
  721. }
  722. }
  723. }
  724. }
  725. else if (format == GV_ASCII_FORMAT_WKT) {
  726. if (ltype & (GV_BOUNDARY | GV_CENTROID | GV_FACE | GV_KERNEL))
  727. continue;
  728. /* Well-Known Text */
  729. Vect_sfa_line_astext(Points, ltype, Vect_is_3d(Map), dp, ascii);
  730. count++;
  731. }
  732. else {
  733. G_fatal_error(_("Unknown format"));
  734. }
  735. count++;
  736. }
  737. if (format == GV_ASCII_FORMAT_WKT) {
  738. /* process areas - topology required */
  739. int i, area, nareas, isle, nisles;
  740. if (Vect_level(Map) < 2) {
  741. G_warning(_("Topology not available, unable to process areas"));
  742. nareas = 0;
  743. }
  744. else {
  745. nareas = Vect_get_num_areas(Map);
  746. }
  747. for (area = 1; area <= nareas; area++) {
  748. if (!Vect_area_alive(Map, area)) /* skip dead areas */
  749. continue;
  750. if (Vect_get_area_cat(Map, area, field) < 0)
  751. continue;
  752. /* get boundary -> linearring */
  753. if (Vect_get_area_points(Map, area, Points) < 0) {
  754. G_warning(_("Unable to get boundary of area id %d"), area);
  755. continue;
  756. }
  757. fprintf(ascii, "POLYGON(");
  758. /* write outter ring */
  759. Vect_sfa_line_astext(Points, GV_BOUNDARY, 0, dp, ascii); /* boundary is always 2D */
  760. /* get isles (holes) -> inner rings */
  761. nisles = Vect_get_area_num_isles(Map, area);
  762. for (i = 0; i < nisles; i++) {
  763. /* get isle boundary -> linearring */
  764. isle = Vect_get_area_isle(Map, area, i);
  765. if (Vect_get_isle_points(Map, isle, Points) < 0) {
  766. G_warning(_("Unable to get boundary of isle id %d (area id %d)"), isle, area);
  767. continue;
  768. }
  769. fprintf(ascii, ", ");
  770. /* write inner ring */
  771. Vect_sfa_line_astext(Points, GV_BOUNDARY, 0, dp, ascii); /* boundary is always 2D */
  772. }
  773. fprintf(ascii, ")%s", HOST_NEWLINE);
  774. count++;
  775. }
  776. }
  777. if (n_skipped > 0)
  778. G_important_message(_("%d features without category skipped. To export also "
  779. "features without category use '%s=-1'."), n_skipped, "layer");
  780. Vect_destroy_line_struct(Points);
  781. Vect_destroy_cats_struct(Cats);
  782. Vect_destroy_cats_struct(ACats);
  783. return count;
  784. }
  785. int srch(const void *pa, const void *pb)
  786. {
  787. int *p1 = (int *)pa;
  788. int *p2 = (int *)pb;
  789. if (*p1 < *p2)
  790. return -1;
  791. if (*p1 > *p2)
  792. return 1;
  793. return 0;
  794. }
  795. /*!
  796. \brief Write data to GRASS ASCII vector format
  797. \param[out] dascii pointer to the output ASCII file
  798. \param Map pointer to Map_info structure
  799. */
  800. void Vect_write_ascii_head(FILE *dascii, struct Map_info *Map)
  801. {
  802. fprintf(dascii, "ORGANIZATION: %s%s",
  803. Vect_get_organization(Map), HOST_NEWLINE);
  804. fprintf(dascii, "DIGIT DATE: %s%s",
  805. Vect_get_date(Map), HOST_NEWLINE);
  806. fprintf(dascii, "DIGIT NAME: %s%s",
  807. Vect_get_person(Map), HOST_NEWLINE);
  808. fprintf(dascii, "MAP NAME: %s%s",
  809. Vect_get_map_name(Map), HOST_NEWLINE);
  810. fprintf(dascii, "MAP DATE: %s%s",
  811. Vect_get_map_date(Map), HOST_NEWLINE);
  812. fprintf(dascii, "MAP SCALE: %d%s",
  813. Vect_get_scale(Map), HOST_NEWLINE);
  814. fprintf(dascii, "OTHER INFO: %s%s",
  815. Vect_get_comment(Map), HOST_NEWLINE);
  816. fprintf(dascii, "ZONE: %d%s",
  817. Vect_get_zone(Map), HOST_NEWLINE);
  818. fprintf(dascii, "MAP THRESH: %f%s",
  819. Vect_get_thresh(Map), HOST_NEWLINE);
  820. }
  821. /* check category */
  822. int get_cat(const struct line_cats *Cats, const struct cat_list *Clist,
  823. const int *cats, int ncats, int field, int *cat)
  824. {
  825. int i;
  826. *cat = -1;
  827. if (field < 1)
  828. return TRUE;
  829. if (Clist && Clist->field == field) {
  830. for (i = 0; i < Cats->n_cats; i++) {
  831. if (Cats->field[i] == field &&
  832. Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
  833. *cat = Cats->cat[i];
  834. return TRUE;
  835. }
  836. }
  837. return FALSE;
  838. }
  839. if (cats) {
  840. int *found;
  841. for (i = 0; i < Cats->n_cats; i++) {
  842. if (Cats->field[i] == field) {
  843. found = (int *)bsearch((void *) &(Cats->cat[i]), cats,
  844. ncats, sizeof(int), srch);
  845. if (found) {
  846. /* found */
  847. *cat = *found;
  848. return TRUE;
  849. }
  850. }
  851. }
  852. return FALSE;
  853. }
  854. if (!Clist && !cats && field > 0) {
  855. Vect_cat_get(Cats, field, cat);
  856. if (*cat > -1)
  857. return TRUE;
  858. }
  859. return FALSE;
  860. }
  861. /* free column arrays, see Vect_write_ascii() */
  862. void free_col_arrays(int *coltypes, char *all_columns, char **columns)
  863. {
  864. G_free(coltypes);
  865. G_free(all_columns);
  866. if (columns) {
  867. int i = 0;
  868. while (columns[i])
  869. G_free(columns[i++]);
  870. G_free(columns);
  871. }
  872. }