driver_select.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /**
  2. \file vdigit/driver_select.cpp
  3. \brief wxvdigit - Display driver (selection methods)
  4. This driver is designed for wxGUI (vector digitizer) - to draw
  5. vector map layer to PseudoDC.
  6. This program is free software under the GNU General Public
  7. License (>=v2). Read the file COPYING that comes with GRASS
  8. for details.
  9. (C) 2008-2009 by Martin Landa, and the GRASS development team
  10. \author Martin Landa <landa.martin gmail.com>
  11. */
  12. #include <cmath>
  13. #include "driver.h"
  14. /**
  15. \brief Select vector objects by given bounding box
  16. If line id is already in the list of selected lines, then it will
  17. be excluded from this list.
  18. \param[in] x1,y1,z1,x2,y2,z3 bounding box definition
  19. \param[in] type feature type
  20. \param[in] onlyInside if true select only features inside
  21. of bounding box (not overlapping)
  22. \return number of selected features
  23. \return -1 on error
  24. */
  25. int DisplayDriver::SelectLinesByBox(double x1, double y1, double z1,
  26. double x2, double y2, double z2,
  27. int type, bool onlyInside, bool drawSeg)
  28. {
  29. if (!mapInfo)
  30. return -1;
  31. int line;
  32. struct ilist *list;
  33. struct line_pnts *bbox;
  34. drawSegments = drawSeg;
  35. drawSelected = true;
  36. /* select by ids */
  37. Vect_reset_list(selected.cats);
  38. list = Vect_new_list();
  39. bbox = Vect_new_line_struct();
  40. Vect_append_point(bbox, x1, y1, z1);
  41. Vect_append_point(bbox, x2, y1, z2);
  42. Vect_append_point(bbox, x2, y2, z1);
  43. Vect_append_point(bbox, x1, y2, z2);
  44. Vect_append_point(bbox, x1, y1, z1);
  45. Vect_select_lines_by_polygon(mapInfo, bbox,
  46. 0, NULL, /* isles */
  47. type, list);
  48. for (int i = 0; i < list->n_values; i++) {
  49. line = list->value[i];
  50. if (onlyInside) {
  51. bool inside;
  52. inside = true;
  53. Vect_read_line(mapInfo, points, cats, line);
  54. for (int p = 0; p < points->n_points; p++) {
  55. if (!Vect_point_in_poly(points->x[p], points->y[p],
  56. bbox)) {
  57. inside = false;
  58. break;
  59. }
  60. }
  61. if (!inside)
  62. continue; /* skip lines just overlapping bbox */
  63. }
  64. if (!IsSelected(line)) {
  65. Vect_list_append(selected.ids, line);
  66. }
  67. else {
  68. Vect_list_delete(selected.ids, line);
  69. }
  70. }
  71. Vect_destroy_line_struct(bbox);
  72. Vect_destroy_list(list);
  73. return list->n_values;
  74. }
  75. /**
  76. \brief Select vector feature by given point in given
  77. threshold
  78. Only one vector object can be selected. Bounding boxes of
  79. all segments are stores.
  80. \param[in] x,y point of searching
  81. \param[in] thresh threshold value where to search
  82. \param[in] type select vector object of given type
  83. \return point on line if line found
  84. */
  85. std::vector<double> DisplayDriver::SelectLineByPoint(double x, double y, double z,
  86. double thresh, int type, int with_z)
  87. {
  88. long int line, line_nearest;
  89. double px, py, pz;
  90. std::vector<double> p;
  91. struct ilist *found;
  92. found = Vect_new_list();
  93. drawSelected = true;
  94. /* select by ids */
  95. Vect_reset_list(selected.cats);
  96. line_nearest = Vect_find_line_list(mapInfo, x, y, z,
  97. type, thresh, with_z,
  98. NULL, found);
  99. if (line_nearest > 0) {
  100. if (!IsSelected(line_nearest)) {
  101. Vect_list_append(selected.ids, line_nearest);
  102. }
  103. else {
  104. Vect_list_delete(selected.ids, line_nearest);
  105. }
  106. type = Vect_read_line (mapInfo, points, cats, line_nearest);
  107. Vect_line_distance (points, x, y, z, with_z,
  108. &px, &py, &pz,
  109. NULL, NULL, NULL);
  110. p.push_back(px);
  111. p.push_back(py);
  112. if (with_z) {
  113. p.push_back(pz);
  114. }
  115. /* check for duplicates */
  116. if (settings.highlightDupl.enabled) {
  117. for (int i = 0; i < found->n_values; i++) {
  118. line = found->value[i];
  119. if (line != line_nearest) {
  120. Vect_list_append(selected.ids, found->value[i]);
  121. }
  122. }
  123. GetDuplicates();
  124. for (int i = 0; i < found->n_values; i++) {
  125. line = found->value[i];
  126. if (line != line_nearest && !IsDuplicated(line)) {
  127. Vect_list_delete(selected.ids, line);
  128. }
  129. }
  130. }
  131. }
  132. Vect_destroy_list(found);
  133. // drawing segments can be very expensive
  134. // only one features selected
  135. drawSegments = true;
  136. return p;
  137. }
  138. /**
  139. \brief Is vector object selected?
  140. \param[in] line id
  141. \return true if vector object is selected
  142. \return false if vector object is not selected
  143. */
  144. bool DisplayDriver::IsSelected(int line, bool force)
  145. {
  146. if (selected.cats->n_values < 1 || force) {
  147. /* select by id */
  148. if (Vect_val_in_list(selected.ids, line)) {
  149. return true;
  150. }
  151. }
  152. else { /* select by cat */
  153. for (int i = 0; i < cats->n_cats; i++) {
  154. if (cats->field[i] == selected.field &&
  155. Vect_val_in_list(selected.cats, cats->cat[i])) {
  156. /* remember id
  157. -> after drawing all features selected.cats is reseted */
  158. Vect_list_append(selected.ids, line);
  159. return true;
  160. }
  161. }
  162. }
  163. return false;
  164. }
  165. /**
  166. \brief Get ids of selected objects
  167. \param[in] grassId if true return GRASS line ids
  168. if false return PseudoDC ids
  169. \return list of ids of selected vector objects
  170. */
  171. std::vector<int> DisplayDriver::GetSelected(bool grassId)
  172. {
  173. if (grassId)
  174. return ListToVector(selected.ids);
  175. std::vector<int> dc_ids;
  176. if (!drawSegments) {
  177. dc_ids.push_back(1);
  178. }
  179. else {
  180. // only first selected feature !
  181. int npoints;
  182. Vect_read_line(mapInfo, points, NULL, selected.ids->value[0]);
  183. npoints = points->n_points;
  184. // node - segment - vertex - segment - node
  185. for (int i = 1; i < 2 * npoints; i++) {
  186. dc_ids.push_back(i);
  187. }
  188. }
  189. return dc_ids;
  190. }
  191. std::map<int, std::vector<double> > DisplayDriver::GetSelectedCoord()
  192. {
  193. std::map<int, std::vector<double> > ret;
  194. int id, npoints;
  195. id = 1;
  196. for (int is = 0; is < selected.ids->n_values; is++) {
  197. if (Vect_read_line(mapInfo, points, NULL, selected.ids->value[is]) < 0) {
  198. ReadLineMsg(selected.ids->value[is]);
  199. return ret;
  200. }
  201. npoints = points->n_points;
  202. for (int i = 0; i < points->n_points; i++, id += 2) {
  203. std::vector<double> c;
  204. c.push_back(points->x[i]);
  205. c.push_back(points->y[i]);
  206. c.push_back(points->z[i]);
  207. ret[id] = c;
  208. }
  209. id--;
  210. }
  211. return ret;
  212. }
  213. /**
  214. \brief Get feature (grass) ids of duplicated objects
  215. \return list of ids
  216. */
  217. std::map<int, std::vector <int> > DisplayDriver::GetDuplicates()
  218. {
  219. std::map<int, std::vector<int> > ids;
  220. struct line_pnts *APoints, *BPoints;
  221. int line;
  222. APoints = Vect_new_line_struct();
  223. BPoints = Vect_new_line_struct();
  224. Vect_reset_list(selected.idsDupl);
  225. for (int i = 0; i < selected.ids->n_values; i++) {
  226. line = selected.ids->value[i];
  227. if (IsDuplicated(line))
  228. continue;
  229. Vect_read_line(mapInfo, APoints, NULL, line);
  230. for (int j = 0; j < selected.ids->n_values; j++) {
  231. if (i == j || IsDuplicated(selected.ids->value[j]))
  232. continue;
  233. Vect_read_line(mapInfo, BPoints, NULL, selected.ids->value[j]);
  234. if (Vect_line_check_duplicate (APoints, BPoints, WITHOUT_Z)) {
  235. if (ids.find(i) == ids.end()) {
  236. ids[i] = std::vector<int> ();
  237. ids[i].push_back(selected.ids->value[i]);
  238. Vect_list_append(selected.idsDupl, selected.ids->value[i]);
  239. }
  240. ids[i].push_back(selected.ids->value[j]);
  241. Vect_list_append(selected.idsDupl, selected.ids->value[j]);
  242. }
  243. }
  244. }
  245. Vect_destroy_line_struct(APoints);
  246. Vect_destroy_line_struct(BPoints);
  247. return ids;
  248. }
  249. /**
  250. \brief Check for already marked duplicates
  251. \param line line id
  252. \return 1 line already marked as duplicated
  253. \return 0 not duplicated
  254. */
  255. bool DisplayDriver::IsDuplicated(int line)
  256. {
  257. if (Vect_val_in_list(selected.idsDupl, line))
  258. return true;
  259. return false;
  260. }
  261. /**
  262. \brief Set selected vector objects
  263. \param id list of feature ids to be set
  264. \param field field number (-1 for ids instead of cats)
  265. \return 1
  266. */
  267. int DisplayDriver::SetSelected(std::vector<int> id, int field)
  268. {
  269. drawSelected = true;
  270. if (field > 0) {
  271. selected.field = field;
  272. VectorToList(selected.cats, id);
  273. }
  274. else {
  275. field = -1;
  276. VectorToList(selected.ids, id);
  277. }
  278. if (id.size() < 1)
  279. drawSegments = false;
  280. return 1;
  281. }
  282. /**
  283. \brief Unselect selected vector features
  284. \param[in] list of GRASS feature ids
  285. \return number of selected features
  286. */
  287. int DisplayDriver::UnSelect(std::vector<int> id)
  288. {
  289. bool checkForDupl;
  290. checkForDupl = false;
  291. for (std::vector<int>::const_iterator i = id.begin(), e = id.end();
  292. i != e; ++i) {
  293. if (IsSelected(*i)) {
  294. Vect_list_delete(selected.ids, *i);
  295. }
  296. if (settings.highlightDupl.enabled && IsDuplicated(*i)) {
  297. checkForDupl = true;
  298. }
  299. }
  300. if (checkForDupl) {
  301. GetDuplicates();
  302. }
  303. return selected.ids->n_values;
  304. }
  305. /**
  306. \brief Get PseudoDC vertex id of selected line
  307. Set bounding box for vertices of line.
  308. \param[in] x,y coordinates of click
  309. \param[in] thresh threshold value
  310. \return id of center, left and right vertex
  311. \return 0 no line found
  312. \return -1 on error
  313. */
  314. std::vector<int> DisplayDriver::GetSelectedVertex(double x, double y, double thresh)
  315. {
  316. int startId;
  317. int line, type;
  318. int Gid, DCid;
  319. double vx, vy, vz; // vertex screen coordinates
  320. double dist, minDist;
  321. std::vector<int> returnId;
  322. // only one object can be selected
  323. if (selected.ids->n_values != 1 || !drawSegments)
  324. return returnId;
  325. startId = 1;
  326. line = selected.ids->value[0];
  327. type = Vect_read_line (mapInfo, points, cats, line);
  328. minDist = 0.0;
  329. Gid = -1;
  330. // find the closest vertex (x, y)
  331. DCid = 1;
  332. for(int idx = 0; idx < points->n_points; idx++) {
  333. dist = Vect_points_distance(x, y, 0.0,
  334. points->x[idx], points->y[idx], points->z[idx], 0);
  335. if (idx == 0) {
  336. minDist = dist;
  337. Gid = idx;
  338. }
  339. else {
  340. if (minDist > dist) {
  341. minDist = dist;
  342. Gid = idx;
  343. }
  344. }
  345. Cell2Pixel(points->x[idx], points->y[idx], points->z[idx],
  346. &vx, &vy, &vz);
  347. wxRect rect (wxPoint ((int) vx, (int) vy), wxPoint ((int) vx, (int) vy));
  348. dc->SetIdBounds(DCid, rect);
  349. DCid+=2;
  350. }
  351. if (minDist > thresh)
  352. return returnId;
  353. // desc = &(ids[line]);
  354. // translate id
  355. DCid = Gid * 2 + 1;
  356. // add selected vertex
  357. returnId.push_back(DCid);
  358. // left vertex
  359. if (DCid == startId) {
  360. returnId.push_back(-1);
  361. }
  362. else {
  363. returnId.push_back(DCid - 2);
  364. }
  365. // right vertex
  366. if (DCid == (points->n_points - 1) * 2 + startId) {
  367. returnId.push_back(-1);
  368. }
  369. else {
  370. returnId.push_back(DCid + 2);
  371. }
  372. return returnId;
  373. }
  374. /*!
  375. \brief Get minimal region extent of selected features
  376. \return n,s,w,e
  377. */
  378. std::vector<double> DisplayDriver::GetRegionSelected()
  379. {
  380. int line, area, nareas;
  381. std::vector<double> region;
  382. struct bound_box region_box, line_box;
  383. struct ilist *list, *list_tmp;
  384. list = list_tmp = NULL;
  385. G_zero(&region_box, sizeof(region_box));
  386. if (selected.cats->n_values > 0) { /* -> cats */
  387. list = Vect_new_list();
  388. list_tmp = Vect_new_list();
  389. /* can't use here
  390. *
  391. Vect_cidx_find_all(mapInfo, 1, GV_POINTS | GV_LINES,
  392. selected.ids->value[i],
  393. list_tmp);
  394. */
  395. int type;
  396. bool found;
  397. for (int line = 1; line <= Vect_get_num_lines(mapInfo); line++) {
  398. type = Vect_read_line (mapInfo, NULL, cats, line);
  399. if (!(type & (GV_POINTS | GV_LINES)))
  400. continue;
  401. found = false;
  402. for (int i = 0; i < cats->n_cats && !found; i++) {
  403. for (int j = 0; j < selected.ids->n_values && !found; j++) {
  404. if (cats->cat[i] == selected.ids->value[j])
  405. found = true;
  406. }
  407. }
  408. if (found)
  409. Vect_list_append(list, line);
  410. }
  411. }
  412. else {
  413. list = selected.ids;
  414. }
  415. nareas = Vect_get_num_areas(mapInfo);
  416. for (int i = 0; i < list->n_values; i++) {
  417. line = list->value[i];
  418. area = Vect_get_centroid_area(mapInfo, line);
  419. if (area > 0 && area <= nareas) {
  420. if (!Vect_get_area_box(mapInfo, area, &line_box))
  421. continue;
  422. }
  423. else {
  424. if (!Vect_get_line_box(mapInfo, line, &line_box))
  425. continue;
  426. }
  427. if (i == 0) {
  428. Vect_box_copy(&region_box, &line_box);
  429. }
  430. else {
  431. Vect_box_extend(&region_box, &line_box);
  432. }
  433. }
  434. if (list && list != selected.ids) {
  435. Vect_destroy_list(list);
  436. }
  437. if (list_tmp)
  438. Vect_destroy_list(list_tmp);
  439. region.push_back(region_box.N);
  440. region.push_back(region_box.S);
  441. region.push_back(region_box.W);
  442. region.push_back(region_box.E);
  443. return region;
  444. }