1 #include <cstring>
2 #include <map>
3 #include <sstream>
4 #include <vector>
5 using namespace std;
6 
7 #include "buildPlanetMap.h"
8 #include "config.h"
9 #include "createMap.h"
10 #include "keywords.h"
11 #include "Map.h"
12 #include "Options.h"
13 #include "PlanetProperties.h"
14 #include "Ring.h"
15 #include "satrings.h"
16 #include "sphericalToPixel.h"
17 #include "xpUtil.h"
18 
19 #include "libannotate/libannotate.h"
20 #include "libdisplay/libdisplay.h"
21 #include "libplanet/Planet.h"
22 #include "libprojection/libprojection.h"
23 #include "libprojection/ProjectionRectangular.h"
24 
25 extern void
26 arrangeMarkers(multimap<double, Annotation *> &annotationMap,
27                DisplayBase *display);
28 
29 void
drawProjection(DisplayBase * display,Planet * target,const double upX,const double upY,const double upZ,map<double,Planet * > & planetsFromSunMap,PlanetProperties * planetProperties)30 drawProjection(DisplayBase *display, Planet *target,
31                const double upX, const double upY, const double upZ,
32                map<double, Planet *> &planetsFromSunMap,
33                PlanetProperties *planetProperties)
34 {
35     const int height = display->Height();
36     const int width = display->Width();
37 
38     // subsolar lat/lon
39     double sLat, sLon;
40     target->XYZToPlanetographic(0, 0, 0, sLat, sLon);
41 
42     // lat/lon of the "up" vector
43     double nLat, nLon;
44     target->XYZToPlanetographic(upX * FAR_DISTANCE,
45                                 upY * FAR_DISTANCE,
46                                 upZ * FAR_DISTANCE,
47                                 nLat, nLon);
48 
49     // Rotate the image so that the "up" vector points to the top of
50     // the screen
51     Options *options = Options::getInstance();
52 
53     double tc, dist;
54     calcGreatArc(options->Latitude(),
55                  options->Longitude() * target->Flipped(),
56                  nLat, nLon * target->Flipped(), tc, dist);
57     options->Rotate(-tc);
58 
59     Ring *ring = NULL;
60     if (target->Index() == SATURN)
61     {
62         double X, Y, Z;
63         target->getPosition(X, Y, Z);
64         ring = new Ring(inner_radius/saturn_radius,
65                         outer_radius/saturn_radius,
66                         ring_brightness, LIT, ring_transparency, TRANSP,
67                         sLon, sLat,
68                         planetProperties->Shade(),
69                         planetsFromSunMap,
70                         target);
71     }
72 
73     Map *m = NULL;
74     m = createMap(sLat, sLon,
75                   options->Latitude(), options->Longitude(),
76                   width, height, options->Radius() * height,
77                   target, ring, planetsFromSunMap,
78                   planetProperties);
79 
80     if (!options->OutputMapRect().empty())
81     {
82         if (!m->Write(options->OutputMapRect().c_str()))
83         {
84             ostringstream errStr;
85             errStr << "Can't create " << options->OutputMapRect()
86                    << "\n";
87             xpWarn(errStr.str(), __FILE__, __LINE__);
88         }
89     }
90 
91     if (target->Index() == SATURN)
92     {
93         delete ring;
94     }
95 
96     ProjectionBase *projection = NULL;
97 
98     if (options->ProjectionMode() == RANDOM)
99         options->Projection(getRandomProjection());
100     else
101         options->Projection(options->ProjectionMode());
102 
103     if (options->Projection() == RECTANGULAR
104         && planetProperties->MapBounds())
105     {
106         projection = new ProjectionRectangular(target->Flipped(),
107                                                width, height,
108                                                m->StartLat(),
109                                                m->StartLon(),
110                                                m->MapHeight(),
111                                                m->MapWidth());
112 
113     }
114     else
115     {
116         projection = getProjection(options->Projection(),
117                                    target->Flipped(),
118                                    width, height);
119     }
120 
121     multimap<double, Annotation *> annotationMap;
122 
123 #ifdef HAVE_CSPICE
124     if (!options->SpiceFiles().empty())
125         addSpiceObjects(planetsFromSunMap, NULL, projection, annotationMap);
126 #endif
127 
128     if (planetProperties->DrawArcs())
129         addArcs(planetProperties, target, NULL, projection,
130                 annotationMap);
131 
132     if (planetProperties->DrawMarkers())
133         addMarkers(planetProperties, target, projection->Radius() * height,
134                    0, 0, 0, NULL, projection, width, height,
135                    planetsFromSunMap, annotationMap);
136 
137     if (planetProperties->DrawSatellites())
138         addSatellites(planetProperties, target, NULL, projection,
139                       annotationMap);
140 
141     // add tabs to make a photocube.  Lines are black, so -background
142     // white will make them stand out.
143     if (options->Projection() == TSC)
144     {
145         unsigned char black[3] = { 0, 0, 0 };
146         const int thickness = 3;
147         const double Z = 0;
148         LineSegment *ls = NULL;
149 
150         int blockWidth = width/4;
151         int blockHeight = blockWidth;
152         int hp0 = (height + blockHeight)/2;
153         int hp1 = hp0 + height/30;
154         int hm0 = (height - blockHeight)/2;
155         int hm1 = hm0 - height/30;
156         for (int i = 0; i < 4; i++)
157         {
158             if (i == 1) continue;
159 
160             double X0 = i * blockWidth;
161 
162             ls = new LineSegment(black, thickness, X0, hp0,
163                                  X0+width/40, hp1);
164             annotationMap.insert(pair<const double, Annotation*>(Z, ls));
165 
166             ls = new LineSegment(black, thickness, X0+width/4, hp0,
167                                  X0+9*width/40, hp1);
168             annotationMap.insert(pair<const double, Annotation*>(Z, ls));
169 
170             ls = new LineSegment(black, thickness, X0+width/40, hp1,
171                                  X0+9*width/40, hp1);
172             annotationMap.insert(pair<const double, Annotation*>(Z, ls));
173 
174             ls = new LineSegment(black, thickness, X0, hm0,
175                                  X0+width/40, hm1);
176             annotationMap.insert(pair<const double, Annotation*>(Z, ls));
177 
178             ls = new LineSegment(black, thickness, X0+width/4, hm0,
179                                  X0+9*width/40, hm1);
180             annotationMap.insert(pair<const double, Annotation*>(Z, ls));
181 
182             ls = new LineSegment(black, thickness, X0+width/40, hm1,
183                                  X0+9*width/40, hm1);
184             annotationMap.insert(pair<const double, Annotation*>(Z, ls));
185         }
186 
187     }
188 
189     const bool limbDarkening = (options->Projection() == HEMISPHERE
190                                 || options->Projection() == ORTHOGRAPHIC);
191 
192     for (int j = 0; j < height; j++)
193     {
194         for (int i = 0; i < width; i++)
195         {
196             double lon, lat;
197             if (projection->pixelToSpherical(i, j, lon, lat))
198             {
199                 unsigned char color[3];
200                 m->GetPixel(lat, lon * target->Flipped(), color);
201 
202                 if (limbDarkening)
203                 {
204                     for (int i = 0; i < 3; i++)
205                         color[i] = (unsigned char)
206                             (color[i] * projection->getDarkening());
207                 }
208                 display->setPixel(i, j, color);
209             }
210         }
211     }
212 
213     if (planetProperties->Grid())
214     {
215         const double grid1 = planetProperties->Grid1();
216         const double grid2 = planetProperties->Grid2();
217         const unsigned char *color = planetProperties->GridColor();
218         for (double lat = -M_PI_2; lat <= M_PI_2; lat += M_PI_2/grid1)
219         {
220             for (double lon = -M_PI; lon <= M_PI; lon += M_PI_2/(grid1 * grid2))
221             {
222                 double X, Y, Z;
223                 if (sphericalToPixel(lat, lon, 1, X, Y, Z, target,
224                                      NULL, projection))
225                     display->setPixel(X, Y, color);
226             }
227         }
228 
229         for (double lat = -M_PI_2; lat <= M_PI_2; lat += M_PI_2/(grid1 * grid2))
230         {
231             for (double lon = -M_PI; lon <= M_PI; lon += M_PI_2/grid1)
232             {
233                 double X, Y, Z;
234                 if (sphericalToPixel(lat, lon, 1, X, Y, Z, target,
235                                      NULL, projection))
236                     display->setPixel(X, Y, color);
237             }
238         }
239     }
240 
241     if (!annotationMap.empty())
242     {
243         multimap<double, Annotation *>::iterator annotationIterator;
244 
245         // place markers so that they don't overlap one another, if
246         // possible
247         arrangeMarkers(annotationMap, display);
248 
249         for (annotationIterator = annotationMap.begin();
250              annotationIterator != annotationMap.end();
251              annotationIterator++)
252         {
253             Annotation *a = annotationIterator->second;
254             a->Draw(display);
255             // if the projection "wraps around", add annotations on
256             // the either side of the screen.
257             if (projection->IsWrapAround()
258                 && !planetProperties->MapBounds())
259             {
260                 a->Shift(-width);
261                 a->Draw(display);
262                 a->Shift(2*width);
263                 a->Draw(display);
264             }
265 
266             delete annotationIterator->second;
267         }
268     }
269 
270     delete m;
271 
272     delete projection;
273 }
274