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

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

Changes here mostly aimed at reducing/removing memory leaks. These were one of:

  • Forgetting to delete something allocated with "new". The Cube destructor has improved with the use of bool variables to keep track of when recon & baseline ahave been allocated.
  • Incorrectly using the wcs->flag parameter (eg. wcsIO had it set to -1 *after* calling wcsini)
  • Not closing a fits file once finished with (dataIO)
  • Allocating the wcsprm structs with calloc before calling wcsini, so that wcsvfree can work (it calls "free", so the memory needs to be allocated with calloc or malloc).

The only other change was the following:

  • A new way of doing the Cube::setCubeStats -- rather than calling the functions in getStats.cc, we explicitly do the calculations. This means we can sort the tempArray that has the BLANKS etc removed. This saves a great deal of memory usage on large FITS files (such as Enno's 2Gb one)
  • The old setCubeStats function is still there but called setCubeStatsOld.
File size: 9.4 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 int numLengths = 15;
172      const double 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.};
177      const float desiredRatio = 0.2;
178
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();
182      std::cerr << "Pixscale = " << pixscale << "\n";
183      double *fraction = new double[numLengths];
184      int best;
185      float x1,x2,y1,y2;
186      cpgqwin(&x1,&x2,&y1,&y2);
187      for(int i=0;i<numLengths;i++){
188        fraction[i] = (lengths[i]/pixscale) / (x2-x1);
189        if(i==0) best=0;
190        else if(fabs(fraction[i] - desiredRatio) <
191                fabs(fraction[best] - desiredRatio)) best=i;
192      }
193      delete [] fraction;
194
195      ANGLE angleType;
196      if(best<4)      angleType = ARCSEC;
197      else if(best<8) angleType = ARCMIN;
198      else            angleType = DEGREE;
199      double scaleLength = lengths[best];  // this is currently in degrees
200
201      // Now work out actual pixel locations for the ends of the scale bar
202      double *pix1   = new double[3];
203      double *pix2   = new double[3];
204      double *world1 = new double[3];
205      double *world2 = new double[3];
206      pix1[0] = pix2[0] = xstart + this->par.getXOffset();
207      pix1[1] = pix2[1] = ystart + this->par.getYOffset();
208      pix1[2] = pix2[2] = channel;
209      this->head.pixToWCS(pix1,world1);
210
211      double angSep=0.;
212      bool keepGoing=false;
213      float error;
214      float step=1.;
215      do{
216        if(angSep>scaleLength){
217          pix2[0] -= step;
218          step /= 2.;
219        }
220        pix2[0] += step;
221        this->head.pixToWCS(pix2,world2);
222        angSep = angularSeparation(world1[0],world1[1],world2[0],world2[1]);
223        error = (angSep-scaleLength)/scaleLength;
224        if(error<0) error = 0 - error;
225      }while(error>0.01); // look for 1% change
226
227      float tickpt1 = pix1[0] - this->par.getXOffset();
228      float tickpt2 = pix2[0] - this->par.getXOffset();
229      float tickpt3 = ystart;
230      int colour;
231      cpgqci(&colour);
232      cpgsci(RED);
233      int thickness;
234      cpgqlw(&thickness);
235      cpgslw(3);
236      cpgerrx(1,&tickpt1,&tickpt2,&tickpt3,2.);
237      cpgslw(thickness);
238
239      std::stringstream text;
240      text << scaleLength * angleScale[angleType] << symbol[angleType];
241      float size,xch,ych;
242      cpgqch(&size);
243      cpgsch(0.4);
244      cpgqcs(4,&xch,&ych); // get the character size in world coords
245      cpgptxt((tickpt1+tickpt2)/2., ystart+ych, 0, 0.5, text.str().c_str());
246      cpgsch(size);
247      cpgsci(colour);
248
249      delete [] pix1;
250      delete [] pix2;
251      delete [] world1;
252      delete [] world2;
253
254    }
255  }
256
257}
258
259void Detection::drawBorders(int xoffset, int yoffset)
260{
261
262  if(!cpgtest())
263    duchampError("drawBorders","There is no PGPlot device open!\n");
264  else{
265
266    float x1,x2,y1,y2;
267    cpgqwin(&x1,&x2,&y1,&y2);
268    int xsize = int(x2 - x1) + 1;
269    int ysize = int(y2 - y1) + 1;
270
271    bool *isObj = new bool[xsize*ysize];
272    for(int i=0;i<xsize*ysize;i++) isObj[i]=false;
273    for(int i=0;i<this->pix.size();i++)
274      isObj[ (this->pix[i].getY()-yoffset)*xsize + (this->pix[i].getX()-xoffset) ] = true;
275 
276
277    cpgswin(0,xsize-1,0,ysize-1);
278    for(int x=this->xmin; x<=this->xmax; x++){
279      // for each column...
280      for(int y=1;y<ysize;y++){
281        int current = y*xsize + (x-xoffset);
282        int previous = (y-1)*xsize + (x-xoffset);
283        if((isObj[current]&&!isObj[previous])||(!isObj[current]&&isObj[previous])){
284          cpgmove(x-xoffset+0, y+0);
285          cpgdraw(x-xoffset+1, y+0);
286        }
287      }
288    }
289    for(int y=this->ymin; y<=this->ymax; y++){
290      // now for each row...
291      for(int x=1;x<xsize;x++){
292        int current = (y-yoffset)*xsize + x;
293        int previous = (y-yoffset)*xsize + x - 1;
294        if((isObj[current]&&!isObj[previous])||(!isObj[current]&&isObj[previous])){
295          cpgmove(x+0, y-yoffset+0);
296          cpgdraw(x+0, y-yoffset+1);
297        }
298      }
299    }
300    cpgswin(x1,x2,y1,y2);
301 
302    delete [] isObj;
303
304  }   
305
306}
307
308void Cube::drawFieldEdge()
309{
310  if(!cpgtest())
311    duchampError("drawFieldEdge","There is no PGPlot device open!\n");
312  else{
313    int ci;
314    cpgqci(&ci);
315    cpgsci(YELLOW);
316 
317    cpgmove(-0.5,-0.5);
318    cpgdraw(-0.5,this->axisDim[1]-0.5);
319    cpgdraw(this->axisDim[0]-0.5,this->axisDim[1]-0.5);
320    cpgdraw(this->axisDim[0]-0.5,-0.5);
321    cpgdraw(-0.5,-0.5);
322
323    cpgsci(ci);
324  }
325}
Note: See TracBrowser for help on using the repository browser.