source: trunk/src/Utils/pgplot_related.c @ 1130

Last change on this file since 1130 was 1130, checked in by MatthewWhiting, 11 years ago

Ticket #132 - allowing fitting of an ellipse to the moment-0 map of a detection. Also allowing it to be written to annotation files and to the moment-0 cutout in the spectral output.

File size: 15.4 KB
Line 
1/*
2// -----------------------------------------------------------------------
3// pgplot_related.c: New functions for use with PGPLOT.
4// -----------------------------------------------------------------------
5// Copyright (C) 2006, Matthew Whiting, ATNF
6//
7// This program is free software; you can redistribute it and/or modify it
8// under the terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// Duchamp is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15// for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with Duchamp; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20//
21// Correspondence concerning Duchamp may be directed to:
22//    Internet email: Matthew.Whiting [at] atnf.csiro.au
23//    Postal address: Dr. Matthew Whiting
24//                    Australia Telescope National Facility, CSIRO
25//                    PO Box 76
26//                    Epping NSW 1710
27//                    AUSTRALIA
28// -----------------------------------------------------------------------
29*/
30#include <stdio.h>
31#include <stdlib.h>
32#include <cpgplot.h>
33#include <math.h>
34#include <string.h>
35#include <ctype.h>
36
37#define WDGPIX 100  /* used by cpgwedglog
38                       --> number of increments in the wedge. */
39
40/*
41 This file contains the following programs, all in C code:
42
43  int cpgtest() --> a front-end to cpgqinf, to test whether a pgplot
44                    device is currently open.
45  void cpgwedglog(const char* side, float disp, float width,
46                  float fg, float bg, const char *label)
47                --> a C-code version of pgwedg, plotting the wedge
48                    scale in logarithmic units.
49  void cpgcumul(int npts, float *data, float datamin, float datamax,
50                       int pgflag)
51                --> a new pgplot routine that draws a cumulative
52                    distribution. Uses _swap and _sort.
53  void cpghistlog(npts, data, datamin, datamax, nbin, pgflag)
54                --> as for cpghist, with the y-axis on a logarithmic scale.
55
56*/
57
58
59/********************************************************************/
60/*   CPGTEST                                                        */
61/********************************************************************/
62
63int cpgtest()
64{
65  /**
66   *     A front-end to cpgqinf, to test whether a pgplot device is
67   *     currently open. Returns 1 if there is, else 0.
68   */
69  char answer[10];                 /* The PGQINF return string */
70  int answer_len = sizeof(answer); /* allocated size of answer[] */
71  cpgqinf("STATE", answer, &answer_len);
72  return strcmp(answer, "OPEN") == 0;
73}
74
75/********************************************************************/
76/*   CPGWEDGLOG                                                     */
77/********************************************************************/
78
79void cpgwedglog(const char* side, float disp, float width, float fg, float bg,
80                const char *label)
81{
82  /**
83   *     A C-code version of PGWEDG that writes the scale of the wedge in
84   *      logarithmic coordinates. All parameters are exactly as for cpgwedg.
85   */
86 
87  float wxa,wxb,wya,wyb, xa,xb,ya,yb; /* Temporary window coord storage.*/
88  float vxa,vxb,vya,vyb;              /* Viewport coords of wedge. */
89  float oldch, newch;                 /* Original and annotation character
90                                         heights. */
91  float ndcsiz;                       /* Size of unit character height
92                                         (NDC units). */
93  int horiz;                          /* Logical: True (=1) if wedge plotted
94                                         horizontally. */
95  int image;                          /* Logical: Use PGIMAG (T=1) or
96                                         PGGRAY (F=0). */
97
98  int nside,i;                        /* nside = symbolic version of side. */
99  const int bot=1,top=2,lft=3,rgt=4;
100  float wedwid, wdginc, vwidth, vdisp, xch, ych, labwid, fg1, bg1;
101  float txtfrc=0.6;                   /* Set the fraction of WIDTH used
102                                             for anotation. */
103  float txtsep=2.2;                   /* Char separation between numbers
104                                             and LABEL. */
105  float wdgarr[WDGPIX];               /* Array to draw wedge in. */
106  float tr[6] = {0.0,1.0,0.0,0.0,0.0,1.0};
107
108/*   if(pgnoto("pgwedg")) return; */
109
110  /* Get a numeric version of SIDE. */
111  nside=bot; /* initialise */
112  horiz=1;   /* initialise */
113  if(tolower(side[0])=='b'){
114    nside = bot;
115    horiz = 1;
116  }
117  else if(tolower(side[0]=='t')){
118    nside = top;
119    horiz = 1;
120  }
121  else if(tolower(side[0]=='l')){
122    nside = lft;
123    horiz = 0;
124  }
125  else if(tolower(side[0]=='r')){
126    nside = rgt;
127    horiz = 0;
128  }
129  /*   else gwarn("Invalid \"SIDE\" argument in PGWEDG.");  */
130  else fprintf(stdout,"%%PGPLOT, Invalid \"SIDE\" argument in CPGWEDGLOG.");
131
132  /* Determine which routine to use. */
133  image=0; /* initialise */
134  if(strlen(side)<2) image = 0;
135  else if(tolower(side[1])=='i') image = 1;
136  else if(tolower(side[1])=='g') image = 0;
137  else fprintf(stdout,"%%PGPLOT, Invalid \"SIDE\" argument in CPGWEDGLOG.");
138
139  cpgbbuf();
140
141  /* Store the current world and viewport coords and the character height. */
142  cpgqwin(&wxa, &wxb, &wya, &wyb);
143  cpgqvp(0, &xa, &xb, &ya, &yb);
144  cpgqch(&oldch);
145
146  /* Determine the unit character height in NDC coords. */
147  cpgsch(1.0);
148  cpgqcs(0, &xch, &ych);
149  if(horiz == 1)  ndcsiz = ych;
150  else ndcsiz = xch;
151
152  /* Convert 'WIDTH' and 'DISP' into viewport units. */
153  vwidth = width * ndcsiz * oldch;
154  vdisp  = disp * ndcsiz * oldch;
155
156  /* Determine the number of character heights required under the wedge. */
157  labwid = txtsep;
158  if(strcmp(label," ")!=0) labwid = labwid + 1.0;
159 
160  /* Determine and set the character height required to fit the wedge
161     anotation text within the area allowed for it. */
162  newch = txtfrc*vwidth / (labwid*ndcsiz);
163  cpgsch(newch);
164
165  /* Determine the width of the wedge part of the plot minus the anotation.
166     (NDC units). */
167  wedwid = vwidth * (1.0-txtfrc);
168
169  /* Use these to determine viewport coordinates for the wedge + annotation.*/
170  vxa = xa;
171  vxb = xb;
172  vya = ya;
173  vyb = yb;
174  if(nside==bot){
175    vyb = ya - vdisp;
176    vya = vyb - wedwid;
177  }
178  else if(nside==top) {
179    vya = yb + vdisp;
180    vyb = vya + wedwid;
181  }
182  else if(nside==lft) {
183    vxb = xa - vdisp;
184    vxa = vxb - wedwid;
185  }
186  else if(nside==rgt) {
187    vxa = xb + vdisp;
188    vxb = vxa + wedwid;
189  }
190
191  /* Set the viewport for the wedge. */
192  cpgsvp(vxa, vxb, vya, vyb);
193
194  /* Swap FG/BG if necessary to get axis direction right. */
195/*   fg1 = max(fg,bg); */
196/*   bg1 = min(fg,bg); */
197  if(fg>bg) {
198    fg1 = fg;
199    bg1 = bg;
200  }
201  else {
202    fg1 = bg;
203    bg1 = fg;
204  }
205
206
207  /* Create a dummy wedge array to be plotted. */
208  wdginc = (fg1-bg1)/(WDGPIX-1);
209  for(i=0;i<WDGPIX;i++)  wdgarr[i] = bg1 + (i-1) * wdginc;
210
211  /* Draw the wedge then change the world coordinates for labelling. */
212  if (horiz==1) {
213    cpgswin(1.0, (float)WDGPIX, 0.9, 1.1);
214    if (image==1) cpgimag(wdgarr, WDGPIX,1, 1,WDGPIX, 1,1, fg,bg, tr);
215    else          cpggray(wdgarr, WDGPIX,1, 1,WDGPIX, 1,1, fg,bg, tr);
216    cpgswin(bg1,fg1,0.0,1.0);
217  }
218  else{
219    cpgswin(0.9, 1.1, 1.0, (float)WDGPIX);
220    if (image==1) cpgimag(wdgarr, 1,WDGPIX, 1,1, 1,WDGPIX, fg,bg, tr);
221    else          cpggray(wdgarr, 1,WDGPIX, 1,1, 1,WDGPIX, fg,bg, tr);
222    cpgswin(0.0, 1.0, bg1, fg1);
223  }
224
225  /* Draw a labelled frame around the wedge -- using a logarithmic scale! */
226  if(nside==bot)  cpgbox("BCNSTL",0.0,0,"BC",0.0,0);
227  else if(nside==top) cpgbox("BCMSTL",0.0,0,"BC",0.0,0);
228  else if(nside==lft) cpgbox("BC",0.0,0,"BCNSTL",0.0,0);
229  else if(nside==rgt) cpgbox("BC",0.0,0,"BCMSTL",0.0,0);
230
231  /* Write the units label. */
232  if((strcmp(label," ")!=0)) cpgmtxt(side,txtsep,1.0,1.0,label);
233
234  /* Reset the original viewport and world coordinates. */
235  cpgsvp(xa,xb,ya,yb);
236  cpgswin(wxa,wxb,wya,wyb);
237  cpgsch(oldch);
238  cpgebuf();
239
240}
241
242
243/********************************************************************/
244/*   CPGCUMUL                                                       */
245/********************************************************************/
246
247void _swap(float *a, float *b)
248{
249  float t;
250  t=*a; *a=*b; *b=t;
251}
252
253void _sort(float *array, int begin, int end)
254{
255  float pivot = array[begin];
256  int i = begin + 1, j = end, k = end;
257  float t;
258
259  while (i < j) {
260    if (array[i] < pivot) i++;
261    else if (array[i] > pivot) {
262      j--; k--;
263      t = array[i];
264      array[i] = array[j];
265      array[j] = array[k];
266      array[k] = t; }
267    else {
268      j--;
269      _swap(&array[i], &array[j]);
270    }  }
271  i--;
272  _swap(&array[begin], &array[i]);       
273  if (i - begin > 1)
274    _sort(array, begin, i);
275  if (end - k   > 1)
276    _sort(array, k, end);                     
277}
278
279
280void cpgcumul(int npts, float *data, float datamin, float datamax, int pgflag)
281{
282  /**
283   *  A new pgplot routine that draws a cumulative distribution.
284   *   The use of pgflag is similar to cpghist & cpghist_log:
285
286   *   <ul><li> 0 --> draw a new graph using cpgenv, going from 0 to 1
287   *                  on the y-axis.
288   *       <li> 2 --> draw the plot on the current graph, without
289   *                  re-drawing any axes. 
290   *   </ul>
291   */
292
293  int i;
294  float *sorted;
295  float MINCOUNT=0.;
296
297  sorted = (float *)calloc(npts,sizeof(float));
298  for(i=0;i<npts;i++) sorted[i] = data[i];
299  _sort(sorted,0,npts);
300
301  cpgbbuf();
302
303  /* DEFINE ENVIRONMENT IF NECESSARY */
304  if(pgflag == 0) cpgenv(datamin,datamax,MINCOUNT,1.0001,0,0);
305  if(pgflag == 2) cpgswin(datamin,datamax,MINCOUNT,1.);
306
307  /* DRAW LINE */
308  cpgmove(datamin,MINCOUNT);
309  for(i=0;i<npts;i++) cpgdraw(sorted[i],(float)(i+1)/(float)(npts));
310  cpgdraw(datamax,1.);
311
312  cpgebuf();
313 
314  free(sorted);
315
316}
317
318/********************************************************************/
319/*   CPGHISTLOG                                                     */
320/********************************************************************/
321
322void cpghistlog(int npts, float *data, float datamin, float datamax, int nbin,
323                int pgflag)
324{
325  /**
326   *  Works exactly as for cpghist, except the y-axis is a logarithmic scale.
327   *
328   */
329
330
331  int i,bin;
332  float *num;
333  float maxNum,binSize,x1,x2,y1,y2,older,newer,fraction;
334  float MINCOUNT=-0.2;
335
336  num = (float *)calloc(nbin,sizeof(float));
337
338  cpgbbuf();
339
340  /* HOW MANY VALUES IN EACH BIN? */
341  for(i=0; i<npts; i++){
342    fraction = (data[i] - datamin) / (datamax - datamin);
343    bin = (int)( floor(fraction*nbin) );
344    if((bin>=0)&&(bin<nbin)) num[bin]+=1.;
345  }
346  for(i=0; i<nbin;i++){
347    if(num[i]>0) num[i] = log10(num[i]);
348    else num[i] = MINCOUNT;
349  }
350  maxNum = num[0];
351  for(i=1; i<nbin; i++) if(num[i]>maxNum) maxNum = num[i];
352  binSize = (datamax - datamin) / (float)nbin;
353
354  /* BOUNDARIES OF PLOT */
355  x1 = datamin;
356  x2 = datamax;
357  y1 = MINCOUNT;
358  y2 = ceil(maxNum);
359
360  /* DEFINE ENVIRONMENT IF NECESSARY */
361  if(pgflag%2 == 0) cpgenv(x1,x2,y1,y2,0,20);
362
363  /* DRAW HISTOGRAM */
364  if(pgflag/2 == 0){
365    older = 0.;
366    x2 = datamin;
367    cpgmove(datamin,MINCOUNT);
368    for(i=0;i<nbin;i++){
369      newer = num[i];
370      x1 = x2;
371      x2 = datamin + i*binSize;
372      if(newer!=MINCOUNT){
373        if(newer<=older){
374          cpgmove(x1,newer);
375          cpgdraw(x2,newer);
376        }
377        else{
378          cpgmove(x1,older);
379          cpgdraw(x1,newer);
380          cpgdraw(x2,newer);
381        }
382      }
383      cpgdraw(x2,MINCOUNT);
384      older=newer;
385    }
386  }
387  else if(pgflag/2 == 1){
388    older = MINCOUNT;
389    x2 = datamin;
390    for(i=0;i<nbin;i++){
391      newer = num[i];
392      x1 = x2;
393      x2 = datamin + i*binSize;
394      if(newer!=MINCOUNT) cpgrect(x1,x2,0.,newer);     
395    }
396  }
397  else if(pgflag/2 == 2){
398    older = 0.;
399    cpgmove(datamin,MINCOUNT);
400    x2 = datamin;
401    for(i=0;i<nbin;i++){
402      newer = num[i];
403      x1 = x2;
404      x2 = datamin + i*binSize;
405      if((newer==MINCOUNT)&&(older==MINCOUNT)) cpgmove(x2,MINCOUNT);
406      else {
407        cpgdraw(x1,newer);
408        if(newer==MINCOUNT) cpgmove(x2,newer);
409        else cpgdraw(x2,newer);
410      }
411      older = newer;
412    }
413  }
414
415  cpgebuf();
416   
417}
418
419/********************************************************************/
420/*   CPGELLIPSE                                                     */
421/********************************************************************/
422
423
424void cpgellipse(float x0, float y0, float maj, float min, float pa)
425{
426  /*
427    Draw an ellipse, using the parametric equation u = a cos(t), v = b sin(t), where u and v are coordinates such that the position angle of the ellipse is zero.
428   */
429  double cospa,sinpa,u,v,x,y,t;
430  int it;
431  cospa = cos(pa*M_PI/180.);
432  sinpa = sin(pa*M_PI/180.);
433  u=maj;
434  v=0.;
435  x=u*cospa+v*sinpa;
436  y=u*sinpa-v*cospa;
437  cpgmove(x+x0,y+y0);
438  for(it=0;it<1000;it++){
439    t=it*2*M_PI/1000.;
440    u=maj*cos(t);
441    v=min*sin(t);
442    x=u*cospa+v*sinpa;
443    y=u*sinpa-v*cospa;
444    cpgdraw(x+x0,y+y0);
445  }
446}
447
448
449/* /\********************************************************************\/ */
450/* /\*   CPGVERTHIST                                                    *\/ */
451/* /\********************************************************************\/ */
452
453/* void cpgverthist(int npts, float *data, float datamin, float datamax, int nbin,  */
454/*               int pgflag) */
455/* { */
456/*   /\** */
457/*    *  Works exactly as for cpghist, except the histogram is draw vertically. */
458/*    * */
459/*    *\/ */
460
461
462/*   int i,bin; */
463/*   float *num; */
464/*   float maxNum,binSize,x1,x2,y1,y2,older,newer,fraction; */
465/*   float MINCOUNT=-0.2; */
466
467/*   num = (float *)calloc(nbin,sizeof(float)); */
468
469/*   cpgbbuf(); */
470
471/*   /\* HOW MANY VALUES IN EACH BIN? *\/ */
472/*   for(i=0; i<npts; i++){ */
473/*     fraction = (data[i] - datamin) / (datamax - datamin); */
474/*     bin = (int)( floor(fraction*nbin) ); */
475/*     if((bin>=0)&&(bin<nbin)) num[bin]+=1.; */
476/*   } */
477/*   for(i=0; i<nbin;i++){ */
478/*     if(num[i]>0) num[i] = log10(num[i]); */
479/*     else num[i] = MINCOUNT; */
480/*   } */
481/*   maxNum = num[0]; */
482/*   for(i=1; i<nbin; i++) if(num[i]>maxNum) maxNum = num[i]; */
483/*   binSize = (datamax - datamin) / (float)nbin; */
484
485/*   /\* BOUNDARIES OF PLOT *\/ */
486/*   x1 = datamin; */
487/*   x2 = datamax; */
488/*   y1 = MINCOUNT; */
489/*   y2 = ceil(maxNum); */
490
491/*   /\* DEFINE ENVIRONMENT IF NECESSARY *\/ */
492/*   if(pgflag%2 == 0) cpgenv(x1,x2,y1,y2,0,20); */
493
494/*   /\* DRAW HISTOGRAM *\/ */
495/*   if(pgflag/2 == 0){ */
496/*     older = 0.; */
497/*     x2 = datamin; */
498/*     cpgmove(datamin,MINCOUNT); */
499/*     for(i=0;i<nbin;i++){ */
500/*       newer = num[i]; */
501/*       x1 = x2; */
502/*       x2 = datamin + i*binSize; */
503/*       if(newer!=MINCOUNT){ */
504/*      if(newer<=older){ */
505/*        cpgmove(x1,newer); */
506/*        cpgdraw(x2,newer); */
507/*      } */
508/*      else{ */
509/*        cpgmove(x1,older); */
510/*        cpgdraw(x1,newer); */
511/*        cpgdraw(x2,newer); */
512/*      } */
513/*       } */
514/*       cpgdraw(x2,MINCOUNT); */
515/*       older=newer; */
516/*     } */
517/*   } */
518/*   else if(pgflag/2 == 1){ */
519/*     older = MINCOUNT; */
520/*     x2 = datamin; */
521/*     for(i=0;i<nbin;i++){ */
522/*       newer = num[i]; */
523/*       x1 = x2; */
524/*       x2 = datamin + i*binSize; */
525/*       if(newer!=MINCOUNT) cpgrect(x1,x2,0.,newer);    */
526/*     } */
527/*   } */
528/*   else if(pgflag/2 == 2){ */
529/*     older = 0.; */
530/*     cpgmove(datamin,MINCOUNT); */
531/*     x2 = datamin; */
532/*     for(i=0;i<nbin;i++){ */
533/*       newer = num[i]; */
534/*       x1 = x2; */
535/*       x2 = datamin + i*binSize; */
536/*       if((newer==MINCOUNT)&&(older==MINCOUNT)) cpgmove(x2,MINCOUNT); */
537/*       else { */
538/*      cpgdraw(x1,newer); */
539/*      if(newer==MINCOUNT) cpgmove(x2,newer); */
540/*      else cpgdraw(x2,newer); */
541/*       } */
542/*       older = newer; */
543/*     } */
544/*   } */
545
546/*   cpgebuf(); */
547   
548/* } */
549
Note: See TracBrowser for help on using the repository browser.