MUSE Pipeline Reference Manual  1.0.2
muse_geo_plot.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set sw=2 sts=2 et cin: */
3 /*
4  * This file is part of the MUSE Instrument Pipeline
5  * Copyright (C) 2013-2014 European Southern Observatory
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21 
22 #include <muse.h>
23 #include <cairo.h>
24 #include <cairo-pdf.h>
25 #include <string.h>
26 
27 /*----------------------------------------------------------------------------*/
57 /*----------------------------------------------------------------------------*/
58 
61 #define PRINT_USAGE(rc) \
62  fprintf(stderr, "Usage: %s [ -f format ] [ -s xscale yscale ] " \
63  "GEOMETRY_TABLE OUTPUT_PLOT\n", argv[0]); \
64  cpl_end(); return (rc);
65 
66 int main(int argc, char **argv)
67 {
68  cpl_init(CPL_INIT_DEFAULT);
69 
70  if (argc <= 2) {
71  /* filename is needed at least */
72  PRINT_USAGE(1);
73  }
74 
75  /* argument processing */
76  char *tiname = NULL, /* input table */
77  *oname = NULL; /* output plot */
78  enum eformats {
79  PLOT_FORMAT_PDF = 0,
80  PLOT_FORMAT_PNG
81  };
82  unsigned char oformat = PLOT_FORMAT_PDF;
83  double xscale = 4.,
84  yscale = 4.;
85  int i;
86  for (i = 1; i < argc; i++) {
87  if (strncmp(argv[i], "-f", 3) == 0) {
88  /* skip to next arg to get start value */
89  i++;
90  if (i < argc) {
91  if (!strncmp(argv[i], "pdf", 4)) {
92  oformat = PLOT_FORMAT_PDF;
93  } else if (!strncmp(argv[i], "png", 4)) {
94  oformat = PLOT_FORMAT_PNG;
95  } else {
96  PRINT_USAGE(3);
97  }
98  } else {
99  PRINT_USAGE(2);
100  }
101  } else if (strncmp(argv[i], "-s", 3) == 0) {
102  if (++i + 1 < argc) {
103  xscale = atof(argv[i++]);
104  yscale = atof(argv[i]);
105  if (xscale <= 0 || yscale <= 0) {
106  PRINT_USAGE(5);
107  }
108  } else {
109  PRINT_USAGE(4);
110  }
111  } else if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
112  PRINT_USAGE(9);
113  } else {
114  if (tiname && oname) {
115  break; /* we have the required name, skip the rest */
116  }
117  if (!tiname) {
118  tiname = argv[i]; /* set the name for the input table */
119  } else {
120  oname = argv[i]; /* set the name for the output plot */
121  }
122  }
123  } /* for i (all arguments) */
124  if (!tiname) {
125  PRINT_USAGE(1);
126  }
127 
128  cpl_table *table = cpl_table_load(tiname, 1, 1);
129  if (!table) {
130  PRINT_USAGE(10);
131  }
132  /* check the critical table columns */
133  if (!cpl_table_has_column(table, MUSE_GEOTABLE_X) ||
134  !cpl_table_has_column(table, MUSE_GEOTABLE_Y) ||
135  !cpl_table_has_column(table, MUSE_GEOTABLE_WIDTH) ||
136  !cpl_table_has_column(table, MUSE_GEOTABLE_ANGLE)) {
137  cpl_table_delete(table);
138  PRINT_USAGE(11);
139  }
140 
141  /* extrema for the size calculation and translation, with some safety margin */
142  double wmax = cpl_table_get_column_max(table, MUSE_GEOTABLE_WIDTH),
143  xmin = cpl_table_get_column_min(table, MUSE_GEOTABLE_X) - wmax / 2.,
144  ymin = cpl_table_get_column_min(table, MUSE_GEOTABLE_Y) - 2,
145  xmax = cpl_table_get_column_max(table, MUSE_GEOTABLE_X) + wmax / 2.,
146  ymax = cpl_table_get_column_max(table, MUSE_GEOTABLE_Y) + 2,
147  sx = xmax - xmin + 1,
148  sy = ymax - ymin + 1;
149  printf("Using scaling of %.3f in x- and %.3f in y-direction\n", xscale, yscale);
150  double xt = -xmin,
151  yt = -ymax;
152  printf("Translating coordinates by %.3f in x- and %.3f in y-direction\n "
153  "(extrema: %f / %f ... %f / %f)\n", xt, yt, xmin, ymin, xmax, ymax);
154 
155  /* create the cairo objects */
156  cairo_status_t rc = CAIRO_STATUS_SUCCESS;
157  cairo_surface_t *cs;
158  if (oformat == PLOT_FORMAT_PDF) { /* PDF surface and output */
159  cs = cairo_pdf_surface_create(oname, xscale * sx, yscale * sy);
160  rc = cairo_surface_status(cs);
161  if (rc != CAIRO_STATUS_SUCCESS) {
162  fprintf(stderr, "opening PDF (\"%s\") returned %d!\n", oname, rc);
163  rc = 50;
164  } else {
165  fprintf(stdout, "writing PDF to \"%s\"\n", oname);
166  }
167  } else { /* image surface and PNG output */
168  cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
169  xscale * sx, yscale * sy);
170  }
171  cairo_t *cr = cairo_create(cs);
172  /* fill with greyish background */
173  cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
174  cairo_paint(cr);
175  /* set up scaling and origin */
176  cairo_scale(cr, xscale, -yscale);
177  cairo_translate(cr, xt, yt);
178 #if 0 /* coordinate transform debugging */
179  cairo_matrix_t *cm = cpl_calloc(1, sizeof(cairo_matrix_t));
180  cairo_get_matrix(cr, cm);
181  cairo_status_t cstat = cairo_status(cr);
182  fprintf(stderr, "cm = %p, cstat = %d/%s, size is %f,%f\n",
183  cm, cstat, cairo_status_to_string(cstat), xscale * sx, yscale * sy);
184  double xtt = xmin, ytt = ymin + 2;
185  cairo_matrix_transform_point(cm, &xtt, &ytt);
186  fprintf(stderr, "%f,%f is transformed to %f,%f\n", xmin, ymin + 2, xtt, ytt);
187  xtt = xmin, ytt = ymax - 2;
188  cairo_matrix_transform_point(cm, &xtt, &ytt);
189  fprintf(stderr, "%f,%f is transformed to %f,%f\n", xmin, ymax - 2, xtt, ytt);
190  xtt = xmax, ytt = ymin + 2;
191  cairo_matrix_transform_point(cm, &xtt, &ytt);
192  fprintf(stderr, "%f,%f is transformed to %f,%f\n", xmax, ymin + 2, xtt, ytt);
193  xtt = xmax, ytt = ymax - 2;
194  cairo_matrix_transform_point(cm, &xtt, &ytt);
195  fprintf(stderr, "%f,%f is transformed to %f,%f\n", xmax, ymax - 2, xtt, ytt);
196  cpl_free(cm);
197 #endif
198 
199  /* mark the origin (x,y) = (0,0) */
200  cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
201  cairo_save(cr);
202  cairo_move_to(cr, -1000., 0.);
203  cairo_rel_line_to(cr, +5000, 0.);
204  cairo_scale(cr, 1., 1. / yscale); /* stroke 1 pixel high */
205  cairo_stroke(cr);
206  cairo_restore(cr);
207  cairo_save(cr);
208  cairo_move_to(cr, 0., -1000);
209  cairo_rel_line_to(cr, 0., +5000);
210  cairo_scale(cr, 1. / xscale, 1.); /* stroke 1 pixel wide */
211  cairo_stroke(cr);
212  cairo_restore(cr);
213 #if 0 /* mark origin with a bit dot */
214  cairo_save(cr);
215  cairo_scale(cr, 1. / xscale, 1. / yscale);
216  cairo_set_source_rgb(cr, 0.0, 0.0, 0.9);
217  cairo_arc(cr, 0, 0, 5., 0, CPL_MATH_2PI);
218  cairo_fill(cr);
219  cairo_restore(cr);
220 #endif
221 
222  /* loop through all table rows and draw the stuff */
223  int n = cpl_table_get_nrow(table);
224  for (i = 0; i < n; i++) {
225  double x = cpl_table_get(table, MUSE_GEOTABLE_X, i, NULL),
226  y = cpl_table_get(table, MUSE_GEOTABLE_Y, i, NULL),
227  width = cpl_table_get(table, MUSE_GEOTABLE_WIDTH, i, NULL),
228  angrad = cpl_table_get(table, MUSE_GEOTABLE_ANGLE, i, NULL)
229  * CPL_MATH_RAD_DEG;
230  unsigned short ifu = cpl_table_get_int(table, MUSE_GEOTABLE_FIELD, i, NULL);
231  if ((ifu - 0) % 3 == 0) { /* e.g. IFU 21 */
232  cairo_set_source_rgba(cr, 0.2, 0.2, 0.4, 0.5); /* blueish-grey */
233  } else if ((ifu - 1) % 3 == 0) { /* e.g. IFU 22 */
234  cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.5);
235  } else if ((ifu - 2) % 3 == 0) { /* e.g. IFU 23 */
236  cairo_set_source_rgba(cr, 1.0, 0.843, 0.0, 0.5); /* gold = #FFD700 */
237  } else {
238  cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.5);
239  }
240 #if 0
241  printf("ifu %hu slicesky %hu angle %f\n",
242  ifu, cpl_table_get_int(table, MUSE_GEOTABLE_SKY, i, NULL),
243  angrad * CPL_MATH_DEG_RAD);
244 #endif
245  /* in the cairo rectangle function, x/y define the top left corner! */
246  cairo_save(cr);
247  cairo_translate(cr, x, y);
248  cairo_rotate(cr, angrad);
249  cairo_rectangle(cr, -width / 2., -0.5, width, 1.);
250  cairo_fill(cr);
251  /* Mark the reference slice. We want a really fine line, so this doesn't *
252  * work with cairo_rectangle() function, but we need to draw vertical *
253  * and horizontal lines separately, with different linewidths. */
254  if (y == 0.0) {
255  cairo_set_source_rgba(cr, 0.0, 0.0, 0.9, 0.8);
256  cairo_move_to(cr, - width / 2., - 0.5);
257  cairo_set_line_width(cr, 1. / yscale);
258  cairo_rel_line_to(cr, width, 0.);
259  cairo_set_line_width(cr, 1. / xscale);
260  cairo_rel_line_to(cr, 0., 1.);
261  cairo_set_line_width(cr, 1. / yscale);
262  cairo_rel_line_to(cr, -width, 0.);
263  cairo_close_path(cr);
264  cairo_stroke(cr);
265  } /* if y == 0.0 (reference slice) */
266  cairo_restore(cr);
267  } /* for i (all table rows) */
268 
269  if (oformat == PLOT_FORMAT_PNG) {
270  cairo_surface_write_to_png(cs, oname);
271  if (rc != CAIRO_STATUS_SUCCESS) {
272  fprintf(stderr, "writing PNG (\"%s\") returned %d!\n", oname, rc);
273  rc = 50;
274  } else {
275  fprintf(stdout, "written PNG to \"%s\"\n", oname);
276  }
277  } /* if PNG */
278  cairo_destroy(cr);
279  cairo_surface_destroy(cs);
280  cairo_debug_reset_static_data();
281  cpl_table_delete(table);
282  cpl_errorstate_dump(0,0,0);
283  cpl_memory_dump();
284  cpl_end();
285  return rc;
286 }
287