source: tags/release-1.0.5/src/Cubes/drawMomentCutout.cc

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

A few new things:

  • Made a mycpgplot.hh file, to keep PGPlot-related constants (enum types)

in a standard namespace (so one can do cpgsci(RED) rather than cpgsci(2)...).
Incorporated this into all code that uses pgplot.

  • Improved the outputting of the number of detected objects in the search

functions. Now shows how many have been detected, before they are merged
into the list.

  • Fixed a bug in columns.cc that was incorrectly updating the precision for

negative velocities.

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