source: tags/release-1.1.11/src/Cubes/drawMomentCutout.cc @ 1441

Last change on this file since 1441 was 634, checked in by MatthewWhiting, 15 years ago

Initialising some variables so that they don't get used uninitialised (not that they would, but it avoids pedantic compilation warnings!).

File size: 11.1 KB
Line 
1// -----------------------------------------------------------------------
2// drawMomentCutout.cc: Drawing a 0th-moment map and related functions.
3// -----------------------------------------------------------------------
4// Copyright (C) 2006, Matthew Whiting, ATNF
5//
6// This program is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 2 of the License, or (at your
9// option) any later version.
10//
11// Duchamp is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14// for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Duchamp; if not, write to the Free Software Foundation,
18// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19//
20// Correspondence concerning Duchamp may be directed to:
21//    Internet email: Matthew.Whiting [at] atnf.csiro.au
22//    Postal address: Dr. Matthew Whiting
23//                    Australia Telescope National Facility, CSIRO
24//                    PO Box 76
25//                    Epping NSW 1710
26//                    AUSTRALIA
27// -----------------------------------------------------------------------
28#include <iostream>
29#include <sstream>
30#include <cpgplot.h>
31#include <math.h>
32#include <wcslib/wcs.h>
33#include <duchamp/duchamp.hh>
34#include <duchamp/param.hh>
35#include <duchamp/fitsHeader.hh>
36#include <duchamp/Cubes/cubes.hh>
37#include <duchamp/Cubes/cubeUtils.hh>
38#include <duchamp/Utils/utils.hh>
39#include <duchamp/Utils/mycpgplot.hh>
40#include <duchamp/PixelMap/Voxel.hh>
41#include <duchamp/PixelMap/Object3D.hh>
42#include <vector>
43
44const int MIN_WIDTH=20;
45using namespace mycpgplot;
46using namespace PixelInfo;
47
48namespace duchamp
49{
50
51  void Cube::drawMomentCutout(Detection &object)
52  {
53    ///  @details
54    ///   A routine to draw the 0th moment for the given detection
55    ///    using the flux given by the pixel array in the Cube.
56    ///   The 0th moment is constructed by adding the flux of each
57    ///    pixel within the full extent of the object (this may be more
58    ///    pixels than were actually detected in the object)
59    ///   A tick mark is also drawn to indicate angular scale (but only
60    ///    if the WCS for the Cube is valid).
61    /// \param object The Detection to be drawn.
62
63    if(!cpgtest())
64      duchampError("Draw Cutout","There is no PGPlot device open!\n");
65    else{
66
67      long size = (object.getXmax()-object.getXmin()+1);
68      if(size<(object.getYmax()-object.getYmin()+1))
69        size = object.getYmax()-object.getYmin()+1;
70      size += MIN_WIDTH;
71
72      long xmin = (object.getXmax()+object.getXmin())/2 - size/2 + 1;
73      long xmax = (object.getXmax()+object.getXmin())/2 + size/2;
74      long ymin = (object.getYmax()+object.getYmin())/2 - size/2 + 1;
75      long ymax = (object.getYmax()+object.getYmin())/2 + size/2;
76      long zmin = object.getZmin();
77      long zmax = object.getZmax();
78
79      bool *isGood = new bool[size*size];
80      for(int i=0;i<size*size;i++) isGood[i]=true;
81      for(int z=zmin; z<=zmax; z++){
82        for(int x=xmin; x<=xmax; x++){
83          for(int y=ymin; y<=ymax; y++){
84            isGood[(y-ymin) * size + (x-xmin)] =
85              ((x>=0)&&(x<this->axisDim[0]))    // if inside the boundaries
86              && ((y>=0)&&(y<this->axisDim[1])) // if inside the boundaries
87              && !this->isBlank(x,y,z);         // if not blank
88          }
89        }
90      }
91
92      float *image = new float[size*size];
93      for(int i=0;i<size*size;i++) image[i]=0.;
94
95      int imPos,cubePos;
96      for(int z=zmin; z<=zmax; z++){
97        for(int x=xmin; x<=xmax; x++){
98          for(int y=ymin; y<=ymax; y++){
99
100            imPos = (y-ymin) * size + (x-xmin);
101            cubePos = z*this->axisDim[0]*this->axisDim[1] +
102              y*this->axisDim[0] + x;
103
104            if(isGood[imPos]) image[imPos] += this->array[cubePos];
105
106          }
107        }
108      }
109
110      for(int i=0;i<size*size;i++){
111        // if there is some signal on this pixel, normalise by the velocity width
112        if(isGood[i]) image[i] /= float(zmax-zmin+1);
113      }
114
115      // now work out the greyscale display limits,
116      //   excluding blank pixels where necessary.
117      float z1,z2;
118      int ct=0;
119      while(!isGood[ct]) ct++; // move to first non-blank pixel
120      z1 = z2 = image[ct];
121      for(int i=1;i<size*size;i++){
122        if(isGood[i]){
123          if(image[i]<z1) z1=image[i];
124          if(image[i]>z2) z2=image[i];
125        }
126      }
127
128      // adjust the values of the blank and extra-image pixels
129      for(int i=0;i<size*size;i++)
130        if(!isGood[i]) image[i] = z1 - 1.;
131
132
133      float tr[6] = {xmin-1,1.,0.,ymin-1,0.,1.};
134
135      cpgswin(xmin-0.5,xmax-0.5,ymin-0.5,ymax-0.5);
136      //     cpggray(image, size, size, 1, size, 1, size, z1, z2, tr);
137      cpggray(image, size, size, 1, size, 1, size, z2, z1, tr);
138      cpgbox("bc",0,0,"bc",0,0);
139
140      delete [] image;
141
142      int ci;
143      cpgqci(&ci);
144
145      // Draw the border of the BLANK region, if there is one...
146      drawBlankEdges(this->array,this->axisDim[0],this->axisDim[1],this->par);
147
148      // Draw the border of cube's pixels
149      this->drawFieldEdge();
150
151      // Draw the borders around the object
152      cpgsci(DUCHAMP_OBJECT_OUTLINE_COLOUR);
153      cpgsfs(OUTLINE);
154      if(this->par.drawBorders())
155        object.drawBorders(xmin,ymin);
156      else
157        cpgrect(object.getXmin()-xmin+0.5,object.getXmax()-xmin+1.5,
158                object.getYmin()-ymin+0.5,object.getYmax()-ymin+1.5);
159      /*
160        To get the borders localised correctly, we need to subtract (xmin-1)
161        from the X values. We then subtract 0.5 for the left hand border
162        (to place it on the pixel border), and add 0.5 for the right hand
163        border. Similarly for y.
164      */
165
166      if(this->head.isWCS()){
167        // Now draw a tick mark to indicate size -- 15 arcmin in length
168        //     this->drawScale(xmin+2.,ymin+2.,object.getZcentre(),0.25);
169        this->drawScale(xmin+2.,ymin+2.,object.getZcentre());
170      }
171
172      cpgsci(ci);
173
174      delete [] isGood;
175
176    }
177
178  }
179
180  void Cube::drawScale(float xstart, float ystart, float channel)
181  {
182    ///  @details
183    ///   A routine to draw a scale bar on a (pre-existing) PGPlot image.
184    ///   It uses an iterative technique to move from the given start position
185    ///    (xstart,ystart) along the positive x-direction so that the length is
186    ///    within 1% of the scaleLength (length in degrees), calculated
187    ///    according to the pixel scale of the cube.
188    ///  \param xstart X-coordinate of the start position (left-hand edge
189    ///  of tick mark typically).
190    ///  \param ystart Y-coordinate of the start position
191    ///  \param channel Which channel to base WCS calculations on: needed
192    ///  as the positions could theoretically change with channel.
193
194    if(!cpgtest())
195      duchampError("Draw Cutout","There is no PGPlot device open!\n");
196    else{
197
198      if(this->head.isWCS()){  // can only do this if the WCS is good!
199
200        enum ANGLE {ARCSEC, ARCMIN, DEGREE};
201        const std::string symbol[3] = {"\"", "'", mycpgplot::degrees };
202        const float angleScale[3] = {3600., 60., 1.};
203        //  degree, arcmin, arcsec symbols
204   
205        const int numLengths = 17;
206        const double lengths[numLengths] =
207          {0.001/3600., 0.005/3600., 0.01/3600., 0.05/3600.,
208           0.1/3600., 0.5/3600.,
209           1./3600., 5./3600., 15./3600., 30./3600.,
210           1./60., 5./60., 15./60., 30./60.,
211           1., 5., 15.};
212        const ANGLE angleType[numLengths] =
213          {ARCSEC, ARCSEC, ARCSEC, ARCSEC,
214           ARCSEC, ARCSEC, ARCSEC, ARCSEC,
215           ARCSEC, ARCSEC,
216           ARCMIN, ARCMIN, ARCMIN, ARCMIN,
217           DEGREE, DEGREE, DEGREE};
218        const float desiredRatio = 0.2;
219
220        // first, work out what is the optimum length of the scale bar,
221        //   based on the pixel scale and size of the image.
222        float pixscale = this->head.getAvPixScale();
223        double *fraction = new double[numLengths];
224        int best=0;
225        float x1,x2,y1,y2;
226        cpgqwin(&x1,&x2,&y1,&y2);
227        for(int i=0;i<numLengths;i++){
228          fraction[i] = (lengths[i]/pixscale) / (x2-x1);
229          if(i==0) best=0;
230          else if(fabs(fraction[i] - desiredRatio) <
231                  fabs(fraction[best] - desiredRatio)) best=i;
232        }
233        delete [] fraction;
234
235        // Now work out actual pixel locations for the ends of the scale bar
236        double *pix1   = new double[3];
237        double *pix2   = new double[3];
238        double *world1 = new double[3];
239        double *world2 = new double[3];
240        pix1[0] = pix2[0] = xstart + this->par.getXOffset();
241        pix1[1] = pix2[1] = ystart + this->par.getYOffset();
242        pix1[2] = pix2[2] = channel;
243        this->head.pixToWCS(pix1,world1);
244
245        double angSep=0.;
246        double error;
247        double step=1.; // this is in pixels
248        double scaleLength = lengths[best];  // this is in degrees
249        pix2[0] = pix1[0] + scaleLength/(2.*pixscale);
250        do{
251          this->head.pixToWCS(pix2,world2);
252          angSep = angularSeparation(world1[0],world1[1],world2[0],world2[1]);
253          error = (angSep-scaleLength)/scaleLength;
254          if(error<0) error = 0 - error;
255          if(angSep>scaleLength){
256            pix2[0] -= step;
257            step /= 2.;
258          }
259          pix2[0] += step;
260        }while(error>0.05); // look for 1% change
261
262        float tickpt1 = pix1[0] - this->par.getXOffset();
263        float tickpt2 = pix2[0] - this->par.getXOffset();
264        float tickpt3 = ystart;
265        int colour;
266        cpgqci(&colour);
267        cpgsci(DUCHAMP_TICKMARK_COLOUR);
268        int thickness;
269        cpgqlw(&thickness);
270        cpgslw(3);
271        cpgerrx(1,&tickpt1,&tickpt2,&tickpt3,2.);
272        cpgslw(thickness);
273
274        std::stringstream text;
275        text << scaleLength * angleScale[angleType[best]]
276             << symbol[angleType[best]];
277        float size,xch,ych;
278        cpgqch(&size);
279        cpgsch(0.4);
280        cpgqcs(4,&xch,&ych); // get the character size in world coords
281        cpgptxt((tickpt1+tickpt2)/2., ystart+ych, 0, 0.5, text.str().c_str());
282        cpgsch(size);
283        cpgsci(colour);
284
285        delete [] pix1;
286        delete [] pix2;
287        delete [] world1;
288        delete [] world2;
289
290      }
291    }
292
293  }
294 
295  void Detection::drawBorders(int xoffset, int yoffset)
296  {
297    ///  @details
298    /// For a given object, draw borders around the spatial extent of the object.
299    /// \param xoffset The offset from 0 of the x-axis of the plotting window
300    /// \param yoffset The offset from 0 of the y-axis of the plotting window
301
302    if(!cpgtest())
303      duchampError("Draw Borders","There is no PGPlot device open!\n");
304    else{
305
306      float x1,x2,y1,y2;
307      cpgqwin(&x1,&x2,&y1,&y2);
308      int xsize = int(x2 - x1) + 1;
309      int ysize = int(y2 - y1) + 1;
310
311      std::vector<int> vertexSet = this->getVertexSet();
312
313      cpgswin(0,xsize-1,0,ysize-1);
314
315      if(vertexSet.size()%4 != 0)
316        duchampError("drawBorders","Vertex set wrong size!");
317      else{
318        for(size_t i=0;i<vertexSet.size()/4;i++){
319          cpgmove(vertexSet[i*4]-xoffset,vertexSet[i*4+1]-yoffset);
320          cpgdraw(vertexSet[i*4+2]-xoffset,vertexSet[i*4+3]-yoffset);
321        }
322      }
323      cpgswin(x1,x2,y1,y2);
324 
325    }   
326
327  }
328
329  void Cube::drawFieldEdge()
330  {
331    /// @details
332    /// Draw a border around the spatial edge of the data. Lines are
333    /// drawn in yellow at 0 and the values of xdim & ydim.  There must
334    /// be a PGPLOT window open, else an error message is returned.
335
336    if(!cpgtest())
337      duchampError("Draw Cutout","There is no PGPlot device open!\n");
338    else{
339      int ci;
340      cpgqci(&ci);
341      cpgsci(DUCHAMP_CUBE_EDGE_COLOUR);
342 
343      cpgmove(-0.5,-0.5);
344      cpgdraw(-0.5,this->axisDim[1]-0.5);
345      cpgdraw(this->axisDim[0]-0.5,this->axisDim[1]-0.5);
346      cpgdraw(this->axisDim[0]-0.5,-0.5);
347      cpgdraw(-0.5,-0.5);
348
349      cpgsci(ci);
350    }
351  }
352
353}
Note: See TracBrowser for help on using the repository browser.