source: branches/pixel-map-branch/src/Cubes/drawMomentCutout.cc @ 244

Last change on this file since 244 was 244, checked in by Matthew Whiting, 17 years ago

Summary of non-minor changes:

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