driver_select.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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)
  29. {
  30. if (!mapInfo)
  31. return -1;
  32. int line;
  33. struct ilist *list;
  34. struct line_pnts *bbox;
  35. drawSegments = false;
  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. drawSegments = true;
  133. return p;
  134. }
  135. /**
  136. \brief Is vector object selected?
  137. \param[in] line id
  138. \return true if vector object is selected
  139. \return false if vector object is not selected
  140. */
  141. bool DisplayDriver::IsSelected(int line, bool force)
  142. {
  143. if (selected.isId || force) {
  144. if (Vect_val_in_list(selected.values, line))
  145. return true;
  146. }
  147. else {
  148. for (int i = 0; i < cats->n_cats; i++) {
  149. if (cats->field[i] == 1 && /* TODO: field */
  150. Vect_val_in_list(selected.values, cats->cat[i]))
  151. return true;
  152. }
  153. }
  154. return false;
  155. }
  156. /**
  157. \brief Get ids of selected objects
  158. \param[in] grassId if true return GRASS line ids
  159. if false return PseudoDC ids
  160. \return list of ids of selected vector objects
  161. */
  162. std::vector<int> DisplayDriver::GetSelected(bool grassId)
  163. {
  164. if (grassId)
  165. return ListToVector(selected.values);
  166. std::vector<int> dc_ids;
  167. if (!drawSegments) {
  168. dc_ids.push_back(1);
  169. }
  170. else {
  171. int npoints;
  172. Vect_read_line(mapInfo, points, NULL, selected.values->value[0]);
  173. npoints = points->n_points;
  174. for (int i = 1; i < 2 * npoints; i++) {
  175. dc_ids.push_back(i);
  176. }
  177. }
  178. return dc_ids;
  179. }
  180. /**
  181. \brief Get feature (grass) ids of duplicated objects
  182. \return list of ids
  183. */
  184. std::map<int, std::vector <int> > DisplayDriver::GetDuplicates()
  185. {
  186. std::map<int, std::vector<int> > ids;
  187. struct line_pnts *APoints, *BPoints;
  188. int line;
  189. APoints = Vect_new_line_struct();
  190. BPoints = Vect_new_line_struct();
  191. Vect_reset_list(selected.valuesDupl);
  192. for (int i = 0; i < selected.values->n_values; i++) {
  193. line = selected.values->value[i];
  194. if (IsDuplicated(line))
  195. continue;
  196. Vect_read_line(mapInfo, APoints, NULL, line);
  197. for (int j = 0; j < selected.values->n_values; j++) {
  198. if (i == j || IsDuplicated(selected.values->value[j]))
  199. continue;
  200. Vect_read_line(mapInfo, BPoints, NULL, selected.values->value[j]);
  201. if (Vect_line_check_duplicate (APoints, BPoints, WITHOUT_Z)) {
  202. if (ids.find(i) == ids.end()) {
  203. ids[i] = std::vector<int> ();
  204. ids[i].push_back(selected.values->value[i]);
  205. Vect_list_append(selected.valuesDupl, selected.values->value[i]);
  206. }
  207. ids[i].push_back(selected.values->value[j]);
  208. Vect_list_append(selected.valuesDupl, selected.values->value[j]);
  209. }
  210. }
  211. }
  212. Vect_destroy_line_struct(APoints);
  213. Vect_destroy_line_struct(BPoints);
  214. return ids;
  215. }
  216. /**
  217. \brief Check for already marked duplicates
  218. \param line line id
  219. \return 1 line already marked as duplicated
  220. \return 0 not duplicated
  221. */
  222. bool DisplayDriver::IsDuplicated(int line)
  223. {
  224. if (Vect_val_in_list(selected.valuesDupl, line))
  225. return true;
  226. return false;
  227. }
  228. /**
  229. \brief Set selected vector objects
  230. \param[in] list of GRASS ids to be set
  231. \param[in] cat if True expect categories instead of feature ids
  232. \return 1
  233. */
  234. int DisplayDriver::SetSelected(std::vector<int> id, bool cat)
  235. {
  236. drawSelected = true;
  237. VectorToList(selected.values, id);
  238. selected.isId = !cat;
  239. if (selected.values->n_values <= 0)
  240. drawSegments = false;
  241. return 1;
  242. }
  243. /**
  244. \brief Unselect selected vector features
  245. \param[in] list of GRASS feature ids
  246. \return number of selected features
  247. */
  248. int DisplayDriver::UnSelect(std::vector<int> id)
  249. {
  250. bool checkForDupl;
  251. checkForDupl = false;
  252. for (std::vector<int>::const_iterator i = id.begin(), e = id.end();
  253. i != e; ++i) {
  254. if (IsSelected(*i)) {
  255. Vect_list_delete(selected.values, *i);
  256. }
  257. if (settings.highlightDupl.enabled && IsDuplicated(*i)) {
  258. checkForDupl = true;
  259. }
  260. }
  261. if (checkForDupl) {
  262. GetDuplicates();
  263. }
  264. return selected.values->n_values;
  265. }
  266. /**
  267. \brief Get PseudoDC vertex id of selected line
  268. Set bounding box for vertices of line.
  269. \param[in] x,y coordinates of click
  270. \param[in] thresh threshold value
  271. \return id of center, left and right vertex
  272. \return 0 no line found
  273. \return -1 on error
  274. */
  275. std::vector<int> DisplayDriver::GetSelectedVertex(double x, double y, double thresh)
  276. {
  277. int startId;
  278. int line, type;
  279. int Gid, DCid;
  280. double vx, vy, vz; // vertex screen coordinates
  281. double dist, minDist;
  282. std::vector<int> returnId;
  283. // only one object can be selected
  284. if (selected.values->n_values != 1 || !drawSegments)
  285. return returnId;
  286. startId = 1;
  287. line = selected.values->value[0];
  288. type = Vect_read_line (mapInfo, points, cats, line);
  289. minDist = 0.0;
  290. Gid = -1;
  291. // find the closest vertex (x, y)
  292. DCid = 1;
  293. for(int idx = 0; idx < points->n_points; idx++) {
  294. dist = Vect_points_distance(x, y, 0.0,
  295. points->x[idx], points->y[idx], points->z[idx], 0);
  296. if (idx == 0) {
  297. minDist = dist;
  298. Gid = idx;
  299. }
  300. else {
  301. if (minDist > dist) {
  302. minDist = dist;
  303. Gid = idx;
  304. }
  305. }
  306. Cell2Pixel(points->x[idx], points->y[idx], points->z[idx],
  307. &vx, &vy, &vz);
  308. wxRect rect (wxPoint ((int) vx, (int) vy), wxPoint ((int) vx, (int) vy));
  309. dc->SetIdBounds(DCid, rect);
  310. DCid+=2;
  311. }
  312. if (minDist > thresh)
  313. return returnId;
  314. // desc = &(ids[line]);
  315. // translate id
  316. DCid = Gid * 2 + 1;
  317. // add selected vertex
  318. returnId.push_back(DCid);
  319. // left vertex
  320. if (DCid == startId) {
  321. returnId.push_back(-1);
  322. }
  323. else {
  324. returnId.push_back(DCid - 2);
  325. }
  326. // right vertex
  327. if (DCid == (points->n_points - 1) * 2 + startId) {
  328. returnId.push_back(-1);
  329. }
  330. else {
  331. returnId.push_back(DCid + 2);
  332. }
  333. return returnId;
  334. }
  335. /*!
  336. \brief Get minimal region extent of selected features
  337. \return n,s,w,e
  338. */
  339. std::vector<double> DisplayDriver::GetRegionSelected()
  340. {
  341. int line, area, nareas;
  342. std::vector<double> region;
  343. BOUND_BOX region_box, line_box;
  344. struct ilist *list, *list_tmp;
  345. list = list_tmp = NULL;
  346. G_zero(&region_box, sizeof(region_box));
  347. if (!selected.isId) { /* -> cats */
  348. list = Vect_new_list();
  349. list_tmp = Vect_new_list();
  350. /* can't use here
  351. *
  352. Vect_cidx_find_all(mapInfo, 1, GV_POINTS | GV_LINES,
  353. selected.values->value[i],
  354. list_tmp);
  355. */
  356. int type;
  357. bool found;
  358. for (int line = 1; line <= Vect_get_num_lines(mapInfo); line++) {
  359. type = Vect_read_line (mapInfo, NULL, cats, line);
  360. if (!(type & (GV_POINTS | GV_LINES)))
  361. continue;
  362. found = false;
  363. for (int i = 0; i < cats->n_cats && !found; i++) {
  364. for (int j = 0; j < selected.values->n_values && !found; j++) {
  365. if (cats->cat[i] == selected.values->value[j])
  366. found = true;
  367. }
  368. }
  369. if (found)
  370. Vect_list_append(list, line);
  371. }
  372. }
  373. else {
  374. list = selected.values;
  375. }
  376. nareas = Vect_get_num_areas(mapInfo);
  377. for (int i = 0; i < list->n_values; i++) {
  378. line = list->value[i];
  379. area = Vect_get_centroid_area(mapInfo, line);
  380. if (area > 0 && area <= nareas) {
  381. if (!Vect_get_area_box(mapInfo, area, &line_box))
  382. continue;
  383. }
  384. else {
  385. if (!Vect_get_line_box(mapInfo, line, &line_box))
  386. continue;
  387. }
  388. if (i == 0) {
  389. Vect_box_copy(&region_box, &line_box);
  390. }
  391. else {
  392. Vect_box_extend(&region_box, &line_box);
  393. }
  394. }
  395. if (list && list != selected.values) {
  396. Vect_destroy_list(list);
  397. }
  398. if (list_tmp)
  399. Vect_destroy_list(list_tmp);
  400. region.push_back(region_box.N);
  401. region.push_back(region_box.S);
  402. region.push_back(region_box.W);
  403. region.push_back(region_box.E);
  404. return region;
  405. }