Isis 3.0 Programmer Reference
Back | Home
GridGraphicsItem.cpp
1 #include "GridGraphicsItem.h"
2 
3 #include <cmath>
4 #include <float.h>
5 #include <iostream>
6 
7 #include <QDebug>
8 #include <QGraphicsScene>
9 #include <QPen>
10 
11 #include "Angle.h"
12 #include "Distance.h"
13 #include "GroundGrid.h"
14 #include "IException.h"
15 #include "Latitude.h"
16 #include "Longitude.h"
17 #include "MosaicGraphicsView.h"
18 #include "MosaicSceneWidget.h"
19 #include "Projection.h"
20 #include "TProjection.h"
21 #include "UniversalGroundMap.h"
22 
23 using namespace std;
24 
25 namespace Isis {
26  GridGraphicsItem::GridGraphicsItem(Latitude baseLat, Longitude baseLon,
27  Angle latInc, Angle lonInc, MosaicSceneWidget *projectionSrc,
28  int density, Latitude latMin, Latitude latMax,
29  Longitude lonMin, Longitude lonMax) {
30  setZValue(DBL_MAX);
31 
32  if (latInc > Angle(0.0, Angle::Degrees) && lonInc > Angle(0.0, Angle::Degrees)) {
33  // Walk the grid, creating a QGraphicsLineItem for each line segment.
34  Projection *proj = projectionSrc->getProjection();
35  Projection::ProjectionType pType = proj->projectionType();
36 
37  if (proj && pType == Projection::Triaxial && lonMin < lonMax && latMin < latMax) {
38  TProjection *tproj = (TProjection *) proj;
39  PvlGroup mappingGroup(tproj->Mapping());
40 
41  Latitude minLat;
42  Latitude maxLat;
43  Latitude startLat;
44  Latitude endLat;
45 
46  if (mappingGroup["LatitudeType"][0] == "Planetographic") {
47 
48  Distance equaRad(tproj->EquatorialRadius(), Distance::Meters);
49  Distance polRad(tproj->PolarRadius(), Distance::Meters);
50 
51  minLat = Latitude(latMin.planetographic(Angle::Degrees), mappingGroup,
52  Angle::Degrees);
53  maxLat = Latitude(latMax.planetographic(Angle::Degrees), mappingGroup,
54  Angle::Degrees);
55  baseLat = Latitude(baseLat.degrees(), equaRad, polRad,
56  Latitude::Planetocentric, Angle::Degrees);
57 
58  // Make sure our lat increment is non-zero
59  if (!qFuzzyCompare(latInc.radians(), 0.0)) {
60  startLat = baseLat;
61 
62  // We need startLat to start above min, and be as close to min as possible
63  try {
64  while (startLat < minLat) {
65  startLat = startLat.add(latInc, mappingGroup);
66  }
67  }
68  catch (IException &) {
69  }
70 
71  try {
72  while (startLat.add(latInc * -1, mappingGroup) >= minLat) {
73  startLat = startLat.add(latInc * -1, mappingGroup);
74  }
75  }
76  catch (IException &) {
77  // Do nothing if we hit up against a pole
78  }
79  }
80 
81  endLat = baseLat;
82 
83  // We need endLat to start below max, and be as close to max as possible
84  try {
85  while (endLat > maxLat) {
86  endLat = endLat.add(latInc * -1, mappingGroup);
87  }
88  }
89  catch (IException &) {
90  }
91 
92 
93  try {
94  while (endLat.add(latInc, mappingGroup) <= maxLat) {
95  endLat = endLat.add(latInc, mappingGroup);
96  }
97  }
98  catch (IException &) {
99  // Do nothing if we hit up against a pole
100  }
101  }
102  else {
103  minLat = Latitude(latMin.degrees(), mappingGroup,
104  Angle::Degrees);
105  maxLat = Latitude(latMax.degrees(), mappingGroup,
106  Angle::Degrees);
107 
108  // Make sure our lat increment is non-zero
109  if (!qFuzzyCompare(latInc.radians(), 0.0)) {
110  startLat = Latitude(
111  baseLat - Angle(floor((baseLat - minLat) / latInc) * latInc), mappingGroup);
112 
113  if (qFuzzyCompare(startLat.degrees(), -90.0))
114  startLat = Latitude(-90.0, mappingGroup, Angle::Degrees);
115  }
116 
117  endLat = Latitude(
118  (long)((maxLat - startLat) / latInc) * latInc + startLat,
119  mappingGroup);
120  if (qFuzzyCompare(endLat.degrees(), 90.0))
121  endLat = Latitude(90.0, mappingGroup, Angle::Degrees);
122  }
123 
124  Longitude minLon(lonMin.degrees(), mappingGroup,
125  Angle::Degrees);
126  Longitude maxLon(lonMax.degrees(), mappingGroup,
127  Angle::Degrees);
128 
129  Longitude startLon;
130  // Make sure our lon increment is non-zero
131  if (!qFuzzyCompare(lonInc.radians(), 0.0)) {
132  startLon = Longitude(
133  baseLon - Angle(floor((baseLon - minLon) / lonInc) * lonInc));
134  }
135 
136  Longitude endLon =
137  (long)((maxLon - startLon) / lonInc) * lonInc + startLon;
138 
139  if (qFuzzyCompare( (endLon + lonInc).radians(), maxLon.radians() )) {
140  endLon = maxLon;
141  }
142 
143  // Make sure our increments will move our lat/lon values... prevent infinite loops
144  if (!qFuzzyCompare( (startLat + latInc).radians(), startLat.radians() ) &&
145  !qFuzzyCompare( (startLon + lonInc).radians(), startLon.radians() )) {
146 
147  int numCurvedLines = (int)ceil(((maxLat - minLat) / latInc) + 1);
148  numCurvedLines += (int)ceil(((maxLon - minLon) / lonInc) + 1);
149 
150  int curvedLineDensity = density / numCurvedLines + 1;
151  Angle latRes((maxLon - minLon) / (double)curvedLineDensity);
152  Angle lonRes((maxLat - minLat) / (double)curvedLineDensity);
153 
154  if (mappingGroup["LatitudeType"][0] == "Planetographic") {
155  lonRes = Angle(
156  (maxLat.planetographic() - minLat.planetographic()) / (double)curvedLineDensity,
157  Angle::Radians);
158  }
159 
160  if (latRes <= Angle(0, Angle::Degrees))
161  latRes = Angle(1E-10, Angle::Degrees);
162 
163  if (lonRes <= Angle(0, Angle::Degrees))
164  lonRes = Angle(1E-10, Angle::Degrees);
165 
166  bool firstIteration = true;
167  bool atMaxLat = false;
168  bool atMaxLon = false;
169 
170  // We're looping like this to guarantee we hit the correct end position in
171  // the loop despite double math.
172 
173 
174  Latitude lat = minLat;
175  while(!atMaxLat) {
176  double previousX = 0;
177  double previousY = 0;
178  bool havePrevious = false;
179 
180  for(Longitude lon = minLon; lon != maxLon + latRes; lon += latRes) {
181 
182  if (lon > maxLon && !atMaxLon) {
183  lon = maxLon;
184  atMaxLon = true;
185  }
186 
187  double x = 0;
188  double y = 0;
189  bool valid = tproj->SetUniversalGround(lat.degrees(), lon.degrees());
190 
191  if (valid) {
192  x = tproj->XCoord();
193  y = -1 * tproj->YCoord();
194 
195  if(havePrevious) {
196  if(previousX != x || previousY != y) {
197  QGraphicsLineItem* latLine =
198  new QGraphicsLineItem(QLineF(previousX, previousY, x, y), this);
199  // Ensure the line is cosmetic
200  // (i.e. the line width is always 1 pixel wide on screen)
201  QPen pen;
202  pen.setCosmetic(true);
203  latLine->setPen(pen);
204  }
205  }
206  }
207 
208  havePrevious = valid;
209  previousX = x;
210  previousY = y;
211  }
212 
213  // if (firstIteration) {
214  // if (startLat.planetographic(Angle::Degrees) - latInc.degrees() < -90.0)
215  // lat = Latitude(-90.0, mappingGroup, Angle::Degrees);
216  // else {
217  // lat = Latitude(startLat.planetographic() - latInc.radians(), mappingGroup,
218  // Angle::Radians);
219  // }
220  // }
221 
222  firstIteration = false;
223  atMaxLon = false;
224 
225  Latitude nextLat;
226 
227  try {
228  nextLat = lat.add(latInc, mappingGroup);
229  }
230  catch (IException &) {
231  nextLat = maxLat;
232  }
233 
234  if (lat == minLat && minLat != startLat) {
235  // If our increment doesn't intersect the lat range, set ourselves to max.
236  if (startLat < minLat || startLat > maxLat) {
237  nextLat = maxLat;
238  }
239  else {
240  // Our increment lands inside the range, go to start and begin incrementing towards
241  // end.
242  nextLat = startLat;
243  }
244  }
245  else if (lat >= maxLat) {
246  atMaxLat = true;
247  }
248  else if (nextLat > endLat) {
249  nextLat = maxLat;
250  }
251 
252  lat = nextLat;
253  }
254 
255  firstIteration = true;
256  atMaxLat = false;
257  atMaxLon = false;
258 
259  // Create the longitude grid lines
260  for (Longitude lon = minLon; lon != maxLon + lonInc; lon += lonInc) {
261 
262  if (lon > endLon && lon < maxLon) {
263  lon = endLon;
264  }
265 
266  if (lon > maxLon && !atMaxLon) {
267  lon = maxLon;
268  atMaxLon = true;
269  }
270 
271  double previousX = 0;
272  double previousY = 0;
273  bool havePrevious = false;
274 
275  Latitude lat = minLat;
276  while (!atMaxLat) {
277  double x = 0;
278  double y = 0;
279  bool valid = tproj->SetUniversalGround(lat.degrees(), lon.degrees());
280 
281  if (valid) {
282  x = tproj->XCoord();
283  y = -1 * tproj->YCoord();
284 
285  if(havePrevious) {
286  x = proj->XCoord();
287  y = -1 * proj->YCoord();
288 
289  if(previousX != x || previousY != y) {
290  QGraphicsLineItem* lonLine =
291  new QGraphicsLineItem(QLineF(previousX, previousY, x, y), this);
292  // Ensure the line is cosmetic
293  // (i.e. the line width is always 1 pixel wide on screen)
294  QPen pen;
295  pen.setCosmetic(true);
296  lonLine->setPen(pen);
297  }
298  }
299  }
300 
301  havePrevious = valid;
302  previousX = x;
303  previousY = y;
304 
305  if (lat >= maxLat) {
306  atMaxLat = true;
307  }
308  else {
309  lat = lat.add(lonRes, mappingGroup);
310  }
311  }
312 
313  if (firstIteration)
314  lon = startLon - lonInc;
315 
316  firstIteration = false;
317  atMaxLat = false;
318  }
319  }
320  }
321  }
322 
323  setRect(calcRect());
324  }
325 
326 
327  GridGraphicsItem::~GridGraphicsItem() {
328  }
329 
330 
331  void GridGraphicsItem::paint(QPainter *painter,
332  const QStyleOptionGraphicsItem *style, QWidget * widget) {
333  }
334 
335 
336  QRectF GridGraphicsItem::boundingRect() const {
337  return m_boundingRect;
338  }
339 
340 
341  QRectF GridGraphicsItem::rect() const {
342  return m_boundingRect;
343  }
344 
345 
346  QRectF GridGraphicsItem::calcRect() const {
347  QRectF sceneRect;
348 
349  foreach (QGraphicsItem *child, childItems()) {
350  sceneRect = sceneRect.united(child->boundingRect());
351  }
352 
353  return sceneRect;
354  }
355 
356 
357  void GridGraphicsItem::setRect(QRectF newBoundingRect) {
358  if (m_boundingRect != newBoundingRect) {
359  prepareGeometryChange();
360  m_boundingRect = newBoundingRect;
361  }
362  }
363 }
364 
const double E(2.7182818284590452354)
Sets some basic constants for use in ISIS programming.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.
Unless noted otherwise, the portions of Isis written by the USGS are public domain.

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the ISIS Support Center
File Modified: 07/12/2023 23:18:47