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