| 1 | /*
|
|---|
| 2 | ***************************************************************
|
|---|
| 3 | *
|
|---|
| 4 | * MODULE: v.out.ogr
|
|---|
| 5 | *
|
|---|
| 6 | * AUTHOR(S): Radim Blazek
|
|---|
| 7 | * Some extensions: Markus Neteler, Benjamin Ducke
|
|---|
| 8 | * Multi-features support by Martin Landa <landa.martin gmail.com>
|
|---|
| 9 | *
|
|---|
| 10 | * PURPOSE: Converts GRASS vector to one of supported OGR vector formats.
|
|---|
| 11 | *
|
|---|
| 12 | * COPYRIGHT: (C) 2001-2017 by the GRASS Development Team
|
|---|
| 13 | *
|
|---|
| 14 | * This program is free software under the GNU General
|
|---|
| 15 | * Public License (>=v2). Read the file COPYING that
|
|---|
| 16 | * comes with GRASS for details.
|
|---|
| 17 | *
|
|---|
| 18 | **************************************************************/
|
|---|
| 19 |
|
|---|
| 20 | #include <stdlib.h>
|
|---|
| 21 | #include <string.h>
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 | #include <grass/gis.h>
|
|---|
| 25 | #include <grass/gprojects.h>
|
|---|
| 26 | #include <grass/glocale.h>
|
|---|
| 27 |
|
|---|
| 28 | #include "local_proto.h"
|
|---|
| 29 |
|
|---|
| 30 | #include <ogr_srs_api.h>
|
|---|
| 31 |
|
|---|
| 32 | int main(int argc, char *argv[])
|
|---|
| 33 | {
|
|---|
| 34 | int i, otype, ftype, donocat;
|
|---|
| 35 | int num_to_export;
|
|---|
| 36 | int field;
|
|---|
| 37 | int overwrite, found;
|
|---|
| 38 |
|
|---|
| 39 | struct GModule *module;
|
|---|
| 40 | struct Options options;
|
|---|
| 41 | struct Flags flags;
|
|---|
| 42 |
|
|---|
| 43 | char buf[SQL_BUFFER_SIZE];
|
|---|
| 44 | char key1[SQL_BUFFER_SIZE], key2[SQL_BUFFER_SIZE];
|
|---|
| 45 | struct Cell_head cellhd;
|
|---|
| 46 | char **tokens;
|
|---|
| 47 |
|
|---|
| 48 | /* Vector */
|
|---|
| 49 | struct Map_info In;
|
|---|
| 50 |
|
|---|
| 51 | /* Attributes */
|
|---|
| 52 | int doatt = 0, ncol = 0, colsqltype, colwidth, keycol = -1;
|
|---|
| 53 | int *colctype = NULL;
|
|---|
| 54 | const char **colname = NULL;
|
|---|
| 55 | struct field_info *Fi = NULL;
|
|---|
| 56 | dbDriver *Driver = NULL;
|
|---|
| 57 | dbTable *Table;
|
|---|
| 58 | dbString dbstring;
|
|---|
| 59 | dbColumn *Column;
|
|---|
| 60 |
|
|---|
| 61 | int n_feat; /* number of written features */
|
|---|
| 62 | int n_nocat, n_noatt; /* number of features without cats/atts written/skip */
|
|---|
| 63 |
|
|---|
| 64 | /* OGR */
|
|---|
| 65 | int drn;
|
|---|
| 66 | OGRFieldType ogr_ftype = OFTInteger;
|
|---|
| 67 | ds_t hDS;
|
|---|
| 68 | dr_t hDriver;
|
|---|
| 69 | OGRLayerH Ogr_layer;
|
|---|
| 70 | OGRFieldDefnH Ogr_field;
|
|---|
| 71 | OGRFeatureDefnH Ogr_featuredefn;
|
|---|
| 72 | OGRwkbGeometryType wkbtype = wkbUnknown;
|
|---|
| 73 | OGRSpatialReferenceH Ogr_projection;
|
|---|
| 74 | char **papszDSCO = NULL, **papszLCO = NULL;
|
|---|
| 75 | int num_types;
|
|---|
| 76 | char *dsn;
|
|---|
| 77 | int outer_ring_ccw;
|
|---|
| 78 |
|
|---|
| 79 | G_gisinit(argv[0]);
|
|---|
| 80 |
|
|---|
| 81 | /* Module options */
|
|---|
| 82 | module = G_define_module();
|
|---|
| 83 | G_add_keyword(_("vector"));
|
|---|
| 84 | G_add_keyword(_("export"));
|
|---|
| 85 | G_add_keyword(_("output"));
|
|---|
| 86 | G_add_keyword("OGR");
|
|---|
| 87 | G_add_keyword(_("output"));
|
|---|
| 88 |
|
|---|
| 89 | module->label =
|
|---|
| 90 | _("Exports a vector map layer to any of the supported OGR vector formats.");
|
|---|
| 91 | module->description = _("By default a vector map layer is exported to OGC GeoPackage format.");
|
|---|
| 92 | module->overwrite = TRUE;
|
|---|
| 93 |
|
|---|
| 94 | /* parse & read options */
|
|---|
| 95 | parse_args(argc, argv, &options, &flags);
|
|---|
| 96 |
|
|---|
| 97 | if (flags.list->answer) {
|
|---|
| 98 | list_formats();
|
|---|
| 99 | exit(EXIT_SUCCESS);
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | /* check for weird options */
|
|---|
| 103 | if (G_strncasecmp(options.dsn->answer, "PG:", 3) == 0 &&
|
|---|
| 104 | strcmp(options.format->answer, "PostgreSQL") != 0)
|
|---|
| 105 | G_warning(_("Data source starts with \"PG:\" prefix, expecting \"PostgreSQL\" "
|
|---|
| 106 | "format (\"%s\" given)"), options.format->answer);
|
|---|
| 107 |
|
|---|
| 108 | /* parse dataset creation options */
|
|---|
| 109 | i = 0;
|
|---|
| 110 | while (options.dsco->answers[i]) {
|
|---|
| 111 | tokens = G_tokenize(options.dsco->answers[i], "=");
|
|---|
| 112 | if (G_number_of_tokens(tokens))
|
|---|
| 113 | papszDSCO = CSLSetNameValue(papszDSCO, tokens[0], tokens[1]);
|
|---|
| 114 | G_free_tokens(tokens);
|
|---|
| 115 | i++;
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | /* parse layer creation options */
|
|---|
| 119 | i = 0;
|
|---|
| 120 | while (options.lco->answers[i]) {
|
|---|
| 121 | tokens = G_tokenize(options.lco->answers[i], "=");
|
|---|
| 122 | if (G_number_of_tokens(tokens))
|
|---|
| 123 | papszLCO = CSLSetNameValue(papszLCO, tokens[0], tokens[1]);
|
|---|
| 124 | G_free_tokens(tokens);
|
|---|
| 125 | i++;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | /*
|
|---|
| 129 | If no output type specified: determine one automatically.
|
|---|
| 130 | Centroids, Boundaries and Kernels always have to be exported
|
|---|
| 131 | explicitly, using the "type=" option.
|
|---|
| 132 | */
|
|---|
| 133 | field = 0;
|
|---|
| 134 | if (!flags.new->answer) {
|
|---|
| 135 | /* open input vector (topology required) */
|
|---|
| 136 | Vect_set_open_level(2);
|
|---|
| 137 | if (Vect_open_old2(&In, options.input->answer, "",
|
|---|
| 138 | options.field->answer) < 0)
|
|---|
| 139 | G_fatal_error(_("Unable to open vector map <%s>"),
|
|---|
| 140 | options.input->answer);
|
|---|
| 141 |
|
|---|
| 142 | if (strcmp(options.type->answer, "auto") == 0) {
|
|---|
| 143 | G_debug(2, "Automatic type determination.");
|
|---|
| 144 |
|
|---|
| 145 | options.type->answers = G_malloc(sizeof(char *) * 10);
|
|---|
| 146 | G_zero(options.type->answers, sizeof(char *) * 10);
|
|---|
| 147 | num_types = 0;
|
|---|
| 148 |
|
|---|
| 149 | if (Vect_get_num_primitives(&In, GV_POINT) > 0) {
|
|---|
| 150 | options.type->answers[num_types++] = G_store("point");
|
|---|
| 151 | G_debug(3, "Adding points to export list.");
|
|---|
| 152 | }
|
|---|
| 153 |
|
|---|
| 154 | if (Vect_get_num_primitives(&In, GV_LINE) > 0) {
|
|---|
| 155 | options.type->answers[num_types++] = G_store("line");
|
|---|
| 156 | G_debug(3, "Adding lines to export list.");
|
|---|
| 157 | }
|
|---|
| 158 |
|
|---|
| 159 | if (Vect_get_num_areas(&In) > 0) {
|
|---|
| 160 | options.type->answers[num_types++] = G_store("area");
|
|---|
| 161 | G_debug(3, "Adding areas to export list.");
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | /* Faces and volumes:
|
|---|
| 165 | For now, volumes will just be exported as sets of faces.
|
|---|
| 166 | */
|
|---|
| 167 | if (Vect_get_num_primitives(&In, GV_FACE) > 0) {
|
|---|
| 168 | options.type->answers[num_types++] = G_store("face");
|
|---|
| 169 | G_debug(3, "Adding faces to export list.");
|
|---|
| 170 | }
|
|---|
| 171 |
|
|---|
| 172 | /* this check HAS TO FOLLOW RIGHT AFTER check for GV_FACE! */
|
|---|
| 173 | if (Vect_get_num_volumes(&In) > 0) {
|
|---|
| 174 | G_warning(_("Volumes will be exported as sets of faces"));
|
|---|
| 175 | if (num_types == 0) {
|
|---|
| 176 | /* no other types yet? */
|
|---|
| 177 | options.type->answers[num_types++] = G_store("volume");
|
|---|
| 178 | G_debug(3, "Adding volumes to export list.");
|
|---|
| 179 | }
|
|---|
| 180 | else {
|
|---|
| 181 | if (strcmp(options.type->answers[num_types - 1], "face")
|
|---|
| 182 | != 0) {
|
|---|
| 183 | /* only put faces on export list if that's not the case already */
|
|---|
| 184 | options.type->answers[num_types++] =
|
|---|
| 185 | G_store("volume");
|
|---|
| 186 | G_debug(3, "Adding volumes to export list.");
|
|---|
| 187 | }
|
|---|
| 188 | }
|
|---|
| 189 | }
|
|---|
| 190 |
|
|---|
| 191 | if (num_types == 0) {
|
|---|
| 192 | G_warning(_("Unable to determine input map's vector feature type(s)."));
|
|---|
| 193 | }
|
|---|
| 194 | }
|
|---|
| 195 | field = Vect_get_field_number(&In, options.field->answer);
|
|---|
| 196 | }
|
|---|
| 197 |
|
|---|
| 198 | /* check output feature type */
|
|---|
| 199 | otype = Vect_option_to_types(options.type);
|
|---|
| 200 | ftype = Vect_option_to_types(options.otype);
|
|---|
| 201 |
|
|---|
| 202 | if (!options.layer->answer) {
|
|---|
| 203 | char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
|
|---|
| 204 |
|
|---|
| 205 | if (G_name_is_fully_qualified(options.input->answer, xname, xmapset))
|
|---|
| 206 | options.layer->answer = G_store(xname);
|
|---|
| 207 | else
|
|---|
| 208 | options.layer->answer = G_store(options.input->answer);
|
|---|
| 209 | }
|
|---|
| 210 |
|
|---|
| 211 | if (ftype == GV_BOUNDARY) {
|
|---|
| 212 | if (!flags.multi->answer)
|
|---|
| 213 | wkbtype = wkbPolygon;
|
|---|
| 214 | else
|
|---|
| 215 | wkbtype = wkbMultiPolygon;
|
|---|
| 216 | }
|
|---|
| 217 | else if (otype & GV_POINTS) {
|
|---|
| 218 | if (!flags.multi->answer)
|
|---|
| 219 | wkbtype = wkbPoint;
|
|---|
| 220 | else
|
|---|
| 221 | wkbtype = wkbMultiPoint;
|
|---|
| 222 | }
|
|---|
| 223 | else if (otype & GV_LINES || ftype == GV_LINE) {
|
|---|
| 224 | if (!flags.multi->answer)
|
|---|
| 225 | wkbtype = wkbLineString;
|
|---|
| 226 | else
|
|---|
| 227 | wkbtype = wkbMultiLineString;
|
|---|
| 228 | }
|
|---|
| 229 | else if (otype & GV_AREA) {
|
|---|
| 230 | if (!flags.multi->answer)
|
|---|
| 231 | wkbtype = wkbPolygon;
|
|---|
| 232 | else
|
|---|
| 233 | wkbtype = wkbMultiPolygon;
|
|---|
| 234 | }
|
|---|
| 235 | else if (otype & (GV_FACE | GV_VOLUME)) {
|
|---|
| 236 | if (!flags.multi->answer)
|
|---|
| 237 | wkbtype = wkbPolygon25D;
|
|---|
| 238 | else
|
|---|
| 239 | wkbtype = wkbMultiPolygon25D;
|
|---|
| 240 | }
|
|---|
| 241 |
|
|---|
| 242 | if (((GV_POINTS & otype) && (GV_LINES & otype)) ||
|
|---|
| 243 | ((GV_POINTS & otype) && (GV_AREA & otype)) ||
|
|---|
| 244 | ((GV_POINTS & otype) && (GV_FACE & otype)) ||
|
|---|
| 245 | ((GV_POINTS & otype) && (GV_KERNEL & otype)) ||
|
|---|
| 246 | ((GV_POINTS & otype) && (GV_VOLUME & otype)) ||
|
|---|
| 247 | ((GV_LINES & otype) && (GV_AREA & otype)) ||
|
|---|
| 248 | ((GV_LINES & otype) && (GV_FACE & otype)) ||
|
|---|
| 249 | ((GV_LINES & otype) && (GV_KERNEL & otype)) ||
|
|---|
| 250 | ((GV_LINES & otype) && (GV_VOLUME & otype)) ||
|
|---|
| 251 | ((GV_KERNEL & otype) && (GV_POINTS & otype)) ||
|
|---|
| 252 | ((GV_KERNEL & otype) && (GV_LINES & otype)) ||
|
|---|
| 253 | ((GV_KERNEL & otype) && (GV_AREA & otype)) ||
|
|---|
| 254 | ((GV_KERNEL & otype) && (GV_FACE & otype)) ||
|
|---|
| 255 | ((GV_KERNEL & otype) && (GV_VOLUME & otype))
|
|---|
| 256 | ) {
|
|---|
| 257 | G_warning(_("The combination of types is not supported"
|
|---|
| 258 | " by all formats."));
|
|---|
| 259 | wkbtype = wkbUnknown;
|
|---|
| 260 | }
|
|---|
| 261 |
|
|---|
| 262 | /* fetch PROJ info */
|
|---|
| 263 | G_get_default_window(&cellhd);
|
|---|
| 264 | Ogr_projection = NULL;
|
|---|
| 265 | if (cellhd.proj != PROJECTION_XY) {
|
|---|
| 266 | struct Key_Value *projinfo, *projunits, *projepsg;
|
|---|
| 267 |
|
|---|
| 268 | projinfo = G_get_projinfo();
|
|---|
| 269 | projunits = G_get_projunits();
|
|---|
| 270 | projepsg = G_get_projepsg();
|
|---|
| 271 | Ogr_projection = GPJ_grass_to_osr2(projinfo, projunits, projepsg);
|
|---|
| 272 |
|
|---|
| 273 | if (Ogr_projection == NULL)
|
|---|
| 274 | G_fatal_error(_("Unable to create OGR spatial reference"));
|
|---|
| 275 |
|
|---|
| 276 | if (flags.esristyle->answer &&
|
|---|
| 277 | (strcmp(options.format->answer, "ESRI_Shapefile") == 0))
|
|---|
| 278 | OSRMorphToESRI(Ogr_projection);
|
|---|
| 279 | }
|
|---|
| 280 |
|
|---|
| 281 | dsn = NULL;
|
|---|
| 282 | if (options.dsn->answer)
|
|---|
| 283 | dsn = G_store(options.dsn->answer);
|
|---|
| 284 |
|
|---|
| 285 | /* create new OGR layer in datasource */
|
|---|
| 286 | if (flags.new->answer) {
|
|---|
| 287 | const char *name;
|
|---|
| 288 |
|
|---|
| 289 | name =
|
|---|
| 290 | options.layer->answer ? options.layer->answer : options.input->
|
|---|
| 291 | answer;
|
|---|
| 292 |
|
|---|
| 293 | create_ogr_layer(dsn, options.format->answer, name,
|
|---|
| 294 | wkbtype, papszDSCO, papszLCO);
|
|---|
| 295 |
|
|---|
| 296 | G_message(_("OGR layer <%s> created in datasource <%s> (format '%s')"),
|
|---|
| 297 | name, options.dsn->answer, options.format->answer);
|
|---|
| 298 | exit(EXIT_SUCCESS);
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 | if (flags.cat->answer)
|
|---|
| 302 | donocat = 1;
|
|---|
| 303 | else
|
|---|
| 304 | donocat = 0;
|
|---|
| 305 |
|
|---|
| 306 | if ((GV_AREA & otype) && Vect_get_num_islands(&In) > 0 &&
|
|---|
| 307 | flags.cat->answer)
|
|---|
| 308 | G_warning(_("The map contains islands. With the -c flag, "
|
|---|
| 309 | "islands will appear as filled areas, not holes in the output map."));
|
|---|
| 310 |
|
|---|
| 311 |
|
|---|
| 312 | /* check what users wants to export and what's present in the map */
|
|---|
| 313 | if (Vect_get_num_primitives(&In, GV_POINT) > 0 && !(otype & GV_POINTS))
|
|---|
| 314 | G_warning(n_("%d point found, but not requested to be exported. "
|
|---|
| 315 | "Verify 'type' parameter.",
|
|---|
| 316 | "%d points found, but not requested to be exported. "
|
|---|
| 317 | "Verify 'type' parameter.",
|
|---|
| 318 | Vect_get_num_primitives(&In, GV_POINT)),
|
|---|
| 319 | Vect_get_num_primitives(&In, GV_POINT));
|
|---|
| 320 |
|
|---|
| 321 | if (Vect_get_num_primitives(&In, GV_LINE) > 0 && !(otype & GV_LINES))
|
|---|
| 322 | G_warning(n_("%d line found, but not requested to be exported. "
|
|---|
| 323 | "Verify 'type' parameter.",
|
|---|
| 324 | "%d line(s) found, but not requested to be exported. "
|
|---|
| 325 | "Verify 'type' parameter.",
|
|---|
| 326 | Vect_get_num_primitives(&In, GV_LINE)),
|
|---|
| 327 | Vect_get_num_primitives(&In, GV_LINE));
|
|---|
| 328 |
|
|---|
| 329 | if (Vect_get_num_primitives(&In, GV_BOUNDARY) > 0 &&
|
|---|
| 330 | !(otype & GV_BOUNDARY) && !(otype & GV_AREA))
|
|---|
| 331 | G_warning(n_("%d boundary found, but not requested to be exported. "
|
|---|
| 332 | "Verify 'type' parameter.",
|
|---|
| 333 | "%d boundaries found, but not requested to be exported. "
|
|---|
| 334 | "Verify 'type' parameter.",
|
|---|
| 335 | Vect_get_num_primitives(&In, GV_BOUNDARY)),
|
|---|
| 336 | Vect_get_num_primitives(&In, GV_BOUNDARY));
|
|---|
| 337 |
|
|---|
| 338 | if (Vect_get_num_primitives(&In, GV_CENTROID) > 0 &&
|
|---|
| 339 | !(otype & GV_CENTROID) && !(otype & GV_AREA))
|
|---|
| 340 | G_warning(n_("%d centroid found, but not requested to be exported. "
|
|---|
| 341 | "Verify 'type' parameter.",
|
|---|
| 342 | "%d centroids found, but not requested to be exported. "
|
|---|
| 343 | "Verify 'type' parameter.",
|
|---|
| 344 | Vect_get_num_primitives(&In, GV_CENTROID)),
|
|---|
| 345 | Vect_get_num_primitives(&In, GV_CENTROID));
|
|---|
| 346 |
|
|---|
| 347 | if (Vect_get_num_areas(&In) > 0 && !(otype & GV_AREA))
|
|---|
| 348 | G_warning(n_("%d area found, but not requested to be exported. "
|
|---|
| 349 | "Verify 'type' parameter.",
|
|---|
| 350 | "%d areas found, but not requested to be exported. "
|
|---|
| 351 | "Verify 'type' parameter.",
|
|---|
| 352 | Vect_get_num_areas(&In)),
|
|---|
| 353 | Vect_get_num_areas(&In));
|
|---|
| 354 |
|
|---|
| 355 | if (Vect_get_num_primitives(&In, GV_FACE) > 0 && !(otype & GV_FACE))
|
|---|
| 356 | G_warning(n_("%d face found, but not requested to be exported. "
|
|---|
| 357 | "Verify 'type' parameter.",
|
|---|
| 358 | "%d faces found, but not requested to be exported. "
|
|---|
| 359 | "Verify 'type' parameter.",
|
|---|
| 360 | Vect_get_num_primitives(&In, GV_FACE)),
|
|---|
| 361 | Vect_get_num_primitives(&In, GV_FACE));
|
|---|
| 362 |
|
|---|
| 363 | if (Vect_get_num_volumes(&In) > 0 && !(otype & GV_VOLUME))
|
|---|
| 364 | G_warning(n_("%d volume found, but not requested to be exported. "
|
|---|
| 365 | "Verify 'type' parameter.",
|
|---|
| 366 | "%d volumes found, but not requested to be exported. "
|
|---|
| 367 | "Verify 'type' parameter.",
|
|---|
| 368 | Vect_get_num_volumes(&In)),
|
|---|
| 369 | Vect_get_num_volumes(&In));
|
|---|
| 370 |
|
|---|
| 371 | /* warn and eventually abort if there is nothing to be exported */
|
|---|
| 372 | num_to_export = 0;
|
|---|
| 373 | if (Vect_get_num_primitives(&In, GV_POINT) < 1 && (otype & GV_POINTS)) {
|
|---|
| 374 | G_warning(_("No points found, but requested to be exported. "
|
|---|
| 375 | "Will skip this feature type."));
|
|---|
| 376 | }
|
|---|
| 377 | else {
|
|---|
| 378 | if (otype & GV_POINT)
|
|---|
| 379 | num_to_export += Vect_get_num_primitives(&In, GV_POINT);
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | if (Vect_get_num_primitives(&In, GV_LINE) < 1 && (otype & GV_LINE)) {
|
|---|
| 383 | G_warning(_("No lines found, but requested to be exported. "
|
|---|
| 384 | "Will skip this feature type."));
|
|---|
| 385 | }
|
|---|
| 386 | else {
|
|---|
| 387 | if (otype & GV_LINE)
|
|---|
| 388 | num_to_export += Vect_get_num_primitives(&In, GV_LINE);
|
|---|
| 389 | }
|
|---|
| 390 |
|
|---|
| 391 | if (Vect_get_num_primitives(&In, GV_BOUNDARY) < 1 &&
|
|---|
| 392 | (otype & GV_BOUNDARY)) {
|
|---|
| 393 | G_warning(_("No boundaries found, but requested to be exported. "
|
|---|
| 394 | "Will skip this feature type."));
|
|---|
| 395 | }
|
|---|
| 396 | else {
|
|---|
| 397 | if (otype & GV_BOUNDARY)
|
|---|
| 398 | num_to_export += Vect_get_num_primitives(&In, GV_BOUNDARY);
|
|---|
| 399 | }
|
|---|
| 400 |
|
|---|
| 401 | if (Vect_get_num_areas(&In) < 1 && (otype & GV_AREA)) {
|
|---|
| 402 | G_warning(_("No areas found, but requested to be exported. "
|
|---|
| 403 | "Will skip this feature type."));
|
|---|
| 404 | }
|
|---|
| 405 | else {
|
|---|
| 406 | if (otype & GV_AREA)
|
|---|
| 407 | num_to_export += Vect_get_num_areas(&In);
|
|---|
| 408 | }
|
|---|
| 409 |
|
|---|
| 410 | if (Vect_get_num_primitives(&In, GV_CENTROID) < 1 &&
|
|---|
| 411 | (otype & GV_CENTROID)) {
|
|---|
| 412 | G_warning(_("No centroids found, but requested to be exported. "
|
|---|
| 413 | "Will skip this feature type."));
|
|---|
| 414 | }
|
|---|
| 415 | else {
|
|---|
| 416 | if (otype & GV_CENTROID)
|
|---|
| 417 | num_to_export += Vect_get_num_primitives(&In, GV_CENTROID);
|
|---|
| 418 | }
|
|---|
| 419 |
|
|---|
| 420 | if (Vect_get_num_primitives(&In, GV_FACE) < 1 && (otype & GV_FACE)) {
|
|---|
| 421 | G_warning(_("No faces found, but requested to be exported. "
|
|---|
| 422 | "Will skip this feature type."));
|
|---|
| 423 | }
|
|---|
| 424 | else {
|
|---|
| 425 | if (otype & GV_FACE)
|
|---|
| 426 | num_to_export += Vect_get_num_primitives(&In, GV_FACE);
|
|---|
| 427 | }
|
|---|
| 428 |
|
|---|
| 429 | if (Vect_get_num_primitives(&In, GV_KERNEL) < 1 && (otype & GV_KERNEL)) {
|
|---|
| 430 | G_warning(_("No kernels found, but requested to be exported. "
|
|---|
| 431 | "Will skip this feature type."));
|
|---|
| 432 | }
|
|---|
| 433 | else {
|
|---|
| 434 | if (otype & GV_KERNEL)
|
|---|
| 435 | num_to_export += Vect_get_num_primitives(&In, GV_KERNEL);
|
|---|
| 436 | }
|
|---|
| 437 |
|
|---|
| 438 | if (Vect_get_num_volumes(&In) < 1 && (otype & GV_VOLUME)) {
|
|---|
| 439 | G_warning(_("No volumes found, but requested to be exported. "
|
|---|
| 440 | "Will skip this feature type."));
|
|---|
| 441 | }
|
|---|
| 442 | else {
|
|---|
| 443 | if (otype & GV_VOLUME)
|
|---|
| 444 | num_to_export += Vect_get_num_volumes(&In);
|
|---|
| 445 | }
|
|---|
| 446 |
|
|---|
| 447 | G_debug(1, "Requested to export %d features", num_to_export);
|
|---|
| 448 |
|
|---|
| 449 | /* Open OGR DSN */
|
|---|
| 450 | #if GDAL_VERSION_NUM >= 2020000
|
|---|
| 451 | G_debug(2, "driver count = %d", GDALGetDriverCount());
|
|---|
| 452 | drn = -1;
|
|---|
| 453 | for (i = 0; i < GDALGetDriverCount(); i++) {
|
|---|
| 454 | hDriver = GDALGetDriver(i);
|
|---|
| 455 | G_debug(2, "driver %d : %s", i, GDALGetDriverShortName(hDriver));
|
|---|
| 456 | /* chg white space to underscore in OGR driver names */
|
|---|
| 457 | sprintf(buf, "%s", GDALGetDriverShortName(hDriver));
|
|---|
| 458 | G_strchg(buf, ' ', '_');
|
|---|
| 459 | if (strcmp(buf, options.format->answer) == 0) {
|
|---|
| 460 | drn = i;
|
|---|
| 461 | G_debug(2, " -> driver = %d", drn);
|
|---|
| 462 | }
|
|---|
| 463 | }
|
|---|
| 464 | #else
|
|---|
| 465 | G_debug(2, "driver count = %d", OGRGetDriverCount());
|
|---|
| 466 | drn = -1;
|
|---|
| 467 | for (i = 0; i < OGRGetDriverCount(); i++) {
|
|---|
| 468 | hDriver = OGRGetDriver(i);
|
|---|
| 469 | G_debug(2, "driver %d : %s", i, OGR_Dr_GetName(hDriver));
|
|---|
| 470 | /* chg white space to underscore in OGR driver names */
|
|---|
| 471 | sprintf(buf, "%s", OGR_Dr_GetName(hDriver));
|
|---|
| 472 | G_strchg(buf, ' ', '_');
|
|---|
| 473 | if (strcmp(buf, options.format->answer) == 0) {
|
|---|
| 474 | drn = i;
|
|---|
| 475 | G_debug(2, " -> driver = %d", drn);
|
|---|
| 476 | }
|
|---|
| 477 | }
|
|---|
| 478 | #endif
|
|---|
| 479 | if (drn == -1)
|
|---|
| 480 | G_fatal_error(_("OGR driver <%s> not found"), options.format->answer);
|
|---|
| 481 | hDriver = get_driver(drn);
|
|---|
| 482 |
|
|---|
| 483 | if (flags.append->answer) {
|
|---|
| 484 | G_debug(1, "Append to OGR layer");
|
|---|
| 485 | #if GDAL_VERSION_NUM >= 2020000
|
|---|
| 486 | hDS = GDALOpenEx(dsn, GDAL_OF_VECTOR | GDAL_OF_UPDATE, NULL, NULL, NULL);
|
|---|
| 487 |
|
|---|
| 488 | if (hDS == NULL) {
|
|---|
| 489 | G_debug(1, "Create OGR data source");
|
|---|
| 490 | hDS = GDALCreate(hDriver, dsn, 0, 0, 0, GDT_Unknown, papszDSCO);
|
|---|
| 491 | }
|
|---|
| 492 | #else
|
|---|
| 493 | hDS = OGR_Dr_Open(hDriver, dsn, TRUE);
|
|---|
| 494 |
|
|---|
| 495 | if (hDS == NULL) {
|
|---|
| 496 | G_debug(1, "Create OGR data source");
|
|---|
| 497 | hDS = OGR_Dr_CreateDataSource(hDriver, dsn, papszDSCO);
|
|---|
| 498 | }
|
|---|
| 499 | #endif
|
|---|
| 500 | }
|
|---|
| 501 | else {
|
|---|
| 502 | #if GDAL_VERSION_NUM >= 2020000
|
|---|
| 503 | if (flags.update->answer) {
|
|---|
| 504 | G_debug(1, "Update OGR data source");
|
|---|
| 505 | hDS = GDALOpenEx(dsn, GDAL_OF_VECTOR | GDAL_OF_UPDATE, NULL, NULL, NULL);
|
|---|
| 506 | }
|
|---|
| 507 | else {
|
|---|
| 508 | G_debug(1, "Create OGR data source");
|
|---|
| 509 | hDS = GDALCreate(hDriver, dsn, 0, 0, 0, GDT_Unknown, papszDSCO);
|
|---|
| 510 | }
|
|---|
| 511 | #else
|
|---|
| 512 | if (flags.update->answer) {
|
|---|
| 513 | G_debug(1, "Update OGR data source");
|
|---|
| 514 | hDS = OGR_Dr_Open(hDriver, dsn, TRUE);
|
|---|
| 515 | }
|
|---|
| 516 | else {
|
|---|
| 517 | G_debug(1, "Create OGR data source");
|
|---|
| 518 | hDS = OGR_Dr_CreateDataSource(hDriver, dsn, papszDSCO);
|
|---|
| 519 | }
|
|---|
| 520 | #endif
|
|---|
| 521 | }
|
|---|
| 522 |
|
|---|
| 523 | CSLDestroy(papszDSCO);
|
|---|
| 524 | if (hDS == NULL)
|
|---|
| 525 | G_fatal_error(_("Unable to open OGR data source '%s'"),
|
|---|
| 526 | options.dsn->answer);
|
|---|
| 527 |
|
|---|
| 528 | /* check if OGR layer exists */
|
|---|
| 529 | overwrite = G_check_overwrite(argc, argv);
|
|---|
| 530 | found = FALSE;
|
|---|
| 531 | #if GDAL_VERSION_NUM >= 2020000
|
|---|
| 532 | for (i = 0; i < GDALDatasetGetLayerCount(hDS); i++) {
|
|---|
| 533 | Ogr_layer = GDALDatasetGetLayer(hDS, i);
|
|---|
| 534 | #else
|
|---|
| 535 | for (i = 0; i < OGR_DS_GetLayerCount(hDS); i++) {
|
|---|
| 536 | Ogr_layer = OGR_DS_GetLayer(hDS, i);
|
|---|
| 537 |
|
|---|
| 538 | #endif
|
|---|
| 539 | Ogr_field = OGR_L_GetLayerDefn(Ogr_layer);
|
|---|
| 540 | if (G_strcasecmp(OGR_FD_GetName(Ogr_field), options.layer->answer))
|
|---|
| 541 | continue;
|
|---|
| 542 |
|
|---|
| 543 | found = TRUE;
|
|---|
| 544 | if (!overwrite && !flags.append->answer) {
|
|---|
| 545 | G_fatal_error(_("Layer <%s> already exists in OGR data source '%s'"),
|
|---|
| 546 | options.layer->answer, options.dsn->answer);
|
|---|
| 547 | }
|
|---|
| 548 | else if (overwrite) {
|
|---|
| 549 | G_warning(_("OGR layer <%s> already exists and will be overwritten"),
|
|---|
| 550 | options.layer->answer);
|
|---|
| 551 | #if GDAL_VERSION_NUM >= 2020000
|
|---|
| 552 | GDALDatasetDeleteLayer(hDS, i);
|
|---|
| 553 | #else
|
|---|
| 554 | OGR_DS_DeleteLayer(hDS, i);
|
|---|
| 555 | #endif
|
|---|
| 556 | break;
|
|---|
| 557 | }
|
|---|
| 558 | }
|
|---|
| 559 |
|
|---|
| 560 | if (flags.append->answer && !found) {
|
|---|
| 561 | G_warning(_("OGR layer <%s> doesn't exists, "
|
|---|
| 562 | "creating new OGR layer instead"),
|
|---|
| 563 | options.layer->answer);
|
|---|
| 564 | flags.append->answer = FALSE;
|
|---|
| 565 | }
|
|---|
| 566 |
|
|---|
| 567 | /* Automatically append driver options for 3D output to layer
|
|---|
| 568 | creation options if '2' is not given.*/
|
|---|
| 569 | if (!flags.force2d->answer &&
|
|---|
| 570 | Vect_is_3d(&In) &&
|
|---|
| 571 | strcmp(options.format->answer, "ESRI_Shapefile") == 0) {
|
|---|
| 572 | /* find right option */
|
|---|
| 573 | char shape_geom[20];
|
|---|
| 574 | if ((otype & GV_POINTS) || (otype & GV_KERNEL))
|
|---|
| 575 | sprintf(shape_geom, "POINTZ");
|
|---|
| 576 | if ((otype & GV_LINES))
|
|---|
| 577 | sprintf(shape_geom, "ARCZ");
|
|---|
| 578 | if ((otype & GV_AREA) || (otype & GV_FACE))
|
|---|
| 579 | sprintf(shape_geom, "POLYGONZ");
|
|---|
| 580 | /* check if the right LCO is already present */
|
|---|
| 581 | const char *shpt;
|
|---|
| 582 | shpt = CSLFetchNameValue(papszLCO, "SHPT");
|
|---|
| 583 | if ((!shpt)) {
|
|---|
| 584 | /* Not set at all? Good! */
|
|---|
| 585 | papszLCO = CSLSetNameValue(papszLCO, "SHPT", shape_geom);
|
|---|
| 586 | } else {
|
|---|
| 587 | if (strcmp(shpt, shape_geom) != 0) {
|
|---|
| 588 | /* Set but to a different value? Override! */
|
|---|
| 589 | G_warning(_("Overriding existing user-defined 'SHPT=' LCO."));
|
|---|
| 590 | }
|
|---|
| 591 | /* Set correct LCO for this geometry type */
|
|---|
| 592 | papszLCO = CSLSetNameValue(papszLCO, "SHPT", shape_geom);
|
|---|
| 593 | }
|
|---|
| 594 | }
|
|---|
| 595 |
|
|---|
| 596 | /* check if the map is 3d */
|
|---|
| 597 | if (Vect_is_3d(&In)) {
|
|---|
| 598 | /* specific check for ESRI ShapeFile */
|
|---|
| 599 | if (strcmp(options.format->answer, "ESRI_Shapefile") == 0) {
|
|---|
| 600 | const char *shpt;
|
|---|
| 601 |
|
|---|
| 602 | shpt = CSLFetchNameValue(papszLCO, "SHPT");
|
|---|
| 603 | if (!shpt || shpt[strlen(shpt) - 1] != 'Z') {
|
|---|
| 604 | G_warning(_("Vector map <%s> is 3D. "
|
|---|
| 605 | "Use format specific layer creation options SHPT (parameter 'lco') "
|
|---|
| 606 | "or '-z' flag to export in 3D rather than 2D (default)"),
|
|---|
| 607 | options.input->answer);
|
|---|
| 608 | }
|
|---|
| 609 | }
|
|---|
| 610 | /* specific check for PostgreSQL */
|
|---|
| 611 | else if (strcmp(options.format->answer, "PostgreSQL") == 0) {
|
|---|
| 612 | const char *dim;
|
|---|
| 613 |
|
|---|
| 614 | dim = CSLFetchNameValue(papszLCO, "DIM");
|
|---|
| 615 | if (!dim || strcmp(dim, "3") != 0) {
|
|---|
| 616 | G_warning(_("Vector map <%s> is 3D. "
|
|---|
| 617 | "Use format specific layer creation options DIM (parameter 'lco') "
|
|---|
| 618 | "to export in 3D rather than 2D (default)."),
|
|---|
| 619 | options.input->answer);
|
|---|
| 620 | }
|
|---|
| 621 | }
|
|---|
| 622 | else {
|
|---|
| 623 | G_warning(_("Vector map <%s> is 3D. "
|
|---|
| 624 | "Use format specific layer creation options (parameter 'lco') "
|
|---|
| 625 | "to export <in 3D rather than 2D (default)."),
|
|---|
| 626 | options.input->answer);
|
|---|
| 627 | }
|
|---|
| 628 | }
|
|---|
| 629 |
|
|---|
| 630 | G_debug(1, "Create OGR layer");
|
|---|
| 631 | #if GDAL_VERSION_NUM >= 2020000
|
|---|
| 632 | if (flags.append->answer)
|
|---|
| 633 | Ogr_layer = GDALDatasetGetLayerByName(hDS, options.layer->answer);
|
|---|
| 634 | else
|
|---|
| 635 | Ogr_layer = GDALDatasetCreateLayer(hDS, options.layer->answer,
|
|---|
| 636 | Ogr_projection, wkbtype,
|
|---|
| 637 | papszLCO);
|
|---|
| 638 | #else
|
|---|
| 639 | if (flags.append->answer)
|
|---|
| 640 | Ogr_layer = OGR_DS_GetLayerByName(hDS, options.layer->answer);
|
|---|
| 641 | else
|
|---|
| 642 | Ogr_layer = OGR_DS_CreateLayer(hDS, options.layer->answer,
|
|---|
| 643 | Ogr_projection, wkbtype,
|
|---|
| 644 | papszLCO);
|
|---|
| 645 | #endif
|
|---|
| 646 |
|
|---|
| 647 | CSLDestroy(papszLCO);
|
|---|
| 648 | if (Ogr_layer == NULL) {
|
|---|
| 649 | if (flags.append->answer)
|
|---|
| 650 | G_fatal_error(_("OGR layer <%s> not found"), options.layer->answer);
|
|---|
| 651 | else
|
|---|
| 652 | G_fatal_error(_("Unable to create OGR layer"));
|
|---|
| 653 | }
|
|---|
| 654 |
|
|---|
| 655 | db_init_string(&dbstring);
|
|---|
| 656 |
|
|---|
| 657 | /* Vector attributes -> OGR fields */
|
|---|
| 658 | if (field > 0) {
|
|---|
| 659 | G_debug(1, "Create attribute table");
|
|---|
| 660 | doatt = 1; /* do attributes */
|
|---|
| 661 | Fi = Vect_get_field(&In, field);
|
|---|
| 662 | if (Fi == NULL) {
|
|---|
| 663 | char create_field = TRUE;
|
|---|
| 664 | G_warning(_("No attribute table found -> using only category numbers as attributes"));
|
|---|
| 665 | /* if we have no more than a 'cat' column, then that has to
|
|---|
| 666 | be exported in any case */
|
|---|
| 667 | if (flags.nocat->answer) {
|
|---|
| 668 | G_warning(_("Exporting 'cat' anyway, as it is the only attribute table field"));
|
|---|
| 669 | flags.nocat->answer = FALSE;
|
|---|
| 670 | }
|
|---|
| 671 |
|
|---|
| 672 | if (flags.append->answer) {
|
|---|
| 673 | Ogr_field = OGR_L_GetLayerDefn(Ogr_layer);
|
|---|
| 674 | if (OGR_FD_GetFieldIndex(Ogr_field, GV_KEY_COLUMN) > -1)
|
|---|
| 675 | create_field = FALSE;
|
|---|
| 676 | else
|
|---|
| 677 | G_warning(_("New attribute column <%s> added to the table"),
|
|---|
| 678 | GV_KEY_COLUMN);
|
|---|
| 679 | }
|
|---|
| 680 |
|
|---|
| 681 | if (create_field) {
|
|---|
| 682 | Ogr_field = OGR_Fld_Create(GV_KEY_COLUMN, OFTInteger);
|
|---|
| 683 | if (OGR_L_CreateField(Ogr_layer, Ogr_field, 0) != OGRERR_NONE)
|
|---|
| 684 | G_fatal_error(_("Unable to create column <%s>"),
|
|---|
| 685 | GV_KEY_COLUMN);
|
|---|
| 686 | OGR_Fld_Destroy(Ogr_field);
|
|---|
| 687 | }
|
|---|
| 688 |
|
|---|
| 689 | doatt = 0;
|
|---|
| 690 | }
|
|---|
| 691 | else {
|
|---|
| 692 | Driver = db_start_driver_open_database(Fi->driver, Fi->database);
|
|---|
| 693 | if (!Driver)
|
|---|
| 694 | G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
|
|---|
| 695 | Fi->database, Fi->driver);
|
|---|
| 696 |
|
|---|
| 697 | db_set_string(&dbstring, Fi->table);
|
|---|
| 698 | if (db_describe_table(Driver, &dbstring, &Table) != DB_OK)
|
|---|
| 699 | G_fatal_error(_("Unable to describe table <%s>"), Fi->table);
|
|---|
| 700 |
|
|---|
| 701 | ncol = db_get_table_number_of_columns(Table);
|
|---|
| 702 | G_debug(2, "ncol = %d", ncol);
|
|---|
| 703 | colctype = G_malloc(ncol * sizeof(int));
|
|---|
| 704 | colname = G_malloc(ncol * sizeof(char *));
|
|---|
| 705 | keycol = -1;
|
|---|
| 706 | for (i = 0; i < ncol; i++) {
|
|---|
| 707 | Column = db_get_table_column(Table, i);
|
|---|
| 708 | colname[i] = G_store(db_get_column_name(Column));
|
|---|
| 709 | colsqltype = db_get_column_sqltype(Column);
|
|---|
| 710 | colctype[i] = db_sqltype_to_Ctype(colsqltype);
|
|---|
| 711 | colwidth = db_get_column_length(Column);
|
|---|
| 712 | G_debug(3, "col %d: %s sqltype=%d ctype=%d width=%d",
|
|---|
| 713 | i, colname[i], colsqltype, colctype[i], colwidth);
|
|---|
| 714 |
|
|---|
| 715 | switch (colctype[i]) {
|
|---|
| 716 | case DB_C_TYPE_INT:
|
|---|
| 717 | ogr_ftype = OFTInteger;
|
|---|
| 718 | break;
|
|---|
| 719 | case DB_C_TYPE_DOUBLE:
|
|---|
| 720 | ogr_ftype = OFTReal;
|
|---|
| 721 | break;
|
|---|
| 722 | case DB_C_TYPE_STRING:
|
|---|
| 723 | ogr_ftype = OFTString;
|
|---|
| 724 | break;
|
|---|
| 725 | case DB_C_TYPE_DATETIME:
|
|---|
| 726 | ogr_ftype = OFTString;
|
|---|
| 727 | break;
|
|---|
| 728 | }
|
|---|
| 729 | G_debug(2, "ogr_ftype = %d", ogr_ftype);
|
|---|
| 730 |
|
|---|
| 731 | strcpy(key1, Fi->key);
|
|---|
| 732 | G_tolcase(key1);
|
|---|
| 733 | strcpy(key2, colname[i]);
|
|---|
| 734 | G_tolcase(key2);
|
|---|
| 735 | if (strcmp(key1, key2) == 0)
|
|---|
| 736 | keycol = i;
|
|---|
| 737 | G_debug(2, "%s x %s -> %s x %s -> keycol = %d", Fi->key,
|
|---|
| 738 | colname[i], key1, key2, keycol);
|
|---|
| 739 |
|
|---|
| 740 | if (flags.nocat->answer &&
|
|---|
| 741 | strcmp(Fi->key, colname[i]) == 0)
|
|---|
| 742 | /* skip export of 'cat' field */
|
|---|
| 743 | continue;
|
|---|
| 744 |
|
|---|
| 745 | if (flags.append->answer) {
|
|---|
| 746 | Ogr_field = OGR_L_GetLayerDefn(Ogr_layer);
|
|---|
| 747 | if (OGR_FD_GetFieldIndex(Ogr_field, colname[i]) > -1)
|
|---|
| 748 | /* skip existing fields */
|
|---|
| 749 | continue;
|
|---|
| 750 | else
|
|---|
| 751 | G_warning(_("New attribute column <%s> added to the table"),
|
|---|
| 752 | colname[i]);
|
|---|
| 753 | }
|
|---|
| 754 |
|
|---|
| 755 | Ogr_field = OGR_Fld_Create(colname[i], ogr_ftype);
|
|---|
| 756 | if (ogr_ftype == OFTString && colwidth > 0)
|
|---|
| 757 | OGR_Fld_SetWidth(Ogr_field, colwidth);
|
|---|
| 758 | if (OGR_L_CreateField(Ogr_layer, Ogr_field, 0) != OGRERR_NONE)
|
|---|
| 759 | G_fatal_error(_("Unable to create column <%s>"),
|
|---|
| 760 | colname[i]);
|
|---|
| 761 |
|
|---|
| 762 | OGR_Fld_Destroy(Ogr_field);
|
|---|
| 763 | }
|
|---|
| 764 | if (keycol == -1)
|
|---|
| 765 | G_fatal_error(_("Key column <%s> not found"), Fi->key);
|
|---|
| 766 | }
|
|---|
| 767 | }
|
|---|
| 768 |
|
|---|
| 769 | Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
|
|---|
| 770 |
|
|---|
| 771 | n_feat = n_nocat = n_noatt = 0;
|
|---|
| 772 |
|
|---|
| 773 | if (OGR_L_TestCapability(Ogr_layer, OLCTransactions))
|
|---|
| 774 | OGR_L_StartTransaction(Ogr_layer);
|
|---|
| 775 |
|
|---|
| 776 | /* export polygons oriented according to OGC simple features standard 1.2.1
|
|---|
| 777 | * outer rings are oriented counter-clockwise (CCW)
|
|---|
| 778 | * inner rings are oriented clockwise (CW) */
|
|---|
| 779 | outer_ring_ccw = 1;
|
|---|
| 780 | /* some formats expect outer rings to be CW and inner rings to be CCW:
|
|---|
| 781 | * ESRI Shapefile, PGeo, FileGDB, OpenFileGDB (all ESRI) */
|
|---|
| 782 | if (strcmp(options.format->answer, "ESRI_Shapefile") == 0 ||
|
|---|
| 783 | strcmp(options.format->answer, "PGeo") == 0 ||
|
|---|
| 784 | strcmp(options.format->answer, "FileGDB") == 0 ||
|
|---|
| 785 | strcmp(options.format->answer, "OpenFileGDB") == 0) {
|
|---|
| 786 | outer_ring_ccw = 0;
|
|---|
| 787 | }
|
|---|
| 788 | G_debug(1, "Format \"%s\", outer ring %s",
|
|---|
| 789 | options.format->answer, (outer_ring_ccw ? "CCW" : "CW"));
|
|---|
| 790 |
|
|---|
| 791 | /* Lines (run always to count features of different type) */
|
|---|
| 792 | if (otype & (GV_POINTS | GV_LINES | GV_KERNEL | GV_FACE)) {
|
|---|
| 793 | G_message(n_("Exporting %d feature...",
|
|---|
| 794 | "Exporting %d features...",
|
|---|
| 795 | Vect_get_num_primitives(&In, otype)),
|
|---|
| 796 | Vect_get_num_primitives(&In, otype));
|
|---|
| 797 |
|
|---|
| 798 | n_feat += export_lines(&In, field, otype, flags.multi->answer ? TRUE : FALSE,
|
|---|
| 799 | donocat, ftype == GV_BOUNDARY ? TRUE : FALSE,
|
|---|
| 800 | Ogr_featuredefn, Ogr_layer,
|
|---|
| 801 | Fi, Driver, ncol, colctype,
|
|---|
| 802 | colname, doatt, flags.nocat->answer ? TRUE : FALSE,
|
|---|
| 803 | &n_noatt, &n_nocat);
|
|---|
| 804 | }
|
|---|
| 805 |
|
|---|
| 806 | /* Areas (run always to count features of different type) */
|
|---|
| 807 | if (Vect_get_num_areas(&In) > 0 && (otype & GV_AREA)) {
|
|---|
| 808 | G_message(n_("Exporting %d area (may take some time)...",
|
|---|
| 809 | "Exporting %d areas (may take some time)...",
|
|---|
| 810 | Vect_get_num_areas(&In)),
|
|---|
| 811 | Vect_get_num_areas(&In));
|
|---|
| 812 |
|
|---|
| 813 | n_feat += export_areas(&In, field, flags.multi->answer ? TRUE : FALSE, donocat,
|
|---|
| 814 | Ogr_featuredefn, Ogr_layer,
|
|---|
| 815 | Fi, Driver, ncol, colctype,
|
|---|
| 816 | colname, doatt, flags.nocat->answer ? TRUE : FALSE,
|
|---|
| 817 | &n_noatt, &n_nocat, outer_ring_ccw);
|
|---|
| 818 | }
|
|---|
| 819 |
|
|---|
| 820 | /*
|
|---|
| 821 | TODO: Volumes. Do not export kernels here, that's already done.
|
|---|
| 822 | We do need to worry about holes, though. NOTE: We can probably
|
|---|
| 823 | just merge this with faces export function. Except for GRASS,
|
|---|
| 824 | which output format would know the difference?
|
|---|
| 825 | */
|
|---|
| 826 | if (Vect_get_num_volumes(&In) > 0 && (otype & GV_VOLUME)) {
|
|---|
| 827 | G_message(n_("Exporting %d volume...",
|
|---|
| 828 | "Exporting %d volumes...",
|
|---|
| 829 | Vect_get_num_volumes(&In)),
|
|---|
| 830 | Vect_get_num_volumes(&In));
|
|---|
| 831 | G_warning(_("Export of volumes not implemented yet. Skipping."));
|
|---|
| 832 | }
|
|---|
| 833 |
|
|---|
| 834 | if (OGR_L_TestCapability(Ogr_layer, OLCTransactions))
|
|---|
| 835 | OGR_L_CommitTransaction(Ogr_layer);
|
|---|
| 836 |
|
|---|
| 837 | ds_close(hDS);
|
|---|
| 838 |
|
|---|
| 839 | Vect_close(&In);
|
|---|
| 840 |
|
|---|
| 841 | if (doatt) {
|
|---|
| 842 | db_close_database(Driver);
|
|---|
| 843 | db_shutdown_driver(Driver);
|
|---|
| 844 | }
|
|---|
| 845 |
|
|---|
| 846 | /* Summary */
|
|---|
| 847 | if (n_noatt > 0)
|
|---|
| 848 | G_important_message(n_("%d feature without attributes was written",
|
|---|
| 849 | "%d features without attributes were written",
|
|---|
| 850 | n_noatt), n_noatt);
|
|---|
| 851 |
|
|---|
| 852 | if (n_nocat > 0) {
|
|---|
| 853 | if (donocat)
|
|---|
| 854 | G_important_message(n_("%d feature without category was written",
|
|---|
| 855 | "%d features without category were written",
|
|---|
| 856 | n_nocat), n_nocat);
|
|---|
| 857 | else
|
|---|
| 858 | G_warning(n_("%d feature without category was skipped. "
|
|---|
| 859 | "Features without category are written only when -%c flag is given.",
|
|---|
| 860 | "%d features without category were skipped. "
|
|---|
| 861 | "Features without category are written only when -%c flag is given.",
|
|---|
| 862 | n_nocat), n_nocat, flags.cat->key);
|
|---|
| 863 | }
|
|---|
| 864 |
|
|---|
| 865 | /* Enable this? May be confusing that for area type are not
|
|---|
| 866 | * reported all boundaries/centroids. OTOH why should be
|
|---|
| 867 | * reported? */
|
|---|
| 868 | /*
|
|---|
| 869 | if (((otype & GV_POINTS) || (otype & GV_LINES)) && fskip > 0)
|
|---|
| 870 | G_warning ("%d features of different type skip", fskip);
|
|---|
| 871 | */
|
|---|
| 872 |
|
|---|
| 873 | if (n_feat < 1)
|
|---|
| 874 | G_warning(_("Output layer is empty, no features written"));
|
|---|
| 875 | G_done_msg(n_("%d feature (%s type) written to <%s> (%s format).",
|
|---|
| 876 | "%d features (%s type) written to <%s> (%s format).",
|
|---|
| 877 | n_feat), n_feat,
|
|---|
| 878 | OGRGeometryTypeToName(wkbtype),
|
|---|
| 879 | options.layer->answer, options.format->answer);
|
|---|
| 880 |
|
|---|
| 881 | exit(EXIT_SUCCESS);
|
|---|
| 882 | }
|
|---|