File failed to load: https://isis.astrogeology.usgs.gov/9.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
MosaicAreaTool.cpp
1#include "MosaicAreaTool.h"
2
3#include <cmath>
4#include <float.h>
5
6#include <QDialog>
7#include <QDoubleValidator>
8#include <QGraphicsEllipseItem>
9#include <QGraphicsScene>
10#include <QGridLayout>
11#include <QLabel>
12#include <QLineEdit>
13#include <QMenu>
14#include <QMessageBox>
15#include <QPushButton>
16
17#include "Angle.h"
18#include "Distance.h"
19#include "IString.h"
20#include "FindSpotGraphicsItem.h"
21#include "MosaicGraphicsView.h"
22#include "MosaicSceneWidget.h"
23#include "Projection.h"
24#include "TProjection.h"
25#include "PvlKeyword.h"
26#include "PvlObject.h"
27
28namespace Isis {
36 MosaicTool(scene) {
37 m_box = NULL;
38 m_drawBox = NULL;
39 m_latLineEdit = NULL;
40 m_lonLineEdit = NULL;
41 m_areaLineEdit = NULL;
42
43 connect(scene, SIGNAL(projectionChanged(Projection *)),
44 this, SLOT(userChangedBox()));
45 }
46
47
52 void MosaicAreaTool::userChangedBox() {
53 bool latValid = false;
54 bool lonValid = false;
55 bool areaValid = false;
56
58 clearBox();
59 return;
60 }
61
62 QString latitude = m_latLineEdit->text();
63
64 if(latitude != "Null" && latitude != "") {
65 int cursorPos = 0;
66 QValidator::State validLat =
67 m_latLineEdit->validator()->validate(latitude, cursorPos);
68 if(validLat != QValidator::Acceptable) {
69 QMessageBox::warning(getWidget(), "Error",
70 "Latitude value must be in the range -90 to 90",
71 QMessageBox::Ok, QMessageBox::NoButton,
72 QMessageBox::NoButton);
73 }
74 else {
75 latValid = true;
76 }
77 }
78
79 //Validate longitude value
80 QString longitude = m_lonLineEdit->text();
81 if(longitude != "Null" && longitude != "" && latValid) {
82 int cursorPos = 0;
83 QValidator::State validLon =
84 m_lonLineEdit->validator()->validate(longitude, cursorPos);
85 if(validLon != QValidator::Acceptable) {
86 QMessageBox::warning(getWidget(), "Error",
87 "Longitude value invalid",
88 QMessageBox::Ok, QMessageBox::NoButton,
89 QMessageBox::NoButton);
90 }
91 else {
92 lonValid = true;
93 }
94 }
95
96 QString areaString = m_areaLineEdit->text();
97 if(areaString != "Null" && areaString != "" && latValid && lonValid) {
98 int cursorPos = 0;
99 QValidator::State validArea =
100 m_areaLineEdit->validator()->validate(areaString, cursorPos);
101 if(validArea != QValidator::Acceptable) {
102 QMessageBox::warning(getWidget(), "Error",
103 "Area value invalid",
104 QMessageBox::Ok, QMessageBox::NoButton,
105 QMessageBox::NoButton);
106 }
107 else {
108 areaValid = true;
109 }
110 }
111
112
113 if(latValid && lonValid && areaValid) {
114 double lat = IString(latitude.toStdString()).ToDouble();
115 double lon = IString(longitude.toStdString()).ToDouble();
116 double area = IString(areaString.toStdString()).ToDouble();
117
118 Projection *projection = getWidget()->getProjection();
119 Projection::ProjectionType ptype = projection->projectionType();
120
121 if (projection && ptype == Projection::Triaxial) {
122 TProjection * tproj = (TProjection *) projection;
123 if (tproj->SetGround(lat, lon)) {
124 QPointF scenePos(projection->XCoord(), -1 * projection->YCoord());
125 QRectF sceneRect(getWidget()->getView()->sceneRect());
126
127 if(sceneRect.contains(scenePos)) {
128 if(m_box != NULL) {
129 clearBox();
130 }
131
132 Distance distance(area, Distance::Meters);
133
134 QPolygonF boxPoly;
135 QRectF latLonRange = calcLatLonRange(QPointF(lon, lat), distance);
136
137 double xStep = latLonRange.width() / 100.0;
138 double yStep = latLonRange.height() / 100.0;
139
140 bool hasPole = (latLonRange.top() == -90 ||
141 latLonRange.bottom() == 90);
142
143 double yPos = latLonRange.top();
144 if (yPos != -90) {
145 for(double xPos = latLonRange.left();
146 xPos <= latLonRange.right();
147 xPos += xStep) {
148 if (tproj->SetGround(yPos, xPos)) {
149 QPointF pos(tproj->XCoord(), -1 * tproj->YCoord());
150 boxPoly << pos;
151 }
152 }
153 }
154
155 double xPos = latLonRange.right();
156 for (double yPos = latLonRange.top();
157 !hasPole && yPos <= latLonRange.bottom();
158 yPos += yStep) {
159 if (tproj->SetGround(yPos, xPos)) {
160 QPointF pos(tproj->XCoord(), -1 * tproj->YCoord());
161 boxPoly << pos;
162 }
163 }
164
165 yPos = latLonRange.bottom();
166 if (yPos != 90) {
167 for (double xPos = latLonRange.right();
168 xPos >= latLonRange.left();
169 xPos -= xStep) {
170 if (tproj->SetGround(yPos, xPos)) {
171 QPointF pos(tproj->XCoord(), -1 * tproj->YCoord());
172 boxPoly << pos;
173 }
174 }
175 }
176
177 xPos = latLonRange.left();
178 for (double yPos = latLonRange.bottom();
179 !hasPole && yPos >= latLonRange.top();
180 yPos -= yStep) {
181 if (tproj->SetGround(yPos, xPos)) {
182 QPointF pos(tproj->XCoord(), -1 * tproj->YCoord());
183 boxPoly << pos;
184 }
185 }
186
187 if (boxPoly.size() > 0) {
188 boxPoly << boxPoly[0];
189
190 m_box = new QGraphicsPolygonItem(boxPoly);
191 m_box->setZValue(DBL_MAX);
192 // Ensure lines are cosmetic (i.e. always 1 pixel on screen)
193 QPen pen;
194 pen.setCosmetic(true);
195 m_box->setPen(pen);
196
197 getWidget()->getScene()->addItem(m_box);
198 getWidget()->getView()->centerOn(scenePos);
199 }
200 }
201 else {
202 QString message = "Lat/Lon not within this view.";
203 QMessageBox::information(getWidget(), "Cannot Calculate Box",
204 message, QMessageBox::Ok);
205 }
206 }
207 }
208 }
209 }
210
211
221 m_action = new QAction(this);
222 m_action->setIcon(getIcon("qmos_area.png"));
223 m_action->setToolTip("Show Area (a)");
224 m_action->setShortcut(Qt::Key_A);
225 QString text =
226 "<b>Function:</b> Draw a box given a distance centered on a "
227 "latitude/longitude.<br><br>"
228 "This tool draws a black square, given an edge length in meters, "
229 "centered on a latitude/longitude point. This box would be a square on "
230 "the surface of the target, and is designed to be modified and warped by "
231 "the current projection."
232 "<p><b>Shortcut:</b> a</p> ";
233 m_action->setWhatsThis(text);
234 return m_action;
235 }
236
237
239 m_latLineEdit = new QLineEdit();
240 m_latLineEdit->setValidator(new QDoubleValidator(-90.0, 90.0, 99, this));
241
242 m_lonLineEdit = new QLineEdit();
243 m_lonLineEdit->setValidator(new QDoubleValidator(this));
244
245 m_areaLineEdit = new QLineEdit();
246 m_areaLineEdit->setValidator(new QDoubleValidator(this));
247 m_areaLineEdit->setText("10000");
248
249 QLabel *latLabel = new QLabel("Latitude");
250 QLabel *lonLabel = new QLabel("Longitude");
251 QLabel *areaLabel = new QLabel("Size (meters)");
252 areaLabel->setToolTip("This is the width and the height of the box");
253
254 // Create the action buttons
255 QPushButton *okButton = new QPushButton("Update Box");
256 connect(okButton, SIGNAL(clicked()), this, SLOT(userChangedBox()));
257
258 QPushButton *clearButton = new QPushButton("Clear Box");
259 connect(clearButton, SIGNAL(clicked()), this, SLOT(clearBox()));
260
261 // Put the buttons in a horizontal orientation
262 QHBoxLayout *actionLayout = new QHBoxLayout();
263 actionLayout->addWidget(latLabel);
264 actionLayout->addWidget(m_latLineEdit);
265 actionLayout->addWidget(lonLabel);
266 actionLayout->addWidget(m_lonLineEdit);
267 actionLayout->addWidget(areaLabel);
268 actionLayout->addWidget(m_areaLineEdit);
269 actionLayout->addWidget(okButton);
270 actionLayout->addWidget(clearButton);
271 actionLayout->addStretch(1);
272 actionLayout->setMargin(0);
273
274 QWidget *toolBarWidget = new QWidget;
275 toolBarWidget->setLayout(actionLayout);
276
277 return toolBarWidget;
278 }
279
280
288
289 }
290
291
292 PvlObject MosaicAreaTool::toPvl() const {
293 PvlObject obj(projectPvlObjectName());
294
295 if(m_box) {
296 obj += PvlKeyword("Latitude", m_latLineEdit->text());
297 obj += PvlKeyword("Longitude", m_lonLineEdit->text());
298 obj += PvlKeyword("Area", m_areaLineEdit->text());
299 obj += PvlKeyword("Visible", toString((int)(m_box != NULL)));
300 }
301
302 return obj;
303 }
304
305
306 void MosaicAreaTool::fromPvl(const PvlObject &obj) {
307 if(obj.hasKeyword("Visible")) {
308 if(obj.hasKeyword("Latitude") && obj["Latitude"][0] != "Null")
309 m_latLineEdit->setText(obj["Latitude"][0]);
310
311 if(obj.hasKeyword("Longitude") && obj["Longitude"][0] != "Null")
312 m_lonLineEdit->setText(obj["Longitude"][0]);
313
314 if(obj.hasKeyword("Area") && obj["Area"][0] != "Null")
315 m_areaLineEdit->setText(obj["Area"][0]);
316
317 if(toBool(obj["Visible"][0]) != false) {
318 userChangedBox();
319 }
320 }
321 }
322
323
324 QString MosaicAreaTool::projectPvlObjectName() const {
325 return "MosaicAreaTool";
326 }
327
328
338 QWidget *widget = new QWidget();
339 return widget;
340 }
341
342
343 void MosaicAreaTool::mouseButtonRelease(QPointF mouseLoc, Qt::MouseButton s) {
344 if(!isActive())
345 return;
346
347 if(s == Qt::LeftButton) {
348 TProjection *tproj = (TProjection *) getWidget()->getProjection();
349
350 if(tproj && getWidget()->getView()->sceneRect().contains(mouseLoc)) {
351 if(tproj->SetCoordinate(mouseLoc.x(), -1 * mouseLoc.y())) {
352 if(m_drawBox != NULL) {
353 clearBox();
354 }
355
356 m_latLineEdit->setText(QString::number(tproj->Latitude(), 'g', 10));
357 m_lonLineEdit->setText(QString::number(tproj->Longitude(), 'g', 10));
358
359 userChangedBox();
360 }
361 }
362 }
363 }
364
365
370 void MosaicAreaTool::clearBox() {
371 if(m_box != NULL) {
372 getWidget()->getScene()->removeItem(m_box);
373
374 delete m_box;
375 m_box = NULL;
376 }
377 }
378
379
387 QRectF MosaicAreaTool::calcLatLonRange(QPointF centerLatLon,
388 Distance size) {
389 Distance distanceFromCenter = size / 2.0;
390 QRectF latLonBoundingBox;
391
392 Angle centerLat(centerLatLon.y(), Angle::Degrees);
393 Angle centerLon(centerLatLon.x(), Angle::Degrees);
394
395 TProjection *tproj = (TProjection *) getWidget()->getProjection();
396
397 if (tproj) {
398 bool longitudeWraps = false;
399 Distance radius(tproj->LocalRadius(centerLat.degrees()),
401
402 // First we can get the angle between the latitudes...
403 // d = arcsin ( movementDistance / radiusDistance )
404 Angle deltaLat(asin( distanceFromCenter / radius ), Angle::Radians);
405
406 latLonBoundingBox.setTop( (centerLat - deltaLat).degrees() );
407
408 if (latLonBoundingBox.top() < -90 && centerLatLon.y() != -90) {
409
410 // Block infinite recursion
411 if (centerLatLon.y() != 90) {
412 qWarning("The pole is included in the area but not centered");
413 centerLatLon.setY(-90);
414 return calcLatLonRange(centerLatLon, size);
415 }
416 else
417 return QRectF();
418 }
419 else if (centerLatLon.y() == -90) {
420 longitudeWraps = true;
421 }
422
423 latLonBoundingBox.setBottom( (centerLat + deltaLat).degrees() );
424
425 if (latLonBoundingBox.bottom() > 90 && centerLatLon.y() != 90) {
426
427 // Block infinite recursion
428 if (centerLatLon.y() != -90) {
429 qWarning("The pole is included in the area but not centered");
430 centerLatLon.setY(90);
431 return calcLatLonRange(centerLatLon, size);
432 }
433 else
434 return QRectF();
435 }
436 else if (centerLatLon.y() == 90) {
437 longitudeWraps = true;
438 }
439
440 // Now let's do lons...
441 Angle widestLat(
442 asin( sin(centerLat.radians()) /
443 cos( distanceFromCenter / radius ) ),
445
446 double valueToASin = sin(distanceFromCenter / radius) /
447 cos(widestLat.radians());
448
449 if(valueToASin < -1 || valueToASin > 1)
450 longitudeWraps = true;
451
452 // Longitude wraps
453 if (longitudeWraps) {
454 if (tproj->Has360Domain()) {
455 latLonBoundingBox.setLeft( 0 );
456 latLonBoundingBox.setRight( 360 );
457 }
458 else {
459 latLonBoundingBox.setLeft( -180 );
460 latLonBoundingBox.setRight( 180 );
461 }
462 }
463 else {
464 Angle deltaLon(
465 asin( sin(distanceFromCenter / radius) /
466 cos(widestLat.radians())),
468 latLonBoundingBox.setLeft( (centerLon - deltaLon).degrees() );
469 latLonBoundingBox.setRight( (centerLon + deltaLon).degrees() );
470 }
471 }
472
473 return latLonBoundingBox;
474 }
475}
476
Defines an angle and provides unit conversions.
Definition Angle.h:45
double radians() const
Convert an angle to a double.
Definition Angle.h:226
double degrees() const
Get the angle in units of Degrees.
Definition Angle.h:232
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition Angle.h:56
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Definition Angle.h:63
Distance measurement, usually in meters.
Definition Distance.h:34
@ Meters
The distance is being specified in meters.
Definition Distance.h:43
QLineEdit * m_lonLineEdit
Input for longitude.
QLineEdit * m_areaLineEdit
Input for latitude.
void addToMenu(QMenu *menu)
Adds the pan action to the given menu.
QWidget * getToolBarWidget()
This method returns a widget that will be put in a tool bar when the tool is activated.
MosaicAreaTool(MosaicSceneWidget *)
MosaicAreaTool constructor.
QAction * getPrimaryAction()
Adds the action to the toolpad.
QLineEdit * m_latLineEdit
Input for latitude.
QRectF calcLatLonRange(QPointF centerLatLon, Distance size)
Given a distance and a center lat,lon this will return the bounding lat,lon rect.
QWidget * createToolBarWidget()
Creates the widget to add to the tool bar.
This widget encompasses the entire mosaic scene.
QPixmap getIcon(QString iconName) const
returns the path to the icon directory.
bool isActive() const
Returns the activeness of this toool.
Definition MosaicTool.h:50
Base class for Map Projections.
Definition Projection.h:155
ProjectionType
This enum defines the subclasses of Projection supported in Isis.
Definition Projection.h:166
@ Triaxial
These projections are used to map triaxial and irregular-shaped bodies.
Definition Projection.h:166
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
Base class for Map TProjections.
double LocalRadius(double lat) const
This method returns the local radius in meters at the specified latitude position.
virtual bool SetCoordinate(const double x, const double y)
This method is used to set the projection x/y.
virtual double Latitude() const
This returns a latitude with correct latitude type as specified in the label object.
bool Has360Domain() const
This indicates if the longitude domain is 0 to 360 (as opposed to -180 to 180).
virtual double Longitude() const
This returns a longitude with correct longitude direction and domain as specified in the label object...
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
bool toBool(const QString &string)
Global function to convert from a string to a boolean.
Definition IString.cpp:38