main.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. /****************************************************************
  2. *
  3. * MODULE: v.in.ogr
  4. *
  5. * AUTHOR(S): Radim Blazek
  6. * Markus Neteler (spatial parm, projection support)
  7. * Paul Kelly (projection support)
  8. *
  9. * PURPOSE: Import OGR vectors
  10. *
  11. * COPYRIGHT: (C) 2003, 2011 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General
  14. * Public License (>=v2). Read the file COPYING that
  15. * comes with GRASS for details.
  16. *
  17. * TODO: - make fixed field length of OFTIntegerList dynamic
  18. * - several other TODOs below
  19. **************************************************************/
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <grass/gis.h>
  23. #include <grass/dbmi.h>
  24. #include <grass/vector.h>
  25. #include <grass/gprojects.h>
  26. #include <grass/glocale.h>
  27. #include <gdal_version.h> /* needed for OFTDate */
  28. #include "ogr_api.h"
  29. #include "global.h"
  30. #ifndef MAX
  31. # define MIN(a,b) ((a<b) ? a : b)
  32. # define MAX(a,b) ((a>b) ? a : b)
  33. #endif
  34. int n_polygons;
  35. int n_polygon_boundaries;
  36. double split_distance;
  37. int geom(OGRGeometryH hGeom, struct Map_info *Map, int field, int cat,
  38. double min_area, int type, int mk_centr);
  39. int centroid(OGRGeometryH hGeom, CENTR * Centr, struct spatial_index * Sindex,
  40. int field, int cat, double min_area, int type);
  41. int poly_count(OGRGeometryH hGeom, int line2boundary);
  42. int main(int argc, char *argv[])
  43. {
  44. struct GModule *module;
  45. struct _param {
  46. struct Option *dsn, *out, *layer, *spat, *where,
  47. *min_area;
  48. struct Option *snap, *type, *outloc, *cnames;
  49. } param;
  50. struct _flag {
  51. struct Flag *list, *tlist, *no_clean, *z, *notab,
  52. *region;
  53. struct Flag *over, *extend, *formats, *tolower, *no_import;
  54. } flag;
  55. int i, j, layer, arg_s_num, nogeom, ncnames;
  56. float xmin, ymin, xmax, ymax;
  57. int ncols = 0, type;
  58. double min_area, snap;
  59. char buf[2000], namebuf[2000], tempvect[GNAME_MAX];
  60. char *separator;
  61. struct Key_Value *loc_proj_info, *loc_proj_units;
  62. struct Key_Value *proj_info, *proj_units;
  63. struct Cell_head cellhd, loc_wind, cur_wind;
  64. char error_msg[8192];
  65. /* Vector */
  66. struct Map_info Map, Tmp, *Out;
  67. int cat;
  68. /* Attributes */
  69. struct field_info *Fi;
  70. dbDriver *driver;
  71. dbString sql, strval;
  72. int dim, with_z;
  73. /* OGR */
  74. OGRDataSourceH Ogr_ds;
  75. OGRLayerH Ogr_layer;
  76. OGRFieldDefnH Ogr_field;
  77. char *Ogr_fieldname;
  78. OGRFieldType Ogr_ftype;
  79. OGRFeatureH Ogr_feature;
  80. OGRFeatureDefnH Ogr_featuredefn;
  81. OGRGeometryH Ogr_geometry, Ogr_oRing, poSpatialFilter;
  82. OGRSpatialReferenceH Ogr_projection;
  83. OGREnvelope oExt;
  84. OGRwkbGeometryType Ogr_geom_type;
  85. int OFTIntegerListlength;
  86. char *output;
  87. char **layer_names; /* names of layers to be imported */
  88. int *layers; /* layer indexes */
  89. int nlayers; /* number of layers to import */
  90. char **available_layer_names; /* names of layers to be imported */
  91. int navailable_layers;
  92. int layer_id;
  93. unsigned int n_features, feature_count;
  94. int overwrite;
  95. double area_size;
  96. int use_tmp_vect;
  97. xmin = ymin = xmax = ymax = 0.0;
  98. loc_proj_info = loc_proj_units = NULL;
  99. Ogr_ds = Ogr_oRing = poSpatialFilter = NULL;
  100. OFTIntegerListlength = 40; /* hack due to limitation in OGR */
  101. area_size = 0.0;
  102. use_tmp_vect = FALSE;
  103. G_gisinit(argv[0]);
  104. module = G_define_module();
  105. G_add_keyword(_("vector"));
  106. G_add_keyword(_("import"));
  107. module->description = _("Converts vector data into a GRASS vector map using OGR library.");
  108. param.dsn = G_define_option();
  109. param.dsn->key = "dsn";
  110. param.dsn->type = TYPE_STRING;
  111. param.dsn->required =YES;
  112. param.dsn->label = _("OGR datasource name");
  113. param.dsn->description = _("Examples:\n"
  114. "\t\tESRI Shapefile: directory containing shapefiles\n"
  115. "\t\tMapInfo File: directory containing mapinfo files");
  116. param.layer = G_define_option();
  117. param.layer->key = "layer";
  118. param.layer->type = TYPE_STRING;
  119. param.layer->required = NO;
  120. param.layer->multiple = YES;
  121. param.layer->label =
  122. _("OGR layer name. If not given, all available layers are imported");
  123. param.layer->description =
  124. _("Examples:\n" "\t\tESRI Shapefile: shapefile name\n"
  125. "\t\tMapInfo File: mapinfo file name");
  126. param.layer->guisection = _("Selection");
  127. param.out = G_define_standard_option(G_OPT_V_OUTPUT);
  128. param.out->required = NO;
  129. param.out->guisection = _("Output");
  130. param.spat = G_define_option();
  131. param.spat->key = "spatial";
  132. param.spat->type = TYPE_DOUBLE;
  133. param.spat->multiple = YES;
  134. param.spat->required = NO;
  135. param.spat->key_desc = "xmin,ymin,xmax,ymax";
  136. param.spat->label = _("Import subregion only");
  137. param.spat->guisection = _("Selection");
  138. param.spat->description =
  139. _("Format: xmin,ymin,xmax,ymax - usually W,S,E,N");
  140. param.where = G_define_standard_option(G_OPT_DB_WHERE);
  141. param.where->guisection = _("Selection");
  142. param.min_area = G_define_option();
  143. param.min_area->key = "min_area";
  144. param.min_area->type = TYPE_DOUBLE;
  145. param.min_area->required = NO;
  146. param.min_area->answer = "0.0001";
  147. param.min_area->label =
  148. _("Minimum size of area to be imported (square units)");
  149. param.min_area->guisection = _("Selection");
  150. param.min_area->description = _("Smaller areas and "
  151. "islands are ignored. Should be greater than snap^2");
  152. param.type = G_define_standard_option(G_OPT_V_TYPE);
  153. param.type->options = "point,line,boundary,centroid";
  154. param.type->answer = "";
  155. param.type->description = _("Optionally change default input type");
  156. param.type->descriptions =
  157. _("point;import area centroids as points;"
  158. "line;import area boundaries as lines;"
  159. "boundary;import lines as area boundaries;"
  160. "centroid;import points as centroids");
  161. param.type->guisection = _("Selection");
  162. param.snap = G_define_option();
  163. param.snap->key = "snap";
  164. param.snap->type = TYPE_DOUBLE;
  165. param.snap->required = NO;
  166. param.snap->answer = "-1";
  167. param.snap->label = _("Snapping threshold for boundaries");
  168. param.snap->description = _("'-1' for no snap");
  169. param.outloc = G_define_option();
  170. param.outloc->key = "location";
  171. param.outloc->type = TYPE_STRING;
  172. param.outloc->required = NO;
  173. param.outloc->description = _("Name for new location to create");
  174. param.outloc->key_desc = "name";
  175. param.cnames = G_define_option();
  176. param.cnames->key = "cnames";
  177. param.cnames->type = TYPE_STRING;
  178. param.cnames->required = NO;
  179. param.cnames->multiple = YES;
  180. param.cnames->description =
  181. _("List of column names to be used instead of original names, "
  182. "first is used for category column");
  183. param.cnames->guisection = _("Attributes");
  184. flag.list = G_define_flag();
  185. flag.list->key = 'l';
  186. flag.list->description = _("List available OGR layers in data source and exit");
  187. flag.list->suppress_required = YES;
  188. flag.list->guisection = _("Print");
  189. flag.tlist = G_define_flag();
  190. flag.tlist->key = 'a';
  191. flag.tlist->description = _("List available OGR layers including feature types "
  192. "in data source and exit");
  193. flag.tlist->suppress_required = YES;
  194. flag.tlist->guisection = _("Print");
  195. flag.formats = G_define_flag();
  196. flag.formats->key = 'f';
  197. flag.formats->description = _("List supported formats and exit");
  198. flag.formats->suppress_required = YES;
  199. flag.formats->guisection = _("Print");
  200. /* if using -c, you lose topological information ! */
  201. flag.no_clean = G_define_flag();
  202. flag.no_clean->key = 'c';
  203. flag.no_clean->description = _("Do not clean polygons (not recommended)");
  204. flag.no_clean->guisection = _("Output");
  205. flag.z = G_define_flag();
  206. flag.z->key = 'z';
  207. flag.z->description = _("Create 3D output");
  208. flag.z->guisection = _("Output");
  209. flag.notab = G_define_flag();
  210. flag.notab->key = 't';
  211. flag.notab->description = _("Do not create attribute table");
  212. flag.notab->guisection = _("Attributes");
  213. flag.over = G_define_flag();
  214. flag.over->key = 'o';
  215. flag.over->description =
  216. _("Override dataset projection (use location's projection)");
  217. flag.region = G_define_flag();
  218. flag.region->key = 'r';
  219. flag.region->guisection = _("Selection");
  220. flag.region->description = _("Limit import to the current region");
  221. flag.extend = G_define_flag();
  222. flag.extend->key = 'e';
  223. flag.extend->description =
  224. _("Extend location extents based on new dataset");
  225. flag.tolower = G_define_flag();
  226. flag.tolower->key = 'w';
  227. flag.tolower->description =
  228. _("Change column names to lowercase characters");
  229. flag.tolower->guisection = _("Attributes");
  230. flag.no_import = G_define_flag();
  231. flag.no_import->key = 'i';
  232. flag.no_import->description =
  233. _("Create the location specified by the \"location\" parameter and exit."
  234. " Do not import the vector data.");
  235. /* The parser checks if the map already exists in current mapset, this is
  236. * wrong if location options is used, so we switch out the check and do it
  237. * in the module after the parser */
  238. overwrite = G_check_overwrite(argc, argv);
  239. if (G_parser(argc, argv))
  240. exit(EXIT_FAILURE);
  241. G_begin_polygon_area_calculations(); /* Used in geom() */
  242. OGRRegisterAll();
  243. /* list supported formats */
  244. if (flag.formats->answer) {
  245. int iDriver;
  246. G_message(_("Available OGR Drivers:"));
  247. for (iDriver = 0; iDriver < OGRGetDriverCount(); iDriver++) {
  248. OGRSFDriverH poDriver = OGRGetDriver(iDriver);
  249. const char *pszRWFlag;
  250. if (OGR_Dr_TestCapability(poDriver, ODrCCreateDataSource))
  251. pszRWFlag = "rw";
  252. else
  253. pszRWFlag = "ro";
  254. fprintf(stdout, " %s (%s): %s\n",
  255. OGR_Dr_GetName(poDriver),
  256. pszRWFlag, OGR_Dr_GetName(poDriver));
  257. }
  258. exit(EXIT_SUCCESS);
  259. }
  260. if (param.dsn->answer == NULL) {
  261. G_fatal_error(_("Required parameter <%s> not set"), param.dsn->key);
  262. }
  263. min_area = atof(param.min_area->answer);
  264. snap = atof(param.snap->answer);
  265. type = Vect_option_to_types(param.type);
  266. ncnames = 0;
  267. if (param.cnames->answers) {
  268. i = 0;
  269. while (param.cnames->answers[i++]) {
  270. ncnames++;
  271. }
  272. }
  273. /* Open OGR DSN */
  274. Ogr_ds = NULL;
  275. if (strlen(param.dsn->answer) > 0)
  276. Ogr_ds = OGROpen(param.dsn->answer, FALSE, NULL);
  277. if (Ogr_ds == NULL)
  278. G_fatal_error(_("Unable to open data source <%s>"), param.dsn->answer);
  279. /* Make a list of available layers */
  280. navailable_layers = OGR_DS_GetLayerCount(Ogr_ds);
  281. available_layer_names =
  282. (char **)G_malloc(navailable_layers * sizeof(char *));
  283. if (flag.list->answer || flag.tlist->answer)
  284. G_message(_("Data source <%s> (format '%s') contains %d layers:"),
  285. param.dsn->answer,
  286. OGR_Dr_GetName(OGR_DS_GetDriver(Ogr_ds)), navailable_layers);
  287. for (i = 0; i < navailable_layers; i++) {
  288. Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i);
  289. Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
  290. Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
  291. available_layer_names[i] =
  292. G_store((char *)OGR_FD_GetName(Ogr_featuredefn));
  293. if (flag.tlist->answer)
  294. fprintf(stdout, "%s (%s)\n", available_layer_names[i],
  295. OGRGeometryTypeToName(Ogr_geom_type));
  296. else if (flag.list->answer)
  297. fprintf(stdout, "%s\n", available_layer_names[i]);
  298. }
  299. if (flag.list->answer || flag.tlist->answer) {
  300. fflush(stdout);
  301. exit(EXIT_SUCCESS);
  302. }
  303. /* Make a list of layers to be imported */
  304. if (param.layer->answer) { /* From option */
  305. nlayers = 0;
  306. while (param.layer->answers[nlayers])
  307. nlayers++;
  308. layer_names = (char **)G_malloc(nlayers * sizeof(char *));
  309. layers = (int *)G_malloc(nlayers * sizeof(int));
  310. for (i = 0; i < nlayers; i++) {
  311. layer_names[i] = G_store(param.layer->answers[i]);
  312. /* Find it in the source */
  313. layers[i] = -1;
  314. for (j = 0; j < navailable_layers; j++) {
  315. if (strcmp(available_layer_names[j], layer_names[i]) == 0) {
  316. layers[i] = j;
  317. break;
  318. }
  319. }
  320. if (layers[i] == -1)
  321. G_fatal_error(_("Layer <%s> not available"), layer_names[i]);
  322. }
  323. }
  324. else { /* use list of all layers */
  325. nlayers = navailable_layers;
  326. layer_names = available_layer_names;
  327. layers = (int *)G_malloc(nlayers * sizeof(int));
  328. for (i = 0; i < nlayers; i++)
  329. layers[i] = i;
  330. }
  331. if (param.out->answer) {
  332. output = G_store(param.out->answer);
  333. }
  334. else {
  335. if (nlayers < 1)
  336. G_fatal_error(_("No OGR layers available"));
  337. output = G_store(layer_names[0]);
  338. G_message(_("All available OGR layers will be imported into vector map <%s>"), output);
  339. }
  340. if (!param.outloc->answer) { /* Check if the map exists */
  341. if (G_find_vector2(output, G_mapset()) && !overwrite)
  342. G_fatal_error(_("Vector map <%s> already exists"),
  343. output);
  344. }
  345. /* Get first imported layer to use for extents and projection check */
  346. Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layers[0]);
  347. if (flag.region->answer) {
  348. if (param.spat->answer)
  349. G_fatal_error(_("Select either the current region flag or the spatial option, not both"));
  350. G_get_window(&cur_wind);
  351. xmin = cur_wind.west;
  352. xmax = cur_wind.east;
  353. ymin = cur_wind.south;
  354. ymax = cur_wind.north;
  355. }
  356. if (param.spat->answer) {
  357. /* See as reference: gdal/ogr/ogr_capi_test.c */
  358. /* cut out a piece of the map */
  359. /* order: xmin,ymin,xmax,ymax */
  360. arg_s_num = 0;
  361. i = 0;
  362. while (param.spat->answers[i]) {
  363. if (i == 0)
  364. xmin = atof(param.spat->answers[i]);
  365. if (i == 1)
  366. ymin = atof(param.spat->answers[i]);
  367. if (i == 2)
  368. xmax = atof(param.spat->answers[i]);
  369. if (i == 3)
  370. ymax = atof(param.spat->answers[i]);
  371. arg_s_num++;
  372. i++;
  373. }
  374. if (arg_s_num != 4)
  375. G_fatal_error(_("4 parameters required for 'spatial' parameter"));
  376. }
  377. if (param.spat->answer || flag.region->answer) {
  378. G_debug(2, "cut out with boundaries: xmin:%f ymin:%f xmax:%f ymax:%f",
  379. xmin, ymin, xmax, ymax);
  380. /* in theory this could be an irregular polygon */
  381. poSpatialFilter = OGR_G_CreateGeometry(wkbPolygon);
  382. Ogr_oRing = OGR_G_CreateGeometry(wkbLinearRing);
  383. OGR_G_AddPoint(Ogr_oRing, xmin, ymin, 0.0);
  384. OGR_G_AddPoint(Ogr_oRing, xmin, ymax, 0.0);
  385. OGR_G_AddPoint(Ogr_oRing, xmax, ymax, 0.0);
  386. OGR_G_AddPoint(Ogr_oRing, xmax, ymin, 0.0);
  387. OGR_G_AddPoint(Ogr_oRing, xmin, ymin, 0.0);
  388. OGR_G_AddGeometryDirectly(poSpatialFilter, Ogr_oRing);
  389. OGR_L_SetSpatialFilter(Ogr_layer, poSpatialFilter);
  390. }
  391. if (param.where->answer) {
  392. /* select by attribute */
  393. OGR_L_SetAttributeFilter(Ogr_layer, param.where->answer);
  394. }
  395. /* fetch boundaries */
  396. if ((OGR_L_GetExtent(Ogr_layer, &oExt, 1)) == OGRERR_NONE) {
  397. G_get_window(&cellhd);
  398. cellhd.north = oExt.MaxY;
  399. cellhd.south = oExt.MinY;
  400. cellhd.west = oExt.MinX;
  401. cellhd.east = oExt.MaxX;
  402. cellhd.rows = 20; /* TODO - calculate useful values */
  403. cellhd.cols = 20;
  404. cellhd.ns_res = (cellhd.north - cellhd.south) / cellhd.rows;
  405. cellhd.ew_res = (cellhd.east - cellhd.west) / cellhd.cols;
  406. }
  407. else {
  408. cellhd.north = 1.;
  409. cellhd.south = 0.;
  410. cellhd.west = 0.;
  411. cellhd.east = 1.;
  412. cellhd.top = 1.;
  413. cellhd.bottom = 1.;
  414. cellhd.rows = 1;
  415. cellhd.rows3 = 1;
  416. cellhd.cols = 1;
  417. cellhd.cols3 = 1;
  418. cellhd.depths = 1;
  419. cellhd.ns_res = 1.;
  420. cellhd.ns_res3 = 1.;
  421. cellhd.ew_res = 1.;
  422. cellhd.ew_res3 = 1.;
  423. cellhd.tb_res = 1.;
  424. }
  425. /* suppress boundary splitting ? */
  426. if (flag.no_clean->answer) {
  427. split_distance = -1.;
  428. }
  429. else {
  430. split_distance = 0.;
  431. area_size =
  432. sqrt((cellhd.east - cellhd.west) * (cellhd.north - cellhd.south));
  433. }
  434. /* Fetch input map projection in GRASS form. */
  435. proj_info = NULL;
  436. proj_units = NULL;
  437. Ogr_projection = OGR_L_GetSpatialRef(Ogr_layer); /* should not be freed later */
  438. /* Do we need to create a new location? */
  439. if (param.outloc->answer != NULL) {
  440. /* Convert projection information non-interactively as we can't
  441. * assume the user has a terminal open */
  442. if (GPJ_osr_to_grass(&cellhd, &proj_info,
  443. &proj_units, Ogr_projection, 0) < 0) {
  444. G_fatal_error(_("Unable to convert input map projection to GRASS "
  445. "format; cannot create new location."));
  446. }
  447. else {
  448. G_make_location(param.outloc->answer, &cellhd,
  449. proj_info, proj_units, NULL);
  450. G_message(_("Location <%s> created"), param.outloc->answer);
  451. }
  452. /* If the i flag is set, clean up? and exit here */
  453. if(flag.no_import->answer)
  454. {
  455. exit(EXIT_SUCCESS);
  456. }
  457. }
  458. else {
  459. int err = 0;
  460. /* Projection only required for checking so convert non-interactively */
  461. if (GPJ_osr_to_grass(&cellhd, &proj_info,
  462. &proj_units, Ogr_projection, 0) < 0)
  463. G_warning(_("Unable to convert input map projection information to "
  464. "GRASS format for checking"));
  465. /* Does the projection of the current location match the dataset? */
  466. /* G_get_window seems to be unreliable if the location has been changed */
  467. G__get_window(&loc_wind, "", "DEFAULT_WIND", "PERMANENT");
  468. /* fetch LOCATION PROJ info */
  469. if (loc_wind.proj != PROJECTION_XY) {
  470. loc_proj_info = G_get_projinfo();
  471. loc_proj_units = G_get_projunits();
  472. }
  473. if (flag.over->answer) {
  474. cellhd.proj = loc_wind.proj;
  475. cellhd.zone = loc_wind.zone;
  476. G_message(_("Over-riding projection check"));
  477. }
  478. else if (loc_wind.proj != cellhd.proj
  479. || (err =
  480. G_compare_projections(loc_proj_info, loc_proj_units,
  481. proj_info, proj_units)) != TRUE) {
  482. int i_value;
  483. strcpy(error_msg,
  484. _("Projection of dataset does not"
  485. " appear to match current location.\n\n"));
  486. /* TODO: output this info sorted by key: */
  487. if (loc_wind.proj != cellhd.proj || err != -2) {
  488. if (loc_proj_info != NULL) {
  489. strcat(error_msg, _("GRASS LOCATION PROJ_INFO is:\n"));
  490. for (i_value = 0; i_value < loc_proj_info->nitems;
  491. i_value++)
  492. sprintf(error_msg + strlen(error_msg), "%s: %s\n",
  493. loc_proj_info->key[i_value],
  494. loc_proj_info->value[i_value]);
  495. strcat(error_msg, "\n");
  496. }
  497. if (proj_info != NULL) {
  498. strcat(error_msg, _("Import dataset PROJ_INFO is:\n"));
  499. for (i_value = 0; i_value < proj_info->nitems; i_value++)
  500. sprintf(error_msg + strlen(error_msg), "%s: %s\n",
  501. proj_info->key[i_value],
  502. proj_info->value[i_value]);
  503. }
  504. else {
  505. strcat(error_msg, _("Import dataset PROJ_INFO is:\n"));
  506. if (cellhd.proj == PROJECTION_XY)
  507. sprintf(error_msg + strlen(error_msg),
  508. "Dataset proj = %d (unreferenced/unknown)\n",
  509. cellhd.proj);
  510. else if (cellhd.proj == PROJECTION_LL)
  511. sprintf(error_msg + strlen(error_msg),
  512. "Dataset proj = %d (lat/long)\n",
  513. cellhd.proj);
  514. else if (cellhd.proj == PROJECTION_UTM)
  515. sprintf(error_msg + strlen(error_msg),
  516. "Dataset proj = %d (UTM), zone = %d\n",
  517. cellhd.proj, cellhd.zone);
  518. else if (cellhd.proj == PROJECTION_SP)
  519. sprintf(error_msg + strlen(error_msg),
  520. "Dataset proj = %d (State Plane), zone = %d\n",
  521. cellhd.proj, cellhd.zone);
  522. else
  523. sprintf(error_msg + strlen(error_msg),
  524. "Dataset proj = %d (unknown), zone = %d\n",
  525. cellhd.proj, cellhd.zone);
  526. }
  527. }
  528. else {
  529. if (loc_proj_units != NULL) {
  530. strcat(error_msg, "GRASS LOCATION PROJ_UNITS is:\n");
  531. for (i_value = 0; i_value < loc_proj_units->nitems;
  532. i_value++)
  533. sprintf(error_msg + strlen(error_msg), "%s: %s\n",
  534. loc_proj_units->key[i_value],
  535. loc_proj_units->value[i_value]);
  536. strcat(error_msg, "\n");
  537. }
  538. if (proj_units != NULL) {
  539. strcat(error_msg, "Import dataset PROJ_UNITS is:\n");
  540. for (i_value = 0; i_value < proj_units->nitems; i_value++)
  541. sprintf(error_msg + strlen(error_msg), "%s: %s\n",
  542. proj_units->key[i_value],
  543. proj_units->value[i_value]);
  544. }
  545. }
  546. sprintf(error_msg + strlen(error_msg),
  547. _("\nYou can use the -o flag to %s to override this projection check.\n"),
  548. G_program_name());
  549. strcat(error_msg,
  550. _("Consider generating a new location with 'location' parameter"
  551. " from input data set.\n"));
  552. G_fatal_error(error_msg);
  553. }
  554. else {
  555. G_message(_("Projection of input dataset and current location "
  556. "appear to match"));
  557. }
  558. }
  559. db_init_string(&sql);
  560. db_init_string(&strval);
  561. /* open output vector */
  562. /* strip any @mapset from vector output name */
  563. G_find_vector(output, G_mapset());
  564. Vect_open_new(&Map, output, flag.z->answer != 0);
  565. Out = &Map;
  566. n_polygon_boundaries = 0;
  567. if (!flag.no_clean->answer) {
  568. /* check if we need a tmp vector */
  569. /* estimate distance for boundary splitting --> */
  570. for (layer = 0; layer < nlayers; layer++) {
  571. layer_id = layers[layer];
  572. Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id);
  573. Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
  574. n_features = feature_count = 0;
  575. n_features = OGR_L_GetFeatureCount(Ogr_layer, 1);
  576. OGR_L_ResetReading(Ogr_layer);
  577. /* count polygons and isles */
  578. G_message(_("Counting polygons for %d features (OGR layer <%s>)..."),
  579. n_features, layer_names[layer]);
  580. while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) {
  581. G_percent(feature_count++, n_features, 1); /* show something happens */
  582. /* Geometry */
  583. Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature);
  584. if (Ogr_geometry != NULL) {
  585. poly_count(Ogr_geometry, (type & GV_BOUNDARY));
  586. }
  587. OGR_F_Destroy(Ogr_feature);
  588. }
  589. }
  590. G_debug(1, "n polygon boundaries: %d", n_polygon_boundaries);
  591. if (n_polygon_boundaries > 50) {
  592. split_distance =
  593. area_size / log(n_polygon_boundaries);
  594. /* divisor is the handle: increase divisor to decrease split_distance */
  595. split_distance = split_distance / 5.;
  596. G_debug(1, "root of area size: %f", area_size);
  597. G_verbose_message(_("Boundary splitting distance in map units: %G"),
  598. split_distance);
  599. }
  600. /* <-- estimate distance for boundary splitting */
  601. use_tmp_vect = n_polygon_boundaries > 0;
  602. if (use_tmp_vect) {
  603. /* open temporary vector, do the work in the temporary vector
  604. * at the end copy alive lines to output vector
  605. * in case of polygons this reduces the coor file size by a factor of 2 to 5
  606. * only needed when cleaning polygons */
  607. sprintf(tempvect, "%s_tmp", output);
  608. G_verbose_message(_("Using temporary vector <%s>"), tempvect);
  609. Vect_open_new(&Tmp, tempvect, flag.z->answer != 0);
  610. Out = &Tmp;
  611. }
  612. }
  613. Vect_hist_command(&Map);
  614. /* Points and lines are written immediately with categories. Boundaries of polygons are
  615. * written to the vector then cleaned and centroids are calculated for all areas in cleaan vector.
  616. * Then second pass through finds all centroids in each polygon feature and adds its category
  617. * to the centroid. The result is that one centroids may have 0, 1 ore more categories
  618. * of one ore more (more input layers) fields. */
  619. with_z = 0;
  620. for (layer = 0; layer < nlayers; layer++) {
  621. layer_id = layers[layer];
  622. Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id);
  623. Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
  624. /* Add DB link */
  625. if (!flag.notab->answer) {
  626. char *cat_col_name = GV_KEY_COLUMN;
  627. if (nlayers == 1) { /* one layer only */
  628. Fi = Vect_default_field_info(&Map, layer + 1, NULL,
  629. GV_1TABLE);
  630. }
  631. else {
  632. Fi = Vect_default_field_info(&Map, layer + 1, NULL,
  633. GV_MTABLE);
  634. }
  635. if (ncnames > 0) {
  636. cat_col_name = param.cnames->answers[0];
  637. }
  638. Vect_map_add_dblink(&Map, layer + 1, layer_names[layer], Fi->table,
  639. cat_col_name, Fi->database, Fi->driver);
  640. ncols = OGR_FD_GetFieldCount(Ogr_featuredefn);
  641. G_debug(2, "%d columns", ncols);
  642. /* Create table */
  643. sprintf(buf, "create table %s (%s integer", Fi->table,
  644. cat_col_name);
  645. db_set_string(&sql, buf);
  646. for (i = 0; i < ncols; i++) {
  647. Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i);
  648. Ogr_ftype = OGR_Fld_GetType(Ogr_field);
  649. G_debug(3, "Ogr_ftype: %i", Ogr_ftype); /* look up below */
  650. if (i < ncnames - 1) {
  651. Ogr_fieldname = G_store(param.cnames->answers[i + 1]);
  652. }
  653. else {
  654. /* Change column names to [A-Za-z][A-Za-z0-9_]* */
  655. Ogr_fieldname = G_store(OGR_Fld_GetNameRef(Ogr_field));
  656. G_debug(3, "Ogr_fieldname: '%s'", Ogr_fieldname);
  657. G_str_to_sql(Ogr_fieldname);
  658. G_debug(3, "Ogr_fieldname: '%s'", Ogr_fieldname);
  659. }
  660. /* avoid that we get the 'cat' column twice */
  661. if (strcmp(Ogr_fieldname, GV_KEY_COLUMN) == 0) {
  662. sprintf(namebuf, "%s_", Ogr_fieldname);
  663. Ogr_fieldname = G_store(namebuf);
  664. }
  665. /* captial column names are a pain in SQL */
  666. if (flag.tolower->answer)
  667. G_str_to_lower(Ogr_fieldname);
  668. if (strcmp(OGR_Fld_GetNameRef(Ogr_field), Ogr_fieldname) != 0) {
  669. G_warning(_("Column name changed: '%s' -> '%s'"),
  670. OGR_Fld_GetNameRef(Ogr_field), Ogr_fieldname);
  671. }
  672. /** Simple 32bit integer OFTInteger = 0 **/
  673. /** List of 32bit integers OFTIntegerList = 1 **/
  674. /** Double Precision floating point OFTReal = 2 **/
  675. /** List of doubles OFTRealList = 3 **/
  676. /** String of ASCII chars OFTString = 4 **/
  677. /** Array of strings OFTStringList = 5 **/
  678. /** Double byte string (unsupported) OFTWideString = 6 **/
  679. /** List of wide strings (unsupported) OFTWideStringList = 7 **/
  680. /** Raw Binary data (unsupported) OFTBinary = 8 **/
  681. /** OFTDate = 9 **/
  682. /** OFTTime = 10 **/
  683. /** OFTDateTime = 11 **/
  684. if (Ogr_ftype == OFTInteger) {
  685. sprintf(buf, ", %s integer", Ogr_fieldname);
  686. }
  687. else if (Ogr_ftype == OFTIntegerList) {
  688. /* hack: treat as string */
  689. sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname,
  690. OFTIntegerListlength);
  691. G_warning(_("Writing column <%s> with fixed length %d chars (may be truncated)"),
  692. Ogr_fieldname, OFTIntegerListlength);
  693. }
  694. else if (Ogr_ftype == OFTReal) {
  695. sprintf(buf, ", %s double precision", Ogr_fieldname);
  696. #if GDAL_VERSION_NUM >= 1320
  697. }
  698. else if (Ogr_ftype == OFTDate) {
  699. sprintf(buf, ", %s date", Ogr_fieldname);
  700. }
  701. else if (Ogr_ftype == OFTTime) {
  702. sprintf(buf, ", %s time", Ogr_fieldname);
  703. }
  704. else if (Ogr_ftype == OFTDateTime) {
  705. sprintf(buf, ", %s datetime", Ogr_fieldname);
  706. #endif
  707. }
  708. else if (Ogr_ftype == OFTString) {
  709. int fwidth;
  710. fwidth = OGR_Fld_GetWidth(Ogr_field);
  711. /* TODO: read all records first and find the longest string length */
  712. if (fwidth == 0) {
  713. G_warning(_("Width for column %s set to 255 (was not specified by OGR), "
  714. "some strings may be truncated!"),
  715. Ogr_fieldname);
  716. fwidth = 255;
  717. }
  718. sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname,
  719. fwidth);
  720. }
  721. else if (Ogr_ftype == OFTStringList) {
  722. /* hack: treat as string */
  723. sprintf(buf, ", %s varchar ( %d )", Ogr_fieldname,
  724. OFTIntegerListlength);
  725. G_warning(_("Writing column %s with fixed length %d chars (may be truncated)"),
  726. Ogr_fieldname, OFTIntegerListlength);
  727. }
  728. else {
  729. G_warning(_("Column type not supported (%s)"),
  730. Ogr_fieldname);
  731. buf[0] = 0;
  732. }
  733. db_append_string(&sql, buf);
  734. G_free(Ogr_fieldname);
  735. }
  736. db_append_string(&sql, ")");
  737. G_debug(3, db_get_string(&sql));
  738. driver =
  739. db_start_driver_open_database(Fi->driver,
  740. Vect_subst_var(Fi->database,
  741. &Map));
  742. if (driver == NULL) {
  743. G_fatal_error(_("Unable open database <%s> by driver <%s>"),
  744. Vect_subst_var(Fi->database, &Map), Fi->driver);
  745. }
  746. if (db_execute_immediate(driver, &sql) != DB_OK) {
  747. db_close_database(driver);
  748. db_shutdown_driver(driver);
  749. G_fatal_error(_("Unable to create table: '%s'"),
  750. db_get_string(&sql));
  751. }
  752. if (db_create_index2(driver, Fi->table, cat_col_name) != DB_OK)
  753. G_warning(_("Unable to create index for table <%s>, key <%s>"),
  754. Fi->table, cat_col_name);
  755. if (db_grant_on_table
  756. (driver, Fi->table, DB_PRIV_SELECT,
  757. DB_GROUP | DB_PUBLIC) != DB_OK)
  758. G_fatal_error(_("Unable to grant privileges on table <%s>"),
  759. Fi->table);
  760. db_begin_transaction(driver);
  761. }
  762. /* Import feature */
  763. cat = 1;
  764. nogeom = 0;
  765. OGR_L_ResetReading(Ogr_layer);
  766. n_features = feature_count = 0;
  767. n_features = OGR_L_GetFeatureCount(Ogr_layer, 1);
  768. G_important_message(_("Importing %d features (OGR layer <%s>)..."),
  769. n_features, layer_names[layer]);
  770. while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) {
  771. G_percent(feature_count++, n_features, 1); /* show something happens */
  772. /* Geometry */
  773. Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature);
  774. if (Ogr_geometry == NULL) {
  775. nogeom++;
  776. }
  777. else {
  778. dim = OGR_G_GetCoordinateDimension(Ogr_geometry);
  779. if (dim > 2)
  780. with_z = 1;
  781. geom(Ogr_geometry, Out, layer + 1, cat, min_area, type,
  782. flag.no_clean->answer);
  783. }
  784. /* Attributes */
  785. if (!flag.notab->answer) {
  786. sprintf(buf, "insert into %s values ( %d", Fi->table, cat);
  787. db_set_string(&sql, buf);
  788. for (i = 0; i < ncols; i++) {
  789. Ogr_field = OGR_FD_GetFieldDefn(Ogr_featuredefn, i);
  790. Ogr_ftype = OGR_Fld_GetType(Ogr_field);
  791. if (OGR_F_IsFieldSet(Ogr_feature, i)) {
  792. if (Ogr_ftype == OFTInteger || Ogr_ftype == OFTReal) {
  793. sprintf(buf, ", %s",
  794. OGR_F_GetFieldAsString(Ogr_feature, i));
  795. #if GDAL_VERSION_NUM >= 1320
  796. /* should we use OGR_F_GetFieldAsDateTime() here ? */
  797. }
  798. else if (Ogr_ftype == OFTDate || Ogr_ftype == OFTTime
  799. || Ogr_ftype == OFTDateTime) {
  800. char *newbuf;
  801. db_set_string(&strval, (char *)
  802. OGR_F_GetFieldAsString(Ogr_feature,
  803. i));
  804. db_double_quote_string(&strval);
  805. sprintf(buf, ", '%s'", db_get_string(&strval));
  806. newbuf = G_str_replace(buf, "/", "-"); /* fix 2001/10/21 to 2001-10-21 */
  807. sprintf(buf, "%s", newbuf);
  808. #endif
  809. }
  810. else if (Ogr_ftype == OFTString ||
  811. Ogr_ftype == OFTIntegerList) {
  812. db_set_string(&strval, (char *)
  813. OGR_F_GetFieldAsString(Ogr_feature,
  814. i));
  815. db_double_quote_string(&strval);
  816. sprintf(buf, ", '%s'", db_get_string(&strval));
  817. }
  818. }
  819. else {
  820. /* G_warning (_("Column value not set" )); */
  821. if (Ogr_ftype == OFTInteger || Ogr_ftype == OFTReal) {
  822. sprintf(buf, ", NULL");
  823. #if GDAL_VERSION_NUM >= 1320
  824. }
  825. else if (Ogr_ftype == OFTString ||
  826. Ogr_ftype == OFTIntegerList ||
  827. Ogr_ftype == OFTDate) {
  828. #else
  829. }
  830. else if (Ogr_ftype == OFTString ||
  831. Ogr_ftype == OFTIntegerList) {
  832. #endif
  833. sprintf(buf, ", ''");
  834. }
  835. }
  836. db_append_string(&sql, buf);
  837. }
  838. db_append_string(&sql, " )");
  839. G_debug(3, db_get_string(&sql));
  840. if (db_execute_immediate(driver, &sql) != DB_OK) {
  841. db_close_database(driver);
  842. db_shutdown_driver(driver);
  843. G_fatal_error(_("Cannot insert new row: %s"),
  844. db_get_string(&sql));
  845. }
  846. }
  847. OGR_F_Destroy(Ogr_feature);
  848. cat++;
  849. }
  850. G_percent(1, 1, 1); /* finish it */
  851. if (!flag.notab->answer) {
  852. db_commit_transaction(driver);
  853. db_close_database_shutdown_driver(driver);
  854. }
  855. if (nogeom > 0)
  856. G_warning(_("%d %s without geometry"), nogeom,
  857. nogeom == 1 ? "feature" : "features");
  858. }
  859. separator = "-----------------------------------------------------";
  860. G_message("%s", separator);
  861. if (use_tmp_vect) {
  862. /* TODO: is it necessary to build here? probably not, consumes time */
  863. /* GV_BUILD_BASE is sufficient to toggle boundary cleaning */
  864. Vect_build_partial(&Tmp, GV_BUILD_BASE);
  865. }
  866. if (use_tmp_vect && !flag.no_clean->answer &&
  867. Vect_get_num_primitives(Out, GV_BOUNDARY) > 0) {
  868. int ret, centr, ncentr, otype, n_overlaps, n_nocat;
  869. CENTR *Centr;
  870. struct spatial_index si;
  871. double x, y, total_area, overlap_area, nocat_area;
  872. struct bound_box box;
  873. struct line_pnts *Points;
  874. int nmodif;
  875. Points = Vect_new_line_struct();
  876. G_message("%s", separator);
  877. G_warning(_("Cleaning polygons, result is not guaranteed!"));
  878. if (snap >= 0) {
  879. G_message("%s", separator);
  880. G_message(_("Snapping boundaries (threshold = %.3e)..."), snap);
  881. Vect_snap_lines(&Tmp, GV_BOUNDARY, snap, NULL);
  882. }
  883. /* It is not to clean to snap centroids, but I have seen data with 2 duplicate polygons
  884. * (as far as decimal places were printed) and centroids were not identical */
  885. /* Disabled, because overlapping polygons result in many duplicate centroids anyway */
  886. /*
  887. fprintf ( stderr, separator );
  888. fprintf ( stderr, "Snap centroids (threshold 0.000001):\n" );
  889. Vect_snap_lines ( &Map, GV_CENTROID, 0.000001, NULL, stderr );
  890. */
  891. G_message("%s", separator);
  892. G_message(_("Breaking polygons..."));
  893. Vect_break_polygons(&Tmp, GV_BOUNDARY, NULL);
  894. /* It is important to remove also duplicate centroids in case of duplicate input polygons */
  895. G_message("%s", separator);
  896. G_message(_("Removing duplicates..."));
  897. Vect_remove_duplicates(&Tmp, GV_BOUNDARY | GV_CENTROID, NULL);
  898. /* in non-pathological cases, the bulk of the cleaning is now done */
  899. /* Vect_clean_small_angles_at_nodes() can change the geometry so that new intersections
  900. * are created. We must call Vect_break_lines(), Vect_remove_duplicates()
  901. * and Vect_clean_small_angles_at_nodes() until no more small angles are found */
  902. do {
  903. G_message("%s", separator);
  904. G_message(_("Breaking boundaries..."));
  905. Vect_break_lines(&Tmp, GV_BOUNDARY, NULL);
  906. G_message("%s", separator);
  907. G_message(_("Removing duplicates..."));
  908. Vect_remove_duplicates(&Tmp, GV_BOUNDARY, NULL);
  909. G_message("%s", separator);
  910. G_message(_("Cleaning boundaries at nodes..."));
  911. nmodif =
  912. Vect_clean_small_angles_at_nodes(&Tmp, GV_BOUNDARY, NULL);
  913. } while (nmodif > 0);
  914. /* merge boundaries */
  915. G_message("%s", separator);
  916. G_message(_("Merging boundaries..."));
  917. Vect_merge_lines(&Tmp, GV_BOUNDARY, NULL, NULL);
  918. G_message("%s", separator);
  919. if (type & GV_BOUNDARY) { /* that means lines were converted to boundaries */
  920. G_message(_("Changing boundary dangles to lines..."));
  921. Vect_chtype_dangles(&Tmp, -1.0, NULL);
  922. }
  923. else {
  924. G_message(_("Removing dangles..."));
  925. Vect_remove_dangles(&Tmp, GV_BOUNDARY, -1.0, NULL);
  926. }
  927. G_message("%s", separator);
  928. if (type & GV_BOUNDARY) {
  929. G_message(_("Changing boundary bridges to lines..."));
  930. Vect_chtype_bridges(&Tmp, NULL);
  931. }
  932. else {
  933. G_message(_("Removing bridges..."));
  934. Vect_remove_bridges(&Tmp, NULL);
  935. }
  936. /* Boundaries are hopefully clean, build areas */
  937. G_message("%s", separator);
  938. Vect_build_partial(&Tmp, GV_BUILD_ATTACH_ISLES);
  939. /* Calculate new centroids for all areas, centroids have the same id as area */
  940. ncentr = Vect_get_num_areas(&Tmp);
  941. G_debug(3, "%d centroids/areas", ncentr);
  942. Centr = (CENTR *) G_calloc(ncentr + 1, sizeof(CENTR));
  943. Vect_spatial_index_init(&si, 0);
  944. for (centr = 1; centr <= ncentr; centr++) {
  945. Centr[centr].valid = 0;
  946. Centr[centr].cats = Vect_new_cats_struct();
  947. ret = Vect_get_point_in_area(&Tmp, centr, &x, &y);
  948. if (ret < 0) {
  949. G_warning(_("Unable to calculate area centroid"));
  950. continue;
  951. }
  952. Centr[centr].x = x;
  953. Centr[centr].y = y;
  954. Centr[centr].valid = 1;
  955. box.N = box.S = y;
  956. box.E = box.W = x;
  957. box.T = box.B = 0;
  958. Vect_spatial_index_add_item(&si, centr, &box);
  959. }
  960. /* Go through all layers and find centroids for each polygon */
  961. for (layer = 0; layer < nlayers; layer++) {
  962. G_message("%s", separator);
  963. G_message(_("Finding centroids for OGR layer <%s>..."), layer_names[layer]);
  964. layer_id = layers[layer];
  965. Ogr_layer = OGR_DS_GetLayer(Ogr_ds, layer_id);
  966. n_features = OGR_L_GetFeatureCount(Ogr_layer, 1);
  967. OGR_L_ResetReading(Ogr_layer);
  968. cat = 0; /* field = layer + 1 */
  969. G_percent(cat, n_features, 2);
  970. while ((Ogr_feature = OGR_L_GetNextFeature(Ogr_layer)) != NULL) {
  971. cat++;
  972. G_percent(cat, n_features, 2);
  973. /* Geometry */
  974. Ogr_geometry = OGR_F_GetGeometryRef(Ogr_feature);
  975. if (Ogr_geometry != NULL) {
  976. centroid(Ogr_geometry, Centr, &si, layer + 1, cat,
  977. min_area, type);
  978. }
  979. OGR_F_Destroy(Ogr_feature);
  980. }
  981. }
  982. /* Write centroids */
  983. G_message("%s", separator);
  984. G_message(_("Writing centroids..."));
  985. n_overlaps = n_nocat = 0;
  986. total_area = overlap_area = nocat_area = 0.0;
  987. for (centr = 1; centr <= ncentr; centr++) {
  988. double area;
  989. G_percent(centr, ncentr, 2);
  990. area = Vect_get_area_area(&Tmp, centr);
  991. total_area += area;
  992. if (!(Centr[centr].valid)) {
  993. continue;
  994. }
  995. if (Centr[centr].cats->n_cats == 0) {
  996. nocat_area += area;
  997. n_nocat++;
  998. continue;
  999. }
  1000. if (Centr[centr].cats->n_cats > 1) {
  1001. Vect_cat_set(Centr[centr].cats, nlayers + 1,
  1002. Centr[centr].cats->n_cats);
  1003. overlap_area += area;
  1004. n_overlaps++;
  1005. }
  1006. Vect_reset_line(Points);
  1007. Vect_append_point(Points, Centr[centr].x, Centr[centr].y, 0.0);
  1008. if (type & GV_POINT)
  1009. otype = GV_POINT;
  1010. else
  1011. otype = GV_CENTROID;
  1012. Vect_write_line(&Tmp, otype, Points, Centr[centr].cats);
  1013. }
  1014. if (Centr)
  1015. G_free(Centr);
  1016. Vect_spatial_index_destroy(&si);
  1017. if (n_overlaps > 0) {
  1018. G_warning(_("%d areas represent more (overlapping) features, because polygons overlap "
  1019. "in input layer(s). Such areas are linked to more than 1 row in attribute table. "
  1020. "The number of features for those areas is stored as category in layer %d"),
  1021. n_overlaps, nlayers + 1);
  1022. }
  1023. G_message("%s", separator);
  1024. Vect_hist_write(&Map, separator);
  1025. Vect_hist_write(&Map, "\n");
  1026. sprintf(buf, _("%d input polygons\n"), n_polygons);
  1027. G_message(_("%d input polygons"), n_polygons);
  1028. Vect_hist_write(&Map, buf);
  1029. sprintf(buf, _("Total area: %G (%d areas)\n"), total_area, ncentr);
  1030. G_message(_("Total area: %G (%d areas)"), total_area, ncentr);
  1031. Vect_hist_write(&Map, buf);
  1032. sprintf(buf, _("Overlapping area: %G (%d areas)\n"), overlap_area,
  1033. n_overlaps);
  1034. G_message(_("Overlapping area: %G (%d areas)"), overlap_area,
  1035. n_overlaps);
  1036. Vect_hist_write(&Map, buf);
  1037. sprintf(buf, _("Area without category: %G (%d areas)\n"), nocat_area,
  1038. n_nocat);
  1039. G_message(_("Area without category: %G (%d areas)"), nocat_area,
  1040. n_nocat);
  1041. Vect_hist_write(&Map, buf);
  1042. G_message("%s", separator);
  1043. }
  1044. /* needed?
  1045. * OGR_DS_Destroy( Ogr_ds );
  1046. */
  1047. if (use_tmp_vect) {
  1048. /* Copy temporary vector to output vector */
  1049. Vect_copy_map_lines(&Tmp, &Map);
  1050. /* release memory occupied by topo, we may need that memory for main output */
  1051. Vect_set_release_support(&Tmp);
  1052. Vect_close(&Tmp);
  1053. Vect_delete(tempvect);
  1054. }
  1055. Vect_build(&Map);
  1056. Vect_close(&Map);
  1057. /* -------------------------------------------------------------------- */
  1058. /* Extend current window based on dataset. */
  1059. /* -------------------------------------------------------------------- */
  1060. if (flag.extend->answer) {
  1061. G_get_default_window(&loc_wind);
  1062. loc_wind.north = MAX(loc_wind.north, cellhd.north);
  1063. loc_wind.south = MIN(loc_wind.south, cellhd.south);
  1064. loc_wind.west = MIN(loc_wind.west, cellhd.west);
  1065. loc_wind.east = MAX(loc_wind.east, cellhd.east);
  1066. loc_wind.rows = (int)ceil((loc_wind.north - loc_wind.south)
  1067. / loc_wind.ns_res);
  1068. loc_wind.south = loc_wind.north - loc_wind.rows * loc_wind.ns_res;
  1069. loc_wind.cols = (int)ceil((loc_wind.east - loc_wind.west)
  1070. / loc_wind.ew_res);
  1071. loc_wind.east = loc_wind.west + loc_wind.cols * loc_wind.ew_res;
  1072. G__put_window(&loc_wind, "../PERMANENT", "DEFAULT_WIND");
  1073. }
  1074. if (with_z && !flag.z->answer)
  1075. G_warning(_("Input data contains 3D features. Created vector is 2D only, "
  1076. "use -z flag to import 3D vector."));
  1077. exit(EXIT_SUCCESS);
  1078. }