driver_select.cpp 12 KB

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