source: trunk/src/Detection/detection.cc @ 1167

Last change on this file since 1167 was 1155, checked in by MatthewWhiting, 11 years ago

Fixing issues with having moved the findShape function. Solving allocation bugs, and making sure the flags are worked out correctly.

File size: 42.3 KB
Line 
1// -----------------------------------------------------------------------
2// detection.cc : Member functions for the Detection class.
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 <iomanip>
30#include <vector>
31#include <map>
32#include <string>
33#include <wcslib/wcs.h>
34#include <math.h>
35#include <duchamp/duchamp.hh>
36#include <duchamp/param.hh>
37#include <duchamp/fitsHeader.hh>
38#include <duchamp/Utils/utils.hh>
39#include <duchamp/PixelMap/Voxel.hh>
40#include <duchamp/PixelMap/Object3D.hh>
41#include <duchamp/Detection/detection.hh>
42#include <duchamp/Cubes/cubeUtils.hh>
43#include <duchamp/Outputs/columns.hh>
44
45using namespace PixelInfo;
46
47namespace duchamp
48{
49
50  void Detection::defaultDetection()
51  {
52    this->xSubOffset = 0;
53    this->ySubOffset = 0;
54    this->zSubOffset = 0;
55    this->haveParams = false;
56    this->totalFlux = 0.;
57    this->eTotalFlux = 0.;
58    this->peakFlux = 0.;
59    this->intFlux = 0.;
60    this->eIntFlux = 0.;
61    this->xpeak = 0;
62    this->ypeak = 0;
63    this->zpeak = 0;
64    this->peakSNR = 0.;
65    this->xCentroid = 0.;
66    this->yCentroid = 0.;
67    this->zCentroid = 0.;
68    this->centreType="centroid";
69    this->negSource = false;
70    this->flagText="";
71    this->id = -1;
72    this->name = "";
73    this->flagWCS=false;
74    this->specOK = true;
75    this->raS = "";
76    this->decS = "";
77    this->ra = 0.;
78    this->dec = 0.;
79    this->raWidth = 0.;
80    this->decWidth = 0.;
81    this->majorAxis = 0.;
82    this->minorAxis = 0.;
83    this->posang = 0.;
84    this->specUnits = "";
85    this->specType = "";
86    this->fluxUnits = "";
87    this->intFluxUnits = "";
88    this->lngtype = "RA";
89    this->lattype = "DEC";
90    this->vel = 0.;
91    this->velWidth = 0.;
92    this->velMin = 0.;
93    this->velMax = 0.;
94    this->w20 = 0.;
95    this->v20min = 0.;
96    this->v20max = 0.;
97    this->w50 = 0.;
98    this->v50min = 0.;
99    this->v50max = 0.;
100    this->posPrec = Catalogues::prPOS;
101    this->xyzPrec = Catalogues::prXYZ;
102    this->fintPrec = Catalogues::prFLUX;
103    this->fpeakPrec = Catalogues::prFLUX;
104    this->velPrec = Catalogues::prVEL;
105    this->snrPrec = Catalogues::prSNR;
106  }
107
108  Detection::Detection():
109    Object3D()
110  {
111    this->defaultDetection();
112  }
113
114  Detection::Detection(const Object3D& o):
115    Object3D(o)
116  {
117    this->defaultDetection();
118  }
119
120  Detection::Detection(const Detection& d):
121    Object3D(d)
122  {
123    operator=(d);
124  }
125
126  Detection& Detection::operator= (const Detection& d)
127  {
128    ((Object3D &) *this) = d;
129    this->xSubOffset   = d.xSubOffset;
130    this->ySubOffset   = d.ySubOffset;
131    this->zSubOffset   = d.zSubOffset;
132    this->haveParams   = d.haveParams;
133    this->totalFlux    = d.totalFlux;
134    this->eTotalFlux   = d.eTotalFlux;
135    this->intFlux      = d.intFlux;
136    this->eIntFlux     = d.eIntFlux;
137    this->peakFlux     = d.peakFlux;
138    this->xpeak        = d.xpeak;
139    this->ypeak        = d.ypeak;
140    this->zpeak        = d.zpeak;
141    this->peakSNR      = d.peakSNR;
142    this->xCentroid    = d.xCentroid;
143    this->yCentroid    = d.yCentroid;
144    this->zCentroid    = d.zCentroid;
145    this->centreType   = d.centreType;
146    this->negSource    = d.negSource;
147    this->flagText     = d.flagText;
148    this->id           = d.id;
149    this->name         = d.name;
150    this->flagWCS      = d.flagWCS;
151    this->specOK       = d.specOK;
152    this->raS          = d.raS;
153    this->decS         = d.decS;
154    this->ra           = d.ra;
155    this->dec          = d.dec;
156    this->raWidth      = d.raWidth;
157    this->decWidth     = d.decWidth;
158    this->majorAxis    = d.majorAxis;
159    this->minorAxis    = d.minorAxis;
160    this->posang       = d.posang;
161    this->specUnits    = d.specUnits;
162    this->specType     = d.specType;
163    this->fluxUnits    = d.fluxUnits;
164    this->intFluxUnits = d.intFluxUnits;
165    this->lngtype      = d.lngtype;
166    this->lattype      = d.lattype;
167    this->vel          = d.vel;
168    this->velWidth     = d.velWidth;
169    this->velMin       = d.velMin;
170    this->velMax       = d.velMax;
171    this->w20          = d.w20;
172    this->v20min       = d.v20min;
173    this->v20max       = d.v20max;
174    this->w50          = d.w50;
175    this->v50min       = d.v50min;
176    this->v50max       = d.v50max;
177    this->posPrec      = d.posPrec;
178    this->xyzPrec      = d.xyzPrec;
179    this->fintPrec     = d.fintPrec;
180    this->fpeakPrec    = d.fpeakPrec;
181    this->velPrec      = d.velPrec;
182    this->snrPrec      = d.snrPrec;
183    return *this;
184  }
185
186  //--------------------------------------------------------------------
187  float Detection::getXcentre()
188  {
189    if(this->centreType=="peak") return this->xpeak;
190    else if(this->centreType=="average") return this->getXaverage();
191    else return this->xCentroid;
192  }
193
194  float Detection::getYcentre()
195  {
196    if(this->centreType=="peak") return this->ypeak;
197    else if(this->centreType=="average") return this->getYaverage();
198    else return this->yCentroid;
199  }
200
201  float Detection::getZcentre()
202  {
203    if(this->centreType=="peak") return this->zpeak;
204    else if(this->centreType=="average") return this->getZaverage();
205    else return this->zCentroid;
206  }
207
208  //--------------------------------------------------------------------
209
210  bool Detection::voxelListsMatch(std::vector<Voxel> voxelList)
211  {
212    /// @details
213    ///  A test to see whether there is a 1-1 correspondence between
214    ///  the given list of Voxels and the voxel positions contained in
215    ///  this Detection's pixel list. No testing of the fluxes of the
216    ///  Voxels is done.
217    ///
218    /// \param voxelList The std::vector list of Voxels to be tested.
219
220    bool listsMatch = true;
221    // compare sizes
222    listsMatch = listsMatch && (voxelList.size() == this->getSize());
223    if(!listsMatch) return listsMatch;
224
225    // make sure all Detection pixels are in voxel list
226    listsMatch = listsMatch && this->voxelListCovered(voxelList);
227
228    // make sure all voxels are in Detection
229    std::vector<Voxel>::iterator vox;
230    for(vox=voxelList.begin();vox<voxelList.end();vox++)
231      listsMatch = listsMatch && this->isInObject(*vox);
232
233    return listsMatch;
234
235  }
236  //--------------------------------------------------------------------
237
238  bool Detection::voxelListCovered(std::vector<Voxel> voxelList)
239  {
240    ///  @details
241    ///  A test to see whether the given list of Voxels contains each
242    ///  position in this Detection's pixel list. It does not look for
243    ///  a 1-1 correspondence: the given list can be a super-set of the
244    ///  Detection. No testing of the fluxes of the Voxels is done.
245    ///
246    /// \param voxelList The std::vector list of Voxels to be tested.
247
248    bool listsMatch = true;
249
250    // make sure all Detection pixels are in voxel list
251    size_t v1=0;
252    std::vector<Voxel> detpixlist = this->getPixelSet();
253    while(listsMatch && v1<detpixlist.size()){
254      bool inList = false;
255      size_t v2=0;
256      while(!inList && v2<voxelList.size()){
257        inList = inList || detpixlist[v1].match(voxelList[v2]);
258        v2++;
259      }
260      listsMatch = listsMatch && inList;
261      v1++;
262    }
263
264    return listsMatch;
265
266  }
267  //--------------------------------------------------------------------
268
269  void Detection::calcFluxes(std::vector<Voxel> voxelList)
270  {
271    ///  @details
272    ///  A function that calculates total & peak fluxes (and the location
273    ///  of the peak flux) for a Detection.
274    ///
275    ///  \param fluxArray The array of flux values to calculate the
276    ///  flux parameters from.
277    ///  \param dim The dimensions of the flux array.
278   
279    //    this->haveParams = true;
280
281    this->totalFlux = this->peakFlux = 0;
282    this->xCentroid = this->yCentroid = this->zCentroid = 0.;
283
284    // first check that the voxel list and the Detection's pixel list
285    // have a 1-1 correspondence
286
287    if(!this->voxelListCovered(voxelList)){
288      DUCHAMPERROR("Detection::calcFluxes","Voxel list provided does not match");
289      return;
290    }
291
292    std::vector<Voxel>::iterator vox;
293    for(vox=voxelList.begin();vox<voxelList.end();vox++){
294      if(this->isInObject(*vox)){
295        long x = vox->getX();
296        long y = vox->getY();
297        long z = vox->getZ();
298        float f = vox->getF();
299        this->totalFlux += f;
300        this->xCentroid += x*f;
301        this->yCentroid += y*f;
302        this->zCentroid += z*f;
303        if( (vox==voxelList.begin()) ||  //first time round
304            (this->negSource&&(f<this->peakFlux)) ||
305            (!this->negSource&&(f>this->peakFlux))   )
306          {
307            this->peakFlux = f;
308            this->xpeak =    x;
309            this->ypeak =    y;
310            this->zpeak =    z;
311          }
312      }
313    }
314
315    this->xCentroid /= this->totalFlux;
316    this->yCentroid /= this->totalFlux;
317    this->zCentroid /= this->totalFlux;
318  }
319  //--------------------------------------------------------------------
320
321  void Detection::calcFluxes(std::map<Voxel,float> &voxelMap)
322  {
323    ///  @details
324    ///  A function that calculates total & peak fluxes (and the location
325    ///  of the peak flux) for a Detection.
326    ///
327    ///  \param fluxArray The array of flux values to calculate the
328    ///  flux parameters from.
329    ///  \param dim The dimensions of the flux array.
330   
331    //    this->haveParams = true;
332
333    this->totalFlux = this->peakFlux = 0;
334    this->xCentroid = this->yCentroid = this->zCentroid = 0.;
335
336    std::vector<Voxel> voxelList = this->getPixelSet();
337    std::vector<Voxel>::iterator vox;
338    for(vox=voxelList.begin();vox<voxelList.end();vox++){
339      if(voxelMap.find(*vox) == voxelMap.end()){
340        DUCHAMPERROR("Detection::calcFluxes","Voxel list provided does not match");
341        return;
342      }
343      else {
344        long x = vox->getX();
345        long y = vox->getY();
346        long z = vox->getZ();
347        float f = voxelMap[*vox];
348        this->totalFlux += f;
349        this->xCentroid += x*f;
350        this->yCentroid += y*f;
351        this->zCentroid += z*f;
352        if( (vox==voxelList.begin()) ||  //first time round
353            (this->negSource&&(f<this->peakFlux)) ||
354            (!this->negSource&&(f>this->peakFlux))   )
355          {
356            this->peakFlux = f;
357            this->xpeak =    x;
358            this->ypeak =    y;
359            this->zpeak =    z;
360          }
361      }
362    }
363
364    this->xCentroid /= this->totalFlux;
365    this->yCentroid /= this->totalFlux;
366    this->zCentroid /= this->totalFlux;
367  }
368  //--------------------------------------------------------------------
369
370  void Detection::calcFluxes(float *fluxArray, size_t *dim)
371  {
372    ///  @details
373    ///  A function that calculates total & peak fluxes (and the location
374    ///  of the peak flux) for a Detection.
375    ///
376    ///  \param fluxArray The array of flux values to calculate the
377    ///  flux parameters from.
378    ///  \param dim The dimensions of the flux array.
379
380    //    this->haveParams = true;
381
382    this->totalFlux = this->peakFlux = 0;
383    this->xCentroid = this->yCentroid = this->zCentroid = 0.;
384
385    std::vector<Voxel> voxList = this->getPixelSet();
386    std::vector<Voxel>::iterator vox=voxList.begin();
387    for(;vox<voxList.end();vox++){
388
389      long x=vox->getX();
390      long y=vox->getY();
391      long z=vox->getZ();
392      size_t ind = vox->arrayIndex(dim);
393      float f = fluxArray[ind];
394      this->totalFlux += f;
395      this->xCentroid += x*f;
396      this->yCentroid += y*f;
397      this->zCentroid += z*f;
398      if( (vox==voxList.begin()) ||
399          (this->negSource&&(f<this->peakFlux)) ||
400          (!this->negSource&&(f>this->peakFlux))   )
401        {
402          this->peakFlux = f;
403          this->xpeak = x;
404          this->ypeak = y;
405          this->zpeak = z;
406        }
407 
408    }
409
410    this->xCentroid /= this->totalFlux;
411    this->yCentroid /= this->totalFlux;
412    this->zCentroid /= this->totalFlux;
413  }
414  //--------------------------------------------------------------------
415
416  void Detection::calcWCSparams(FitsHeader &head)
417  {
418    ///  @details
419    ///  Use the input wcs to calculate the position and velocity
420    ///    information for the Detection.
421    ///  Quantities calculated:
422    ///  <ul><li> RA: ra [deg], ra (string), ra width.
423    ///      <li> Dec: dec [deg], dec (string), dec width.
424    ///      <li> Vel: vel [km/s], min & max vel, vel width.
425    ///      <li> coord type for all three axes, nuRest,
426    ///      <li> name (IAU-style, in equatorial or Galactic)
427    ///  </ul>
428    ///
429    ///  Note that the regular parameters are NOT recalculated!
430    ///
431    ///  \param head FitsHeader object that contains the WCS information.
432
433    if(head.isWCS()){
434
435      double *pixcrd = new double[15];
436      double *world  = new double[15];
437      /*
438        define a five-point array in 3D:
439        (x,y,z), (x,y,z1), (x,y,z2), (x1,y1,z), (x2,y2,z)
440        [note: x = central point, x1 = minimum x, x2 = maximum x etc.]
441        and convert to world coordinates.   
442      */
443      pixcrd[0]  = pixcrd[3] = pixcrd[6] = this->getXcentre();
444      pixcrd[9]  = this->getXmin()-0.5;
445      pixcrd[12] = this->getXmax()+0.5;
446      pixcrd[1]  = pixcrd[4] = pixcrd[7] = this->getYcentre();
447      pixcrd[10] = this->getYmin()-0.5;
448      pixcrd[13] = this->getYmax()+0.5;
449      pixcrd[2] = pixcrd[11] = pixcrd[14] = this->getZcentre();
450      pixcrd[5] = this->getZmin();
451      pixcrd[8] = this->getZmax();
452      int flag = head.pixToWCS(pixcrd, world, 5);
453      delete [] pixcrd;
454      if(flag!=0) {
455        DUCHAMPERROR("calcWCSparams", "Error in calculating the WCS for this object.");
456      }
457      else{
458       
459        // world now has the WCS coords for the five points
460        //    -- use this to work out WCS params
461 
462        this->haveParams = true;
463
464        this->specOK = head.canUseThirdAxis();
465        this->lngtype = head.lngtype();
466        this->lattype = head.lattype();
467        this->specUnits = head.getSpectralUnits();
468        this->specType  = head.getSpectralType();
469        this->fluxUnits = head.getFluxUnits();
470        // if fluxUnits are eg. Jy/beam, make intFluxUnits = Jy km/s
471        this->intFluxUnits = head.getIntFluxUnits();
472        this->ra   = world[0];
473        this->dec  = world[1];
474        int precision = -int(log10(fabs(head.WCS().cdelt[head.WCS().lng]*3600./10.)));
475        this->raS  = decToDMS(this->ra, this->lngtype,precision);
476        this->decS = decToDMS(this->dec,this->lattype,precision);
477        this->raWidth = angularSeparation(world[9],world[1],
478                                          world[12],world[1]) * 60.;
479        this->decWidth  = angularSeparation(world[0],world[10],
480                                            world[0],world[13]) * 60.;
481
482        this->name = head.getIAUName(this->ra, this->dec);
483        this->vel    = head.specToVel(world[2]);
484        this->velMin = head.specToVel(world[5]);
485        this->velMax = head.specToVel(world[8]);
486        this->velWidth = fabs(this->velMax - this->velMin);
487
488        this->flagWCS = true;
489      }
490      delete [] world;
491
492    }
493    else {
494      double x=this->getXcentre(),y=this->getYcentre(),z=this->getZmin();
495      this->velMin = head.pixToVel(x,y,z);
496      z=this->getZmax();
497      this->velMax = head.pixToVel(x,y,z);
498      this->velWidth = fabs(this->velMax - this->velMin);
499    }
500
501     
502  }
503  //--------------------------------------------------------------------
504
505  void Detection::calcIntegFlux(size_t zdim, std::vector<Voxel> voxelList, FitsHeader &head)
506  {
507    ///  @details
508    ///  Uses the input WCS to calculate the velocity-integrated flux,
509    ///   putting velocity in units of km/s.
510    ///  The fluxes used are taken from the Voxels, rather than an
511    ///   array of flux values.
512    ///  Integrates over full spatial and velocity range as given
513    ///   by the extrema calculated by calcWCSparams.
514    ///
515    ///  If the flux units end in "/beam" (eg. Jy/beam), then the flux is
516    ///  corrected by the beam size (in pixels). This is done by
517    ///  multiplying the integrated flux by the number of spatial pixels,
518    ///  and dividing by the beam size in pixels (e.g. Jy/beam * pix /
519    ///  pix/beam --> Jy)
520    ///
521    ///  \param zdim The size of the spectral axis (needed to find the velocity widths)
522    ///  \param voxelList The list of Voxels with flux information
523    ///  \param head FitsHeader object that contains the WCS information.
524
525    if(!this->voxelListCovered(voxelList)){
526      DUCHAMPERROR("Detection::calcIntegFlux","Voxel list provided does not match");
527      return;
528    }
529
530    if(!head.is2D()){
531
532      this->haveParams = true;
533
534      const int border = 1;  // include one pixel either side in each direction
535      size_t xsize = size_t(this->xmax-this->xmin+2*border+1);
536      size_t ysize = size_t(this->ymax-this->ymin+2*border+1);
537      size_t zsize = size_t(this->zmax-this->zmin+2*border+1);
538      size_t xzero = size_t(std::max(0L,this->xmin-border));
539      size_t yzero = size_t(std::max(0L,this->ymin-border));
540      size_t zzero = size_t(std::max(0L,this->zmin-border));
541      size_t spatsize=xsize*ysize;
542      size_t size = xsize*ysize*zsize;
543      std::vector <bool> isObj(size,false);
544      double *localFlux = new double[size];
545      for(size_t i=0;i<size;i++) localFlux[i]=0.;
546
547      std::vector<Voxel>::iterator vox;
548      for(vox=voxelList.begin();vox<voxelList.end();vox++){
549        if(this->isInObject(*vox)){
550          size_t pos=(vox->getX()-xzero) + (vox->getY()-yzero)*xsize + (vox->getZ()-zzero)*spatsize;
551          localFlux[pos] = vox->getF();
552          isObj[pos] = true;
553        }
554      }
555 
556      // work out the WCS coords for each pixel
557      double *world  = new double[size];
558      double xpt,ypt,zpt;
559      for(size_t i=0;i<size;i++){
560        xpt = double( this->getXmin() - border + i%xsize );
561        ypt = double( this->getYmin() - border + (i/xsize)%ysize );
562        zpt = double( this->getZmin() - border + i/(xsize*ysize) );
563        world[i] = head.pixToVel(xpt,ypt,zpt);
564      }
565
566      double integrated = 0.;
567      for(size_t pix=0; pix<spatsize; pix++){ // loop over each spatial pixel.
568        for(size_t z=0; z<zsize; z++){
569          size_t pos =  z*xsize*ysize + pix;
570          if(isObj[pos]){ // if it's an object pixel...
571            double deltaVel;
572            if(z==0)
573              deltaVel = (world[pos+xsize*ysize] - world[pos]);
574            else if(z==(zsize-1))
575              deltaVel = (world[pos] - world[pos-xsize*ysize]);
576            else
577              deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
578            integrated += localFlux[pos] * fabs(deltaVel);
579          }
580        }
581      }
582      this->intFlux = integrated;
583
584      delete [] world;
585      delete [] localFlux;
586
587      calcVelWidths(zdim,voxelList,head);
588
589    }
590    else // in this case there is just a 2D image.
591      this->intFlux = this->totalFlux;
592
593    if(head.isWCS()){
594      // correct for the beam size if the flux units string ends in "/beam"
595      if(head.needBeamSize()) this->intFlux  /= head.beam().area();
596    }
597
598  }
599  //--------------------------------------------------------------------
600
601  void Detection::calcIntegFlux(size_t zdim, std::map<Voxel,float> voxelMap, FitsHeader &head)
602  {
603    ///  @details
604    ///  Uses the input WCS to calculate the velocity-integrated flux,
605    ///   putting velocity in units of km/s.
606    ///  The fluxes used are taken from the Voxels, rather than an
607    ///   array of flux values.
608    ///  Integrates over full spatial and velocity range as given
609    ///   by the extrema calculated by calcWCSparams.
610    ///
611    ///  If the flux units end in "/beam" (eg. Jy/beam), then the flux is
612    ///  corrected by the beam size (in pixels). This is done by
613    ///  multiplying the integrated flux by the number of spatial pixels,
614    ///  and dividing by the beam size in pixels (e.g. Jy/beam * pix /
615    ///  pix/beam --> Jy)
616    ///
617    ///  \param zdim The size of the spectral axis (needed to find the velocity widths)
618    ///  \param voxelList The list of Voxels with flux information
619    ///  \param head FitsHeader object that contains the WCS information.
620
621    if(!head.is2D()){
622
623      this->haveParams = true;
624
625       const int border = 1; // include one pixel either side in each direction
626      size_t xsize = size_t(this->xmax-this->xmin+2*border+1);
627      size_t ysize = size_t(this->ymax-this->ymin+2*border+1);
628      size_t zsize = size_t(this->zmax-this->zmin+2*border+1);
629      size_t xzero = size_t(std::max(0L,this->xmin-border));
630      size_t yzero = size_t(std::max(0L,this->ymin-border));
631      size_t zzero = size_t(std::max(0L,this->zmin-border));
632      size_t spatsize=xsize*ysize;
633      size_t size = xsize*ysize*zsize;
634      std::vector <bool> isObj(size,false);
635      double *localFlux = new double[size];
636      for(size_t i=0;i<size;i++) localFlux[i]=0.;
637
638      std::vector<Voxel> voxelList = this->getPixelSet();
639      std::vector<Voxel>::iterator vox;
640      for(vox=voxelList.begin();vox<voxelList.end();vox++){
641        if(voxelMap.find(*vox) == voxelMap.end()){
642          DUCHAMPERROR("Detection::calcIntegFlux","Voxel list provided does not match");
643          return;
644        }       
645        else {
646          size_t pos=(vox->getX()-xzero) + (vox->getY()-yzero)*xsize + (vox->getZ()-zzero)*spatsize;
647          localFlux[pos] = voxelMap[*vox];
648          isObj[pos] = true;
649        }
650      }
651 
652      // work out the WCS coords for each pixel
653      double *world  = new double[size];
654      double xpt,ypt,zpt;
655      for(size_t i=0;i<xsize*ysize*zsize;i++){
656        xpt = double( this->getXmin() - border + i%xsize );
657        ypt = double( this->getYmin() - border + (i/xsize)%ysize );
658        zpt = double( this->getZmin() - border + i/(xsize*ysize) );
659        world[i] = head.pixToVel(xpt,ypt,zpt);
660      }
661
662      double integrated = 0.;
663      for(size_t pix=0; pix<spatsize; pix++){ // loop over each spatial pixel.
664        for(size_t z=0; z<zsize; z++){
665          size_t pos =  z*xsize*ysize + pix;
666          if(isObj[pos]){ // if it's an object pixel...
667            double deltaVel;
668            if(z==0)
669              deltaVel = (world[pos+xsize*ysize] - world[pos]);
670            else if(z==(zsize-1))
671              deltaVel = (world[pos] - world[pos-xsize*ysize]);
672            else
673              deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
674            integrated += localFlux[pos] * fabs(deltaVel);
675          }
676        }
677      }
678      this->intFlux = integrated;
679
680      delete [] world;
681      delete [] localFlux;
682
683      calcVelWidths(zdim,voxelMap,head);
684
685    }
686    else // in this case there is just a 2D image.
687      this->intFlux = this->totalFlux;
688
689    if(head.isWCS()){
690      // correct for the beam size if the flux units string ends in "/beam"
691      if(head.needBeamSize()) this->intFlux  /= head.beam().area();
692    }
693
694  }
695  //--------------------------------------------------------------------
696
697  void Detection::calcIntegFlux(float *fluxArray, size_t *dim, FitsHeader &head)
698  {
699    ///  @details
700    ///  Uses the input WCS to calculate the velocity-integrated flux,
701    ///   putting velocity in units of km/s.
702    ///  Integrates over full spatial and velocity range as given
703    ///   by the extrema calculated by calcWCSparams.
704    ///
705    ///  If the flux units end in "/beam" (eg. Jy/beam), then the flux is
706    ///  corrected by the beam size (in pixels). This is done by
707    ///  multiplying the integrated flux by the number of spatial pixels,
708    ///  and dividing by the beam size in pixels (e.g. Jy/beam * pix /
709    ///  pix/beam --> Jy)
710    ///
711    ///  \param fluxArray The array of flux values.
712    ///  \param dim The dimensions of the flux array.
713    ///  \param head FitsHeader object that contains the WCS information.
714
715    this->haveParams = true;
716
717    const int border=1; // include one pixel either side in each direction
718    size_t xsize = std::min(size_t(this->xmax-this->xmin+2*border+1),dim[0]);
719    size_t ysize = std::min(size_t(this->ymax-this->ymin+2*border+1),dim[1]);
720    size_t zsize = std::min(size_t(this->zmax-this->zmin+2*border+1),dim[2]);
721    size_t xzero = size_t(std::max(0L,this->xmin-border));
722    size_t yzero = size_t(std::max(0L,this->ymin-border));
723    size_t zzero = size_t(std::max(0L,this->zmin-border));
724    size_t spatsize = xsize*ysize;
725    size_t size = xsize*ysize*zsize;
726    std::vector <bool> isObj(size,false);
727    double *localFlux = new double[size];
728    for(size_t i=0;i<size;i++) localFlux[i]=0.;
729    float *momMap = new float[spatsize];
730    for(size_t i=0;i<spatsize;i++) momMap[i]=0.;
731    // work out which pixels are object pixels
732    std::vector<Voxel> voxlist = this->getPixelSet();
733    for(std::vector<Voxel>::iterator v=voxlist.begin();v<voxlist.end();v++){
734      size_t spatpos=(v->getX()-xzero) + (v->getY()-yzero)*xsize;
735      size_t pos= spatpos + (v->getZ()-zzero)*spatsize;
736      localFlux[pos] = fluxArray[v->arrayIndex(dim)];
737      momMap[spatpos] += fluxArray[v->arrayIndex(dim)]*head.WCS().cdelt[head.WCS().spec];
738      isObj[pos] = true;
739    }
740 
741     if(!head.is2D()){
742
743     // work out the WCS coords for each pixel
744      double *world  = new double[size];
745      double xpt,ypt,zpt;
746      size_t i=0;
747      for(size_t z=zzero;z<zzero+zsize;z++){
748        for(size_t y=yzero;y<yzero+ysize;y++){
749          for(size_t x=xzero;x<xzero+xsize;x++){
750            xpt=double(x);
751            ypt=double(y);
752            zpt=double(z);
753            world[i++] = head.pixToVel(xpt,ypt,zpt);
754          }
755        }
756      }
757
758      double integrated = 0.;
759      for(size_t pix=0; pix<xsize*ysize; pix++){ // loop over each spatial pixel.
760        for(size_t z=0; z<zsize; z++){
761          size_t pos =  z*xsize*ysize + pix;
762          if(isObj[pos]){ // if it's an object pixel...
763            double deltaVel;
764            if(z==0)
765              deltaVel = (world[pos+xsize*ysize] - world[pos]);
766            else if(z==(zsize-1))
767              deltaVel = (world[pos] - world[pos-xsize*ysize]);
768            else
769              deltaVel = (world[pos+xsize*ysize] - world[pos-xsize*ysize]) / 2.;
770            integrated += localFlux[pos] * fabs(deltaVel);
771          }
772        }
773      }
774
775      delete [] world;
776     
777      this->intFlux = integrated;
778     
779      calcVelWidths(fluxArray, dim, head);
780
781     }
782      else // in this case there is just a 2D image.
783      this->intFlux = this->totalFlux;
784   
785     delete [] localFlux;
786     delete [] momMap;
787   
788
789    if(head.isWCS()){
790      // correct for the beam size if the flux units string ends in "/beam" and we have beam info
791      if(head.needBeamSize()) this->intFlux  /= head.beam().area();
792    }
793
794  }
795  //--------------------------------------------------------------------
796
797  void Detection::findShape(const float *fluxArray, const size_t *dim, FitsHeader &head)
798  {
799
800      const size_t border=1; // include one pixel either side in each direction
801      size_t xmin = size_t(std::max(size_t(0),this->xmin-border));
802      size_t ymin = size_t(std::max(size_t(0),this->ymin-border));
803      size_t xmax = size_t(std::min(dim[0]-1,this->xmax+border));
804      size_t ymax = size_t(std::min(dim[1]-1,this->ymax+border));
805      size_t xsize = xmax-xmin+1;
806      size_t ysize = ymax-ymin+1;
807      size_t spatsize = xsize*ysize;
808
809      float *momentMap = new float[spatsize];
810      for(size_t i=0;i<spatsize;i++) momentMap[i]=0.;
811      // work out which pixels are object pixels
812      std::vector<Voxel> voxlist = this->getPixelSet();
813      float delta = head.isWCS() ? fabs(head.WCS().cdelt[head.WCS().spec]) : 1.;
814      for(std::vector<Voxel>::iterator v=voxlist.begin();v<voxlist.end();v++){
815          size_t spatpos=(v->getX()-xmin) + (v->getY()-ymin)*xsize;
816          if(spatpos>=0 && spatpos<spatsize)
817              momentMap[spatpos] += fluxArray[v->arrayIndex(dim)] * delta;
818          else DUCHAMPTHROW("findShape","Memory overflow - accessing spatpos="<<spatpos<<" when spatsize="<<spatsize);
819      }
820
821      /*
822        bool ellipseGood = this->spatialMap.findEllipse(true, momentMap, xsize, ysize, xmin, ymin, this->xCentroid, this->yCentroid);  // try first by weighting the pixels by their flux
823        if(!ellipseGood) {
824        ellipseGood = this->spatialMap.findEllipse(false, momentMap, xsize, ysize, xmin, ymin, this->xCentroid, this->yCentroid); // if that fails, remove the flux weighting
825        this->flagText += "W";
826        }
827        if(ellipseGood){
828        // multiply axes by 2 to go from semi-major to FWHM...
829        this->majorAxis = this->spatialMap.major() * head.getAvPixScale() * 2.;
830        this->minorAxis = this->spatialMap.minor() * head.getAvPixScale() * 2.;
831        this->posang = this->spatialMap.posAng() * 180. / M_PI;
832        }
833      */
834      size_t smldim[2]; smldim[0]=xsize; smldim[1]=ysize;
835      Image *smlIm = new Image(smldim);
836      smlIm->saveArray(momentMap,spatsize);
837      smlIm->setMinSize(1);
838      float max = *std::max_element(momentMap,momentMap+spatsize);
839      smlIm->stats().setThreshold(max/2.);
840      std::vector<Object2D> objlist=smlIm->findSources2D();
841      // std::cerr << max << " " << smlIm->stats().getThreshold() << " " << objlist.size()<<"\n";
842
843      Object2D combined;
844      for(size_t i=0;i<objlist.size();i++) combined = combined + objlist[i];
845      bool ellipseGood = combined.findEllipse(true, momentMap, xsize, ysize, 0,0, this->getXcentre()-xmin, this->getYcentre()-ymin); // try first by weighting the pixels by their flux
846      if(!ellipseGood) {
847          ellipseGood = combined.findEllipse(false, momentMap, xsize, ysize, 0,0, this->getXcentre()-xmin, this->getYcentre()-ymin); // if that fails, remove the flux weighting
848          this->flagText += "W";
849      }
850      if(ellipseGood){
851          // multiply axes by 2 to go from semi-major to FWHM...
852          float scale=head.getShapeScale();
853          this->majorAxis = combined.major() * head.getAvPixScale() * 2. * scale;
854          this->minorAxis = combined.minor() * head.getAvPixScale() * 2. * scale;
855          this->posang =    combined.posAng() * 180. / M_PI;
856
857          // std::cerr << "*** " << combined.getSize()<< " " << majorAxis<<" " << minorAxis << " " << posang<< "\n";
858      }
859      else {
860          Object2D spatMap = this->getSpatialMap();
861          std::pair<double,double> axes = spatMap.getPrincipleAxes();
862          this->majorAxis = std::max(axes.first,axes.second) * head.getAvPixScale();
863          this->minorAxis = std::min(axes.first,axes.second) * head.getAvPixScale();
864          this->posang = spatMap.getPositionAngle() * 180. / M_PI;
865      }
866     
867
868      delete smlIm;
869      delete [] momentMap;
870  }
871
872  //--------------------------------------------------------------------
873
874  void Detection::calcVelWidths(size_t zdim, std::vector<Voxel> voxelList, FitsHeader &head)
875  {
876    ///  @details
877    /// Calculates the widths of the detection at 20% and 50% of the
878    /// peak integrated flux. The procedure is as follows: first
879    /// generate an integrated flux spectrum (using all given voxels
880    /// that lie in the object's spatial map); find the peak; starting
881    /// at the spectral edges of the detection, move in or out until
882    /// you reach the 20% or 50% peak flux level. Linear interpolation
883    /// between points is done.
884    ///
885    ///  \param zdim The size of the spectral axis in the cube
886    ///  \param voxelList The list of Voxels with flux information
887    ///  \param head FitsHeader object that contains the WCS information.
888
889    float *intSpec = new float[zdim];
890    for(size_t i=0;i<zdim;i++) intSpec[i]=0;
891       
892    Object2D spatMap = this->getSpatialMap();
893    for(int s=0;s<spatMap.getNumScan();s++){
894      std::vector<Voxel>::iterator vox;
895      for(vox=voxelList.begin();vox<voxelList.end();vox++){
896        if(spatMap.isInObject(*vox)){
897          intSpec[vox->getZ()] += vox->getF();
898        }
899      }
900    }
901   
902    calcVelWidths(zdim, intSpec, head);
903
904    delete [] intSpec;
905
906  }
907
908  //--------------------------------------------------------------------
909
910  void Detection::calcVelWidths(size_t zdim, std::map<Voxel,float> voxelMap, FitsHeader &head)
911  {
912    ///  @details
913    /// Calculates the widths of the detection at 20% and 50% of the
914    /// peak integrated flux. The procedure is as follows: first
915    /// generate an integrated flux spectrum (using all given voxels
916    /// that lie in the object's spatial map); find the peak; starting
917    /// at the spectral edges of the detection, move in or out until
918    /// you reach the 20% or 50% peak flux level. Linear interpolation
919    /// between points is done.
920    ///
921    ///  \param zdim The size of the spectral axis in the cube
922    ///  \param voxelList The list of Voxels with flux information
923    ///  \param head FitsHeader object that contains the WCS information.
924
925    float *intSpec = new float[zdim];
926    for(size_t i=0;i<zdim;i++) intSpec[i]=0;
927       
928    std::vector<Voxel> voxelList = this->getPixelSet();
929    std::vector<Voxel>::iterator vox;
930    for(vox=voxelList.begin();vox<voxelList.end();vox++){
931      if(voxelMap.find(*vox) == voxelMap.end()){
932        DUCHAMPERROR("Detection::calcVelWidths","Voxel list provided does not match");
933        return;
934      }
935      else {
936        intSpec[vox->getZ()] += voxelMap[*vox];
937      }
938    }
939
940    calcVelWidths(zdim, intSpec, head);
941
942    delete [] intSpec;
943
944  }
945
946  //--------------------------------------------------------------------
947
948  void Detection::calcVelWidths(size_t zdim, float *intSpec, FitsHeader &head)
949  {
950
951    // finding the 20% & 50% points.  Start at the velmin & velmax
952    //  points. Then, if the int flux there is above the 20%/50%
953    //  limit, go out, otherwise go in. This is to deal with the
954    //  problems from double- (or multi-) peaked sources.
955
956    this->haveParams = true;
957
958    double zpt,xpt=double(this->getXcentre()),ypt=double(this->getYcentre());
959    bool goLeft;
960   
961    if(this->negSource){
962      // if we've inverted the source, need to make the feature
963      // positive for the interpolation/extrapolation to work
964      for(size_t i=0;i<zdim;i++) intSpec[i] *= -1.;
965    }
966
967    float peak=0.;
968    size_t peakLoc=0;
969    for(size_t z=this->getZmin();z<=size_t(this->getZmax());z++) {
970      if(z==0 || peak<intSpec[z]){
971        peak = intSpec[z];
972        peakLoc = z;
973      }
974    }
975   
976    size_t z=this->getZmin();
977    goLeft = intSpec[z]>peak*0.5;
978    if(goLeft) while(z>0 && intSpec[z]>peak*0.5) z--;
979    else       while(z<peakLoc && intSpec[z]<peak*0.5) z++;
980    if(z==0) this->v50min = this->velMin;
981    else{
982      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
983      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
984      this->v50min = head.pixToVel(xpt,ypt,zpt);
985    }
986    z=this->getZmax();
987    goLeft = intSpec[z]<peak*0.5;
988    if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.5) z--;
989    else       while(z<zdim    && intSpec[z]>peak*0.5) z++;
990    if(z==zdim) this->v50max = this->velMax;
991    else{
992      if(goLeft) zpt = z + (peak*0.5-intSpec[z])/(intSpec[z+1]-intSpec[z]);
993      else       zpt = z - (peak*0.5-intSpec[z])/(intSpec[z-1]-intSpec[z]);
994      this->v50max = head.pixToVel(xpt,ypt,zpt);
995    }
996    z=this->getZmin();
997    goLeft = intSpec[z]>peak*0.2;
998    if(goLeft) while(z>0 && intSpec[z]>peak*0.2) z--;
999    else       while(z<peakLoc && intSpec[z]<peak*0.2) z++;
1000    if(z==0) this->v20min = this->velMin;
1001    else{
1002      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
1003      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
1004      this->v20min = head.pixToVel(xpt,ypt,zpt);
1005    }
1006    z=this->getZmax();
1007    goLeft = intSpec[z]<peak*0.2;
1008    if(goLeft) while(z>peakLoc && intSpec[z]<peak*0.2) z--;
1009    else       while(z<zdim    && intSpec[z]>peak*0.2) z++;
1010    if(z==zdim) this->v20max = this->velMax;
1011    else{
1012      if(goLeft) zpt = z + (peak*0.2-intSpec[z])/(intSpec[z+1]-intSpec[z]);
1013      else       zpt = z - (peak*0.2-intSpec[z])/(intSpec[z-1]-intSpec[z]);
1014      this->v20max = head.pixToVel(xpt,ypt,zpt);
1015    }
1016
1017    this->w20 = fabs(this->v20min - this->v20max);
1018    this->w50 = fabs(this->v50min - this->v50max);
1019   
1020    if(this->negSource){
1021      // un-do the inversion, in case intSpec is needed elsewhere
1022      for(size_t i=0;i<zdim;i++) intSpec[i] *= -1.;
1023    }
1024
1025
1026  }
1027  //--------------------------------------------------------------------
1028
1029  void Detection::calcVelWidths(float *fluxArray, size_t *dim, FitsHeader &head)
1030  {
1031    ///  @details
1032    /// Calculates the widths of the detection at 20% and 50% of the
1033    /// peak integrated flux. The procedure is as follows: first
1034    /// generate an integrated flux spectrum (summing each spatial
1035    /// pixel's spectrum); find the peak; starting at the spectral
1036    /// edges of the detection, move in or out until you reach the 20%
1037    /// or 50% peak flux level. Linear interpolation between points is
1038    /// done.
1039    ///
1040    ///  \param fluxArray The array of flux values.
1041    ///  \param dim The dimensions of the flux array.
1042    ///  \param head FitsHeader object that contains the WCS information.
1043
1044    if(dim[2] > 2){
1045
1046      float *intSpec = new float[dim[2]];
1047      size_t size=dim[0]*dim[1]*dim[2];
1048      std::vector<bool> mask(size,true);
1049      getIntSpec(*this,fluxArray,dim,mask,1.,intSpec);
1050
1051      this->calcVelWidths(dim[2],intSpec,head);
1052
1053      delete [] intSpec;
1054
1055    }
1056    else{
1057      this->v50min = this->v20min = this->velMin;
1058      this->v50max = this->v20max = this->velMax;
1059      this->w20 = fabs(this->v20min - this->v20max);
1060      this->w50 = fabs(this->v50min - this->v50max);
1061    }
1062
1063  }
1064  //--------------------------------------------------------------------
1065
1066  void Detection::setOffsets(Param &par)
1067  {
1068    ///  @details
1069    /// This function stores the values of the offsets for each cube axis.
1070    /// The offsets are the starting values of the cube axes that may differ from
1071    ///  the default value of 0 (for instance, if a subsection is being used).
1072    /// The values will be used when the detection is outputted.
1073
1074    this->xSubOffset = par.getXOffset();
1075    this->ySubOffset = par.getYOffset();
1076    this->zSubOffset = par.getZOffset();
1077  }
1078  //--------------------------------------------------------------------
1079
1080  bool Detection::hasEnoughChannels(int minNumber)
1081  {
1082    ///  @details
1083    /// A function to determine if the Detection has enough
1084    /// contiguous channels to meet the minimum requirement
1085    /// given as the argument.
1086    /// \param minNumber How many channels is the minimum acceptable number?
1087    /// \return True if there is at least one occurence of minNumber consecutive
1088    /// channels present to return true. False otherwise.
1089
1090    // Preferred method -- need a set of minNumber consecutive channels present.
1091
1092    int numChan = this->getMaxAdjacentChannels();
1093    bool result = (numChan >= minNumber);
1094
1095    return result;
1096 
1097  }
1098  //--------------------------------------------------------------------
1099
1100  std::vector<int> Detection::getVertexSet()
1101  {
1102    ///  @details
1103    /// Gets a list of points being the end-points of 1-pixel long
1104    /// segments drawing a border around the spatial extend of a
1105    /// detection. The vector is a series of 4 integers, being: x_0,
1106    /// y_0, x_1, y_1.
1107    /// \return The vector of vertex positions.
1108
1109    std::vector<int> vertexSet;
1110
1111    int xmin = this->getXmin() - 1;
1112    int xmax = this->getXmax() + 1;
1113    int ymin = this->getYmin() - 1;
1114    int ymax = this->getYmax() + 1;
1115    int xsize = xmax - xmin + 1;
1116    int ysize = ymax - ymin + 1;
1117
1118    std::vector<Voxel> voxlist = this->getPixelSet();
1119    std::vector<bool> isObj(xsize*ysize,false);
1120    std::vector<Voxel>::iterator vox;
1121    for(vox=voxlist.begin();vox<voxlist.end();vox++){
1122      size_t pos = (vox->getX()-xmin) +
1123        (vox->getY()-ymin)*xsize;
1124      isObj[pos] = true;
1125    }
1126    voxlist.clear();
1127   
1128    for(int x=xmin; x<=xmax; x++){
1129      // for each column...
1130      for(int y=ymin+1;y<=ymax;y++){
1131        int current  = (y-ymin)*xsize + x-xmin;
1132        int previous = (y-ymin-1)*xsize + x-xmin;
1133        if((isObj[current]&&!isObj[previous])   ||
1134           (!isObj[current]&&isObj[previous])){
1135          vertexSet.push_back(x);
1136          vertexSet.push_back(y);
1137          vertexSet.push_back(x+1);
1138          vertexSet.push_back(y);
1139        }
1140      }
1141    }
1142    for(int y=ymin; y<=ymax; y++){
1143      // now for each row...
1144      for(int x=xmin+1;x<=xmax;x++){
1145        int current  = (y-ymin)*xsize + x-xmin;
1146        int previous = (y-ymin)*xsize + x-xmin - 1;
1147        if((isObj[current]&&!isObj[previous])   ||
1148           (!isObj[current]&&isObj[previous])){
1149          vertexSet.push_back(x);
1150          vertexSet.push_back(y);
1151          vertexSet.push_back(x);
1152          vertexSet.push_back(y+1);
1153        }
1154      }
1155    }
1156
1157    return vertexSet;
1158 
1159  }
1160
1161 
1162  void Detection::addDetection(Detection &other)
1163  {
1164    for(std::map<long, Object2D>::iterator it = other.chanlist.begin(); it!=other.chanlist.end();it++)
1165      //      this->addChannel(*it);
1166      this->addChannel(it->first, it->second);
1167    this->haveParams = false; // make it appear as if the parameters haven't been calculated, so that we can re-calculate them 
1168  }
1169
1170  Detection operator+ (Detection &lhs, Detection &rhs)
1171  {
1172    Detection output = lhs;
1173    for(std::map<long, Object2D>::iterator it = rhs.chanlist.begin(); it!=rhs.chanlist.end();it++)
1174      output.addChannel(it->first, it->second);
1175    output.haveParams = false; // make it appear as if the parameters haven't been calculated, so that we can re-calculate them
1176    return output;
1177  }
1178   
1179
1180  bool Detection::canMerge(Detection &other, Param &par)
1181  {
1182    bool near = this->isNear(other,par);
1183    if(near) return this->isClose(other,par);
1184    else return near;
1185  }
1186
1187  bool Detection::isNear(Detection &other, Param &par)
1188  {
1189
1190    bool flagAdj = par.getFlagAdjacent();
1191    float threshS = par.getThreshS();
1192    float threshV = par.getThreshV();
1193
1194    long gap;
1195    if(flagAdj) gap = 1;
1196    else gap = long( ceil(threshS) );
1197
1198    bool areNear;
1199    // Test X ranges
1200    if((this->xmin-gap)<other.xmin) areNear=((this->xmax+gap)>=other.xmin);
1201    else areNear=(other.xmax>=(this->xmin-gap));
1202    // Test Y ranges
1203    if(areNear){
1204      if((this->ymin-gap)<other.ymin) areNear=areNear&&((this->ymax+gap)>=other.ymin);
1205      else areNear=areNear&&(other.ymax>=(this->ymin-gap));
1206    }
1207    // Test Z ranges
1208    if(areNear){
1209      gap = long(ceil(threshV));
1210      if((this->zmin-gap)<other.zmin) areNear=areNear&&((this->zmax+gap)>=other.zmin);
1211      else areNear=areNear&&(other.zmax>=(this->zmin-gap));
1212    }
1213   
1214    return areNear;
1215
1216  }
1217
1218  bool Detection::isClose(Detection &other, Param &par)
1219  {
1220    bool close = false;   // this will be the value returned
1221   
1222    bool flagAdj = par.getFlagAdjacent();
1223    float threshS = par.getThreshS();
1224    float threshV = par.getThreshV();
1225
1226    //
1227    // If we get to here, the pixel ranges overlap -- so we do a
1228    // pixel-by-pixel comparison to make sure they are actually
1229    // "close" according to the thresholds.  Otherwise, close=false,
1230    // and so don't need to do anything else before returning.
1231    //
1232
1233    std::vector<long> zlist1 = this->getChannelList();
1234    std::vector<long> zlist2 = other.getChannelList();
1235    Scan test1,test2;
1236
1237    for(size_t ct1=0; (!close && (ct1<zlist1.size())); ct1++){
1238      for(size_t ct2=0; (!close && (ct2<zlist2.size())); ct2++){
1239       
1240        if(abs(zlist1[ct1]-zlist2[ct2])<=threshV){
1241             
1242          Object2D temp1 = this->getChanMap(zlist1[ct1]);
1243          Object2D temp2 = other.getChanMap(zlist2[ct2]);
1244
1245          close = temp1.canMerge(temp2,threshS,flagAdj);
1246
1247        }
1248
1249      }
1250    }
1251       
1252    return close;
1253   
1254  }
1255
1256
1257
1258}
Note: See TracBrowser for help on using the repository browser.