1 #include "RubberBandTool.h" 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" 35 RubberBandTool::RubberBandTool(
QWidget *parent) :
Tool(parent) {
39 p_mouseLoc =
new QPoint;
41 p_bandingMode = LineMode;
48 RubberBandTool::~RubberBandTool() {
74 QPen pen(QColor(255, 0, 0));
75 QPen greenPen(QColor(0, 255, 0));
76 pen.setStyle(Qt::SolidLine);
77 greenPen.setStyle(Qt::SolidLine);
86 switch(p_bandingMode) {
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);
108 if(!p_tracking && p_vertices->size() > 0) {
109 painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]);
115 if(p_vertices->size() != 0) {
117 int width = 2 * (verticesList[1].x() - verticesList[0].x());
118 int height = 2 * (verticesList[1].y() - verticesList[0].y());
121 painter->drawEllipse(verticesList[0].x() - width / 2, verticesList[0].y() - height / 2,
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);
137 if(p_tracking && p_vertices->size() > 0) {
140 else if(p_vertices->size() > 0) {
142 painter->drawLine((*p_vertices)[0], (*p_vertices)[ p_vertices->size() - 1 ]);
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]);
155 else if(p_vertices->size() == 4) {
156 painter->drawLine((*p_vertices)[0], (*p_vertices)[ 3 ]);
162 if(p_indicatorColors) {
163 painter->setPen(greenPen);
164 if(p_vertices->size() > 1) {
165 painter->drawLine((*p_vertices)[0], (*p_vertices)[1]);
167 else if(p_vertices->size() == 1) {
168 painter->drawLine((*p_vertices)[0], *p_mouseLoc);
171 painter->setPen(pen);
176 case SegmentedLineMode:
191 double slope = ((double)corner2.y() - (double)corner1.y()) / ((
double)corner2.x() - (double)corner1.x());
193 if((fabs(slope) > DBL_EPSILON) && (slope < DBL_MAX) && (slope > -DBL_MAX)) {
198 double parallelB = -1 * slope * corner3.x() + corner3.y();
203 double perpSlope = -1.0 / slope;
204 double perpLineMode1b = perpSlope * (-1 * corner1.x()) + corner1.y();
205 double perpLineMode2b = perpSlope * (-1 * corner2.x()) + corner2.y();
210 double perpLineMode1k = perpLineMode1b - parallelB;
211 double perpLineMode2k = perpLineMode2b - parallelB;
218 double perpLineMode1IntersectX = perpLineMode1k / (slope - perpSlope);
219 double perpLineMode2IntersectX = perpLineMode2k / (slope - perpSlope);
223 corner3.setX((
int)perpLineMode2IntersectX);
224 corner3.setY((
int)(perpLineMode2IntersectX * slope + parallelB));
225 corner4.setX((
int)perpLineMode1IntersectX);
226 corner4.setY((
int)(perpLineMode1IntersectX * slope + parallelB));
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());
235 corner3.setX(corner3.x());
236 corner3.setY(corner2.y());
237 corner4.setX(corner3.x());
238 corner4.setY(corner1.y());
249 for(
int vertex = 1; vertex < p_vertices->size(); vertex++) {
250 QPoint start = (*p_vertices)[vertex - 1];
251 QPoint end = (*p_vertices)[vertex];
253 painter->drawLine(start, end);
256 if(p_tracking && (p_vertices->size() > 0)) {
257 QPoint start = (*p_vertices)[p_vertices->size() - 1];
258 QPoint end = *p_mouseLoc;
260 painter->drawLine(start, end);
272 QPoint upperRight = QPoint(lowerRight.x(), upperLeft.y());
273 QPoint lowerLeft = QPoint(upperLeft.x(), lowerRight.y());
275 paintRectangle(upperLeft, upperRight, lowerLeft, lowerRight, painter);
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);
303 RubberBandMode oldMode = p_bandingMode;
304 p_bandingMode = mode;
305 p_indicatorColors = showIndicatorColors;
309 p_drawActiveOnly =
false;
313 if(oldMode != mode) {
334 p_drawActiveOnly = activeOnly;
344 p_doubleClicking =
true;
347 switch(p_bandingMode) {
353 case RotatedRectangleMode:
356 case SegmentedLineMode:
360 emit bandingComplete();
390 if((s & Qt::LeftButton) != Qt::LeftButton && !p_allClicks) {
394 switch(p_bandingMode) {
404 p_vertices->push_back(p);
407 case RotatedRectangleMode:
408 if(p_vertices->size() == 4) {
412 if(p_vertices->size() == 0) {
413 p_vertices->push_back(p);
418 case SegmentedLineMode:
425 if(p_vertices->size() == 0 || (*p_vertices)[ p_vertices->size() - 1 ] != p) {
426 p_vertices->push_back(p);
476 if ((s & Qt::ControlModifier) == Qt::ControlModifier)
483 if((s & Qt::LeftButton) == Qt::LeftButton || p_allClicks) {
490 switch(p_bandingMode) {
492 if(p_vertices->size() == 3) {
496 p_vertices->push_back(*p_mouseLoc);
499 if(p_vertices->size() == 3) {
501 emit bandingComplete();
509 case RectangleMode: {
512 emit bandingComplete();
516 case RotatedRectangleMode: {
517 if(p_vertices->size() == 1) {
518 p_vertices->push_back(*p_mouseLoc);
520 else if(p_vertices->size() == 2) {
523 emit bandingComplete();
528 case SegmentedLineMode:
533 p_doubleClicking =
false;
539 if (curViewport == activeViewport ||
541 curViewport->viewport()->repaint();
555 if (p_vertices->size()) {
556 QPoint lastVertex = p_vertices->at(p_vertices->size() - 1);
558 int deltaX = abs(p.x() - lastVertex.x());
559 int deltaY = abs(p.y() - lastVertex.y());
562 p.setY(lastVertex.y());
564 p.setX(lastVertex.x());
596 if ((p_mouseButton & Qt::ControlModifier) == Qt::ControlModifier)
601 switch(p_bandingMode) {
603 case RotatedRectangleMode:
604 if(p_vertices->size() == 2) {
605 emit measureChange();
612 if(p_vertices->size() == 1) {
613 emit measureChange();
618 emit measureChange();
621 case SegmentedLineMode:
623 if(p_mouseDown && p != (*p_vertices)[ p_vertices->size() - 1 ]) {
624 p_vertices->push_back(p);
627 if (p_bandingMode == SegmentedLineMode)
628 emit measureChange();
636 if (curViewport == activeViewport ||
638 curViewport->viewport()->repaint();
675 if(!figureComplete())
679 switch(p_bandingMode) {
682 case SegmentedLineMode:
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());
696 case RotatedRectangleMode: {
697 QPoint missingVertex;
698 calcRectCorners((*p_vertices)[0], (*p_vertices)[1], *p_mouseLoc, missingVertex);
706 int xradius = abs(p_mouseLoc->x() -
vertices[0].x()) / 2;
707 int yradius = xradius;
709 if(p_mouseLoc->x() -
vertices[0].x() < 0) {
713 if(p_mouseLoc->y() -
vertices[0].y() < 0) {
730 double xradius = (p_mouseLoc->x() -
vertices[0].x()) / 2.0;
731 double yradius = (p_mouseLoc->y() -
vertices[0].y()) / 2.0;
756 p_doubleClicking =
false;
760 Angle RubberBandTool::angle() {
763 if(currentMode() == AngleMode) {
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);
794 while(angle >
PI * 2) {
800 angle = (
PI * 2.0) - angle;
824 geos::geom::Geometry *
geometry = NULL;
827 switch(p_bandingMode) {
829 if(verticesList.size() != 3)
832 geos::geom::CoordinateSequence *points1 =
new geos::geom::CoordinateArraySequence();
833 geos::geom::CoordinateSequence *points2 =
new geos::geom::CoordinateArraySequence();
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()));
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);
846 geos::geom::MultiLineString *angle = globalFactory.createMultiLineString(lines);
853 if(verticesList.size() != 2)
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());
873 double originalX = 0.0, originalY = 0.0;
874 geos::geom::CoordinateSequence *points =
new geos::geom::CoordinateArraySequence();
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));
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));
893 points->add(geos::geom::Coordinate(originalX, originalY));
895 geometry = globalFactory.createPolygon(
896 globalFactory.createLinearRing(points), NULL
902 case RotatedRectangleMode:
904 if(verticesList.size() < 3)
907 geos::geom::CoordinateSequence *points =
new geos::geom::CoordinateArraySequence();
909 for(
int vertex = 0; vertex < verticesList.size(); vertex++) {
910 points->add(geos::geom::Coordinate(verticesList[vertex].x(), verticesList[vertex].y()));
913 points->add(geos::geom::Coordinate(verticesList[0].x(), verticesList[0].y()));
915 geometry = globalFactory.createPolygon(globalFactory.createLinearRing(points), NULL);
921 if(verticesList.size() != 2)
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);
932 case SegmentedLineMode: {
933 if(verticesList.size() < 2)
935 geos::geom::CoordinateSequence *points =
new geos::geom::CoordinateArraySequence();
937 for(
int vertex = 0; vertex < verticesList.size(); vertex++) {
938 points->add(geos::geom::Coordinate(verticesList[vertex].x(), verticesList[vertex].y()));
941 geos::geom::LineString *line = globalFactory.createLineString(points);
969 if(currentMode() == RectangleMode && figureValid()) {
975 if(verticesList[0].x() < verticesList[2].x()) {
976 x1 = verticesList[0].x();
977 x2 = verticesList[2].x();
981 x1 = verticesList[2].x();
982 x2 = verticesList[0].x();
986 if(verticesList[0].y() < verticesList[2].y()) {
987 y1 = verticesList[0].y();
988 y2 = verticesList[2].y();
992 y1 = verticesList[2].y();
993 y2 = verticesList[0].y();
996 rect = QRect(x1, y1, x2 - x1, y2 - y1);
1000 QMessageBox::information((
QWidget *)parent(),
1001 "Error",
"**PROGRAMMER ERROR** Invalid RectangleMode");
1013 return p_mouseButton;
1017 return figureComplete() && figureValid();
1021 bool RubberBandTool::figureComplete() {
1022 bool complete =
false;
1024 switch(p_bandingMode) {
1026 complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 3);
1029 complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2);
1033 complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 4);
1036 case RotatedRectangleMode:
1037 complete = (p_vertices->size() == 2 && p_tracking) || (p_vertices->size() == 4);
1042 complete = (p_vertices->size() == 1 && p_tracking) || (p_vertices->size() == 2);
1045 case SegmentedLineMode:
1046 complete = (p_vertices->size() > 1 && !p_tracking) || (p_vertices->size() > 0);
1050 complete = (p_vertices->size() > 2 && !p_tracking);
1056 bool RubberBandTool::figureValid() {
1057 if(!figureComplete())
1062 switch(p_bandingMode) {
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();
1072 if(p_pointTolerance == 0) {
1073 valid = verticesList[0].x() != verticesList[1].x() || verticesList[0].y() != verticesList[1].y();
1078 case RectangleMode: {
1080 if(p_pointTolerance == 0) {
1081 valid = verticesList[0].x() != verticesList[2].x() && verticesList[0].y() != verticesList[2].y();
1086 case RotatedRectangleMode: {
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();
1096 valid = verticesList[0].x() != verticesList[1].x() && verticesList[0].y() != verticesList[1].y();
1100 case SegmentedLineMode: {
1101 valid = verticesList.size() > 1;
1107 geos::geom::Geometry *poly =
geometry();
1108 valid = poly && poly->isValid();
1117 void RubberBandTool::enablePoints(
unsigned int pixTolerance) {
1118 p_pointTolerance = pixTolerance;
1121 bool RubberBandTool::figureIsPoint() {
1124 bool isPoint =
true;
1127 switch(p_bandingMode) {
1129 case RotatedRectangleMode:
1133 case SegmentedLineMode:
1138 isPoint = (abs(verticesList[0].x() - verticesList[1].x()) +
1139 abs(verticesList[0].y() - verticesList[1].y()) < (int)p_pointTolerance);
1143 case RectangleMode: {
1144 isPoint = (abs(verticesList[0].x() - verticesList[2].x()) +
1145 abs(verticesList[0].y() - verticesList[2].y()) < (int)p_pointTolerance);
1161 RubberBandTool::RubberBandMode RubberBandTool::currentMode() {
1162 return p_bandingMode;
1166 double RubberBandTool::area() {
1171 void RubberBandTool::enableAllClicks() {
1176 void RubberBandTool::escapeKeyPress() {
1181 void RubberBandTool::scaleChanged() {
Cube display widget for certain Isis MDI applications.
const double PI
The mathematical constant PI.
Namespace for the standard library.
bool isLinked() const
Is the viewport linked with other viewports.
Defines an angle and provides unit conversions.
Namespace for ISIS/Bullet specific routines.
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...