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