cats.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /**
  2. \file vdigit/cats.cpp
  3. \brief wxvdigit - category management
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. (C) 2008-2009 by Martin Landa, and the GRASS development team
  8. \author Martin Landa <landa.martin gmail.com>
  9. */
  10. extern "C" {
  11. #include <grass/dbmi.h>
  12. }
  13. #include "driver.h"
  14. #include "digit.h"
  15. /**
  16. \brief Initialize cats structure.
  17. \return 0 on success
  18. \return -1 on error
  19. */
  20. int Digit::InitCats()
  21. {
  22. int ndblinks, nfields, field, ncats;
  23. int cat, type, id;
  24. struct field_info *fi;
  25. if (!cats.empty()) {
  26. cats.clear();
  27. }
  28. if (!display->mapInfo) {
  29. /* DisplayMsg(); */
  30. return -1;
  31. }
  32. /* initialization */
  33. ndblinks = Vect_get_num_dblinks(display->mapInfo);
  34. for (int i = 0; i < ndblinks; i++) {
  35. fi = Vect_get_dblink(display->mapInfo, i);
  36. if (fi) {
  37. cats[fi->number] = PORT_INT_MIN;
  38. }
  39. }
  40. /* find max category */
  41. nfields = Vect_cidx_get_num_fields (display->mapInfo);
  42. G_debug(2, "wxDigit.InitCats(): nfields=%d", nfields);
  43. for (int i = 0; i < nfields; i++ ) {
  44. field = Vect_cidx_get_field_number(display->mapInfo, i);
  45. ncats = Vect_cidx_get_num_cats_by_index(display->mapInfo, i);
  46. if (field <= 0) {
  47. continue;
  48. }
  49. for (int j = 0; j < ncats; j++) {
  50. Vect_cidx_get_cat_by_index (display->mapInfo, i, j, &cat, &type, &id);
  51. if (cat > cats[field])
  52. cats[field] = cat;
  53. }
  54. G_debug(3, "wxDigit.InitCats(): layer=%d, cat=%d", field, cats[field]);
  55. }
  56. /* set default values */
  57. for(std::map<int, int>::const_iterator b = cats.begin(), e = cats.end();
  58. b != e; ++b ) {
  59. if (b->second == PORT_INT_MIN) {
  60. cats[b->first] = 0; /* first category 1 */
  61. G_debug(3, "wxDigit.InitCats(): layer=%d, cat=%d", b->first, cats[b->first]);
  62. }
  63. }
  64. return 0;
  65. }
  66. /**
  67. \brief Get max category number for layer
  68. \param layer layer number
  69. \return category number (0 if no category found)
  70. \return -1 on error
  71. */
  72. int Digit::GetCategory(int layer)
  73. {
  74. if (cats.find(layer) != cats.end()) {
  75. G_debug(3, "v.digit.GetCategory(): layer=%d, cat=%d", layer, cats[layer]);
  76. return cats[layer];
  77. }
  78. return 0;
  79. }
  80. /**
  81. \brief Set max category number for layer
  82. \param layer layer number
  83. \param cats category number to be set
  84. \return previously set category
  85. \return -1 if layer not available
  86. */
  87. int Digit::SetCategory(int layer, int cat)
  88. {
  89. int old_cat;
  90. if (cats.find(layer) != cats.end()) {
  91. old_cat = cats[layer];
  92. }
  93. else {
  94. old_cat = -1;
  95. }
  96. cats[layer] = cat;
  97. G_debug(3, "wxDigit.SetCategory(): layer=%d, cat=%d old_cat=%d",
  98. layer, cat, old_cat);
  99. return old_cat;
  100. }
  101. /**
  102. Get list of layers
  103. Requires InitCats() to be called.
  104. \return list of layers
  105. */
  106. std::vector<int> Digit::GetLayers()
  107. {
  108. std::vector<int> layers;
  109. for(std::map<int, int>::const_iterator b = cats.begin(), e = cats.end();
  110. b != e; ++b ) {
  111. layers.push_back(b->first);
  112. }
  113. return layers;
  114. }
  115. /**
  116. \brief Get list of layer/category(ies) for selected feature.
  117. \param line feature id (-1 for first selected feature)
  118. \return list of layer/cats
  119. */
  120. std::map<int, std::vector<int> > Digit::GetLineCats(int line_id)
  121. {
  122. std::map<int, std::vector<int> > lc;
  123. int line;
  124. struct line_cats *Cats;
  125. if (!display->mapInfo) {
  126. display->DisplayMsg();
  127. return lc;
  128. }
  129. if (line_id == -1 && display->selected.ids->n_values < 1) {
  130. /* GetLineCatsMsg(line_id); */
  131. return lc;
  132. }
  133. line = line_id;
  134. if (line_id == -1) {
  135. line = display->selected.ids->value[0];
  136. }
  137. if (!Vect_line_alive(display->mapInfo, line)) {
  138. display->DeadLineMsg(line);
  139. return lc;
  140. }
  141. Cats = Vect_new_cats_struct();
  142. if (Vect_read_line(display->mapInfo, NULL, Cats, line) < 0) {
  143. Vect_destroy_cats_struct(Cats);
  144. display->ReadLineMsg(line);
  145. return lc;
  146. }
  147. for (int i = 0; i < Cats->n_cats; i++) {
  148. if (lc.find(Cats->field[i]) == lc.end()) {
  149. std::vector<int> cats;
  150. lc[Cats->field[i]] = cats;
  151. }
  152. lc[Cats->field[i]].push_back(Cats->cat[i]);
  153. }
  154. Vect_destroy_cats_struct(Cats);
  155. return lc;
  156. }
  157. /**
  158. \brief Set categories for given feature/layer
  159. \param line feature id (-1 for first selected feature)
  160. \param layer layer number
  161. \param cats list of cats
  162. \param add True for add, False for delete
  163. \return new feature id (feature need to be rewritten)
  164. \return -1 on error
  165. */
  166. int Digit::SetLineCats(int line_id, int layer, std::vector<int> cats, bool add)
  167. {
  168. int line, ret, type;
  169. struct line_pnts *Points;
  170. struct line_cats *Cats;
  171. if (!display->mapInfo) {
  172. display->DisplayMsg();
  173. return -1;
  174. }
  175. if (line_id == -1 && display->selected.ids->n_values < 1) {
  176. display->GetLineCatsMsg(line_id);
  177. return -1;
  178. }
  179. if (line_id == -1) {
  180. line = display->selected.ids->value[0];
  181. }
  182. else {
  183. line = line_id;
  184. }
  185. if (!Vect_line_alive(display->mapInfo, line)) {
  186. display->DeadLineMsg(line);
  187. return -1;
  188. }
  189. Points = Vect_new_line_struct();
  190. Cats = Vect_new_cats_struct();
  191. type = Vect_read_line(display->mapInfo, Points, Cats, line);
  192. if (type < 0) {
  193. Vect_destroy_line_struct(Points);
  194. Vect_destroy_cats_struct(Cats);
  195. display->ReadLineMsg(line);
  196. return -1;
  197. }
  198. for (std::vector<int>::const_iterator c = cats.begin(), e = cats.end();
  199. c != e; ++c) {
  200. if (add) {
  201. Vect_cat_set(Cats, layer, *c);
  202. }
  203. else {
  204. Vect_field_cat_del(Cats, layer, *c);
  205. }
  206. G_debug(3, "Digit.SetLineCats(): layer=%d, cat=%d, add=%d",
  207. layer, *c, add);
  208. }
  209. /* register changeset */
  210. // AddActionToChangeset(changesets.size(), REWRITE, display->selected.ids->value[0]);
  211. ret = Vect_rewrite_line(display->mapInfo, line, type,
  212. Points, Cats);
  213. /* TODO
  214. updates feature id (id is changed since line has been rewriten)
  215. if (ret > 0) {
  216. changesets[changesets.size()-1][0].line = ret;
  217. }
  218. else {
  219. changesets.erase(changesets.size()-1);
  220. }
  221. */
  222. if (line_id == -1) {
  223. /* update line id since the line was rewritten */
  224. display->selected.ids->value[0] = ret;
  225. }
  226. Vect_destroy_line_struct(Points);
  227. Vect_destroy_cats_struct(Cats);
  228. return ret;
  229. }
  230. /**
  231. \brief Copy categories from one vector feature to other
  232. \param fromId list of 'from' feature ids
  233. \param toId list of 'to' feature ids
  234. \param copyAttrb duplicate attribures instead of copying categories
  235. \return number of modified features
  236. \return -1 on error
  237. */
  238. int Digit::CopyCats(std::vector<int> fromId, std::vector<int> toId, bool copyAttrb)
  239. {
  240. int fline, tline, nlines, type;
  241. int cat;
  242. struct line_pnts *Points;
  243. struct line_cats *Cats_from, *Cats_to;
  244. Points = Vect_new_line_struct();
  245. Cats_from = Vect_new_cats_struct();
  246. Cats_to = Vect_new_cats_struct();
  247. nlines = 0;
  248. for (std::vector<int>::const_iterator fi = fromId.begin(), fe = fromId.end();
  249. fi != fe; ++fi) {
  250. fline = *fi;
  251. if (!Vect_line_alive(display->mapInfo, fline))
  252. continue;
  253. type = Vect_read_line(display->mapInfo, NULL, Cats_from, fline);
  254. if (type < 0) {
  255. display->ReadLineMsg(fline);
  256. return -1;
  257. }
  258. for(std::vector<int>::const_iterator ti = toId.begin(), te = toId.end();
  259. ti != te; ++ti) {
  260. tline = *ti;
  261. if (!Vect_line_alive(display->mapInfo, tline))
  262. continue;
  263. type = Vect_read_line(display->mapInfo, Points, Cats_to, tline);
  264. if (type < 0) {
  265. display->ReadLineMsg(tline);
  266. return -1;
  267. }
  268. for (int i = 0; i < Cats_from->n_cats; i++) {
  269. if (!copyAttrb) {
  270. cat = Cats_from->cat[i]; /* duplicate category */
  271. }
  272. else {
  273. /* duplicate attributes */
  274. struct field_info *fi;
  275. char buf[GSQL_MAX];
  276. dbDriver *driver;
  277. dbHandle handle;
  278. dbCursor cursor;
  279. dbTable *table;
  280. dbColumn *column;
  281. dbValue *value;
  282. dbString stmt, value_string;
  283. int col, ncols;
  284. int more, ctype;
  285. cat = ++cats[Cats_from->field[i]];
  286. fi = Vect_get_field(display->mapInfo, Cats_from->field[i]);
  287. if (fi == NULL) {
  288. display->DblinkMsg(Cats_from->field[i]);
  289. return -1;
  290. }
  291. driver = db_start_driver(fi->driver);
  292. if (driver == NULL) {
  293. display->DbDriverMsg(fi->driver);
  294. return -1;
  295. }
  296. db_init_handle (&handle);
  297. db_set_handle (&handle, fi->database, NULL);
  298. if (db_open_database(driver, &handle) != DB_OK) {
  299. db_shutdown_driver(driver);
  300. display->DbDatabaseMsg(fi->driver, fi->database);
  301. return -1;
  302. }
  303. db_init_string (&stmt);
  304. sprintf (buf, "SELECT * FROM %s WHERE %s=%d",
  305. fi->table, fi->key, Cats_from->cat[i]);
  306. db_set_string(&stmt, buf);
  307. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK) {
  308. db_close_database(driver);
  309. db_shutdown_driver(driver);
  310. display->DbSelectCursorMsg(db_get_string(&stmt));
  311. return -1;
  312. }
  313. table = db_get_cursor_table(&cursor);
  314. ncols = db_get_table_number_of_columns(table);
  315. sprintf(buf, "INSERT INTO %s VALUES (", fi->table);
  316. db_set_string(&stmt, buf);
  317. /* fetch the data */
  318. while (1) {
  319. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
  320. db_close_database(driver);
  321. db_shutdown_driver(driver);
  322. return -1;
  323. }
  324. if (!more)
  325. break;
  326. for (col = 0; col < ncols; col++) {
  327. if (col > 0)
  328. db_append_string(&stmt, ",");
  329. column = db_get_table_column(table, col);
  330. if (strcmp(db_get_column_name(column), fi->key) == 0) {
  331. sprintf(buf, "%d", cat);
  332. db_append_string(&stmt, buf);
  333. continue;
  334. }
  335. value = db_get_column_value(column);
  336. db_convert_column_value_to_string(column, &value_string);
  337. if (db_test_value_isnull(value))
  338. db_append_string(&stmt, "NULL");
  339. else {
  340. ctype = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  341. if (ctype != DB_C_TYPE_STRING)
  342. db_append_string(&stmt, db_get_string(&value_string));
  343. else {
  344. sprintf(buf, "'%s'", db_get_string(&value_string));
  345. db_append_string(&stmt, buf);
  346. }
  347. }
  348. }
  349. }
  350. db_append_string(&stmt, ")");
  351. if (db_execute_immediate (driver, &stmt) != DB_OK ) {
  352. db_close_database(driver);
  353. db_shutdown_driver(driver);
  354. display->DbExecuteMsg(db_get_string(&stmt));
  355. return -1;
  356. }
  357. db_close_database(driver);
  358. db_shutdown_driver(driver);
  359. }
  360. if (Vect_cat_set(Cats_to, Cats_from->field[i], cat) < 1) {
  361. continue;
  362. }
  363. }
  364. if (Vect_rewrite_line(display->mapInfo, tline, type, Points, Cats_to) < 0) {
  365. display->WriteLineMsg();
  366. return -1;
  367. }
  368. G_debug(1, "Digit::CopyCats(): fline=%d, tline=%d", fline, tline);
  369. nlines++;
  370. }
  371. }
  372. Vect_destroy_line_struct(Points);
  373. Vect_destroy_cats_struct(Cats_from);
  374. Vect_destroy_cats_struct(Cats_to);
  375. return nlines;
  376. }