2 * Copyright (C) 2008 Liam Girdwood
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "projection.h"
23 #include "astro_object.h"
25 #define D2R (1.7453292519943295769e-2) /* deg->radian */
26 #define R2D (5.7295779513082320877e1) /* radian->deg */
28 #define PROJ_MAX_RA 360.0
29 #define PROJ_MIN_RA 0.0
31 /* Max/Min Declination != 90 or -90 to speed up rendering */
32 #define PROJ_MAX_DEC 89.5
33 #define PROJ_MIN_DEC -89.5
35 #define PROJ_MIN_FOV 0.5
36 #define PROJ_MAX_FOV 270.0
38 #define PROJ_MAG_BASE 4.2
39 #define PROJ_MAG_FAINT 16
40 #define PROJ_MAG_BRIGHT -2
42 #define PROJ_MAG_CONST 0.005
43 #define PROJ_MAG_FOV_DIFF 110
50 static struct _mag_const mag_const
[] = {
51 {180.0, 2.5 * PROJ_MAG_CONST
},
52 {160.0, 2.6 * PROJ_MAG_CONST
},
53 {140.0, 2.7 * PROJ_MAG_CONST
},
54 {130.0, 2.7 * PROJ_MAG_CONST
},
55 {120.0, 3.0 * PROJ_MAG_CONST
},
56 {110.0, 3.3 * PROJ_MAG_CONST
},
57 {100.0, 3.7 * PROJ_MAG_CONST
},
58 {90.0, 3.9 * PROJ_MAG_CONST
},
59 {80.0, 4.1 * PROJ_MAG_CONST
},
60 {70.0, 4.3 * PROJ_MAG_CONST
},
61 {60.0, 4.5 * PROJ_MAG_CONST
},
62 {50.0, 4.7 * PROJ_MAG_CONST
},
63 {40.0, 5.0 * PROJ_MAG_CONST
},
64 {35.0, 5.2 * PROJ_MAG_CONST
},
65 {30.0, 5.4 * PROJ_MAG_CONST
},
66 {25.0, 5.6 * PROJ_MAG_CONST
},
67 {20.0, 5.8 * PROJ_MAG_CONST
},
68 {16.0, 6.0 * PROJ_MAG_CONST
},
69 {12.0, 6.5 * PROJ_MAG_CONST
},
70 {10.0, 7.0 * PROJ_MAG_CONST
},
71 {8.0, 7.5 * PROJ_MAG_CONST
},
72 {5.0, 7.8 * PROJ_MAG_CONST
},
73 {4.0, 8.0 * PROJ_MAG_CONST
},
74 {3.0, 8.5 * PROJ_MAG_CONST
},
75 {2.0, 9.0 * PROJ_MAG_CONST
},
76 {1.5, 10.0 * PROJ_MAG_CONST
},
77 {1.0, 11.0 * PROJ_MAG_CONST
},
80 gint
projection_set_flip(struct projection
*proj
, enum projection_flip flip
)
84 proj
->trans
= &transform_flip_none
;
87 proj
->trans
= &transform_flip_tb
;
90 proj
->trans
= &transform_flip_lr
;
93 proj
->trans
= &transform_flip_lr_tb
;
98 proj
->clip_mag_faint
= PROJ_MAG_FAINT
;
99 proj
->clip_mag_bright
= PROJ_MAG_BRIGHT
;
103 /*! \fn void void proj_calc_fov_bounds(struct projection* projection)
105 * Calculate the boundaries, magnitude level and field of view for the
106 * virtual sky projection.
108 void projection_fov_bounds(struct projection
* proj
)
110 gfloat mag_coeff
= PROJ_MAG_CONST
;
113 proj
->sky_mid_width
= proj
->sky_width
/ 2.0;
114 proj
->sky_mid_height
= proj
->sky_height
/ 2.0;
116 if (proj
->sky_width
> proj
->sky_height
) {
117 proj
->pixels_per_degree
= proj
->sky_width
/ proj
->fov
;
118 proj
->pixels_per_radian
= proj
->pixels_per_degree
/ D2R
;
120 proj
->pixels_per_degree
= proj
->sky_height
/ proj
->fov
;
121 proj
->pixels_per_radian
= proj
->pixels_per_degree
/ D2R
;
123 while (mag_const
[i
].limit
> proj
->fov
&& i
< nsize(mag_const
)) {
124 mag_coeff
= mag_const
[i
].coeff
;
127 proj
->clip_mag_faint
=
128 PROJ_MAG_BASE
+ (PROJ_MAG_FOV_DIFF
- proj
->fov
) * mag_coeff
;
130 proj
->centre_ra_rad
= proj
->centre_ra
* D2R
;
131 proj
->centre_dec_rad
= proj
->centre_dec
* D2R
;
132 proj
->centre_ra_rad_sin
= sin(proj
->centre_ra_rad
);
133 proj
->centre_dec_rad_sin
= sin(proj
->centre_dec_rad
);
134 proj
->centre_ra_rad_cos
= cos(proj
->centre_ra_rad
);
135 proj
->centre_dec_rad_cos
= cos(proj
->centre_dec_rad
);
138 void projection_check_bounds (struct projection
* proj
)
140 if (proj
->centre_ra
> PROJ_MAX_RA
)
141 proj
->centre_ra
-= PROJ_MAX_RA
;
142 if (proj
->centre_ra
< PROJ_MIN_RA
)
143 proj
->centre_ra
+= PROJ_MAX_RA
;
144 if (proj
->centre_dec
> PROJ_MAX_DEC
)
145 proj
->centre_dec
= PROJ_MAX_DEC
;
146 if (proj
->centre_dec
< PROJ_MIN_DEC
)
147 proj
->centre_dec
= PROJ_MIN_DEC
;
148 if (proj
->fov
> PROJ_MAX_FOV
)
149 proj
->fov
= PROJ_MAX_FOV
;
150 if (proj
->fov
< PROJ_MIN_FOV
)
151 proj
->fov
= PROJ_MIN_FOV
;
154 static void sky_to_cairo(struct projection
*proj
, struct render_object
*robject
)
156 gdouble mid_x
, mid_y
, k
;
157 gdouble centre_ra
= proj
->centre_ra_rad
;
158 gdouble centre_dec_cos
= proj
->centre_dec_rad_cos
;
159 gdouble centre_dec_sin
= proj
->centre_dec_rad_sin
;
162 mid_x
= proj
->sky_mid_width
;
163 mid_y
= proj
->sky_mid_height
;
165 for (i
= 0; i
< robject
->num_coords
; i
++) {
167 gdouble ra
= robject
->coord
[i
].posn
->ra
* D2R
;
168 gdouble dec
= robject
->coord
[i
].posn
->dec
* D2R
;
169 gdouble sin_dec
= sin(dec
);
170 gdouble cos_dec
= cos(dec
);
171 gdouble cos_ra_delta
= cos(ra
- centre_ra
);
173 k
= 2.0 / (1 + centre_dec_sin
* sin_dec
+
174 centre_dec_cos
* cos_dec
* cos_ra_delta
);
176 robject
->coord
[i
].x
=
177 k
* (cos_dec
* sin(ra
- centre_ra
));
178 robject
->coord
[i
].y
=
179 k
* (centre_dec_cos
* sin_dec
- centre_dec_sin
*
180 cos_dec
* cos_ra_delta
);
182 robject
->coord
[i
].x
=
183 mid_x
- robject
->coord
[i
].x
* proj
->pixels_per_radian
;
184 robject
->coord
[i
].y
=
185 mid_y
- robject
->coord
[i
].y
* proj
->pixels_per_radian
;
189 static void cairo_to_sky(struct projection
*proj
, struct render_object
*robject
)
191 gdouble mid_x
, mid_y
, p
, c
;
192 gdouble centre_ra
= proj
->centre_ra_rad
;
193 gdouble centre_dec
= proj
->centre_dec_rad
;
195 mid_x
= proj
->sky_mid_width
;
196 mid_y
= proj
->sky_mid_height
;
198 robject
->coord
[0].x
=
199 (mid_x
- robject
->coord
[0].x
) / proj
->pixels_per_radian
;
200 robject
->coord
[0].y
=
201 (mid_y
- robject
->coord
[0].y
) / proj
->pixels_per_radian
;
203 p
= sqrt(robject
->coord
[0].x
* robject
->coord
[0].x
+
204 robject
->coord
[0].y
* robject
->coord
[0].y
);
205 c
= 2.0 * atan2(p
, 2.0);
207 robject
->coord
[0].posn
->dec
= asin(cos(c
) * sin(centre_dec
) +
208 ((robject
->coord
[0].y
* sin(c
) * cos (centre_dec
)) / p
));
210 robject
->coord
[0].posn
->ra
= centre_ra
+
211 atan2(robject
->coord
[0].x
* sin(c
),
212 p
* cos(centre_dec
) * cos(c
) -
213 robject
->coord
[0].y
* sin(centre_dec
) * sin(c
));
215 robject
->coord
[0].posn
->dec
= robject
->coord
[0].posn
->dec
* R2D
;
216 robject
->coord
[0].posn
->ra
= robject
->coord
[0].posn
->ra
* R2D
;
219 static void sky_to_cairo_tb(struct projection
*proj
, struct render_object
*robject
)
221 gdouble mid_x
, mid_y
, k
;
222 gdouble centre_ra
= proj
->centre_ra_rad
;
223 gdouble centre_dec
= proj
->centre_dec_rad
;
226 mid_x
= proj
->sky_mid_width
;
227 mid_y
= proj
->sky_mid_height
;
229 for (i
= 0; i
< robject
->num_coords
; i
++) {
231 gdouble ra
= robject
->coord
[i
].posn
->ra
* D2R
;
232 gdouble dec
= robject
->coord
[i
].posn
->dec
* D2R
;
234 k
= 2.0 / (1 + sin(centre_dec
) * sin(dec
) +
235 cos(centre_dec
) * cos(dec
) * cos(ra
- centre_ra
));
237 robject
->coord
[i
].x
=
238 k
* (cos(dec
) * sin(ra
- centre_ra
));
239 robject
->coord
[i
].y
=
240 k
* (cos(centre_dec
) * sin(dec
) - sin(centre_dec
) *
241 cos(dec
) * cos(ra
- centre_ra
));
243 robject
->coord
[i
].x
=
244 mid_x
- robject
->coord
[i
].x
* proj
->pixels_per_radian
;
245 robject
->coord
[i
].y
=
246 mid_y
+ robject
->coord
[i
].y
* proj
->pixels_per_radian
;
250 static void cairo_to_sky_tb(struct projection
*proj
, struct render_object
*robject
)
252 gdouble mid_x
, mid_y
, p
, c
;
253 gdouble centre_ra
= proj
->centre_ra_rad
;
254 gdouble centre_dec
= proj
->centre_dec_rad
;
256 mid_x
= proj
->sky_mid_width
;
257 mid_y
= proj
->sky_mid_height
;
259 robject
->coord
[0].x
=
260 (mid_x
+ robject
->coord
[0].x
) / proj
->pixels_per_radian
;
261 robject
->coord
[0].y
=
262 (mid_y
- robject
->coord
[0].y
) / proj
->pixels_per_radian
;
264 p
= sqrt(robject
->coord
[0].x
* robject
->coord
[0].x
+
265 robject
->coord
[0].y
* robject
->coord
[0].y
);
266 c
= 2.0 * atan2(p
, 2.0);
268 robject
->coord
[0].posn
->dec
= asin(cos(c
) * sin(centre_dec
) +
269 ((robject
->coord
[0].y
* sin(c
) * cos (centre_dec
)) / p
));
271 robject
->coord
[0].posn
->ra
= centre_ra
+
272 atan2(robject
->coord
[0].x
* sin(c
),
273 p
* cos(centre_dec
) * cos(c
) -
274 robject
->coord
[0].y
* sin(centre_dec
) * sin(c
));
276 robject
->coord
[0].posn
->dec
= robject
->coord
[0].posn
->dec
* R2D
;
277 robject
->coord
[0].posn
->ra
= robject
->coord
[0].posn
->ra
* R2D
;
280 static void sky_to_cairo_lr(struct projection
*proj
, struct render_object
*robject
)
282 gdouble mid_x
, mid_y
, k
;
283 gdouble centre_ra
= proj
->centre_ra_rad
;
284 gdouble centre_dec
= proj
->centre_dec_rad
;
287 mid_x
= proj
->sky_mid_width
;
288 mid_y
= proj
->sky_mid_height
;
290 for (i
= 0; i
< robject
->num_coords
; i
++) {
292 gdouble ra
= robject
->coord
[i
].posn
->ra
* D2R
;
293 gdouble dec
= robject
->coord
[i
].posn
->dec
* D2R
;
295 k
= 2.0 / (1 + sin(centre_dec
) * sin(dec
) +
296 cos(centre_dec
) * cos(dec
) * cos(ra
- centre_ra
));
298 robject
->coord
[i
].x
=
299 k
* (cos(dec
) * sin(ra
- centre_ra
));
300 robject
->coord
[i
].y
=
301 k
* (cos(centre_dec
) * sin(dec
) - sin(centre_dec
) *
302 cos(dec
) * cos(ra
- centre_ra
));
304 robject
->coord
[i
].x
=
305 mid_x
+ robject
->coord
[i
].x
* proj
->pixels_per_radian
;
306 robject
->coord
[i
].y
=
307 mid_y
- robject
->coord
[i
].y
* proj
->pixels_per_radian
;
311 static void cairo_to_sky_lr(struct projection
*proj
, struct render_object
*robject
)
313 gdouble mid_x
, mid_y
, p
, c
;
314 gdouble centre_ra
= proj
->centre_ra_rad
;
315 gdouble centre_dec
= proj
->centre_dec_rad
;
317 mid_x
= proj
->sky_mid_width
;
318 mid_y
= proj
->sky_mid_height
;
320 robject
->coord
[0].x
=
321 (mid_x
- robject
->coord
[0].x
) / proj
->pixels_per_radian
;
322 robject
->coord
[0].y
=
323 (mid_y
+ robject
->coord
[0].y
) / proj
->pixels_per_radian
;
325 p
= sqrt(robject
->coord
[0].x
* robject
->coord
[0].x
+
326 robject
->coord
[0].y
* robject
->coord
[0].y
);
327 c
= 2.0 * atan2(p
, 2.0);
329 robject
->coord
[0].posn
->dec
= asin(cos(c
) * sin(centre_dec
) +
330 ((robject
->coord
[0].y
* sin(c
) * cos (centre_dec
)) / p
));
332 robject
->coord
[0].posn
->ra
= centre_ra
+
333 atan2(robject
->coord
[0].x
* sin(c
),
334 p
* cos(centre_dec
) * cos(c
) -
335 robject
->coord
[0].y
* sin(centre_dec
) * sin(c
));
337 robject
->coord
[0].posn
->dec
= robject
->coord
[0].posn
->dec
* R2D
;
338 robject
->coord
[0].posn
->ra
= robject
->coord
[0].posn
->ra
* R2D
;
341 static void sky_to_cairo_lr_tb(struct projection
*proj
, struct render_object
*robject
)
343 gdouble mid_x
, mid_y
, k
;
344 gdouble centre_ra
= proj
->centre_ra_rad
;
345 gdouble centre_dec
= proj
->centre_dec_rad
;
348 mid_x
= proj
->sky_mid_width
;
349 mid_y
= proj
->sky_mid_height
;
351 for (i
= 0; i
< robject
->num_coords
; i
++) {
353 gdouble ra
= robject
->coord
[i
].posn
->ra
* D2R
;
354 gdouble dec
= robject
->coord
[i
].posn
->dec
* D2R
;
356 k
= 2.0 / (1 + sin(centre_dec
) * sin(dec
) +
357 cos(centre_dec
) * cos(dec
) * cos(ra
- centre_ra
));
359 robject
->coord
[i
].x
=
360 k
* (cos(dec
) * sin(ra
- centre_ra
));
361 robject
->coord
[i
].y
=
362 k
* (cos(centre_dec
) * sin(dec
) - sin(centre_dec
) *
363 cos(dec
) * cos(ra
- centre_ra
));
365 robject
->coord
[i
].x
=
366 mid_x
+ robject
->coord
[i
].x
* proj
->pixels_per_radian
;
367 robject
->coord
[i
].y
=
368 mid_y
+ robject
->coord
[i
].y
* proj
->pixels_per_radian
;
372 static void cairo_to_sky_lr_tb(struct projection
*proj
, struct render_object
*robject
)
374 gdouble mid_x
, mid_y
, p
, c
;
375 gdouble centre_ra
= proj
->centre_ra_rad
;
376 gdouble centre_dec
= proj
->centre_dec_rad
;
378 mid_x
= proj
->sky_mid_width
;
379 mid_y
= proj
->sky_mid_height
;
381 robject
->coord
[0].x
=
382 (mid_x
+ robject
->coord
[0].x
) / proj
->pixels_per_radian
;
383 robject
->coord
[0].y
=
384 (mid_y
+ robject
->coord
[0].y
) / proj
->pixels_per_radian
;
386 p
= sqrt(robject
->coord
[0].x
* robject
->coord
[0].x
+
387 robject
->coord
[0].y
* robject
->coord
[0].y
);
388 c
= 2.0 * atan2(p
, 2.0);
390 robject
->coord
[0].posn
->dec
= asin(cos(c
) * sin(centre_dec
) +
391 ((robject
->coord
[0].y
* sin(c
) * cos (centre_dec
)) / p
));
393 robject
->coord
[0].posn
->ra
= centre_ra
+
394 atan2(robject
->coord
[0].x
* sin(c
),
395 p
* cos(centre_dec
) * cos(c
) -
396 robject
->coord
[0].y
* sin(centre_dec
) * sin(c
));
398 robject
->coord
[0].posn
->dec
= robject
->coord
[0].posn
->dec
* R2D
;
399 robject
->coord
[0].posn
->ra
= robject
->coord
[0].posn
->ra
* R2D
;
403 struct transform transform_flip_none
= {
404 .sky_to_proj
= sky_to_cairo
,
405 .proj_to_sky
= cairo_to_sky
,
408 struct transform transform_flip_tb
= {
409 .sky_to_proj
= sky_to_cairo_tb
,
410 .proj_to_sky
= cairo_to_sky_tb
,
413 struct transform transform_flip_lr
= {
414 .sky_to_proj
= sky_to_cairo_lr
,
415 .proj_to_sky
= cairo_to_sky_lr
,
418 struct transform transform_flip_lr_tb
= {
419 .sky_to_proj
= sky_to_cairo_lr_tb
,
420 .proj_to_sky
= cairo_to_sky_lr_tb
,