driver_draw.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /**
  2. \file driver_draw.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 Draw content of the vector map to device
  17. \return number of lines which were drawn
  18. \return -1 on error
  19. */
  20. int DisplayDriver::DrawMap(bool force)
  21. {
  22. if (!mapInfo || !dc)
  23. return -1;
  24. int nlines;
  25. BOUND_BOX mapBox;
  26. struct ilist *listLines;
  27. // ids.clear();
  28. listLines = Vect_new_list();
  29. ResetTopology();
  30. /* nlines = Vect_get_num_lines(mapInfo); */
  31. Vect_get_map_box(mapInfo, &mapBox);
  32. // draw lines inside of current display region
  33. nlines = Vect_select_lines_by_box(mapInfo, &(region.box),
  34. GV_POINTS | GV_LINES, // fixme
  35. listLines);
  36. G_debug(3, "wxDriver.DrawMap(): region: w=%f, e=%f, s=%f, n=%f",
  37. region.box.W, region.box.E, region.box.S, region.box.N);
  38. dc->BeginDrawing();
  39. if (settings.area.enabled) {
  40. /* draw area fills first */
  41. int area, centroid, isle;
  42. int num_isles;
  43. bool draw;
  44. struct ilist *listAreas, *listCentroids;
  45. struct line_pnts *points, *ipoints, **isles;
  46. wxBrush *fillArea, *fillAreaSelected, *fillIsle;
  47. // fillArea = new wxBrush(settings.area.color);
  48. fillArea = new wxBrush(wxColour(100,100,100,0));
  49. fillAreaSelected = new wxBrush(settings.highlight);
  50. fillIsle = new wxBrush(*wxWHITE_BRUSH);
  51. listAreas = Vect_new_list();
  52. listCentroids = Vect_new_list();
  53. points = Vect_new_line_struct();
  54. ipoints = NULL;
  55. Vect_select_areas_by_box(mapInfo, &region.box,
  56. listAreas);
  57. for (int i = 0; i < listAreas->n_values; i++) {
  58. area = listAreas->value[i];
  59. if (!Vect_area_alive (mapInfo, area))
  60. return -1;
  61. /* check for other centroids -- only area with one centroid is valid */
  62. centroid = Vect_get_area_centroid(mapInfo, area);
  63. if(centroid > 0) {
  64. /* check for isles */
  65. num_isles = Vect_get_area_num_isles(mapInfo, area); /* TODO */
  66. if (num_isles < 1)
  67. isles = NULL;
  68. else
  69. isles = (struct line_pnts **) G_malloc(num_isles * sizeof(struct line_pnts *));
  70. for (int j = 0; j < num_isles; j++) {
  71. ipoints = Vect_new_line_struct();
  72. isle = Vect_get_area_isle(mapInfo, area, j);
  73. if (!Vect_isle_alive (mapInfo, isle))
  74. return -1;
  75. Vect_get_isle_points(mapInfo, isle, ipoints);
  76. isles[j] = ipoints;
  77. }
  78. Vect_get_area_points(mapInfo, area, points);
  79. /* avoid processing areas with large number of polygon points (ugly) */
  80. if (points->n_points < 5000) {
  81. Vect_select_lines_by_polygon(mapInfo, points,
  82. num_isles, isles, GV_CENTROID, listCentroids);
  83. }
  84. else {
  85. Vect_reset_list(listCentroids);
  86. }
  87. draw = true;
  88. for (int c = 0; c < listCentroids->n_values; c++) {
  89. if(Vect_get_centroid_area(mapInfo, listCentroids->value[c]) < 0) {
  90. draw = false;
  91. break;
  92. }
  93. }
  94. if (draw) {
  95. int cat;
  96. cat = Vect_get_area_cat(mapInfo, area, 1); /* TODO: field */
  97. if (cat > -1 && IsSelected(cat, true)) {
  98. dc->SetBrush(*fillAreaSelected);
  99. }
  100. else {
  101. dc->SetBrush(*fillArea);
  102. }
  103. dc->SetPen(*wxTRANSPARENT_PEN);
  104. DrawArea(points);
  105. for (int j = 0; j < num_isles; j++) {
  106. /* draw isles in white */
  107. dc->SetBrush(*fillIsle);
  108. dc->SetPen(*wxTRANSPARENT_PEN);
  109. DrawArea(isles[j]);
  110. }
  111. }
  112. if(isles) {
  113. for (int j = 0; j < num_isles; j++) {
  114. Vect_destroy_line_struct(isles[j]);
  115. isles[j] = NULL;
  116. }
  117. G_free((void *) isles);
  118. }
  119. }
  120. }
  121. delete fillArea;
  122. delete fillIsle;
  123. Vect_destroy_line_struct(points);
  124. Vect_destroy_list(listAreas);
  125. Vect_destroy_list(listCentroids);
  126. }
  127. for (int i = 0; i < listLines->n_values; i++) {
  128. DrawLine(listLines->value[i]);
  129. }
  130. dc->EndDrawing();
  131. // PrintIds();
  132. Vect_destroy_list(listLines);
  133. return listLines->n_values;
  134. }
  135. /**
  136. \brief Draw area fill
  137. \param area boundary points
  138. \return 1 on success
  139. \return -1 on failure (vector object is dead, etc.)
  140. */
  141. int DisplayDriver::DrawArea(const line_pnts* points)
  142. {
  143. double x, y, z;
  144. // convert EN -> xy
  145. wxPoint wxPoints[points->n_points];
  146. for (int i = 0; i < points->n_points; i++) {
  147. Cell2Pixel(points->x[i], points->y[i], points->z[i],
  148. &x, &y, &z);
  149. wxPoints[i] = wxPoint((int) x, (int) y);
  150. }
  151. // draw polygon
  152. dc->DrawPolygon(points->n_points, wxPoints);
  153. return 1;
  154. }
  155. /**
  156. \brief Draw selected vector objects to the device
  157. \param[in] line id
  158. \return 1 on success
  159. \return -1 on failure (vector object is dead, etc.)
  160. */
  161. int DisplayDriver::DrawLine(int line)
  162. {
  163. int dcId; // 0 | 1 | segment id
  164. int type; // line type
  165. double x, y, z; // screen coordinates
  166. bool draw; // draw object ?
  167. wxPen *pen;
  168. pen = NULL;
  169. draw = false;
  170. if (!dc || !Vect_line_alive (mapInfo, line))
  171. return -1;
  172. // read line
  173. type = Vect_read_line (mapInfo, points, cats, line);
  174. // add ids
  175. // -> node1, line1, vertex1, line2, ..., node2
  176. // struct lineDesc desc = {points->n_points, dcId};
  177. // ids[line] = desc;
  178. // update id for next line
  179. // dcId += points->n_points * 2 - 1;
  180. if (IsSelected(line)) { // line selected ?
  181. if (settings.highlightDupl.enabled && IsDuplicated(line)) {
  182. pen = new wxPen(settings.highlightDupl.color, settings.lineWidth, wxSOLID);
  183. }
  184. else {
  185. pen = new wxPen(settings.highlight, settings.lineWidth, wxSOLID);
  186. }
  187. if (drawSelected) {
  188. draw = true;
  189. }
  190. else {
  191. draw = false;
  192. }
  193. dcId = 1;
  194. topology.highlight++;
  195. }
  196. else {
  197. dcId = 0;
  198. if (type & GV_LINES) {
  199. switch (type) {
  200. case GV_LINE:
  201. pen = new wxPen(settings.line.color, settings.lineWidth, wxSOLID);
  202. topology.line++;
  203. draw = settings.line.enabled;
  204. break;
  205. case GV_BOUNDARY:
  206. int left, right;
  207. Vect_get_line_areas(mapInfo, line,
  208. &left, &right);
  209. if (left == 0 && right == 0) {
  210. pen = new wxPen(settings.boundaryNo.color, settings.lineWidth, wxSOLID);
  211. topology.boundaryNo++;
  212. draw = settings.boundaryNo.enabled;
  213. }
  214. else if (left > 0 && right > 0) {
  215. pen = new wxPen(settings.boundaryTwo.color, settings.lineWidth, wxSOLID);
  216. topology.boundaryTwo++;
  217. draw = settings.boundaryTwo.enabled;
  218. }
  219. else {
  220. pen = new wxPen(settings.boundaryOne.color, settings.lineWidth, wxSOLID);
  221. topology.boundaryOne++;
  222. draw = settings.boundaryOne.enabled;
  223. }
  224. break;
  225. default:
  226. draw = false;
  227. break;
  228. }
  229. }
  230. else if (type & GV_POINTS) {
  231. if (type == GV_POINT && settings.point.enabled) {
  232. pen = new wxPen(settings.point.color, settings.lineWidth, wxSOLID);
  233. topology.point++;
  234. draw = settings.point.enabled;
  235. }
  236. else if (type == GV_CENTROID) {
  237. int cret = Vect_get_centroid_area(mapInfo, line);
  238. if (cret > 0) { // -> area
  239. draw = settings.centroidIn.enabled;
  240. pen = new wxPen(settings.centroidIn.color, settings.lineWidth, wxSOLID);
  241. topology.centroidIn++;
  242. }
  243. else if (cret == 0) {
  244. draw = settings.centroidOut.enabled;
  245. pen = new wxPen(settings.centroidOut.color, settings.lineWidth, wxSOLID);
  246. topology.centroidOut++;
  247. }
  248. else {
  249. draw = settings.centroidDup.enabled;
  250. pen = new wxPen(settings.centroidDup.color, settings.lineWidth, wxSOLID);
  251. topology.centroidDup++;
  252. }
  253. }
  254. }
  255. }
  256. // clear screen points & convert EN -> xy
  257. pointsScreen->Clear();
  258. for (int i = 0; i < points->n_points; i++) {
  259. Cell2Pixel(points->x[i], points->y[i], points->z[i],
  260. &x, &y, &z);
  261. pointsScreen->Append((wxObject*) new wxPoint((int) x, (int) y)); /* TODO: 3D */
  262. }
  263. dc->SetId(dcId); /* 0 | 1 (selected) */
  264. if (draw) {
  265. dc->SetPen(*pen);
  266. if (type & GV_POINTS) {
  267. DrawCross(line, (const wxPoint *) pointsScreen->GetFirst()->GetData());
  268. }
  269. else {
  270. // long int startId = ids[line].startId + 1;
  271. if (dcId > 0 && drawSegments) {
  272. dcId = 2; // first segment
  273. for (size_t i = 0; i < pointsScreen->GetCount() - 1; dcId += 2) {
  274. wxPoint *point_beg = (wxPoint *) pointsScreen->Item(i)->GetData();
  275. wxPoint *point_end = (wxPoint *) pointsScreen->Item(++i)->GetData();
  276. // set bounds for line
  277. // wxRect rect (*point_beg, *point_end);
  278. // dc->SetIdBounds(startId, rect);
  279. dc->SetId(dcId); // set unique id & set bbox for each segment
  280. dc->SetPen(*pen);
  281. wxRect rect (*point_beg, *point_end);
  282. dc->SetIdBounds(dcId, rect);
  283. dc->DrawLine(point_beg->x, point_beg->y,
  284. point_end->x, point_end->y);
  285. }
  286. }
  287. else {
  288. wxPoint wxPoints[pointsScreen->GetCount()];
  289. for (size_t i = 0; i < pointsScreen->GetCount(); i++) {
  290. wxPoint *point_beg = (wxPoint *) pointsScreen->Item(i)->GetData();
  291. wxPoints[i] = *point_beg;
  292. }
  293. dc->DrawLines(pointsScreen->GetCount(), wxPoints);
  294. if (!IsSelected(line) && settings.direction.enabled) {
  295. DrawDirectionArrow();
  296. // restore pen
  297. dc->SetPen(*pen);
  298. }
  299. }
  300. }
  301. }
  302. if (type & GV_LINES) {
  303. DrawLineVerteces(line); // draw vertices
  304. DrawLineNodes(line); // draw nodes
  305. }
  306. delete pen;
  307. return 1;
  308. }
  309. /**
  310. \brief Draw line verteces to the device
  311. Except of first and last vertex, see DrawLineNodes().
  312. \param line id
  313. \return number of verteces which were drawn
  314. \return -1 if drawing vertices is disabled
  315. */
  316. int DisplayDriver::DrawLineVerteces(int line)
  317. {
  318. int dcId;
  319. wxPoint *point;
  320. wxPen *pen;
  321. if (!IsSelected(line) && !settings.vertex.enabled)
  322. return -1;
  323. // determine color
  324. if (!IsSelected(line)) {
  325. pen = new wxPen(settings.vertex.color, settings.lineWidth, wxSOLID);
  326. dcId = 0;
  327. }
  328. else {
  329. if (!drawSelected) {
  330. return -1;
  331. }
  332. if (settings.highlightDupl.enabled && IsDuplicated(line)) {
  333. pen = new wxPen(settings.highlightDupl.color, settings.lineWidth, wxSOLID);
  334. }
  335. else {
  336. pen = new wxPen(settings.highlight, settings.lineWidth, wxSOLID);
  337. }
  338. if (drawSegments) {
  339. dcId = 3; // first vertex
  340. }
  341. else {
  342. dcId = 1;
  343. }
  344. }
  345. dc->SetId(dcId); /* 0 | 1 (selected) */
  346. dc->SetPen(*pen);
  347. for (size_t i = 1; i < pointsScreen->GetCount() - 1; i++, dcId += 2) {
  348. point = (wxPoint*) pointsScreen->Item(i)->GetData();
  349. if (IsSelected(line) && drawSegments) {
  350. dc->SetId(dcId);
  351. dc->SetPen(*pen);
  352. wxRect rect (*point, *point);
  353. dc->SetIdBounds(dcId, rect);
  354. }
  355. if (settings.vertex.enabled) {
  356. DrawCross(line, (const wxPoint*) pointsScreen->Item(i)->GetData());
  357. topology.vertex++;
  358. }
  359. }
  360. delete pen;
  361. return pointsScreen->GetCount() - 2;
  362. }
  363. /**
  364. \brief Draw line nodes to the device
  365. \param line id
  366. \return 1
  367. \return -1 if no nodes were drawn
  368. */
  369. int DisplayDriver::DrawLineNodes(int line)
  370. {
  371. int dcId;
  372. int node;
  373. double east, north, depth;
  374. double x, y, z;
  375. int nodes [2];
  376. bool draw;
  377. wxPen *pen;
  378. // draw nodes??
  379. if (!settings.nodeOne.enabled && !settings.nodeTwo.enabled)
  380. return -1;
  381. // get nodes
  382. Vect_get_line_nodes(mapInfo, line, &(nodes[0]), &(nodes[1]));
  383. for (size_t i = 0; i < sizeof(nodes) / sizeof(int); i++) {
  384. node = nodes[i];
  385. // get coordinates
  386. Vect_get_node_coor(mapInfo, node,
  387. &east, &north, &depth);
  388. // convert EN->xy
  389. Cell2Pixel(east, north, depth,
  390. &x, &y, &z);
  391. // determine color
  392. if (IsSelected(line)) {
  393. if (!drawSelected) {
  394. return -1;
  395. }
  396. if (settings.highlightDupl.enabled && IsDuplicated(line)) {
  397. pen = new wxPen(settings.highlightDupl.color, settings.lineWidth, wxSOLID);
  398. }
  399. else {
  400. pen = new wxPen(settings.highlight, settings.lineWidth, wxSOLID);
  401. }
  402. draw = true;
  403. if (!drawSegments) {
  404. dcId = 1;
  405. }
  406. else {
  407. // node1, line1, vertex1, line2, vertex2, ..., node2
  408. if (i == 0) // first node
  409. dcId = 1;
  410. else // last node
  411. dcId = 2 * points->n_points - 1;
  412. }
  413. }
  414. else {
  415. dcId = 0;
  416. if (Vect_get_node_n_lines(mapInfo, node) == 1) {
  417. pen = new wxPen(settings.nodeOne.color, settings.lineWidth, wxSOLID);
  418. topology.nodeOne++;
  419. draw = settings.nodeOne.enabled;
  420. }
  421. else {
  422. pen = new wxPen(settings.nodeTwo.color, settings.lineWidth, wxSOLID);
  423. topology.nodeTwo++;
  424. draw = settings.nodeTwo.enabled;
  425. }
  426. }
  427. wxPoint point((int) x, (int) y);
  428. if (IsSelected(line) && drawSegments) {
  429. wxRect rect (point, point);
  430. dc->SetIdBounds(dcId, rect);
  431. }
  432. // draw node if needed
  433. if (draw) {
  434. dc->SetId(dcId);
  435. dc->SetPen(*pen);
  436. DrawCross(line, &point);
  437. }
  438. }
  439. delete pen;
  440. return 1;
  441. }
  442. /**
  443. \brief Draw cross symbol of given size to device content
  444. Used for points, nodes, vertices
  445. \param[in] point coordinates of center
  446. \param[in] size size of the cross symbol
  447. \return 1 on success
  448. \return -1 on failure
  449. */
  450. int DisplayDriver::DrawCross(int line, const wxPoint* point, int size)
  451. {
  452. if (!dc || !point)
  453. return -1;
  454. dc->DrawLine(point->x - size, point->y, point->x + size, point->y);
  455. dc->DrawLine(point->x, point->y - size, point->x, point->y + size);
  456. return 1;
  457. }
  458. /**
  459. \brief Draw selected features
  460. \param draw if true draw selected features
  461. */
  462. void DisplayDriver::DrawSelected(bool draw)
  463. {
  464. drawSelected = draw;
  465. return;
  466. }
  467. /**
  468. \brief Draw line direction arrow
  469. \return number of drawn arrows
  470. */
  471. int DisplayDriver::DrawDirectionArrow()
  472. {
  473. int narrows;
  474. int size; // arrow length in pixels
  475. int limit; // segment length limit for drawing symbol (in pixels)
  476. double dist, angle, pos;
  477. double e, n, d, x0, y0, z0, x1, y1, z1;
  478. struct line_pnts *points_seg;
  479. wxPen *pen_arrow;
  480. narrows = 0;
  481. size = 5;
  482. limit = 5; // 5px for line segment
  483. points_seg = Vect_new_line_struct();
  484. pen_arrow = new wxPen(settings.direction.color, settings.lineWidth, wxSOLID);
  485. dc->SetPen(*pen_arrow);
  486. dist = Vect_line_length(points);
  487. if (DistanceInPixels(dist) >= limit) {
  488. while (1) {
  489. pos = (narrows + 1) * 8 * limit * region.map_res;
  490. if (Vect_point_on_line(points, pos,
  491. &e, &n, &d, NULL, NULL) < 1) {
  492. break;
  493. }
  494. Cell2Pixel(e, n, d, &x0, &y0, &z0);
  495. if (Vect_point_on_line(points, pos - 3 * size * region.map_res,
  496. &e, &n, &d, &angle, NULL) < 1) {
  497. break;
  498. }
  499. Cell2Pixel(e, n, d, &x1, &y1, &z1);
  500. DrawArrow(x0, y0, x1, y1, angle, size);
  501. if(narrows > 1e2) // low resolution, break
  502. break;
  503. narrows++;
  504. }
  505. // draw at least one arrow in the middle of line
  506. if (narrows < 1) {
  507. dist /= 2.;
  508. if (Vect_point_on_line(points, dist,
  509. &e, &n, &d, NULL, NULL) > 0) {
  510. Cell2Pixel(e, n, d, &x0, &y0, &z0);
  511. if (Vect_point_on_line(points, dist - 3 * size * region.map_res,
  512. &e, &n, &d, &angle, NULL) > 0) {
  513. Cell2Pixel(e, n, d, &x1, &y1, &z1);
  514. DrawArrow(x0, y0, x1, y1, angle, size);
  515. }
  516. }
  517. }
  518. }
  519. Vect_destroy_line_struct(points_seg);
  520. return narrows;
  521. }
  522. /**
  523. \brief Draw arrow symbol on line
  524. \param x0,y0 arrow origin
  525. \param x1,x1 arrow ending point (on line)
  526. \param angle point ending point angle
  527. \param size arrow size
  528. \return 1
  529. */
  530. int DisplayDriver::DrawArrow(double x0, double y0,
  531. double x1, double y1, double angle,
  532. int size)
  533. {
  534. double x, y;
  535. double angle_symb;
  536. angle_symb = angle - M_PI / 2.;
  537. x = x1 + size * std::cos(angle_symb);
  538. y = y1 - size * std::sin(angle_symb);
  539. dc->DrawLine((wxCoord) x, (wxCoord) y, (wxCoord) x0, (wxCoord) y0);
  540. angle_symb = M_PI / 2. + angle;
  541. x = x1 + size * std::cos(angle_symb);
  542. y = y1 - size * std::sin(angle_symb);
  543. dc->DrawLine((wxCoord) x0, (wxCoord) y0, (wxCoord) x, (wxCoord) y);
  544. return 1;
  545. }