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