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