source: trunk/src/Cubes/drawMomentCutout.cc @ 187

Last change on this file since 187 was 187, checked in by Matthew Whiting, 18 years ago

Large suite of edits, mostly due to testing with valgrind, which clear up bad memory allocations and so on.
Improved the printing of progress bars in some routines by introducing a new ProgressBar? class, with associated functions to do the printing (now much cleaner).

File size: 9.2 KB
Line 
1#include <iostream>
2#include <sstream>
3#include <cpgplot.h>
4#include <math.h>
5#include <wcs.h>
6#include <duchamp.hh>
7#include <param.hh>
8#include <Cubes/cubes.hh>
9#include <Utils/utils.hh>
10#include <Utils/mycpgplot.hh>
11
12const int MIN_WIDTH=20;
13using namespace mycpgplot;
14
15void Cube::drawMomentCutout(Detection &object)
16{
17  /**
18   *  Cube::drawMomentCutout(object)
19   *
20   *   A routine to draw the 0th moment for the given detection
21   *    using the flux given by the pixel array in the Cube.
22   *   The 0th moment is constructed by adding the flux of each
23   *    pixel within the full extent of the object (this may be more
24   *    pixels than were actually detected in the object)
25   *   A tick mark is also drawn to indicate angular scale (but only
26   *    if the WCS for the Cube is valid).
27   */
28
29  if(!cpgtest())
30    duchampError("drawMomentCutout","There is no PGPlot device open!\n");
31  else{
32
33    long size = (object.getXmax()-object.getXmin()+1);
34    if(size<(object.getYmax()-object.getYmin()+1))
35      size = object.getYmax()-object.getYmin()+1;
36    size += MIN_WIDTH;
37
38    long xmin = (object.getXmax()+object.getXmin())/2 - size/2 + 1;
39    long xmax = (object.getXmax()+object.getXmin())/2 + size/2;
40    long ymin = (object.getYmax()+object.getYmin())/2 - size/2 + 1;
41    long ymax = (object.getYmax()+object.getYmin())/2 + size/2;
42    long zmin = object.getZmin();
43    long zmax = object.getZmax();
44
45    float *image = new float[size*size];
46    for(int i=0;i<size*size;i++) image[i]=0.;
47
48    bool *isGood = new bool[size*size];
49    for(int i=0;i<size*size;i++) isGood[i]=true;
50    for(int z=zmin; z<=zmax; z++){
51      for(int x=xmin; x<=xmax; x++){
52        for(int y=ymin; y<=ymax; y++){
53          isGood[(y-ymin) * size + (x-xmin)] =
54            ((x>=0)&&(x<this->axisDim[0]))    // if inside the boundaries
55            && ((y>=0)&&(y<this->axisDim[1])) // if inside the boundaries
56            && !this->isBlank(x,y,z);         // if not blank
57        }
58      }
59    }
60
61    int imPos,cubePos;
62    for(int z=zmin; z<=zmax; z++){
63      for(int x=xmin; x<=xmax; x++){
64        for(int y=ymin; y<=ymax; y++){
65
66          imPos = (y-ymin) * size + (x-xmin);
67          cubePos = z*this->axisDim[0]*this->axisDim[1] + y*this->axisDim[0] + x;
68
69          if(isGood[imPos]) image[imPos] += this->array[cubePos];
70
71        }
72      }
73    }
74
75    for(int i=0;i<size*size;i++){
76      // if there is some signal on this pixel, normalise by the velocity width
77      if(isGood[i]) image[i] /= float(zmax-zmin+1);
78    }
79
80    // now work out the greyscale display limits,
81    //   excluding blank pixels where necessary.
82    float z1,z2,median,madfm;
83    int ct=0;
84    while(!isGood[ct]) ct++; // move to first non-blank pixel
85    z1 = z2 = image[ct];
86    for(int i=1;i<size*size;i++){
87      if(isGood[i]){
88        if(image[i]<z1) z1=image[i];
89        if(image[i]>z2) z2=image[i];
90      }
91    }
92
93    // adjust the values of the blank and extra-image pixels
94    for(int i=0;i<size*size;i++){
95      if(!isGood[i]){
96        if(this->par.getFlagBlankPix()) //blank pixels --> BLANK
97          image[i] = this->par.getBlankPixVal();
98        else        // lies outside image boundary --> black
99          image[i] = z1 - 1.;
100      }
101    }
102
103    float tr[6] = {xmin-1,1.,0.,ymin-1,0.,1.};
104
105    cpgswin(xmin-0.5,xmax-0.5,ymin-0.5,ymax-0.5);
106    cpggray(image, size, size, 1, size, 1, size, z1, z2, tr);
107
108    delete [] image;
109
110    int ci;
111    cpgqci(&ci);
112
113    // Draw the border of the BLANK region, if there is one...
114    this->plotBlankEdges();
115
116    // Draw the border of cube's pixels
117    this->drawFieldEdge();
118
119    // Draw the borders around the object
120    cpgsci(BLUE);
121    cpgsfs(OUTLINE);
122    if(this->par.drawBorders())
123      object.drawBorders(xmin,ymin);
124    else
125      cpgrect(object.getXmin()-xmin+0.5,object.getXmax()-xmin+1.5,
126              object.getYmin()-ymin+0.5,object.getYmax()-ymin+1.5);
127    /*
128      To get the borders localised correctly, we need to subtract (xmin-1)
129      from the X values. We then subtract 0.5 for the left hand border
130      (to place it on the pixel border), and add 0.5 for the right hand
131      border. Similarly for y.
132    */
133
134    if(this->head.isWCS()){
135      // Now draw a tick mark to indicate size -- 15 arcmin in length
136      //     this->drawScale(xmin+2.,ymin+2.,object.getZcentre(),0.25);
137      this->drawScale(xmin+2.,ymin+2.,object.getZcentre());
138    }
139
140    cpgsci(ci);
141
142  }
143
144}
145
146void Cube::drawScale(float xstart, float ystart, float channel)
147{
148  /**
149   *  Cube::drawScale(xstart, ystart, channel)
150   *
151   *   A routine to draw a scale bar on a (pre-existing) PGPlot image.
152   *   It uses an iterative technique to move from the given start position
153   *    (xstart,ystart) along the positive x-direction so that the length is
154   *    within 1% of the scaleLength (length in degrees), calculated
155   *    according to the pixel scale of the cube.
156   *   The parameter "channel" is required for the wcslib calculations, as the
157   *    positions could theoretically change with channel.
158   */
159
160  if(!cpgtest())
161    duchampError("drawScale","There is no PGPlot device open!\n");
162  else{
163
164    if(this->head.isWCS()){  // can only do this if the WCS is good!
165
166      enum ANGLE {ARCSEC, ARCMIN, DEGREE};
167      const string symbol[3] = {"\"", "'", mycpgplot::degrees };
168      const float angleScale[3] = {3600., 60., 1.};
169      //  degree, arcmin, arcsec symbols
170   
171      const float lengths[11] = {1./3600., 5./3600., 15./3600., 30./3600.,
172                                 1./60., 5./60., 15./60., 30./60.,
173                                 1., 5., 15.};
174      const float desiredRatio = 0.2;
175
176      // first, work out what is the optimum length of the scale bar,
177      //   based on the pixel scale and size of the image.
178      float pixscale = this->head.getAvPixScale();
179      float *fraction = new float[11];
180      int best;
181      float x1,x2,y1,y2;
182      cpgqwin(&x1,&x2,&y1,&y2);
183      for(int i=0;i<11;i++){
184        fraction[i] = (lengths[i]/pixscale) / (x2-x1);
185        if(i==0) best=0;
186        else if(fabs(fraction[i] - desiredRatio) <
187                fabs(fraction[best] - desiredRatio)) best=i;
188      }
189      delete [] fraction;
190
191      ANGLE angleType;
192      if(best<4)      angleType = ARCSEC;
193      else if(best<8) angleType = ARCMIN;
194      else            angleType = DEGREE;
195      float scaleLength = lengths[best];  // this is currently in degrees
196
197      // Now work out actual pixel locations for the ends of the scale bar
198      double *pix1   = new double[3];
199      double *pix2   = new double[3];
200      double *world1 = new double[3];
201      double *world2 = new double[3];
202      pix1[0] = pix2[0] = xstart + this->par.getXOffset();
203      pix1[1] = pix2[1] = ystart + this->par.getYOffset();
204      pix1[2] = pix2[2] = channel;
205      this->head.pixToWCS(pix1,world1);
206
207      double angSep=0.;
208      bool keepGoing=false;
209      float step = 1.;
210      do{
211        if(angSep>scaleLength){
212          pix2[0] -= step;
213          step /= 2.;
214        }
215        pix2[0] += step;
216        this->head.pixToWCS(pix2,world2);
217        angSep = angularSeparation(world1[0],world1[1],world2[0],world2[1]);
218      }while((fabs(angSep-scaleLength)/scaleLength)>0.01); // look for 1% change
219
220      float tickpt1 = pix1[0] - this->par.getXOffset();
221      float tickpt2 = pix2[0] - this->par.getXOffset();
222      float tickpt3 = ystart;
223      int colour;
224      cpgqci(&colour);
225      cpgsci(RED);
226      int thickness;
227      cpgqlw(&thickness);
228      cpgslw(3);
229      cpgerrx(1,&tickpt1,&tickpt2,&tickpt3,2.);
230      cpgslw(thickness);
231
232      std::stringstream text;
233      text << scaleLength * angleScale[angleType] << symbol[angleType];
234      float size,xch,ych;
235      cpgqch(&size);
236      cpgsch(0.4);
237      cpgqcs(4,&xch,&ych); // get the character size in world coords
238      cpgptxt((tickpt1+tickpt2)/2., ystart+ych, 0, 0.5, text.str().c_str());
239      cpgsch(size);
240      cpgsci(colour);
241
242      delete [] pix1,pix2;
243      delete [] world1,world2;
244
245    }
246  }
247
248}
249
250void Detection::drawBorders(int xoffset, int yoffset)
251{
252
253  if(!cpgtest())
254    duchampError("drawBorders","There is no PGPlot device open!\n");
255  else{
256
257    float x1,x2,y1,y2;
258    cpgqwin(&x1,&x2,&y1,&y2);
259    int xsize = int(x2 - x1) + 1;
260    int ysize = int(y2 - y1) + 1;
261
262    bool *isObj = new bool[xsize*ysize];
263    for(int i=0;i<xsize*ysize;i++) isObj[i]=false;
264    for(int i=0;i<this->pix.size();i++)
265      isObj[ (this->pix[i].getY()-yoffset)*xsize + (this->pix[i].getX()-xoffset) ] = true;
266 
267
268    cpgswin(0,xsize-1,0,ysize-1);
269    for(int x=this->xmin; x<=this->xmax; x++){
270      // for each column...
271      for(int y=1;y<ysize;y++){
272        int current = y*xsize + (x-xoffset);
273        int previous = (y-1)*xsize + (x-xoffset);
274        if((isObj[current]&&!isObj[previous])||(!isObj[current]&&isObj[previous])){
275          cpgmove(x-xoffset+0, y+0);
276          cpgdraw(x-xoffset+1, y+0);
277        }
278      }
279    }
280    for(int y=this->ymin; y<=this->ymax; y++){
281      // now for each row...
282      for(int x=1;x<xsize;x++){
283        int current = (y-yoffset)*xsize + x;
284        int previous = (y-yoffset)*xsize + x - 1;
285        if((isObj[current]&&!isObj[previous])||(!isObj[current]&&isObj[previous])){
286          cpgmove(x+0, y-yoffset+0);
287          cpgdraw(x+0, y-yoffset+1);
288        }
289      }
290    }
291    cpgswin(x1,x2,y1,y2);
292 
293    delete [] isObj;
294
295  }   
296
297}
298
299void Cube::drawFieldEdge()
300{
301  if(!cpgtest())
302    duchampError("drawFieldEdge","There is no PGPlot device open!\n");
303  else{
304    int ci;
305    cpgqci(&ci);
306    cpgsci(YELLOW);
307 
308    cpgmove(-0.5,-0.5);
309    cpgdraw(-0.5,this->axisDim[1]-0.5);
310    cpgdraw(this->axisDim[0]-0.5,this->axisDim[1]-0.5);
311    cpgdraw(this->axisDim[0]-0.5,-0.5);
312    cpgdraw(-0.5,-0.5);
313
314    cpgsci(ci);
315  }
316}
Note: See TracBrowser for help on using the repository browser.