driver_draw.cpp 16 KB

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