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

Last change on this file since 203 was 203, checked in by Matthew Whiting, 18 years ago
  • Explicitly defined the various template options for StatsContainer::madfmToSigma.
  • Added a new way to do the momentmap plots : plotMomentMap can now take a vector<string> as its argument, so that multiple plots can be written while only calculating the array values once. This speeds up this part of the program.
  • This mean some changes to the plots.hh file, so that we store the identifier for each plot/device, and have a new function that is a front-end to cpgslct.
  • More flexibility in the drawScale function, so that finer-scale images can be dealt with.
File size: 9.3 KB
RevLine 
[3]1#include <iostream>
[103]2#include <sstream>
[3]3#include <cpgplot.h>
4#include <math.h>
5#include <wcs.h>
[142]6#include <duchamp.hh>
7#include <param.hh>
[3]8#include <Cubes/cubes.hh>
9#include <Utils/utils.hh>
[146]10#include <Utils/mycpgplot.hh>
[3]11
[142]12const int MIN_WIDTH=20;
[146]13using namespace mycpgplot;
[142]14
[103]15void Cube::drawMomentCutout(Detection &object)
[3]16{
[83]17  /**
[103]18   *  Cube::drawMomentCutout(object)
[83]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
[142]29  if(!cpgtest())
30    duchampError("drawMomentCutout","There is no PGPlot device open!\n");
31  else{
[117]32
[142]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;
[3]37
[142]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();
[3]44
[142]45    float *image = new float[size*size];
46    for(int i=0;i<size*size;i++) image[i]=0.;
[3]47
[142]48    bool *isGood = new bool[size*size];
[187]49    for(int i=0;i<size*size;i++) isGood[i]=true;
[142]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        }
[137]58      }
59    }
60
[142]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++){
[137]65
[142]66          imPos = (y-ymin) * size + (x-xmin);
67          cubePos = z*this->axisDim[0]*this->axisDim[1] + y*this->axisDim[0] + x;
[137]68
[142]69          if(isGood[imPos]) image[imPos] += this->array[cubePos];
[137]70
[142]71        }
[3]72      }
73    }
74
[142]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    }
[3]79
[142]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      }
[3]91    }
92
[142]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    }
[3]102
[142]103    float tr[6] = {xmin-1,1.,0.,ymin-1,0.,1.};
[3]104
[142]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);
[3]107
[142]108    delete [] image;
[137]109
[142]110    int ci;
111    cpgqci(&ci);
[137]112
[142]113    // Draw the border of the BLANK region, if there is one...
114    this->plotBlankEdges();
[3]115
[142]116    // Draw the border of cube's pixels
117    this->drawFieldEdge();
[3]118
[142]119    // Draw the borders around the object
[146]120    cpgsci(BLUE);
121    cpgsfs(OUTLINE);
[142]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    */
[3]133
[142]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
[135]142  }
[117]143
[3]144}
145
[142]146void Cube::drawScale(float xstart, float ystart, float channel)
[83]147{
148  /**
[142]149   *  Cube::drawScale(xstart, ystart, channel)
[83]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
[142]154   *    within 1% of the scaleLength (length in degrees), calculated
155   *    according to the pixel scale of the cube.
[83]156   *   The parameter "channel" is required for the wcslib calculations, as the
157   *    positions could theoretically change with channel.
158   */
159
[142]160  if(!cpgtest())
161    duchampError("drawScale","There is no PGPlot device open!\n");
162  else{
[83]163
[146]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
[142]170   
[203]171      const int numLengths = 15;
172      const float lengths[numLengths] =
173        {0.01/3600., 0.05/3600., 0.1/3600., 0.5/3600.,
174         1./3600., 5./3600., 15./3600., 30./3600.,
175         1./60., 5./60., 15./60., 30./60.,
176         1., 5., 15.};
[146]177      const float desiredRatio = 0.2;
[142]178
[146]179      // first, work out what is the optimum length of the scale bar,
180      //   based on the pixel scale and size of the image.
181      float pixscale = this->head.getAvPixScale();
[203]182      float *fraction = new float[numLengths];
[146]183      int best;
184      float x1,x2,y1,y2;
185      cpgqwin(&x1,&x2,&y1,&y2);
[203]186      for(int i=0;i<numLengths;i++){
[146]187        fraction[i] = (lengths[i]/pixscale) / (x2-x1);
188        if(i==0) best=0;
189        else if(fabs(fraction[i] - desiredRatio) <
190                fabs(fraction[best] - desiredRatio)) best=i;
191      }
192      delete [] fraction;
[83]193
[146]194      ANGLE angleType;
195      if(best<4)      angleType = ARCSEC;
196      else if(best<8) angleType = ARCMIN;
197      else            angleType = DEGREE;
198      float scaleLength = lengths[best];  // this is currently in degrees
[103]199
[146]200      // Now work out actual pixel locations for the ends of the scale bar
201      double *pix1   = new double[3];
202      double *pix2   = new double[3];
203      double *world1 = new double[3];
204      double *world2 = new double[3];
205      pix1[0] = pix2[0] = xstart + this->par.getXOffset();
206      pix1[1] = pix2[1] = ystart + this->par.getYOffset();
207      pix1[2] = pix2[2] = channel;
208      this->head.pixToWCS(pix1,world1);
[83]209
[146]210      double angSep=0.;
211      bool keepGoing=false;
212      float step = 1.;
213      do{
214        if(angSep>scaleLength){
215          pix2[0] -= step;
216          step /= 2.;
217        }
218        pix2[0] += step;
219        this->head.pixToWCS(pix2,world2);
220        angSep = angularSeparation(world1[0],world1[1],world2[0],world2[1]);
221      }while((fabs(angSep-scaleLength)/scaleLength)>0.01); // look for 1% change
[83]222
[146]223      float tickpt1 = pix1[0] - this->par.getXOffset();
224      float tickpt2 = pix2[0] - this->par.getXOffset();
225      float tickpt3 = ystart;
226      int colour;
227      cpgqci(&colour);
228      cpgsci(RED);
229      int thickness;
230      cpgqlw(&thickness);
231      cpgslw(3);
232      cpgerrx(1,&tickpt1,&tickpt2,&tickpt3,2.);
233      cpgslw(thickness);
[83]234
[146]235      std::stringstream text;
236      text << scaleLength * angleScale[angleType] << symbol[angleType];
237      float size,xch,ych;
238      cpgqch(&size);
239      cpgsch(0.4);
240      cpgqcs(4,&xch,&ych); // get the character size in world coords
241      cpgptxt((tickpt1+tickpt2)/2., ystart+ych, 0, 0.5, text.str().c_str());
242      cpgsch(size);
243      cpgsci(colour);
[142]244
[146]245      delete [] pix1,pix2;
246      delete [] world1,world2;
[142]247
[146]248    }
[142]249  }
250
[83]251}
252
[3]253void Detection::drawBorders(int xoffset, int yoffset)
254{
255
[142]256  if(!cpgtest())
257    duchampError("drawBorders","There is no PGPlot device open!\n");
258  else{
[3]259
[142]260    float x1,x2,y1,y2;
261    cpgqwin(&x1,&x2,&y1,&y2);
262    int xsize = int(x2 - x1) + 1;
263    int ysize = int(y2 - y1) + 1;
264
265    bool *isObj = new bool[xsize*ysize];
266    for(int i=0;i<xsize*ysize;i++) isObj[i]=false;
267    for(int i=0;i<this->pix.size();i++)
268      isObj[ (this->pix[i].getY()-yoffset)*xsize + (this->pix[i].getX()-xoffset) ] = true;
[3]269 
270
[142]271    cpgswin(0,xsize-1,0,ysize-1);
272    for(int x=this->xmin; x<=this->xmax; x++){
273      // for each column...
274      for(int y=1;y<ysize;y++){
275        int current = y*xsize + (x-xoffset);
276        int previous = (y-1)*xsize + (x-xoffset);
277        if((isObj[current]&&!isObj[previous])||(!isObj[current]&&isObj[previous])){
278          cpgmove(x-xoffset+0, y+0);
279          cpgdraw(x-xoffset+1, y+0);
280        }
[3]281      }
282    }
[142]283    for(int y=this->ymin; y<=this->ymax; y++){
284      // now for each row...
285      for(int x=1;x<xsize;x++){
286        int current = (y-yoffset)*xsize + x;
287        int previous = (y-yoffset)*xsize + x - 1;
288        if((isObj[current]&&!isObj[previous])||(!isObj[current]&&isObj[previous])){
289          cpgmove(x+0, y-yoffset+0);
290          cpgdraw(x+0, y-yoffset+1);
291        }
[3]292      }
293    }
[142]294    cpgswin(x1,x2,y1,y2);
[3]295 
[142]296    delete [] isObj;
[3]297
[142]298  }   
299
300}
301
302void Cube::drawFieldEdge()
303{
304  if(!cpgtest())
305    duchampError("drawFieldEdge","There is no PGPlot device open!\n");
306  else{
307    int ci;
308    cpgqci(&ci);
[146]309    cpgsci(YELLOW);
[142]310 
311    cpgmove(-0.5,-0.5);
312    cpgdraw(-0.5,this->axisDim[1]-0.5);
313    cpgdraw(this->axisDim[0]-0.5,this->axisDim[1]-0.5);
314    cpgdraw(this->axisDim[0]-0.5,-0.5);
315    cpgdraw(-0.5,-0.5);
316
317    cpgsci(ci);
318  }
319}
Note: See TracBrowser for help on using the repository browser.