driver_select.cpp 12 KB

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