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.
19 * Fast sky grid render engine. Mostly working, although probably needs
20 * checking by a maths trig guru to further optimise (and clip RA line at 80).
22 * TODO: Clip RA grid lines at 80 and -80 on DEC. This needs cairo_arc_to() or
23 * someone who knows another solution.
26 #define _GNU_SOURCE /* for NAN and INF */
30 #include "astro_object.h"
34 #define D2R (1.7453292519943295769e-2) /* deg->radian */
35 #define R2D (5.7295779513082320877e1) /* radian->deg */
37 #define ARC_MAGIC 1000.0 /* need better method to determine line from arc */
38 #define GRID_BISECT 128.0
39 #define GRID_NIGHT_ALPHA 0.35
40 #define GRID_DAY_ALPHA 0.55
43 /* RA grid in arcsecs */
44 static const gdouble grid_hms_ra
[] = {
56 /* DEC drid in arcsecs */
57 static const gdouble grid_dms_dec
[] = {
70 static inline int is_tile_visible(struct projection
*proj
, gint ra
, gint dec
)
72 struct render_object robject
;
73 struct ln_equ_posn pos
;
76 pos
.dec
= -90 + dec
* 10.0;
77 robject
.coord
[0].posn
= &pos
;
78 proj
->trans
->sky_to_proj_equ(proj
, &robject
.coord
[0]);
79 return projection_is_visible0(proj
, &robject
);
82 static inline void mark_tiles(struct projection
*proj
,
85 gint ra_start
= ra
- 1, ra_end
= ra
+ 1;
86 gint dec_start
= dec
- 1, dec_end
= dec
+ 1;
89 ra_start
= GRID_RA_TILES
-1;
90 if (ra_end
== GRID_RA_TILES
)
94 if (dec_end
== GRID_DEC_TILES
)
95 dec_end
= GRID_DEC_TILES
- 1;
97 proj
->grid_tile
[ra
][dec
] = 1;
98 proj
->grid_tile
[ra_start
][dec_start
] = 1;
99 proj
->grid_tile
[ra_end
][dec_start
] = 1;
100 proj
->grid_tile
[ra_start
][dec_end
] = 1;
101 proj
->grid_tile
[ra_end
][dec_end
] = 1;
102 proj
->grid_tile
[ra
][dec_start
] = 1;
103 proj
->grid_tile
[ra
][dec_end
] = 1;
104 proj
->grid_tile
[ra_start
][dec
] = 1;
105 proj
->grid_tile
[ra_end
][dec
] = 1;
108 static void get_visible_tiles(struct projection
*proj
)
112 /* clear all tiles first */
113 for (ra
= 0; ra
< GRID_RA_TILES
; ra
++) {
114 for (dec
= 0; dec
< GRID_DEC_TILES
; dec
++) {
115 proj
->grid_tile
[ra
][dec
] = 0;
119 /* check each tile */
120 for (ra
= 0; ra
< GRID_RA_TILES
; ra
++) {
121 for (dec
= 0; dec
< GRID_DEC_TILES
; dec
++) {
122 if (is_tile_visible(proj
, ra
, dec
))
123 mark_tiles(proj
, ra
, dec
);
127 /* now check centre RA, DEC if tile size > fov */
128 if (proj
->fov
<= 17.0)
129 mark_tiles(proj
, (gint
)(proj
->centre_1ra
/ 15.0),
130 (gint
)(proj
->centre_1dec
/ 10.0 + 9));
133 /* get grid RA step size for projection in arcsecs */
134 static gdouble
get_ra_step_delta(struct projection
*proj
)
138 for (i
= 0; i
< nsize(grid_hms_ra
); i
++) {
139 if (proj
->fov
/ 1.1 > grid_hms_ra
[i
] / 3600.0)
140 return grid_hms_ra
[i
] / 3600.0;
142 return grid_hms_ra
[i
] / 3600.0;
145 /* get grid DEC step size for projection in arcsecs */
146 static gdouble
get_dec_step_delta(struct projection
*proj
)
150 for (i
= 0; i
< nsize(grid_dms_dec
); i
++) {
151 if (proj
->fov
/ 1.1 > grid_dms_dec
[i
] / 3600.0)
152 return grid_dms_dec
[i
] / 3600.0;
154 return grid_dms_dec
[i
] / 3600.0;
157 static void render_dec_labels_at(struct projection
*proj
,
158 struct render_object
*robject
, gdouble dec
)
161 gdouble step_delta
, delta_div
= 2.0;
162 struct ln_equ_posn pos_start
, pos_end
;
165 step_delta
= get_dec_step_delta(proj
);
167 pos_start
.ra
= proj
->centre_ra
;
168 pos_end
.ra
= proj
->centre_ra
;
169 pos_start
.dec
= pos_end
.dec
= dec
;
170 robject
->coord
[0].posn
= &pos_start
;
171 robject
->coord
[1].posn
= &pos_end
;
173 /* find start position */
175 pos_start
.ra
-= step_delta
;
176 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
177 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
178 } while (projection_is_visible0(proj
, robject
) &&
179 proj
->centre_ra
- pos_start
.ra
< 90.0);
180 pos_start
.ra
+= step_delta
;
182 /* binary chop start */
184 pos_start
.ra
-= step_delta
/ delta_div
;
185 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
186 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
187 if (!projection_is_visible0(proj
, robject
))
188 pos_start
.ra
+= step_delta
/ delta_div
;
190 } while (delta_div
< GRID_BISECT
);
192 /* find end position */
194 pos_end
.ra
+= step_delta
;
195 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
196 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
197 } while (projection_is_visible1(proj
, robject
) &&
198 pos_end
.ra
- proj
->centre_ra
< 90.0);
199 pos_end
.ra
-= step_delta
;
201 /* binary chop end */
204 pos_end
.ra
+= step_delta
/ delta_div
;
205 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
206 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
207 if (!projection_is_visible1(proj
, robject
))
208 pos_end
.ra
-= step_delta
/ delta_div
;
210 } while (delta_div
< GRID_BISECT
);
212 ln_deg_to_dms(dec
, &dms
);
217 if (dms
.minutes
== 0 && dms
.seconds
== 0.0)
218 sprintf(&text
[1], "%2.2dº", dms
.degrees
);
219 else if (dms
.seconds
< 0.1)
220 sprintf(&text
[1], "%2.2dº%2.2dm", dms
.degrees
, dms
.minutes
);
222 sprintf(&text
[1], "%2.2dº%2.2dm%2.0f", dms
.degrees
, dms
.minutes
,
225 cairo_move_to(robject
->cr
,
226 robject
->coord
[0].x
- 30.0,
227 robject
->coord
[0].y
- 1.0);
228 cairo_show_text(robject
->cr
, text
);
229 cairo_move_to(robject
->cr
,
230 robject
->coord
[1].x
+ 1.0,
231 robject
->coord
[1].y
- 1.0);
232 cairo_show_text(robject
->cr
, text
);
235 static void render_ra_labels_at(struct projection
*proj
,
236 struct render_object
*robject
, gdouble ra
)
239 gdouble step_delta
, delta_div
= 2.0;
240 struct ln_equ_posn pos_start
, pos_end
;
243 step_delta
= get_ra_step_delta(proj
);
245 pos_start
.dec
= proj
->centre_dec
;
246 pos_end
.dec
= proj
->centre_dec
;
247 pos_start
.ra
= pos_end
.ra
= ra
;
248 robject
->coord
[0].posn
= &pos_start
;
249 robject
->coord
[1].posn
= &pos_end
;
251 /* find start position */
253 pos_start
.dec
-= step_delta
;
254 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
255 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
256 } while (projection_is_visible0(proj
, robject
) &&
257 proj
->centre_dec
- pos_start
.dec
< 90.0);
258 pos_start
.dec
+= step_delta
;
260 /* binary chop start */
262 pos_start
.dec
-= step_delta
/ delta_div
;
263 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
264 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
265 if (!projection_is_visible0(proj
, robject
))
266 pos_start
.dec
+= step_delta
/ delta_div
;
268 } while (delta_div
< GRID_BISECT
);
270 /* find end position */
272 pos_end
.dec
+= step_delta
;
273 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
274 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
275 } while (projection_is_visible1(proj
, robject
) &&
276 pos_end
.dec
- proj
->centre_dec
< 90.0);
277 pos_end
.dec
-= step_delta
;
279 /* binary chop end */
282 pos_end
.dec
+= step_delta
/ delta_div
;
283 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
284 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[1]);
285 if (!projection_is_visible1(proj
, robject
))
286 pos_end
.dec
-= step_delta
/ delta_div
;
288 } while (delta_div
< GRID_BISECT
);
290 ln_deg_to_hms(ra
, &hms
);
291 if (hms
.minutes
== 0 && hms
.seconds
== 0.0)
292 sprintf(text
, "%2.0dh", hms
.hours
);
293 else if (hms
.seconds
< 0.1)
294 sprintf(text
, "%2.0dh%2.2dm", hms
.hours
, hms
.minutes
);
296 sprintf(text
, "%2.0dh%2.2dm%2.0f", hms
.hours
, hms
.minutes
,
299 cairo_move_to(robject
->cr
,
301 robject
->coord
[0].y
);
302 cairo_show_text(robject
->cr
, text
);
303 cairo_move_to(robject
->cr
,
305 robject
->coord
[1].y
+ 15.0); // font size
306 cairo_show_text(robject
->cr
, text
);
310 void equ_render_dec_labels(struct render_object
*robject
, struct projection
*proj
)
312 gdouble step
, step_delta
, dec_start
, dec_end
;
313 struct ln_equ_posn pos1
;
315 pos1
.ra
= proj
->centre_ra
;
317 step_delta
= get_dec_step_delta(proj
);
318 //clip_dec_equ_grid(proj, step_delta, &dec_start, &dec_end);
319 robject
->coord
[0].posn
= &pos1
;
321 for (step
= dec_start
; step
<= dec_end
; step
+= step_delta
) {
323 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
324 render_dec_labels_at(proj
, robject
, step
);
328 void equ_render_ra_labels(struct render_object
*robject
, struct projection
*proj
)
330 gdouble step
, step_delta
, ra_start
, ra_end
;
331 struct ln_equ_posn pos1
;
333 pos1
.ra
= proj
->centre_dec
;
335 step_delta
= get_ra_step_delta(proj
);
336 //clip_ra_equ_grid(proj, step_delta, &ra_start, &ra_end);
337 robject
->coord
[0].posn
= &pos1
;
339 for (step
= ra_start
; step
<= ra_end
; step
+= step_delta
) {
341 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
342 render_ra_labels_at(proj
, robject
, step
);
346 void hrz_render_dec_labels(struct render_object
*robject
, struct projection
*proj
)
348 gdouble step
, step_delta
, dec_start
, dec_end
;
349 struct ln_equ_posn pos1
;
351 pos1
.ra
= proj
->centre_ra
;
353 step_delta
= get_dec_step_delta(proj
);
354 //clip_dec_equ_grid(proj, step_delta, &dec_start, &dec_end);
355 robject
->coord
[0].posn
= &pos1
;
357 for (step
= dec_start
; step
<= dec_end
; step
+= step_delta
) {
359 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
360 render_dec_labels_at(proj
, robject
, step
);
364 void hrz_render_ra_labels(struct render_object
*robject
, struct projection
*proj
)
366 gdouble step
, step_delta
, ra_start
, ra_end
;
367 struct ln_equ_posn pos1
;
369 pos1
.ra
= proj
->centre_dec
;
371 step_delta
= get_ra_step_delta(proj
);
372 //clip_ra_equ_grid(proj, step_delta, &ra_start, &ra_end);
373 robject
->coord
[0].posn
= &pos1
;
375 for (step
= ra_start
; step
<= ra_end
; step
+= step_delta
) {
377 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
378 render_ra_labels_at(proj
, robject
, step
);
382 static inline void ra_line(struct render_object
*robject
,
383 struct projection
*proj
, struct ln_equ_posn
*pos
,
384 struct ln_equ_posn
*end
)
386 gdouble divs
= 5.0;//proj->pixels_per_degree
387 gdouble step
= (end
->dec
- pos
->dec
) / divs
;
390 for (pos
->dec
= pos
->dec
+ step
;
391 pos
->dec
<= end
->dec
; pos
->dec
+= step
) {
393 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
394 cairo_line_to(robject
->cr
,
395 robject
->coord
[0].x
, robject
->coord
[0].y
);
399 static inline void dec_line(struct render_object
*robject
,
400 struct projection
*proj
, struct ln_equ_posn
*pos
,
401 struct ln_equ_posn
*end
)
403 gdouble divs
= 5.0;//proj->pixels_per_degree
404 gdouble step
= (end
->ra
- pos
->ra
) / divs
;
406 /* draw to DEC end */
407 for (pos
->ra
= pos
->ra
+ step
;
408 pos
->ra
<= end
->ra
; pos
->ra
+= step
) {
410 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
411 cairo_line_to(robject
->cr
,
412 robject
->coord
[0].x
, robject
->coord
[0].y
);
416 static inline void render_square(struct render_object
*robject
,
417 struct projection
*proj
, gint ra
, gint dec
)
419 gdouble ra_step_delta
, dec_step_delta
;
420 struct ln_equ_posn pos
, start_pos
, end_pos
;
422 ra_step_delta
= get_ra_step_delta(proj
);
423 dec_step_delta
= get_dec_step_delta(proj
);
424 robject
->coord
[0].posn
= &pos
;
427 start_pos
.ra
= pos
.ra
= ra
* 15.0;
428 start_pos
.dec
= pos
.dec
= -90.0 + dec
* 10.0;
431 end_pos
.ra
= start_pos
.ra
+ 15.0;
432 end_pos
.dec
= start_pos
.dec
+ 10.0;
435 for (; pos
.ra
<= end_pos
.ra
; pos
.ra
+= ra_step_delta
) {
437 /* move to RA start */
438 pos
.dec
= start_pos
.dec
;
439 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
440 cairo_move_to(robject
->cr
,
441 robject
->coord
[0].x
, robject
->coord
[0].y
);
443 ra_line(robject
, proj
, &pos
, &end_pos
);
444 //render_ra_labels_at(proj, robject, ra_step_delta);
448 for (pos
.dec
= start_pos
.dec
; pos
.dec
<= end_pos
.dec
;
449 pos
.dec
+= dec_step_delta
) {
451 /* move to DEC start */
452 pos
.ra
= start_pos
.ra
;
453 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
454 cairo_move_to(robject
->cr
,
455 robject
->coord
[0].x
, robject
->coord
[0].y
);
457 dec_line(robject
, proj
, &pos
, &end_pos
);
461 void equ_render_grid(struct render_object
*robject
, struct projection
*proj
)
465 for (ra
= 0; ra
< GRID_RA_TILES
; ra
++) {
466 for (dec
= 1; dec
< GRID_DEC_TILES
- 2; dec
++)
467 if (proj
->grid_tile
[ra
][dec
])
468 render_square(robject
, proj
, ra
, dec
);
472 void grid_horizon_ra(struct render_object
*robject
, struct projection
*proj
)
475 struct ln_equ_posn pos1
;
476 int start_visible
, end_visible
;
480 robject
->coord
[0].posn
= &pos1
;
481 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
482 start_visible
= projection_is_visible0(proj
, robject
);
483 cairo_move_to(robject
->cr
,
485 robject
->coord
[0].y
);
487 for (step
= 10; step
<= 360; step
+= 10) {
489 proj
->trans
->sky_to_proj_equ(proj
, &robject
->coord
[0]);
490 end_visible
= projection_is_visible0(proj
, robject
);
491 if (start_visible
|| end_visible
)
492 cairo_line_to(robject
->cr
,
494 robject
->coord
[0].y
);
496 cairo_move_to(robject
->cr
,
498 robject
->coord
[0].y
);
499 start_visible
= end_visible
;
503 void grid_horizon_altaz(struct render_object
*robject
, struct projection
*proj
)
506 struct ln_equ_posn pos1
;
507 int start_visible
, end_visible
;
509 cairo_save(robject
->cr
);
510 cairo_set_source_rgba(robject
->cr
, 1, 0.35, 0.55, 0.7);
514 robject
->coord
[0].posn
= &pos1
;
516 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
517 start_visible
= projection_is_visible0(proj
, robject
);
518 cairo_move_to(robject
->cr
,
520 robject
->coord
[0].y
);
522 for (step
= 10; step
<= 360; step
+= 10) {
524 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
525 end_visible
= projection_is_visible0(proj
, robject
);
526 if (start_visible
|| end_visible
)
527 cairo_line_to(robject
->cr
,
529 robject
->coord
[0].y
);
531 cairo_move_to(robject
->cr
,
533 robject
->coord
[0].y
);
534 start_visible
= end_visible
;
536 cairo_stroke(robject
->cr
);
537 cairo_restore(robject
->cr
);
540 void grid_horizon_news(struct render_object
*robject
, struct projection
*proj
)
542 struct ln_equ_posn pos1
;
544 cairo_save(robject
->cr
);
545 cairo_set_font_size (robject
->cr
, 20.0);
546 cairo_set_source_rgba(robject
->cr
, 1, 0.35, 0.55, 0.7);
547 robject
->coord
[0].posn
= &pos1
;
551 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
552 cairo_move_to(robject
->cr
,
554 robject
->coord
[0].y
);
555 cairo_show_text(robject
->cr
, "S");
558 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
559 cairo_move_to(robject
->cr
,
561 robject
->coord
[0].y
);
562 cairo_show_text(robject
->cr
, "W");
565 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
566 cairo_move_to(robject
->cr
,
568 robject
->coord
[0].y
);
569 cairo_show_text(robject
->cr
, "N");
572 proj
->trans
->sky_to_proj_hrz(proj
, &robject
->coord
[0]);
573 cairo_move_to(robject
->cr
,
575 robject
->coord
[0].y
);
576 cairo_show_text(robject
->cr
, "E");
578 cairo_restore(robject
->cr
);
581 void grid_render(Sky
*sky
)
583 struct render_object
*robject
= &sky
->robject
;
584 struct projection
*proj
= &sky
->projection
;
585 gint labels
= sky
->marker_settings
.show_grid_labels
;
588 if (robject
->flags
.night_mode
)
589 alpha
= GRID_NIGHT_ALPHA
;
591 alpha
= GRID_DAY_ALPHA
;
593 cairo_save(robject
->cr
);
594 cairo_set_source_rgba(robject
->cr
, 0, 0.35, 0.55, alpha
);
595 cairo_set_font_size (robject
->cr
, 13.0);
597 if (robject
->type
== RT_FAST
) //TODO make step size * 2.0 when fast
598 cairo_set_tolerance (robject
->cr
, 1.0);
600 get_visible_tiles(proj
);
602 switch (proj
->grid_coords
) {
604 equ_render_grid(robject
, proj
);
605 //equ_render_dec_labels(robject, proj);
606 //equ_render_ra_labels(robject, proj);
609 //hrz_render_ra(robject, proj, labels);
610 //hrz_render_dec(robject, proj, labels);
611 hrz_render_dec_labels(robject
, proj
);
612 hrz_render_ra_labels(robject
, proj
);
615 cairo_stroke(robject
->cr
);
617 //grid_horizon_ra(robject, proj);
618 grid_horizon_altaz(robject
, proj
);
620 grid_horizon_news(robject
, proj
);
622 if (robject
->type
== RT_FAST
)
623 cairo_set_tolerance (robject
->cr
, 0.1); /* do we need this */
624 cairo_restore(robject
->cr
);