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