USGS

Isis 3.0 Object Programmers' Reference

Home

RubberBandTool.cpp
1 #include "RubberBandTool.h"
2 
3 #include <cmath>
4 #include <float.h>
5 
6 #include <QDebug>
7 #include <QList>
8 #include <QMessageBox>
9 #include <QPainter>
10 #include <QPen>
11 #include <QPoint>
12 #include <QRect>
13 
14 #include "geos/geom/CoordinateArraySequence.h"
15 #include "geos/geom/CoordinateSequence.h"
16 #include "geos/geom/Coordinate.h"
17 #include "geos/geom/LineString.h"
18 #include "geos/geom/MultiLineString.h"
19 #include "geos/geom/Polygon.h"
20 
21 #include "Angle.h"
22 #include "Constants.h"
23 #include "MdiCubeViewport.h"
24 #include "PolygonTools.h"
25 #include "SerialNumberList.h"
26 
27 using namespace std;
28 
29 namespace Isis {
35  RubberBandTool::RubberBandTool(QWidget *parent) : Tool(parent) {
36  p_mouseLoc = NULL;
37  p_vertices = NULL;
38 
39  p_mouseLoc = new QPoint;
40  p_vertices = new QList< QPoint >;
41  p_bandingMode = LineMode;
42 
43  activate(false);
44  repaint();
45  }
46 
47 
48  RubberBandTool::~RubberBandTool() {
49  if(p_mouseLoc) {
50  delete p_mouseLoc;
51  p_mouseLoc = NULL;
52  }
53 
54  if(p_vertices) {
55  delete p_vertices;
56  p_vertices = NULL;
57  }
58  }
59 
73  void RubberBandTool::paintViewport(MdiCubeViewport *vp, QPainter *painter) {
74  QPen pen(QColor(255, 0, 0));
75  QPen greenPen(QColor(0, 255, 0));
76  pen.setStyle(Qt::SolidLine);
77  greenPen.setStyle(Qt::SolidLine);
78  painter->setPen(pen);
79 
80  if ( (vp != cubeViewport() && p_drawActiveOnly) ||
81  !(vp == cubeViewport() || (cubeViewport()->isLinked() &&
82  vp->isLinked()))) {
83  return;
84  }
85 
86  switch(p_bandingMode) {
87  case AngleMode:
88  paintVerticesConnected(painter);
89  break;
90 
91  case LineMode:
92  // if point needed, draw an X
93  if(figureIsPoint() && !p_tracking) {
94  painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() - 10,
95  (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() + 10);
96  painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() + 10,
97  (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() - 10);
98  }
99  else {
100  paintVerticesConnected(painter);
101  }
102 
103  break;
104 
105  case PolygonMode:
106  paintVerticesConnected(painter);
107 
108  if(!p_tracking && p_vertices->size() > 0) {
109  painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]);
110  }
111  break;
112 
113  case CircleMode:
114  case EllipseMode: {
115  if(p_vertices->size() != 0) {
116  QList<QPoint> verticesList = vertices();
117  int width = 2 * (verticesList[1].x() - verticesList[0].x());
118  int height = 2 * (verticesList[1].y() - verticesList[0].y());
119 
120  // upper left x,y,width,height
121  painter->drawEllipse(verticesList[0].x() - width / 2, verticesList[0].y() - height / 2,
122  width,
123  height
124  );
125  }
126  }
127  break;
128 
129  case RectangleMode: {
130  if(figureIsPoint() && !p_tracking) {
131  painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() - 10,
132  (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() + 10);
133  painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() + 10,
134  (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() - 10);
135  }
136  else {
137  if(p_tracking && p_vertices->size() > 0) {
138  paintRectangle((*p_vertices)[0], *p_mouseLoc, painter);
139  }
140  else if(p_vertices->size() > 0) {
141  paintVerticesConnected(painter);
142  painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]);
143  }
144  }
145  }
146  break;
147 
148  case RotatedRectangleMode: {
149  if(p_vertices->size() == 2) {
150  QPoint missingVertex;
151  calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex);
152  painter->drawLine(*p_mouseLoc, missingVertex);
153  painter->drawLine(missingVertex, (*p_vertices)[0]);
154  }
155  else if(p_vertices->size() == 4) {
156  painter->drawLine((*p_vertices)[0], (*p_vertices)[ 3 ]);
157  }
158 
159  paintVerticesConnected(painter);
160 
161  // Draw indicator on top of original lines if applicable
162  if(p_indicatorColors) {
163  painter->setPen(greenPen);
164  if(p_vertices->size() > 1) {
165  painter->drawLine((*p_vertices)[0], (*p_vertices)[1]);
166  }
167  else if(p_vertices->size() == 1) {
168  painter->drawLine((*p_vertices)[0], *p_mouseLoc);
169  }
170 
171  painter->setPen(pen);
172  }
173  }
174  break;
175 
176  case SegmentedLineMode:
177  paintVerticesConnected(painter);
178  break;
179  }
180  }
181 
190  void RubberBandTool::calcRectCorners(QPoint corner1, QPoint corner2, QPoint &corner3, QPoint &corner4) {
191  double slope = ((double)corner2.y() - (double)corner1.y()) / ((double)corner2.x() - (double)corner1.x());
192 
193  if((fabs(slope) > DBL_EPSILON) && (slope < DBL_MAX) && (slope > -DBL_MAX)) {
194  // corner1,corner2 make up y=m(x-x1)+y1
195  // corner3,corner4 must make up || line crossing corner3.
196  // b (y-intercept) is what differs from the original line and our parallel line.
197  // Go ahead and figure out our new b by using b = -mx1+y1 from the point-slope formula.
198  double parallelB = -1 * slope * corner3.x() + corner3.y();
199 
200  // Now we have our equation for a parallel line, which our new points lie on. Let's find the perpendicular lines
201  // which cross corner1,corner2 in order to figure out where they cross it. Use -1/slope = perpendicular slope and
202  // now we have y=m(x-x1)+y1. What we care about is b in y=mx+b, so figure it out using b = m*(-x1)+y1
203  double perpSlope = -1.0 / slope;
204  double perpLineMode1b = perpSlope * (-1 * corner1.x()) + corner1.y();
205  double perpLineMode2b = perpSlope * (-1 * corner2.x()) + corner2.y();
206 
207  // Now let's find the perpendicular lines' intercepts on the parallel line.
208  // y = mx+b = y = mx+b => mx+b(perpendicular) = mx+b(parallel) for the perp. lines and the parallel line.
209  // Combine the b's on the left to make y= m(perp)x+k = m(par)x.
210  double perpLineMode1k = perpLineMode1b - parallelB;
211  double perpLineMode2k = perpLineMode2b - parallelB;
212 
213  // Now we have mx + k = mx (parallel). Divive the parallel slope out to get
214  // (m(perp)x+k)/m(parallel) = x. Move the x over from the left side of the equation by subtracting...
215  // k/m(parallel) = x - m(perp)x/m(parallel). Factor out the x's... k/m(par) = x(1-m(per)/m(par)) and divive
216  // both sides by "(1-m(per)/m(par))". So we end up with: (k/m(par)) / (1 - m(per) / m(par) ) =
217  // k/m(par) / ( (m(par)-m(per)) / m(par) ) = k / m(par) * m(par) / (m(par) - m(per)) = k / (m(par) - m(per))
218  double perpLineMode1IntersectX = perpLineMode1k / (slope - perpSlope);
219  double perpLineMode2IntersectX = perpLineMode2k / (slope - perpSlope);
220 
221  // The intersecting X values are now known, and the equation of the parallel line, so let's roll with it and
222  // get our two corners set. perpLineMode1 => corner1 => corner4, perpLineMode2 => corner2 => corner3
223  corner3.setX((int)perpLineMode2IntersectX);
224  corner3.setY((int)(perpLineMode2IntersectX * slope + parallelB)); //mx+b
225  corner4.setX((int)perpLineMode1IntersectX);
226  corner4.setY((int)(perpLineMode1IntersectX * slope + parallelB)); //mx+b
227  }
228  else if(fabs(slope) < DBL_EPSILON) {
229  corner3.setX(corner2.x());
230  corner3.setY(corner3.y());
231  corner4.setX(corner1.x());
232  corner4.setY(corner3.y());
233  }
234  else {
235  corner3.setX(corner3.x());
236  corner3.setY(corner2.y());
237  corner4.setX(corner3.x());
238  corner4.setY(corner1.y());
239  }
240  }
241 
248  void RubberBandTool::paintVerticesConnected(QPainter *painter) {
249  for(int vertex = 1; vertex < p_vertices->size(); vertex++) {
250  QPoint start = (*p_vertices)[vertex - 1];
251  QPoint end = (*p_vertices)[vertex];
252 
253  painter->drawLine(start, end);
254  }
255 
256  if(p_tracking && (p_vertices->size() > 0)) {
257  QPoint start = (*p_vertices)[p_vertices->size() - 1];
258  QPoint end = *p_mouseLoc;
259 
260  painter->drawLine(start, end);
261  }
262  }
263 
271  void RubberBandTool::paintRectangle(QPoint upperLeft, QPoint lowerRight, QPainter *painter) {
272  QPoint upperRight = QPoint(lowerRight.x(), upperLeft.y());
273  QPoint lowerLeft = QPoint(upperLeft.x(), lowerRight.y());
274 
275  paintRectangle(upperLeft, upperRight, lowerLeft, lowerRight, painter);
276  }
277 
287  void RubberBandTool::paintRectangle(QPoint upperLeft, QPoint upperRight,
288  QPoint lowerLeft, QPoint lowerRight, QPainter *painter) {
289  painter->drawLine(upperLeft, upperRight);
290  painter->drawLine(upperRight, lowerRight);
291  painter->drawLine(lowerRight, lowerLeft);
292  painter->drawLine(lowerLeft, upperLeft);
293  }
294 
302  void RubberBandTool::enable(RubberBandMode mode, bool showIndicatorColors) {
303  RubberBandMode oldMode = p_bandingMode;
304  p_bandingMode = mode;
305  p_indicatorColors = showIndicatorColors;
306  //Took this out because it was reseting and not letting us plot single points.
307  //p_pointTolerance = 0;
308  p_allClicks = false;
309  p_drawActiveOnly = false;
310  reset();
311  activate(true);
312 
313  if(oldMode != mode) {
314  emit modeChanged();
315  }
316  }
317 
323 
324  activate(false);
325  reset();
326  repaint();
327  }
328 
334  p_drawActiveOnly = activeOnly;
335  repaint();
336  }
337 
344  p_doubleClicking = true;
345  *p_mouseLoc = p;
346 
347  switch(p_bandingMode) {
348  case AngleMode:
349  case CircleMode:
350  case EllipseMode:
351  case LineMode:
352  case RectangleMode:
353  case RotatedRectangleMode:
354  break;
355 
356  case SegmentedLineMode:
357  case PolygonMode:
358  p_tracking = false;
359  repaint();
360  emit bandingComplete();
361  break;
362  }
363  }
364 
386  void RubberBandTool::mouseButtonPress(QPoint p, Qt::MouseButton s) {
387  *p_mouseLoc = p;
388  p_mouseButton = s;
389 
390  if((s & Qt::LeftButton) != Qt::LeftButton && !p_allClicks) {
391  return;
392  }
393 
394  switch(p_bandingMode) {
395  case AngleMode:
396  break;
397 
398  case CircleMode:
399  case EllipseMode:
400  case LineMode:
401  case RectangleMode:
402  reset();
403  p_tracking = true;
404  p_vertices->push_back(p);
405  break;
406 
407  case RotatedRectangleMode:
408  if(p_vertices->size() == 4) {
409  reset();
410  }
411 
412  if(p_vertices->size() == 0) {
413  p_vertices->push_back(p);
414  p_tracking = true;
415  }
416  break;
417 
418  case SegmentedLineMode:
419  case PolygonMode:
420  if(!p_tracking) {
421  reset();
422  p_tracking = true;
423  }
424 
425  if(p_vertices->size() == 0 || (*p_vertices)[ p_vertices->size() - 1 ] != p) {
426  p_vertices->push_back(p);
427  }
428 
429  break;
430  }
431 
432  p_mouseDown = true;
433  }
434 
475  void RubberBandTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) {
476  if ((s & Qt::ControlModifier) == Qt::ControlModifier)
477  *p_mouseLoc = snapMouse(p);
478  else
479  *p_mouseLoc = p;
480 
481  p_mouseButton = s;
482 
483  if((s & Qt::LeftButton) == Qt::LeftButton || p_allClicks) {
484  p_mouseDown = false;
485  }
486  else {
487  return;
488  }
489 
490  switch(p_bandingMode) {
491  case AngleMode: {
492  if(p_vertices->size() == 3) {
493  reset();
494  }
495 
496  p_vertices->push_back(*p_mouseLoc);
497  p_tracking = true;
498 
499  if(p_vertices->size() == 3) {
500  p_tracking = false;
501  emit bandingComplete();
502  }
503  }
504  break;
505 
506  case LineMode:
507  case CircleMode:
508  case EllipseMode:
509  case RectangleMode: {
510  *p_vertices = vertices();
511  p_tracking = false;
512  emit bandingComplete();
513  }
514  break;
515 
516  case RotatedRectangleMode: {
517  if(p_vertices->size() == 1) {
518  p_vertices->push_back(*p_mouseLoc);
519  }
520  else if(p_vertices->size() == 2) {
521  *p_vertices = vertices();
522  p_tracking = false;
523  emit bandingComplete();
524  }
525  }
526  break;
527 
528  case SegmentedLineMode:
529  case PolygonMode:
530  break;
531  }
532 
533  p_doubleClicking = false; // If we were in a double click, it's over now.
534 
535 
536  MdiCubeViewport * activeViewport = cubeViewport();
537  for (int i = 0; i < (int) cubeViewportList()->size(); i++) {
538  MdiCubeViewport * curViewport = cubeViewportList()->at(i);
539  if (curViewport == activeViewport ||
540  (activeViewport->isLinked() && curViewport->isLinked())) {
541  curViewport->viewport()->repaint();
542  }
543  }
544  }
545 
546 
554  QPoint RubberBandTool::snapMouse(QPoint p) {
555  if (p_vertices->size()) {
556  QPoint lastVertex = p_vertices->at(p_vertices->size() - 1);
557 
558  int deltaX = abs(p.x() - lastVertex.x());
559  int deltaY = abs(p.y() - lastVertex.y());
560 
561  if (deltaX > deltaY)
562  p.setY(lastVertex.y());
563  else
564  p.setX(lastVertex.x());
565  }
566 
567  return p;
568  }
569 
570 
589  void RubberBandTool::mouseMove(QPoint p, Qt::MouseButton mouseButton) {
590  if(!p_tracking) {
591  return;
592  }
593 
594  p_mouseButton = mouseButton;
595 
596  if ((p_mouseButton & Qt::ControlModifier) == Qt::ControlModifier)
597  *p_mouseLoc = snapMouse(p);
598  else
599  *p_mouseLoc = p;
600 
601  switch(p_bandingMode) {
602  case AngleMode:
603  case RotatedRectangleMode:
604  if(p_vertices->size() == 2) {
605  emit measureChange();
606  }
607  break;
608 
609  case CircleMode:
610  case EllipseMode:
611  case RectangleMode:
612  if(p_vertices->size() == 1) {
613  emit measureChange();
614  }
615  break;
616 
617  case LineMode:
618  emit measureChange();
619  break;
620 
621  case SegmentedLineMode:
622  case PolygonMode: {
623  if(p_mouseDown && p != (*p_vertices)[ p_vertices->size() - 1 ]) {
624  p_vertices->push_back(p);
625  }
626 
627  if (p_bandingMode == SegmentedLineMode)
628  emit measureChange();
629  }
630  break;
631  }
632 
633  MdiCubeViewport * activeViewport = cubeViewport();
634  for (int i = 0; i < (int) cubeViewportList()->size(); i++) {
635  MdiCubeViewport * curViewport = cubeViewportList()->at(i);
636  if (curViewport == activeViewport ||
637  (activeViewport->isLinked() && curViewport->isLinked())) {
638  curViewport->viewport()->repaint();
639  }
640  }
641  }
642 
673  QList<QPoint> vertices = *p_vertices;
674 
675  if(!figureComplete())
676  return vertices;
677 
678  if(p_tracking) {
679  switch(p_bandingMode) {
680  case AngleMode:
681  case LineMode:
682  case SegmentedLineMode:
683  vertices.push_back(*p_mouseLoc);
684  break;
685 
686  case RectangleMode: {
687  QPoint corner1 = QPoint(p_mouseLoc->x(), vertices[0].y());
688  QPoint corner2 = QPoint(p_mouseLoc->x(), p_mouseLoc->y());
689  QPoint corner3 = QPoint(vertices[0].x(), p_mouseLoc->y());
690  vertices.push_back(corner1);
691  vertices.push_back(corner2);
692  vertices.push_back(corner3);
693  }
694  break;
695 
696  case RotatedRectangleMode: {
697  QPoint missingVertex;
698  calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex);
699  vertices.push_back(*p_mouseLoc);
700  vertices.push_back(missingVertex);
701  }
702  break;
703 
704 
705  case CircleMode: {
706  int xradius = abs(p_mouseLoc->x() - vertices[0].x()) / 2;
707  int yradius = xradius;
708 
709  if(p_mouseLoc->x() - vertices[0].x() < 0) {
710  xradius *= -1;
711  }
712 
713  if(p_mouseLoc->y() - vertices[0].y() < 0) {
714  yradius *= -1;
715  }
716 
717  // Adjust p_vertices[0] from upper left to center
718  vertices[0].setX(vertices[0].x() + xradius);
719  vertices[0].setY(vertices[0].y() + yradius);
720 
721  vertices.push_back(*p_mouseLoc);
722 
723  vertices[1].setX(vertices[0].x() + xradius);
724  vertices[1].setY(vertices[0].y() + yradius);
725  }
726  break;
727 
728  case EllipseMode: {
729  // Adjust p_vertices[0] from upper left to center
730  double xradius = (p_mouseLoc->x() - vertices[0].x()) / 2.0;
731  double yradius = (p_mouseLoc->y() - vertices[0].y()) / 2.0;
732  vertices[0].setX((int)(vertices[0].x() + xradius));
733  vertices[0].setY((int)(vertices[0].y() + yradius));
734 
735  vertices.push_back(*p_mouseLoc);
736  }
737  break;
738 
739  case PolygonMode:
740  break;
741  }
742  }
743 
744  return vertices;
745  }
746 
753  p_vertices->clear();
754  p_tracking = false;
755  p_mouseDown = false;
756  p_doubleClicking = false;
757  repaint();
758  }
759 
760  Angle RubberBandTool::angle() {
761  Angle result;
762 
763  if(currentMode() == AngleMode) {
764  // We cancluate the angle by considering each line an angle itself, with respect to the
765  // X-Axis, and then differencing them.
766  //
767  // theta1 = arctan((point0Y - point1Y) / (point0X - point1X))
768  // theta2 = arctan((point2Y - point1Y) / (point2X - point1X))
769  // |
770  // | / <-- point0
771  // | / |
772  // | / |
773  // theta1 | / |
774  // --> |/ | <-- 90 degrees
775  // point1 --> ------|---------------------------
776  //(vertex) --> |\ | <-- 90 degrees
777  // theta2 | \ |
778  // | \ |
779  // | \ |
780  // | \ |
781  // | \|
782  // | | <-- point 2
783  //
784  // angle = theta1 - theta2; **
785  QList<QPoint> verticesList = vertices();
786  double theta1 = atan2((double)(verticesList[0].y() - verticesList[1].y()), (double)(verticesList[0].x() - verticesList[1].x()));
787  double theta2 = atan2((double)(verticesList[2].y() - verticesList[1].y()), (double)(verticesList[2].x() - verticesList[1].x()));
788  double angle = (theta1 - theta2);
789 
790  // Force the angle into [0,2PI]
791  while(angle < 0.0) {
792  angle += PI * 2;
793  }
794  while(angle > PI * 2) {
795  angle -= PI * 2;
796  }
797 
798  // With our [0,2PI] angle, let's make it [0,PI] to get the interior angle.
799  if(angle > PI) {
800  angle = (PI * 2.0) - angle;
801  }
802 
803  result = Angle(angle, Angle::Radians);
804  }
805 
806  return result;
807  }
808 
813  if(cubeViewport() != NULL) {
814  cubeViewport()->viewport()->repaint();
815  }
816  }
817 
823  geos::geom::Geometry *RubberBandTool::geometry() {
824  geos::geom::Geometry *geometry = NULL;
825  QList<QPoint> verticesList = vertices();
826 
827  switch(p_bandingMode) {
828  case AngleMode: {
829  if(verticesList.size() != 3)
830  break;
831 
832  geos::geom::CoordinateSequence *points1 = new geos::geom::CoordinateArraySequence();
833  geos::geom::CoordinateSequence *points2 = new geos::geom::CoordinateArraySequence();
834 
835  points1->add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
836  points1->add(geos::geom::Coordinate(verticesList[1].x(), verticesList[1].y()));
837  points2->add(geos::geom::Coordinate(verticesList[1].x(), verticesList[1].y()));
838  points2->add(geos::geom::Coordinate(verticesList[2].x(), verticesList[2].y()));
839 
840  geos::geom::LineString *line1 = globalFactory.createLineString(points1);
841  geos::geom::LineString *line2 = globalFactory.createLineString(points2);
842  std::vector<geos::geom::Geometry *> *lines = new std::vector<geos::geom::Geometry *>;
843  lines->push_back(line1);
844  lines->push_back(line2);
845 
846  geos::geom::MultiLineString *angle = globalFactory.createMultiLineString(lines);
847  geometry = angle;
848  }
849  break;
850 
851  case CircleMode:
852  case EllipseMode: {
853  if(verticesList.size() != 2)
854  break;
855  // A circle is an ellipse, so it gets no special case
856  // Equation of an ellipse: (x-h)^2/a^2 + (y-k)^2/b^2 = 1 where
857  // h is the X-location of the center, k is the Y-location of the center
858  // a is the x-radius and b is the y-radius.
859  // Solving for y, we get
860  // y = +-sqrt(b^2(1-(x-h)^2/a^2)) + k
861  // and our domain is [h-a,h+a]
862  // We need the equation of this ellipse!
863  double h = verticesList[0].x();
864  double k = verticesList[0].y();
865  double a = abs(verticesList[0].x() - verticesList[1].x());
866  double b = abs(verticesList[0].y() - verticesList[1].y());
867  if(a == 0)
868  break; // Return null, we can't make an ellipse from this.
869  if(b == 0)
870  break; // Return null, we can't make an ellipse from this.
871 
872  // We're ready to try to solve
873  double originalX = 0.0, originalY = 0.0;
874  geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence();
875 
876  // Now iterate through our domain, solving for y positive, using 1/5th of a pixel increments
877  for(double x = h - a; x <= h + a; x += 0.2) {
878  double y = sqrt(pow(b, 2) * (1.0 - pow((x - h), 2) / pow(a, 2))) + k;
879  points->add(geos::geom::Coordinate(x, y));
880 
881  if(x == h - a) {
882  originalX = x;
883  originalY = y;
884  }
885  }
886 
887  // Iterate through our domain backwards, solving for y negative, using 1/5th of a pixel decrements
888  for(double x = h + a; x >= h - a; x -= 0.2) {
889  double y = -1.0 * sqrt(pow(b, 2) * (1.0 - pow((x - h), 2) / pow(a, 2))) + k;
890  points->add(geos::geom::Coordinate(x, y));
891  }
892 
893  points->add(geos::geom::Coordinate(originalX, originalY));
894 
895  geometry = globalFactory.createPolygon(
896  globalFactory.createLinearRing(points), NULL
897  );
898  }
899  break;
900 
901  case RectangleMode:
902  case RotatedRectangleMode:
903  case PolygonMode: {
904  if(verticesList.size() < 3)
905  break;
906 
907  geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence();
908 
909  for(int vertex = 0; vertex < verticesList.size(); vertex++) {
910  points->add(geos::geom::Coordinate(verticesList[vertex].x(), verticesList[vertex].y()));
911  }
912 
913  points->add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
914 
915  geometry = globalFactory.createPolygon(globalFactory.createLinearRing(points), NULL);
916 
917  }
918  break;
919 
920  case LineMode: {
921  if(verticesList.size() != 2)
922  break;
923 
924  geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence();
925  points->add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
926  points->add(geos::geom::Coordinate(verticesList[1].x(), verticesList[1].y()));
927  geos::geom::LineString *line = globalFactory.createLineString(points);
928  geometry = line;
929  }
930  break;
931 
932  case SegmentedLineMode: {
933  if(verticesList.size() < 2)
934  break;
935  geos::geom::CoordinateSequence *points = new geos::geom::CoordinateArraySequence();
936 
937  for(int vertex = 0; vertex < verticesList.size(); vertex++) {
938  points->add(geos::geom::Coordinate(verticesList[vertex].x(), verticesList[vertex].y()));
939  }
940 
941  geos::geom::LineString *line = globalFactory.createLineString(points);
942  geometry = line;
943  }
944  break;
945  }
946 
947  if(geometry != NULL && !geometry->isValid()) {
948  geometry = NULL;
949  }
950 
951  return geometry;
952  }
953 
967  QRect rect;
968 
969  if(currentMode() == RectangleMode && figureValid()) {
970  QList<QPoint> verticesList = vertices();
971 
972  //Check the corners for upper left and lower right.
973  int x1, x2, y1, y2;
974  //Point 1 is in the left, make point1.x upperleft.x
975  if(verticesList[0].x() < verticesList[2].x()) {
976  x1 = verticesList[0].x();
977  x2 = verticesList[2].x();
978  }
979  //Otherwise Point1 is in the right, make point1.x lowerright.x
980  else {
981  x1 = verticesList[2].x();
982  x2 = verticesList[0].x();
983  }
984 
985  //Point 1 is in the top, make point1.y upperleft.y
986  if(verticesList[0].y() < verticesList[2].y()) {
987  y1 = verticesList[0].y();
988  y2 = verticesList[2].y();
989  }
990  //Otherwise Point1 is in the bottom, make point1.y lowerright.y
991  else {
992  y1 = verticesList[2].y();
993  y2 = verticesList[0].y();
994  }
995 
996  rect = QRect(x1, y1, x2 - x1, y2 - y1);
997  }
998  //RectangleMode is not valid, or RubberBandTool is in the wrong mode, return error
999  else {
1000  QMessageBox::information((QWidget *)parent(),
1001  "Error", "**PROGRAMMER ERROR** Invalid RectangleMode");
1002  }
1003 
1004  return rect;
1005  }
1006 
1012  Qt::MouseButton RubberBandTool::mouseButton() {
1013  return p_mouseButton;
1014  }
1015 
1017  return figureComplete() && figureValid();
1018  }
1019 
1020 
1021  bool RubberBandTool::figureComplete() {
1022  bool complete = false;
1023 
1024  switch(p_bandingMode) {
1025  case AngleMode:
1026  complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 3);
1027  break;
1028  case LineMode:
1029  complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2);
1030  break;
1031 
1032  case RectangleMode:
1033  complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 4);
1034  break;
1035 
1036  case RotatedRectangleMode:
1037  complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 4);
1038  break;
1039 
1040  case CircleMode:
1041  case EllipseMode:
1042  complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2);
1043  break;
1044 
1045  case SegmentedLineMode:
1046  complete = (p_vertices->size() > 1 && !p_tracking) || (p_vertices->size() > 0);
1047  break;
1048 
1049  case PolygonMode:
1050  complete = (p_vertices->size() > 2 && !p_tracking);
1051  break;
1052  }
1053  return complete;
1054  }
1055 
1056  bool RubberBandTool::figureValid() {
1057  if(!figureComplete())
1058  return false;
1059  bool valid = true;
1060  QList<QPoint> verticesList = vertices();
1061 
1062  switch(p_bandingMode) {
1063  case AngleMode: {
1064  // Just make sure the vertex and an angle side don't lie on the same point
1065  // No point tolerance allowed
1066  valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1067  valid &= verticesList[2].x() != verticesList[1].x() || verticesList[2].y() != verticesList[1].y();
1068  }
1069  break;
1070  case LineMode: {
1071  // Just make sure the line doesnt start/end at same point if point not allowed
1072  if(p_pointTolerance == 0) {
1073  valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1074  }
1075  }
1076  break;
1077 
1078  case RectangleMode: {
1079  // Make sure there's a height and width if point not allowed
1080  if(p_pointTolerance == 0) {
1081  valid = verticesList[0].x() != verticesList[2].x() && verticesList[0].y() != verticesList[2].y();
1082  }
1083  }
1084  break;
1085 
1086  case RotatedRectangleMode: {
1087  // Make sure there's a height and width once again, point tolerance not allowed
1088  valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1089  valid &= verticesList[1].x() != verticesList[2].x() || verticesList[1].y() != verticesList[2].y();
1090  }
1091  break;
1092 
1093  case CircleMode:
1094  case EllipseMode: {
1095  // Make sure there's a height and width, point tolerance not allowed
1096  valid = verticesList[0].x() != verticesList[1].x() && verticesList[0].y() != verticesList[1].y();
1097  }
1098  break;
1099 
1100  case SegmentedLineMode: {
1101  valid = verticesList.size() > 1;
1102  }
1103  break;
1104 
1105  case PolygonMode: {
1106  // For polygons, we must revert back to using geos
1107  geos::geom::Geometry *poly = geometry();
1108  valid = poly && poly->isValid();
1109  delete poly;
1110  }
1111  break;
1112  }
1113 
1114  return valid;
1115  }
1116 
1117  void RubberBandTool::enablePoints(unsigned int pixTolerance) {
1118  p_pointTolerance = pixTolerance;
1119  }
1120 
1121  bool RubberBandTool::figureIsPoint() {
1122  if(!figureValid())
1123  return false;
1124  bool isPoint = true;
1125  QList<QPoint> verticesList = vertices();
1126 
1127  switch(p_bandingMode) {
1128  case AngleMode:
1129  case RotatedRectangleMode:
1130  case CircleMode:
1131  case EllipseMode:
1132  case PolygonMode:
1133  case SegmentedLineMode:
1134  isPoint = false;
1135  break;
1136 
1137  case LineMode: {
1138  isPoint = (abs(verticesList[0].x() - verticesList[1].x()) +
1139  abs(verticesList[0].y() - verticesList[1].y()) < (int)p_pointTolerance);
1140  }
1141  break;
1142 
1143  case RectangleMode: {
1144  isPoint = (abs(verticesList[0].x() - verticesList[2].x()) +
1145  abs(verticesList[0].y() - verticesList[2].y()) < (int)p_pointTolerance);
1146  }
1147  break;
1148  }
1149 
1150  return isPoint;
1151  }
1152 
1153 
1156  reset();
1157  repaint();
1158  }
1159 
1160 
1161  RubberBandTool::RubberBandMode RubberBandTool::currentMode() {
1162  return p_bandingMode;
1163  };
1164 
1165 
1166  double RubberBandTool::area() {
1167  return 0.0; //<! Returns the area of the figure
1168  }
1169 
1170 
1171  void RubberBandTool::enableAllClicks() {
1172  p_allClicks = true;
1173  }
1174 
1175 
1176  void RubberBandTool::escapeKeyPress() {
1177  reset();
1178  }
1179 
1180 
1181  void RubberBandTool::scaleChanged() {
1182  reset();
1183  }
1184 
1185 
1186 }