1#include "RubberBandTool.h"
14#include "geos/geom/CoordinateSequence.h"
15#include "geos/geom/Coordinate.h"
16#include "geos/geom/LineString.h"
17#include "geos/geom/MultiLineString.h"
18#include "geos/geom/Polygon.h"
22#include "MdiCubeViewport.h"
23#include "PolygonTools.h"
24#include "SerialNumberList.h"
38 p_mouseLoc =
new QPoint;
40 p_bandingMode = LineMode;
47 RubberBandTool::~RubberBandTool() {
73 QPen pen(QColor(255, 0, 0));
74 QPen greenPen(QColor(0, 255, 0));
75 pen.setStyle(Qt::SolidLine);
76 greenPen.setStyle(Qt::SolidLine);
85 switch(p_bandingMode) {
92 if(figureIsPoint() && !p_tracking) {
93 painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() - 10,
94 (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() + 10);
95 painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() + 10,
96 (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() - 10);
107 if(!p_tracking && p_vertices->size() > 0) {
108 painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]);
114 if(p_vertices->size() != 0) {
115 QList<QPoint> verticesList =
vertices();
116 int width = 2 * (verticesList[1].x() - verticesList[0].x());
117 int height = 2 * (verticesList[1].y() - verticesList[0].y());
120 painter->drawEllipse(verticesList[0].x() - width / 2, verticesList[0].y() - height / 2,
128 case RectangleMode: {
129 if(figureIsPoint() && !p_tracking) {
130 painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() - 10,
131 (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() + 10);
132 painter->drawLine((*p_vertices)[0].x() - 10, (*p_vertices)[0].y() + 10,
133 (*p_vertices)[0].x() + 10, (*p_vertices)[0].y() - 10);
136 if(p_tracking && p_vertices->size() > 0) {
139 else if(p_vertices->size() > 0) {
141 painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]);
147 case RotatedRectangleMode: {
148 if(p_vertices->size() == 2) {
149 QPoint missingVertex;
150 calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex);
151 painter->drawLine(*p_mouseLoc, missingVertex);
152 painter->drawLine(missingVertex, (*p_vertices)[0]);
154 else if(p_vertices->size() == 4) {
155 painter->drawLine((*p_vertices)[0], (*p_vertices)[ 3 ]);
161 if(p_indicatorColors) {
162 painter->setPen(greenPen);
163 if(p_vertices->size() > 1) {
164 painter->drawLine((*p_vertices)[0], (*p_vertices)[1]);
166 else if(p_vertices->size() == 1) {
167 painter->drawLine((*p_vertices)[0], *p_mouseLoc);
170 painter->setPen(pen);
175 case SegmentedLineMode:
190 double slope = ((double)corner2.y() - (double)corner1.y()) / ((
double)corner2.x() - (double)corner1.x());
192 if((fabs(slope) > DBL_EPSILON) && (slope < DBL_MAX) && (slope > -DBL_MAX)) {
197 double parallelB = -1 * slope * corner3.x() + corner3.y();
202 double perpSlope = -1.0 / slope;
203 double perpLineMode1b = perpSlope * (-1 * corner1.x()) + corner1.y();
204 double perpLineMode2b = perpSlope * (-1 * corner2.x()) + corner2.y();
209 double perpLineMode1k = perpLineMode1b - parallelB;
210 double perpLineMode2k = perpLineMode2b - parallelB;
217 double perpLineMode1IntersectX = perpLineMode1k / (slope - perpSlope);
218 double perpLineMode2IntersectX = perpLineMode2k / (slope - perpSlope);
222 corner3.setX((
int)perpLineMode2IntersectX);
223 corner3.setY((
int)(perpLineMode2IntersectX * slope + parallelB));
224 corner4.setX((
int)perpLineMode1IntersectX);
225 corner4.setY((
int)(perpLineMode1IntersectX * slope + parallelB));
227 else if(fabs(slope) < DBL_EPSILON) {
228 corner3.setX(corner2.x());
229 corner3.setY(corner3.y());
230 corner4.setX(corner1.x());
231 corner4.setY(corner3.y());
234 corner3.setX(corner3.x());
235 corner3.setY(corner2.y());
236 corner4.setX(corner3.x());
237 corner4.setY(corner1.y());
248 for(
int vertex = 1; vertex < p_vertices->size(); vertex++) {
249 QPoint start = (*p_vertices)[vertex - 1];
250 QPoint end = (*p_vertices)[vertex];
252 painter->drawLine(start, end);
255 if(p_tracking && (p_vertices->size() > 0)) {
256 QPoint start = (*p_vertices)[p_vertices->size() - 1];
257 QPoint end = *p_mouseLoc;
259 painter->drawLine(start, end);
271 QPoint upperRight = QPoint(lowerRight.x(), upperLeft.y());
272 QPoint lowerLeft = QPoint(upperLeft.x(), lowerRight.y());
274 paintRectangle(upperLeft, upperRight, lowerLeft, lowerRight, painter);
287 QPoint lowerLeft, QPoint lowerRight, QPainter *painter) {
288 painter->drawLine(upperLeft, upperRight);
289 painter->drawLine(upperRight, lowerRight);
290 painter->drawLine(lowerRight, lowerLeft);
291 painter->drawLine(lowerLeft, upperLeft);
302 RubberBandMode oldMode = p_bandingMode;
303 p_bandingMode = mode;
304 p_indicatorColors = showIndicatorColors;
308 p_drawActiveOnly =
false;
312 if(oldMode != mode) {
333 p_drawActiveOnly = activeOnly;
343 p_doubleClicking =
true;
346 switch(p_bandingMode) {
352 case RotatedRectangleMode:
355 case SegmentedLineMode:
359 emit bandingComplete();
389 if((s & Qt::LeftButton) != Qt::LeftButton && !p_allClicks) {
393 switch(p_bandingMode) {
403 p_vertices->push_back(p);
406 case RotatedRectangleMode:
407 if(p_vertices->size() == 4) {
411 if(p_vertices->size() == 0) {
412 p_vertices->push_back(p);
417 case SegmentedLineMode:
424 if(p_vertices->size() == 0 || (*p_vertices)[ p_vertices->size() - 1 ] != p) {
425 p_vertices->push_back(p);
475 if ((s & Qt::ControlModifier) == Qt::ControlModifier)
482 if((s & Qt::LeftButton) == Qt::LeftButton || p_allClicks) {
489 switch(p_bandingMode) {
491 if(p_vertices->size() == 3) {
495 p_vertices->push_back(*p_mouseLoc);
498 if(p_vertices->size() == 3) {
500 emit bandingComplete();
508 case RectangleMode: {
511 emit bandingComplete();
515 case RotatedRectangleMode: {
516 if(p_vertices->size() == 1) {
517 p_vertices->push_back(*p_mouseLoc);
519 else if(p_vertices->size() == 2) {
522 emit bandingComplete();
527 case SegmentedLineMode:
532 p_doubleClicking =
false;
538 if (curViewport == activeViewport ||
539 (activeViewport->isLinked() && curViewport->isLinked())) {
540 curViewport->viewport()->repaint();
554 if (p_vertices->size()) {
555 QPoint lastVertex = p_vertices->at(p_vertices->size() - 1);
557 int deltaX = abs(p.x() - lastVertex.x());
558 int deltaY = abs(p.y() - lastVertex.y());
561 p.setY(lastVertex.y());
563 p.setX(lastVertex.x());
595 if ((p_mouseButton & Qt::ControlModifier) == Qt::ControlModifier)
600 switch(p_bandingMode) {
602 case RotatedRectangleMode:
603 if(p_vertices->size() == 2) {
604 emit measureChange();
611 if(p_vertices->size() == 1) {
612 emit measureChange();
617 emit measureChange();
620 case SegmentedLineMode:
622 if(p_mouseDown && p != (*p_vertices)[ p_vertices->size() - 1 ]) {
623 p_vertices->push_back(p);
626 if (p_bandingMode == SegmentedLineMode)
627 emit measureChange();
635 if (curViewport == activeViewport ||
636 (activeViewport->isLinked() && curViewport->isLinked())) {
637 curViewport->viewport()->repaint();
672 QList<QPoint>
vertices = *p_vertices;
674 if(!figureComplete())
678 switch(p_bandingMode) {
681 case SegmentedLineMode:
685 case RectangleMode: {
686 QPoint corner1 = QPoint(p_mouseLoc->x(),
vertices[0].y());
687 QPoint corner2 = QPoint(p_mouseLoc->x(), p_mouseLoc->y());
688 QPoint corner3 = QPoint(
vertices[0].x(), p_mouseLoc->y());
695 case RotatedRectangleMode: {
696 QPoint missingVertex;
697 calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex);
705 int xradius = abs(p_mouseLoc->x() -
vertices[0].x()) / 2;
706 int yradius = xradius;
708 if(p_mouseLoc->x() -
vertices[0].x() < 0) {
712 if(p_mouseLoc->y() -
vertices[0].y() < 0) {
729 double xradius = (p_mouseLoc->x() -
vertices[0].x()) / 2.0;
730 double yradius = (p_mouseLoc->y() -
vertices[0].y()) / 2.0;
755 p_doubleClicking =
false;
759 Angle RubberBandTool::angle() {
762 if(currentMode() == AngleMode) {
784 QList<QPoint> verticesList =
vertices();
785 double theta1 = atan2((
double)(verticesList[0].y() - verticesList[1].y()), (
double)(verticesList[0].x() - verticesList[1].x()));
786 double theta2 = atan2((
double)(verticesList[2].y() - verticesList[1].y()), (
double)(verticesList[2].x() - verticesList[1].x()));
787 double angle = (theta1 - theta2);
793 while(angle >
PI * 2) {
799 angle = (
PI * 2.0) - angle;
823 geos::geom::Geometry *
geometry = NULL;
824 QList<QPoint> verticesList =
vertices();
826 switch(p_bandingMode) {
828 if(verticesList.size() != 3)
831 geos::geom::CoordinateSequence points1;
832 geos::geom::CoordinateSequence points2;
834 points1.add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
835 points1.add(geos::geom::Coordinate(verticesList[1].x(), verticesList[1].y()));
836 points2.add(geos::geom::Coordinate(verticesList[1].x(), verticesList[1].y()));
837 points2.add(geos::geom::Coordinate(verticesList[2].x(), verticesList[2].y()));
839 geos::geom::LineString *line1 = globalFactory->createLineString(points1).release();
840 geos::geom::LineString *line2 = globalFactory->createLineString(points2).release();
841 std::vector<const geos::geom::Geometry *> lines;
842 lines.push_back(line1);
843 lines.push_back(line2);
845 geos::geom::MultiLineString *angle = globalFactory->createMultiLineString(lines).release();
852 if(verticesList.size() != 2)
862 double h = verticesList[0].x();
863 double k = verticesList[0].y();
864 double a = abs(verticesList[0].x() - verticesList[1].x());
865 double b = abs(verticesList[0].y() - verticesList[1].y());
872 double originalX = 0.0, originalY = 0.0;
873 geos::geom::CoordinateSequence points;
876 for(
double x = h - a; x <= h + a; x += 0.2) {
877 double y = sqrt(pow(b, 2) * (1.0 - pow((x - h), 2) / pow(a, 2))) + k;
878 points.add(geos::geom::Coordinate(x, y));
887 for(
double x = h + a; x >= h - a; x -= 0.2) {
888 double y = -1.0 * sqrt(pow(b, 2) * (1.0 - pow((x - h), 2) / pow(a, 2))) + k;
889 points.add(geos::geom::Coordinate(x, y));
892 points.add(geos::geom::Coordinate(originalX, originalY));
894 geometry = globalFactory->createPolygon(
895 globalFactory->createLinearRing(points)).release();
900 case RotatedRectangleMode:
902 if(verticesList.size() < 3)
905 geos::geom::CoordinateSequence points;
907 for(
int vertex = 0; vertex < verticesList.size(); vertex++) {
908 points.add(geos::geom::Coordinate(verticesList[vertex].x(), verticesList[vertex].y()));
911 points.add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
913 geometry = globalFactory->createPolygon(globalFactory->createLinearRing(points)).release();
919 if(verticesList.size() != 2)
922 geos::geom::CoordinateSequence points;
923 points.add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
924 points.add(geos::geom::Coordinate(verticesList[1].x(), verticesList[1].y()));
925 geos::geom::LineString *line = globalFactory->createLineString(points).release();
930 case SegmentedLineMode: {
931 if(verticesList.size() < 2)
933 geos::geom::CoordinateSequence points;
935 for(
int vertex = 0; vertex < verticesList.size(); vertex++) {
936 points.add(geos::geom::Coordinate(verticesList[vertex].x(), verticesList[vertex].y()));
939 geos::geom::LineString *line = globalFactory->createLineString(points).release();
967 if(currentMode() == RectangleMode && figureValid()) {
968 QList<QPoint> verticesList =
vertices();
973 if(verticesList[0].x() < verticesList[2].x()) {
974 x1 = verticesList[0].x();
975 x2 = verticesList[2].x();
979 x1 = verticesList[2].x();
980 x2 = verticesList[0].x();
984 if(verticesList[0].y() < verticesList[2].y()) {
985 y1 = verticesList[0].y();
986 y2 = verticesList[2].y();
990 y1 = verticesList[2].y();
991 y2 = verticesList[0].y();
994 rect = QRect(x1, y1, x2 - x1, y2 - y1);
998 QMessageBox::information((
QWidget *)parent(),
999 "Error",
"**PROGRAMMER ERROR** Invalid RectangleMode");
1011 return p_mouseButton;
1015 return figureComplete() && figureValid();
1019 bool RubberBandTool::figureComplete() {
1020 bool complete =
false;
1022 switch(p_bandingMode) {
1024 complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 3);
1027 complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2);
1031 complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 4);
1034 case RotatedRectangleMode:
1035 complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 4);
1040 complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2);
1043 case SegmentedLineMode:
1044 complete = (p_vertices->size() > 1 && !p_tracking) || (p_vertices->size() > 0);
1048 complete = (p_vertices->size() > 2 && !p_tracking);
1054 bool RubberBandTool::figureValid() {
1055 if(!figureComplete())
1058 QList<QPoint> verticesList =
vertices();
1060 switch(p_bandingMode) {
1064 valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1065 valid &= verticesList[2].x() != verticesList[1].x() || verticesList[2].y() != verticesList[1].y();
1070 if(p_pointTolerance == 0) {
1071 valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1076 case RectangleMode: {
1078 if(p_pointTolerance == 0) {
1079 valid = verticesList[0].x() != verticesList[2].x() && verticesList[0].y() != verticesList[2].y();
1084 case RotatedRectangleMode: {
1086 valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1087 valid &= verticesList[1].x() != verticesList[2].x() || verticesList[1].y() != verticesList[2].y();
1094 valid = verticesList[0].x() != verticesList[1].x() && verticesList[0].y() != verticesList[1].y();
1098 case SegmentedLineMode: {
1099 valid = verticesList.size() > 1;
1105 geos::geom::Geometry *poly =
geometry();
1106 valid = poly && poly->isValid();
1115 void RubberBandTool::enablePoints(
unsigned int pixTolerance) {
1116 p_pointTolerance = pixTolerance;
1119 bool RubberBandTool::figureIsPoint() {
1122 bool isPoint =
true;
1123 QList<QPoint> verticesList =
vertices();
1125 switch(p_bandingMode) {
1127 case RotatedRectangleMode:
1131 case SegmentedLineMode:
1136 isPoint = (abs(verticesList[0].x() - verticesList[1].x()) +
1137 abs(verticesList[0].y() - verticesList[1].y()) < (int)p_pointTolerance);
1141 case RectangleMode: {
1142 isPoint = (abs(verticesList[0].x() - verticesList[2].x()) +
1143 abs(verticesList[0].y() - verticesList[2].y()) < (int)p_pointTolerance);
1159 RubberBandTool::RubberBandMode RubberBandTool::currentMode() {
1160 return p_bandingMode;
1164 double RubberBandTool::area() {
1169 void RubberBandTool::enableAllClicks() {
1174 void RubberBandTool::escapeKeyPress() {
1179 void RubberBandTool::scaleChanged() {
Defines an angle and provides unit conversions.
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Cube display widget for certain Isis MDI applications.
bool isLinked() const
Is the viewport linked with other viewports.
This is free and unencumbered software released into the public domain.
const double PI
The mathematical constant PI.
Namespace for the standard library.