GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-d3092090e5
ascii.c
Go to the documentation of this file.
1 /*!
2  \file lib/vector/Vlib/ascii.c
3 
4  \brief Vector library - GRASS ASCII vector format
5 
6  Higher level functions for reading/writing/manipulating vectors.
7 
8  (C) 2001-2015 by the GRASS Development Team
9 
10  This program is free software under the GNU General Public License
11  (>=v2). Read the file COPYING that comes with GRASS for details.
12 
13  \author Original author CERL
14  \author Updated for GRASS 7 (SF support) by Martin Landa <landa.martin
15  gmail.com>
16  */
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include <grass/vector.h>
23 #include <grass/dbmi.h>
24 #include <grass/glocale.h>
25 
26 #define BUFFSIZE 128
27 
28 static int srch(const void *, const void *);
29 static int get_cat(const struct line_cats *, const struct cat_list *,
30  const int *, int, int, int *);
31 static void free_col_arrays(int *, char *, char **);
32 
33 /*!
34  \brief Read data in GRASS ASCII vector format
35 
36  \param ascii pointer to the input ASCII file
37  \param[out] Map pointer to the output Map_info structure
38 
39  \return number of read features
40  \return -1 on error
41  */
42 int Vect_read_ascii(FILE *ascii, struct Map_info *Map)
43 {
44  char ctype;
45  char buff[BUFFSIZE];
46  char east_str[256], north_str[256];
47  double *xarray;
48  double *yarray;
49  double *zarray;
50  double *x, *y, *z;
51  int i, n_points, n_coors, n_cats, n_lines;
52  int type, with_z, skip_feat, nskipped_3d;
53  int alloc_points;
54  struct line_pnts *Points;
55  struct line_cats *Cats;
56  int catn, cat;
57 
58  /* Must always use this to create an initialized line_pnts structure */
59  Points = Vect_new_line_struct();
60  Cats = Vect_new_cats_struct();
61 
62  /*alloc_points = 1000 ; */
63  alloc_points = 1;
64  xarray = (double *)G_calloc(alloc_points, sizeof(double));
65  yarray = (double *)G_calloc(alloc_points, sizeof(double));
66  zarray = (double *)G_calloc(alloc_points, sizeof(double));
67 
68  n_lines = nskipped_3d = 0;
69 
70  with_z = Vect_is_3d(Map);
71 
72  while (G_getl2(buff, BUFFSIZE - 1, ascii) != 0) {
73  n_cats = 0;
74  skip_feat = FALSE;
75  if (buff[0] == '\0') {
76  G_debug(3, "a2b: skipping blank line");
77  continue;
78  }
79 
80  if (sscanf(buff, "%1c%d%d", &ctype, &n_coors, &n_cats) < 2 ||
81  n_coors < 0 || n_cats < 0) {
82  if (ctype == '#') {
83  G_debug(2, "a2b: skipping commented line");
84  continue;
85  }
86  G_warning(_("Error reading ASCII file: (bad type) [%s]"), buff);
87  n_lines = -1;
88  goto cleanup_exit;
89  }
90  if (ctype == '#') {
91  G_debug(2, "a2b: Skipping commented line");
92  continue;
93  }
94 
95  switch (ctype) {
96  case 'A':
97  type = GV_BOUNDARY;
98  break;
99  case 'B':
100  type = GV_BOUNDARY;
101  break;
102  case 'C':
103  type = GV_CENTROID;
104  break;
105  case 'L':
106  type = GV_LINE;
107  break;
108  case 'P':
109  type = GV_POINT;
110  break;
111  case 'F':
112  type = GV_FACE;
113  break;
114  case 'K':
115  type = GV_KERNEL;
116  break;
117  case 'a':
118  case 'b':
119  case 'c':
120  case 'l':
121  case 'p':
122  type = 0; /* dead -> ignore */
123  break;
124  default: {
125  G_warning(_("Error reading ASCII file: (unknown type) [%s]"), buff);
126  n_lines = -1;
127  goto cleanup_exit;
128  }
129  }
130  G_debug(5, "feature type = %d", type);
131 
132  if ((type & (GV_FACE | GV_KERNEL)) && !with_z) {
133  skip_feat = TRUE;
134  nskipped_3d++;
135  }
136 
137  n_points = 0;
138  x = xarray;
139  y = yarray;
140  z = zarray;
141 
142  /* Collect the points */
143  for (i = 0; i < n_coors; i++) {
144  if (G_getl2(buff, BUFFSIZE - 1, ascii) == 0) {
145  G_warning(
146  _("End of ASCII file reached before end of coordinates"));
147  return -1;
148  }
149  if (buff[0] == '\0') {
150  G_debug(3, "a2b: skipping blank line while reading vertices");
151  i--;
152  continue;
153  }
154 
155  *z = 0;
156  if (sscanf(buff, "%lf%lf%lf", x, y, z) < 2) {
157  if (sscanf(buff, " %s %s %lf", east_str, north_str, z) < 2) {
158  G_warning(_("Error reading ASCII file: (bad point) [%s]"),
159  buff);
160  n_lines = -1;
161  goto cleanup_exit;
162  }
163  else {
164  if (!G_scan_easting(east_str, x, G_projection())) {
165  G_warning(_("Unparsable longitude value: [%s]"),
166  east_str);
167  n_lines = -1;
168  goto cleanup_exit;
169  }
170  if (!G_scan_northing(north_str, y, G_projection())) {
171  G_warning(_("Unparsable latitude value: [%s]"),
172  north_str);
173  n_lines = -1;
174  goto cleanup_exit;
175  }
176  }
177  }
178 
179  G_debug(5, "coor in: %s -> x = %f y = %f z = %f", G_chop(buff), *x,
180  *y, *z);
181 
182  n_points++;
183  x++;
184  y++;
185  z++;
186 
187  if (n_points >= alloc_points) {
188  alloc_points = n_points + 1000;
189  xarray = (double *)G_realloc((void *)xarray,
190  alloc_points * sizeof(double));
191  yarray = (double *)G_realloc((void *)yarray,
192  alloc_points * sizeof(double));
193  zarray = (double *)G_realloc((void *)zarray,
194  alloc_points * sizeof(double));
195  x = xarray + n_points;
196  y = yarray + n_points;
197  z = zarray + n_points;
198  }
199  }
200 
201  /* Collect the cats */
202  Vect_reset_cats(Cats);
203  for (i = 0; i < n_cats; i++) {
204  if (G_getl2(buff, BUFFSIZE - 1, ascii) == 0) {
205  G_warning(
206  _("End of ASCII file reached before end of categories"));
207  return -1;
208  }
209  if (buff[0] == '\0') {
210  G_debug(3,
211  "a2b: skipping blank line while reading category info");
212  i--;
213  continue;
214  }
215 
216  if (sscanf(buff, "%d%d", &catn, &cat) != 2) {
217  G_warning(_("Error reading categories: [%s]"), buff);
218  n_lines = -1;
219  goto cleanup_exit;
220  }
221 
222  Vect_cat_set(Cats, catn, cat);
223  }
224 
225  if (skip_feat)
226  continue;
227 
228  /* Allocation is handled for line_pnts */
229  if (0 >
230  Vect_copy_xyz_to_pnts(Points, xarray, yarray, zarray, n_points)) {
231  G_warning(_("Unable to copy points"));
232  n_lines = -1;
233  goto cleanup_exit;
234  }
235 
236  if (type > 0) {
237  if (-1 == Vect_write_line(Map, type, Points, Cats)) {
238  n_lines = -1;
239  goto cleanup_exit;
240  }
241  n_lines++;
242  }
243  }
244 
245  if (nskipped_3d > 0)
246  G_warning(_("Vector map <%s> is 2D. %d 3D features (faces or kernels) "
247  "skipped."),
248  Vect_get_name(Map), nskipped_3d);
249 cleanup_exit:
250  Vect_destroy_line_struct(Points);
252  G_free(xarray);
253  G_free(yarray);
254  G_free(zarray);
255 
256  return n_lines;
257 }
258 
259 /*!
260  \brief Read header of GRASS ASCII vector format
261 
262  \param dascii pointer to the ASCII file
263  \param Map pointer to Map_info structure
264 
265  \return 0 on success
266  \return -1 on error
267  */
268 int Vect_read_ascii_head(FILE *dascii, struct Map_info *Map)
269 {
270  char buff[1024];
271  char *ptr;
272 
273  for (;;) {
274  if (0 == G_getl2(buff, sizeof(buff) - 1, dascii))
275  return (0);
276 
277  /* Last line of header */
278  if (strncmp(buff, "VERTI:", 6) == 0)
279  return (0);
280 
281  if (!(ptr = strchr(buff, ':'))) {
282  G_warning(_("Unexpected data in vector header:\n[%s]"), buff);
283  return -1;
284  }
285 
286  ptr++; /* Search for the start of text */
287  while (*ptr == ' ')
288  ptr++;
289 
290  if (strncmp(buff, "ORGANIZATION:", 13) == 0)
291  Vect_set_organization(Map, ptr);
292  else if (strncmp(buff, "DIGIT DATE:", 11) == 0)
293  Vect_set_date(Map, ptr);
294  else if (strncmp(buff, "DIGIT NAME:", 11) == 0)
295  Vect_set_person(Map, ptr);
296  else if (strncmp(buff, "MAP NAME:", 9) == 0)
297  Vect_set_map_name(Map, ptr);
298  else if (strncmp(buff, "MAP DATE:", 9) == 0)
299  Vect_set_map_date(Map, ptr);
300  else if (strncmp(buff, "MAP SCALE:", 10) == 0)
301  Vect_set_scale(Map, atoi(ptr));
302  else if (strncmp(buff, "OTHER INFO:", 11) == 0)
303  Vect_set_comment(Map, ptr);
304  else if (strncmp(buff, "ZONE:", 5) == 0 ||
305  strncmp(buff, "UTM ZONE:", 9) == 0)
306  Vect_set_zone(Map, atoi(ptr));
307  else if (strncmp(buff, "WEST EDGE:", 10) == 0) {
308  }
309  else if (strncmp(buff, "EAST EDGE:", 10) == 0) {
310  }
311  else if (strncmp(buff, "SOUTH EDGE:", 11) == 0) {
312  }
313  else if (strncmp(buff, "NORTH EDGE:", 11) == 0) {
314  }
315  else if (strncmp(buff, "MAP THRESH:", 11) == 0)
316  Vect_set_thresh(Map, atof(ptr));
317  else {
318  G_warning(_("Unknown keyword <%s> in vector head"), buff);
319  }
320  }
321  /* NOTREACHED */
322 }
323 
324 /*!
325  \brief Write data to GRASS ASCII vector format
326 
327  Prints message if some features without category are skipped.
328 
329  \param[out] ascii pointer to the output ASCII file
330  \param[out] att att file (< version 5 only)
331  \param Map pointer to Map_info structure
332  \param ver version number 4 or 5
333  \param format format GV_ASCII_FORMAT_POINT or GV_ASCII_FORMAT_STD
334  \param dp number of significant digits
335  \param fs field separator
336  \param region_flag check region
337  \param type feature type filter
338  \param field field number
339  \param Clist list of categories to filter features or NULL
340  \param where SQL select where statement to filter features or NULL
341  \param column_names array of columns to be included to the output or NULL
342  "*" as the first item in the array indicates all columns
343  \param header TRUE to print also header
344 
345  \return number of written features
346  \return -1 on error
347  */
348 int Vect_write_ascii(FILE *ascii, FILE *att, struct Map_info *Map, int ver,
349  int format, int dp, char *fs, int region_flag, int type,
350  int field, const struct cat_list *Clist, const char *where,
351  const char **column_names, int header)
352 {
353  int ltype, ctype, i, cat, line, left, right, found;
354  double *xptr, *yptr, *zptr, x, y;
355  static struct line_pnts *Points;
356  struct line_cats *Cats, *ACats;
357  char *xstring, *ystring, *zstring;
358  size_t xsize, ysize, zsize;
359  struct Cell_head window;
360  struct ilist *fcats;
361  int count, n_skipped;
362 
363  /* where || columns */
364  struct field_info *Fi;
365  dbDriver *driver;
366  dbValue value;
367  dbHandle handle;
368  int *cats, ncats, more;
369  dbTable *Table;
370  dbString dbstring;
371  dbColumn *Column;
372  dbValue *Value;
373  char *buf;
374  size_t bufsize;
375  dbCursor cursor;
376 
377  /* columns */
378  char **columns;
379  int *coltypes;
380  char *all_columns;
381 
382  Fi = NULL;
383  driver = NULL;
384  columns = NULL;
385  coltypes = NULL;
386  all_columns = NULL;
387 
388  G_zero(&value, sizeof(dbValue));
389  db_init_string(&dbstring);
390 
391  xstring = NULL;
392  ystring = NULL;
393  zstring = NULL;
394  xsize = 0;
395  ysize = 0;
396  zsize = 0;
397  buf = NULL;
398  bufsize = 0;
399 
400  /* get the region */
401  G_get_window(&window);
402 
403  count = ncats = 0;
404  xstring = ystring = zstring = NULL;
405  cats = NULL;
406 
407  if (field > 0 && (where || column_names)) {
408  Fi = Vect_get_field(Map, field);
409  if (!Fi) {
410  G_fatal_error(_("Database connection not defined for layer %d"),
411  field);
412  }
413 
415  if (!driver)
416  G_fatal_error(_("Unable to start driver <%s>"), Fi->driver);
417 
418  db_init_handle(&handle);
419  db_set_handle(&handle, Fi->database, NULL);
420 
421  if (db_open_database(driver, &handle) != DB_OK)
422  G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
423  Fi->database, Fi->driver);
424 
425  /* select cats (sorted array) */
426  ncats = db_select_int(driver, Fi->table, Fi->key, where, &cats);
427  G_debug(3, "%d categories selected from table <%s>", ncats, Fi->table);
428 
429  if (!column_names) {
432  }
433  else {
434  int icol, ncols;
435  const char *col_name;
436  int len_all = 0;
437 
438  db_set_string(&dbstring, Fi->table);
439  if (db_describe_table(driver, &dbstring, &Table) != DB_OK) {
440  G_warning(_("Unable to describe table <%s>"), Fi->table);
443  return -1;
444  }
445 
446  ncols = db_get_table_number_of_columns(Table);
447  columns = (char **)G_malloc((ncols + 1) * sizeof(char *));
448 
449  if (column_names[0] && strcmp(column_names[0], "*") == 0) {
450 
451  /* all columns */
452  icol = 0;
453  for (i = 0; i < ncols; i++) {
454  col_name =
456  /* key column skipped */
457  if (strcmp(Fi->key, col_name) != 0)
458  columns[icol++] = G_store(col_name);
459  }
460  columns[icol] = NULL;
461  }
462  else {
463  int j;
464 
465  icol = 0;
466  i = 0;
467  while (column_names[i]) {
468  /* key column skipped */
469  if (strcmp(Fi->key, column_names[i]) != 0) {
470  found = 0;
471  for (j = 0; j < ncols; j++) {
472  col_name = db_get_column_name(
473  db_get_table_column(Table, j));
474  if (strcmp(col_name, column_names[i]) == 0) {
475  columns[icol++] = G_store(col_name);
476  found = 1;
477  break;
478  }
479  }
480  if (!found) {
481  G_warning(_("Column <%s> does not exist"),
482  column_names[i]);
483  G_important_message(_("Available columns:"));
484  for (j = 0; j < ncols; j++) {
485  col_name = db_get_column_name(
486  db_get_table_column(Table, j));
487  G_important_message("%s", col_name);
488  }
489  G_warning(_("Export cancelled"));
493  free_col_arrays(NULL, NULL, columns);
494  return -1;
495  }
496  }
497  i++;
498  }
499  columns[icol] = NULL;
500  }
501 
502  db_zero_string(&dbstring);
503  db_free_table(Table);
504  Table = NULL;
505 
506  if (columns[0]) {
507  /* selected columns only */
508  i = 0;
509  while (columns[i])
510  len_all += strlen(columns[i++]);
511 
512  coltypes = G_malloc(i * sizeof(int));
513 
514  all_columns = G_malloc(len_all + i + 2);
515 
516  i = 0;
517  strcpy(all_columns, columns[0]);
518  while (columns[i]) {
519  /* get column types */
520  coltypes[i] =
522  if (coltypes[i] < 0) {
525  G_warning(
526  _("Unknown type of column <%s>, export cancelled"),
527  columns[i]);
529  G_free(cats);
530  free_col_arrays(coltypes, all_columns, columns);
531  return -1;
532  }
533  if (i > 0) {
534  strcat(all_columns, ",");
535  strcat(all_columns, columns[i]);
536  }
537  i++;
538  }
539  }
540  else {
541  /* no column or only key column selected */
542  free_col_arrays(NULL, NULL, columns);
543  columns = NULL;
544 
547  }
548  }
549  }
550 
551  if (format == GV_ASCII_FORMAT_POINT && header) {
552 
553  /* print header */
554  if (Map->head.with_z)
555  fprintf(ascii, "east%snorth%sheight%scat", fs, fs, fs);
556  else
557  fprintf(ascii, "east%snorth%scat", fs, fs);
558  if (columns) {
559  for (i = 0; columns[i]; i++) {
560  if (db_select_value(driver, Fi->table, Fi->key, 0, columns[i],
561  &value) < 0)
562  G_fatal_error(_("Unable to select record from table <%s> "
563  "(key %s, column %s)"),
564  Fi->table, Fi->key, columns[i]);
565  if (columns[i])
566  fprintf(ascii, "%s%s", fs, columns[i]);
567  else
568  fprintf(ascii, "%s", columns[i]); /* can not happen */
569  }
570  }
571  fprintf(ascii, "%s", HOST_NEWLINE);
572  }
573 
574  Points = Vect_new_line_struct();
575  Cats = Vect_new_cats_struct();
576  ACats = Vect_new_cats_struct();
577  fcats = Vect_new_list();
578 
579  /* by default, read_next_line will NOT read Dead lines */
580  /* but we can override that (in Level I only) by specifying */
581  /* the type -1, which means match all line types */
582 
583  Vect_rewind(Map);
584 
585  count = n_skipped = line = 0;
586  while (TRUE) {
587  ltype = Vect_read_next_line(Map, Points, Cats);
588  if (ltype == -1) { /* failure */
589  if (columns) {
592 
593  free_col_arrays(
594  coltypes, all_columns,
595  column_names && strcmp(column_names[0], "*") == 0 ? columns
596  : NULL);
597  }
599  Vect_destroy_list(fcats);
601  G_free(cats);
602 
603  return -1;
604  }
605 
606  if (ltype == -2) { /* EOF */
607  if (columns) {
610 
611  free_col_arrays(
612  coltypes, all_columns,
613  column_names && strcmp(column_names[0], "*") == 0 ? columns
614  : NULL);
615  }
616  break;
617  }
618 
619  line++;
620 
621  if (!(ltype & type))
622  continue;
623 
624  if (format == GV_ASCII_FORMAT_POINT && !(ltype & GV_POINTS))
625  continue;
626 
627  found = get_cat(Cats, Clist, cats, ncats, field, &cat);
628 
629  if (!found && field > 0 && ltype == GV_BOUNDARY && type & GV_AREA &&
630  Vect_level(Map) > 1) {
631  Vect_get_line_areas(Map, line, &left, &right);
632  if (left < 0)
633  left = Vect_get_isle_area(Map, abs(left));
634  if (left > 0) {
635  Vect_get_area_cats(Map, left, ACats);
636  found = get_cat(ACats, Clist, cats, ncats, field, &cat);
637  }
638  if (right < 0)
639  right = Vect_get_isle_area(Map, abs(right));
640  if (!found && right > 0) {
641  Vect_get_area_cats(Map, right, ACats);
642  found = get_cat(ACats, Clist, cats, ncats, field, &cat);
643  }
644  }
645 
646  if (!found) {
647  if (Cats->n_cats < 1)
648  n_skipped++;
649 
650  continue;
651  }
652 
653  if (ver < 5) {
654  Vect_cat_get(Cats, 1, &cat);
655  }
656 
657  switch (ltype) {
658  case GV_BOUNDARY:
659  if (ver == 5)
660  ctype = 'B';
661  else
662  ctype = 'A';
663  break;
664  case GV_CENTROID:
665  if (ver < 5) {
666  if (att != NULL) {
667  if (cat > 0) {
668  G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]);
669  G_trim_decimal(xstring);
670  G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]);
671  G_trim_decimal(ystring);
672  fprintf(att, "A %s %s %d%s", xstring, ystring, cat,
673  HOST_NEWLINE);
674  }
675  }
676  continue;
677  }
678  ctype = 'C';
679  break;
680  case GV_LINE:
681  ctype = 'L';
682  break;
683  case GV_POINT:
684  ctype = 'P';
685  break;
686  case GV_FACE:
687  ctype = 'F';
688  break;
689  case GV_KERNEL:
690  ctype = 'K';
691  break;
692  default:
693  ctype = 'X';
694  G_warning(_("Unknown feature type %d"), (int)ltype);
695  break;
696  }
697 
698  if (format == GV_ASCII_FORMAT_POINT) {
699  if (region_flag) {
700  if ((window.east < Points->x[0]) ||
701  (window.west > Points->x[0]))
702  continue;
703  }
704  G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]);
705  G_trim_decimal(xstring);
706 
707  if (region_flag) {
708  if ((window.north < Points->y[0]) ||
709  (window.south > Points->y[0]))
710  continue;
711  }
712  G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]);
713  G_trim_decimal(ystring);
714 
715  Vect_field_cat_get(Cats, field, fcats);
716 
717  if (Map->head.with_z && ver == 5) {
718  if (region_flag) {
719  if ((window.top < Points->z[0]) ||
720  (window.bottom > Points->z[0]))
721  continue;
722  }
723  G_rasprintf(&zstring, &zsize, "%.*f", dp, Points->z[0]);
724  G_trim_decimal(zstring);
725  fprintf(ascii, "%s%s%s%s%s", xstring, fs, ystring, fs, zstring);
726  }
727  else {
728  fprintf(ascii, "%s%s%s", xstring, fs, ystring);
729  }
730 
731  if (fcats->n_values > 0 && cat > -1) {
732  if (fcats->n_values > 1) {
733  G_warning(
734  _("Feature has more categories. Only one category (%d) "
735  "is exported."),
736  cat);
737  }
738  fprintf(ascii, "%s%d", fs, cat);
739 
740  /* print attributes */
741  if (columns) {
742 
743  G_rasprintf(&buf, &bufsize,
744  "SELECT %s FROM %s WHERE %s = %d", all_columns,
745  Fi->table, Fi->key, cat);
746  G_debug(2, "SQL: %s", buf);
747  db_set_string(&dbstring, buf);
748 
749  if (db_open_select_cursor(driver, &dbstring, &cursor,
750  DB_SEQUENTIAL) != DB_OK) {
754  _("Cannot select attributes for cat = %d"), cat);
755  }
756  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
759  G_fatal_error(_("Unable to fetch data from table"));
760  }
761 
762  Table = db_get_cursor_table(&cursor);
763 
764  for (i = 0; columns[i]; i++) {
765  Column = db_get_table_column(Table, i);
766  Value = db_get_column_value(Column);
767 
768  if (db_test_value_isnull(Value)) {
769  fprintf(ascii, "%s", fs);
770  }
771  else {
772  switch (coltypes[i]) {
773  case DB_C_TYPE_INT: {
774  fprintf(ascii, "%s%d", fs,
775  db_get_value_int(Value));
776  break;
777  }
778  case DB_C_TYPE_DOUBLE: {
779  fprintf(ascii, "%s%.*f", fs, dp,
780  db_get_value_double(Value));
781  break;
782  }
783  case DB_C_TYPE_STRING: {
784  fprintf(ascii, "%s%s", fs,
785  db_get_value_string(Value));
786  break;
787  }
788  case DB_C_TYPE_DATETIME: {
789  break;
790  }
791  case -1:
793  _("Column <%s> not found in table <%s>"),
794  columns[i], Fi->table);
795  default:
797  _("Column <%s>: unsupported data type"),
798  columns[i]);
799  }
800  }
801  }
802  db_close_cursor(&cursor);
803  }
804  }
805 
806  fprintf(ascii, "%s", HOST_NEWLINE);
807  }
808  else if (format == GV_ASCII_FORMAT_STD) {
809  /* FORMAT_STANDARD */
810  if (ver == 5 && Cats->n_cats > 0)
811  fprintf(ascii, "%c %d %d%s", ctype, Points->n_points,
812  Cats->n_cats, HOST_NEWLINE);
813  else
814  fprintf(ascii, "%c %d%s", ctype, Points->n_points,
815  HOST_NEWLINE);
816 
817  xptr = Points->x;
818  yptr = Points->y;
819  zptr = Points->z;
820 
821  while (Points->n_points--) {
822 
823  G_rasprintf(&xstring, &xsize, "%.*f", dp, *xptr++);
824  G_trim_decimal(xstring);
825  G_rasprintf(&ystring, &ysize, "%.*f", dp, *yptr++);
826  G_trim_decimal(ystring);
827 
828  if (ver == 5) {
829  if (Map->head.with_z) {
830  G_rasprintf(&zstring, &zsize, "%.*f", dp, *zptr++);
831  G_trim_decimal(zstring);
832  fprintf(ascii, " %-12s %-12s %-12s%s", xstring, ystring,
833  zstring, HOST_NEWLINE);
834  }
835  else {
836  fprintf(ascii, " %-12s %-12s%s", xstring, ystring,
837  HOST_NEWLINE);
838  }
839  } /*Version 4 */
840  else {
841  fprintf(ascii, " %-12s %-12s%s", ystring, xstring,
842  HOST_NEWLINE);
843  }
844  }
845 
846  if (ver == 5) {
847  for (i = 0; i < Cats->n_cats; i++) {
848  fprintf(ascii, " %-5d %-10d%s", Cats->field[i],
849  Cats->cat[i], HOST_NEWLINE);
850  }
851  }
852  else {
853  if (cat > -1) {
854  if (ltype == GV_POINT) {
855  G_rasprintf(&xstring, &xsize, "%.*f", dp, Points->x[0]);
856  G_trim_decimal(xstring);
857  G_rasprintf(&ystring, &ysize, "%.*f", dp, Points->y[0]);
858  G_trim_decimal(ystring);
859  fprintf(att, "P %s %s %d%s", xstring, ystring, cat,
860  HOST_NEWLINE);
861  }
862  else {
863  x = (Points->x[1] + Points->x[0]) / 2;
864  y = (Points->y[1] + Points->y[0]) / 2;
865 
866  G_rasprintf(&xstring, &xsize, "%.*f", dp, x);
867  G_trim_decimal(xstring);
868  G_rasprintf(&ystring, &ysize, "%.*f", dp, y);
869  G_trim_decimal(ystring);
870  fprintf(att, "L %s %s %d%s", xstring, ystring, cat,
871  HOST_NEWLINE);
872  }
873  }
874  }
875  }
876  else if (format == GV_ASCII_FORMAT_WKT) {
877  if (ltype & (GV_BOUNDARY | GV_CENTROID | GV_FACE | GV_KERNEL))
878  continue;
879  /* Well-Known Text */
880  Vect_sfa_line_astext(Points, ltype, Vect_is_3d(Map), dp, ascii);
881  count++;
882  }
883  else {
884  G_fatal_error(_("Unknown format"));
885  }
886  count++;
887  }
888 
889  if (format == GV_ASCII_FORMAT_WKT) {
890  /* process areas - topology required */
891  int i, area, nareas, isle, nisles;
892 
893  if (Vect_level(Map) < 2) {
894  G_warning(_("Topology not available, unable to process areas"));
895  nareas = 0;
896  }
897  else {
898  nareas = Vect_get_num_areas(Map);
899  }
900  for (area = 1; area <= nareas; area++) {
901  if (!Vect_area_alive(Map, area)) /* skip dead areas */
902  continue;
903  if (Vect_get_area_cat(Map, area, field) < 0)
904  continue;
905  /* get boundary -> linearring */
906  if (Vect_get_area_points(Map, area, Points) < 0) {
907  G_warning(_("Unable to get boundary of area id %d"), area);
908  continue;
909  }
910  fprintf(ascii, "POLYGON(");
911  /* write outer ring */
912  Vect_sfa_line_astext(Points, GV_BOUNDARY, 0, dp,
913  ascii); /* boundary is always 2D */
914  /* get isles (holes) -> inner rings */
915  nisles = Vect_get_area_num_isles(Map, area);
916  for (i = 0; i < nisles; i++) {
917  /* get isle boundary -> linearring */
918  isle = Vect_get_area_isle(Map, area, i);
919  if (Vect_get_isle_points(Map, isle, Points) < 0) {
920  G_warning(
921  _("Unable to get boundary of isle id %d (area id %d)"),
922  isle, area);
923  continue;
924  }
925  fprintf(ascii, ", ");
926  /* write inner ring */
927  Vect_sfa_line_astext(Points, GV_BOUNDARY, 0, dp,
928  ascii); /* boundary is always 2D */
929  }
930  fprintf(ascii, ")%s", HOST_NEWLINE);
931 
932  count++;
933  }
934  }
935 
936  if (n_skipped > 0)
938  _("%d features without category skipped. To export also "
939  "features without category use '%s=-1'."),
940  n_skipped, "layer");
941 
942  Vect_destroy_line_struct(Points);
945  Vect_destroy_list(fcats);
947  G_free(cats);
948 
949  return count;
950 }
951 
952 int srch(const void *pa, const void *pb)
953 {
954  int *p1 = (int *)pa;
955  int *p2 = (int *)pb;
956 
957  if (*p1 < *p2)
958  return -1;
959  if (*p1 > *p2)
960  return 1;
961  return 0;
962 }
963 
964 /*!
965  \brief Write data to GRASS ASCII vector format
966 
967  \param[out] dascii pointer to the output ASCII file
968  \param Map pointer to Map_info structure
969  */
970 void Vect_write_ascii_head(FILE *dascii, struct Map_info *Map)
971 {
972  fprintf(dascii, "ORGANIZATION: %s%s", Vect_get_organization(Map),
973  HOST_NEWLINE);
974  fprintf(dascii, "DIGIT DATE: %s%s", Vect_get_date(Map), HOST_NEWLINE);
975  fprintf(dascii, "DIGIT NAME: %s%s", Vect_get_person(Map), HOST_NEWLINE);
976  fprintf(dascii, "MAP NAME: %s%s", Vect_get_map_name(Map), HOST_NEWLINE);
977  fprintf(dascii, "MAP DATE: %s%s", Vect_get_map_date(Map), HOST_NEWLINE);
978  fprintf(dascii, "MAP SCALE: %d%s", Vect_get_scale(Map), HOST_NEWLINE);
979  fprintf(dascii, "OTHER INFO: %s%s", Vect_get_comment(Map), HOST_NEWLINE);
980  fprintf(dascii, "ZONE: %d%s", Vect_get_zone(Map), HOST_NEWLINE);
981  fprintf(dascii, "MAP THRESH: %f%s", Vect_get_thresh(Map), HOST_NEWLINE);
982 }
983 
984 /* check category */
985 int get_cat(const struct line_cats *Cats, const struct cat_list *Clist,
986  const int *cats, int ncats, int field, int *cat)
987 {
988  int i;
989 
990  *cat = -1;
991 
992  if (field < 1)
993  return TRUE;
994 
995  if (Clist && Clist->field == field) {
996  for (i = 0; i < Cats->n_cats; i++) {
997  if (Cats->field[i] == field &&
998  Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
999  *cat = Cats->cat[i];
1000  return TRUE;
1001  }
1002  }
1003  return FALSE;
1004  }
1005  if (cats) {
1006  int *found;
1007 
1008  for (i = 0; i < Cats->n_cats; i++) {
1009  if (Cats->field[i] == field) {
1010  found = (int *)bsearch((void *)&(Cats->cat[i]), cats, ncats,
1011  sizeof(int), srch);
1012  if (found) {
1013  /* found */
1014  *cat = *found;
1015  return TRUE;
1016  }
1017  }
1018  }
1019  return FALSE;
1020  }
1021  if (!Clist && !cats && field > 0) {
1022  Vect_cat_get(Cats, field, cat);
1023  if (*cat > -1)
1024  return TRUE;
1025  }
1026 
1027  return FALSE;
1028 }
1029 
1030 /* free column arrays, see Vect_write_ascii() */
1031 void free_col_arrays(int *coltypes, char *all_columns, char **columns)
1032 {
1033  G_free(coltypes);
1034  G_free(all_columns);
1035  if (columns) {
1036  int i = 0;
1037 
1038  while (columns[i])
1039  G_free(columns[i++]);
1040  G_free(columns);
1041  }
1042 }
int Vect_write_ascii(FILE *ascii, FILE *att, struct Map_info *Map, int ver, int format, int dp, char *fs, int region_flag, int type, int field, const struct cat_list *Clist, const char *where, const char **column_names, int header)
Write data to GRASS ASCII vector format.
Definition: ascii.c:348
#define BUFFSIZE
Definition: ascii.c:26
int Vect_read_ascii_head(FILE *dascii, struct Map_info *Map)
Read header of GRASS ASCII vector format.
Definition: ascii.c:268
void Vect_write_ascii_head(FILE *dascii, struct Map_info *Map)
Write data to GRASS ASCII vector format.
Definition: ascii.c:970
int Vect_read_ascii(FILE *ascii, struct Map_info *Map)
Read data in GRASS ASCII vector format.
Definition: ascii.c:42
int columns
Definition: calc.c:11
#define NULL
Definition: ccmath.h:32
#define DB_C_TYPE_INT
Definition: dbmi.h:108
#define DB_SEQUENTIAL
Definition: dbmi.h:123
#define DB_C_TYPE_STRING
Definition: dbmi.h:107
#define DB_C_TYPE_DOUBLE
Definition: dbmi.h:109
#define DB_OK
Definition: dbmi.h:71
#define DB_C_TYPE_DATETIME
Definition: dbmi.h:110
#define DB_NEXT
Definition: dbmi.h:114
int db_column_Ctype(dbDriver *, const char *, const char *)
Get column ctype.
int db_test_value_isnull(dbValue *)
Check of value is null.
Definition: value.c:26
const char * db_get_value_string(dbValue *)
Get string value.
Definition: value.c:92
int db_describe_table(dbDriver *, dbString *, dbTable **)
Describe table.
Definition: c_desc_table.c:28
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
int db_select_value(dbDriver *, const char *, const char *, int, const char *, dbValue *)
Select one (first) value from table/column for key/id.
double db_get_value_double(dbValue *)
Get double precision value.
Definition: value.c:50
int db_shutdown_driver(dbDriver *)
Closedown the driver, and free the driver structure.
Definition: shutdown.c:36
dbDriver * db_start_driver(const char *)
Initialize a new dbDriver for db transaction.
Definition: start.c:51
void db_free_table(dbTable *)
Free the table.
int db_open_database(dbDriver *, dbHandle *)
Open database connection.
Definition: c_opendb.c:27
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
Definition: cursor.c:67
void db_zero_string(dbString *)
Zero string.
Definition: string.c:79
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition: db.c:61
int db_select_int(dbDriver *, const char *, const char *, const char *, int **)
Select array of ordered integers from table/column.
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
Definition: string.c:41
int db_set_handle(dbHandle *, const char *, const char *)
Set handle (database and schema name)
Definition: handle.c:39
int db_close_database(dbDriver *)
Close database connection.
Definition: c_closedb.c:26
int db_get_value_int(dbValue *)
Get integer value.
Definition: value.c:38
void db_init_handle(dbHandle *)
Initialize handle (i.e database/schema)
Definition: handle.c:23
void db_init_string(dbString *)
Initialize dbString.
Definition: string.c:25
int db_close_cursor(dbCursor *)
Close cursor.
Definition: c_close_cur.c:27
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
Definition: c_openselect.c:37
const char * db_get_column_name(dbColumn *)
Returns column name for given column.
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
Definition: c_fetch.c:28
int db_get_table_number_of_columns(dbTable *)
Return the number of columns of the table.
int int G_rasprintf(char **, size_t *, const char *,...) __attribute__((format(printf
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:60
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
#define G_calloc(m, n)
Definition: defs/gis.h:95
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_scan_easting(const char *, double *, int)
ASCII easting to double.
Definition: wind_scan.c:69
#define G_malloc(n)
Definition: defs/gis.h:94
void G_trim_decimal(char *)
Removes trailing zeros from decimal number.
Definition: trim_dec.c:24
void void void G_important_message(const char *,...) __attribute__((format(printf
char * G_chop(char *)
Chop leading and trailing white spaces.
Definition: strings.c:332
int G_debug(int, const char *,...) __attribute__((format(printf
int G_scan_northing(const char *, double *, int)
ASCII northing to double.
Definition: wind_scan.c:38
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
void G_get_window(struct Cell_head *)
Get the current region.
Definition: get_window.c:47
int G_projection(void)
Query cartographic projection.
Definition: proj1.c:32
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
int Vect_set_map_name(struct Map_info *, const char *)
Set map name in map header.
const char * Vect_get_map_date(struct Map_info *)
Get date when the source map was originally produced from map header.
plus_t Vect_get_num_areas(struct Map_info *)
Get number of areas in vector map.
Definition: level_two.c:87
int Vect_cat_in_cat_list(int, const struct cat_list *)
Check if category number is in list.
int Vect_set_zone(struct Map_info *, int)
Set projection zone in map header.
int Vect_reset_cats(struct line_cats *)
Reset category structure to make sure cats structure is clean to be re-used.
int Vect_area_alive(struct Map_info *, int)
Check if area is alive or dead (topological level required)
const char * Vect_get_organization(struct Map_info *)
Get organization string from map header.
const char * Vect_get_comment(struct Map_info *)
Get comment or other info string from map header.
int Vect_get_scale(struct Map_info *)
Get map scale from map header.
const char * Vect_get_date(struct Map_info *)
Get date of digitization from map header.
int Vect_cat_set(struct line_cats *, int, int)
Add new field/cat to category structure if doesn't exist yet.
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
int Vect_get_area_cats(struct Map_info *, int, struct line_cats *)
Get area categories.
int Vect_set_scale(struct Map_info *, int)
Set map scale in map header.
int Vect_get_isle_points(struct Map_info *, int, struct line_pnts *)
Returns polygon array of points for given isle.
int Vect_get_area_points(struct Map_info *, int, struct line_pnts *)
Returns polygon array of points (outer ring) of given area.
void Vect_destroy_list(struct ilist *)
Frees all memory associated with a struct ilist, including the struct itself.
int Vect_level(struct Map_info *)
Returns level that Map is opened at.
Definition: level.c:29
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_set_map_date(struct Map_info *, const char *)
Set date when the source map was originally produced in map header.
int Vect_copy_xyz_to_pnts(struct line_pnts *, const double *, const double *, const double *, int)
Copy points from array to line_pnts structure.
Definition: line.c:99
int Vect_set_comment(struct Map_info *, const char *)
Set comment or other info string in map header.
int Vect_get_zone(struct Map_info *)
int Vect_get_area_isle(struct Map_info *, int, int)
Returns isle id for area.
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int Vect_get_area_num_isles(struct Map_info *, int)
Returns number of isles for given area.
double Vect_get_thresh(struct Map_info *)
Get threshold used for digitization from map header.
int Vect_set_organization(struct Map_info *, const char *)
Set organization string in map header.
int Vect_get_area_cat(struct Map_info *, int, int)
Find FIRST category of given field and area.
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
struct field_info * Vect_get_field(struct Map_info *, int)
Get information about link to database (by layer number)
Definition: field.c:515
void Vect_destroy_field_info(struct field_info *)
Free a struct field_info and all memory associated with it.
Definition: field.c:633
int Vect_set_date(struct Map_info *, const char *)
Set date of digitization in map header.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
const char * Vect_get_person(struct Map_info *)
Get user name string who digitized the map from map header.
int Vect_rewind(struct Map_info *)
Rewind vector map to cause reads to start at beginning.
const char * Vect_get_name(struct Map_info *)
Get name of vector map.
int Vect_read_next_line(struct Map_info *, struct line_pnts *, struct line_cats *)
Read next vector feature.
int Vect_sfa_line_astext(const struct line_pnts *, int, int, int, FILE *)
Export geometry to Well-Known Text.
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_get_line_areas(struct Map_info *, int, int *, int *)
Get area id on the left and right side of the boundary.
Definition: level_two.c:346
int Vect_field_cat_get(const struct line_cats *, int, struct ilist *)
Get list of categories of given field.
int Vect_set_person(struct Map_info *, const char *)
Set name of user who digitized the map in map header.
int Vect_set_thresh(struct Map_info *, double)
Set threshold used for digitization in map header.
int Vect_is_3d(struct Map_info *)
Check if vector map is 3D.
const char * Vect_get_map_name(struct Map_info *)
Get map name from map header.
int Vect_get_isle_area(struct Map_info *, int)
Returns area id for isle.
#define GV_ASCII_FORMAT_WKT
GRASS ASCII vector format - well-known-text format.
Definition: dig_defines.h:226
#define GV_CENTROID
Definition: dig_defines.h:186
#define GV_LINE
Definition: dig_defines.h:184
#define GV_POINT
Feature types used in memory on run time (may change)
Definition: dig_defines.h:183
#define GV_ASCII_FORMAT_STD
GRASS ASCII vector format - standard format.
Definition: dig_defines.h:224
#define GV_BOUNDARY
Definition: dig_defines.h:185
#define GV_FACE
Definition: dig_defines.h:187
#define GV_POINTS
Definition: dig_defines.h:192
#define GV_ASCII_FORMAT_POINT
GRASS ASCII vector format - point format.
Definition: dig_defines.h:222
#define GV_AREA
Definition: dig_defines.h:189
#define GV_KERNEL
Definition: dig_defines.h:188
const struct driver * driver
Definition: driver/init.c:25
#define HOST_NEWLINE
Definition: gis.h:90
#define TRUE
Definition: gis.h:78
#define FALSE
Definition: gis.h:82
#define _(str)
Definition: glocale.h:10
GRASS_INTERPFL_EXPORT int count
#define strcpy
Definition: parson.c:62
2D/3D raster map header (used also for region)
Definition: gis.h:446
double north
Extent coordinates (north)
Definition: gis.h:492
double bottom
Extent coordinates (bottom) - 3D data.
Definition: gis.h:502
double east
Extent coordinates (east)
Definition: gis.h:496
double top
Extent coordinates (top) - 3D data.
Definition: gis.h:500
double south
Extent coordinates (south)
Definition: gis.h:494
double west
Extent coordinates (west)
Definition: gis.h:498
Vector map info.
Definition: dig_structs.h:1243
struct dig_head head
Header info.
Definition: dig_structs.h:1388
Category list.
Definition: dig_structs.h:1697
int field
Category layer (field)
Definition: dig_structs.h:1701
int with_z
2D/3D vector data
Definition: dig_structs.h:339
Definition: driver.h:27
Layer (old: field) information.
Definition: dig_structs.h:131
char * table
Name of DB table.
Definition: dig_structs.h:151
char * driver
Name of DB driver ('sqlite', 'dbf', ...)
Definition: dig_structs.h:143
char * database
Definition: dig_structs.h:147
char * key
Name of key column (usually 'cat')
Definition: dig_structs.h:155
List of integers.
Definition: gis.h:715
int n_values
Number of values in the list.
Definition: gis.h:723
Feature category info.
Definition: dig_structs.h:1677
int * field
Array of layers (fields)
Definition: dig_structs.h:1681
int * cat
Array of categories.
Definition: dig_structs.h:1685
int n_cats
Number of categories attached to element.
Definition: dig_structs.h:1689
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663
#define x