source: branches/pixelmap-refactor-branch/src/PixelMap/Object2D.cc @ 1441

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

Renaming the get?centre() functions to get?average() as this is a more accurate name and will help the Detection class.

File size: 14.9 KB
RevLine 
[301]1// -----------------------------------------------------------------------
2// Object2D.cc: Member functions for the Object2D 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// -----------------------------------------------------------------------
[393]28#include <duchamp/PixelMap/Scan.hh>
29#include <duchamp/PixelMap/Object2D.hh>
30#include <duchamp/PixelMap/Voxel.hh>
[238]31#include <iostream>
32#include <vector>
[469]33#include <algorithm>
34#include <math.h>
[238]35
[252]36namespace PixelInfo
37{
[243]38
[365]39  Object2D::Object2D()
40  {
41    this->numPix = 0;
42  }
43
[252]44  Object2D::Object2D(const Object2D& o)
45  {
[365]46    operator=(o);
[252]47  } 
[243]48
[252]49  Object2D& Object2D::operator= (const Object2D& o)
50  {
[270]51    if(this == &o) return *this;
[252]52    this->scanlist = o.scanlist;
53    this->numPix   = o.numPix;
54    this->xSum     = o.xSum;
55    this->ySum     = o.ySum;
56    this->xmin     = o.xmin;
57    this->ymin     = o.ymin;
58    this->xmax     = o.xmax;
59    this->ymax     = o.ymax;
[270]60    return *this;
[252]61  } 
62  //------------------------------------------------------
[238]63
[252]64  void Object2D::addPixel(long x, long y)
65  {
[528]66    ///  This function has three parts to it:
67    ///  <ul><li> First, it searches through the existing scans to see if
68    ///            a) there is a scan of the same y-value present, and
69    ///            b) whether the (x,y) pixel lies in or next to an existing
70    ///            Scan. If so, it is added and the Scan is grown if need be.
71    ///            If this isn't the case, a new Scan of length 1 is added to
72    ///            the list.
73    ///      <li> If the Scan list was altered, all are checked to see whether
74    ///            there is now a case of Scans touching. If so, they are
75    ///            combined and added to the end of the list.
76    ///      <li> If the pixel was added, the parameters are updated and the
77    ///           pixel counter incremented.
78    ///  </ul>
[238]79
80
[252]81    bool flagDone=false,flagChanged=false, isNew=false;
82
[541]83    unsigned int scanCount = 0;
[252]84    while(!flagDone && (scanCount<this->scanlist.size()) ){
85      Scan scan = this->scanlist[scanCount];   
86      if(y == scan.itsY){ // if the y value is already in the list
87        if(scan.isInScan(x,y)) flagDone = true; // pixel already here.
88        else{ // it's a new pixel!
89          if((x==(scan.itsX-1)) || (x == (scan.getXmax()+1)) ){
90            // if it is adjacent to the existing range, add to that range
91            if(x==(scan.itsX-1)) this->scanlist[scanCount].growLeft();
92            else                 this->scanlist[scanCount].growRight();
93            flagDone = true;
94            flagChanged = true;
95            isNew = true;
[238]96          }
[252]97        }     
[239]98      }
[252]99      scanCount++;
[238]100    }
101
[252]102    if(!flagDone){
103      Scan newOne(y,x,1);
104      this->scanlist.push_back(newOne);
105      isNew = true;
106    }
107 
108    if(flagChanged){
109      // this is true only if one of the pre-existing scans has changed
110      //
111      // need to clean up, to see if there is a case of two scans when
112      // there should be one.
113      //
114      // because there has been only one pixel added, only 2 AT MOST
115      // scans will need to be combined, so once we meet a pair that
116      // overlap, we can finish.
[238]117
[252]118      std::vector <Scan>::iterator iter;
119      bool combined = false;
120      int size = this->scanlist.size();
121      int count1=0;
122      while(!combined && count1<size){
123        int count2 = count1 + 1;
124        while(!combined && count2<size){
125          Scan first = this->scanlist[count1];
126          Scan second = this->scanlist[count2];
127          if(y==first.itsY && y==second.itsY){
128            combined = touching(first, second);
129            if(combined){
130              Scan newOne = unite(first,second);;
131              iter = this->scanlist.begin() + count2;
132              this->scanlist.erase(iter);
133              iter = this->scanlist.begin() + count1;
134              this->scanlist.erase(iter);
135              this->scanlist.push_back(newOne);
136            }
137          }     
138          count2++;
139        }
140        count1++;
141      }
142
[246]143    }
[252]144
145    if(isNew){ 
146      // update the centres, mins, maxs and increment the pixel counter
147      if(this->numPix==0){
148        this->xSum = this->xmin = this->xmax = x;
149        this->ySum = this->ymin = this->ymax = y;
150      }
151      else{
152        this->xSum += x;
153        this->ySum += y;
154        if(x<this->xmin) this->xmin = x;
155        if(x>this->xmax) this->xmax = x;
156        if(y<this->ymin) this->ymin = y;
157        if(y>this->ymax) this->ymax = y;
158      }
159      this->numPix++;
[246]160    }
[252]161
[246]162  }
[252]163  //------------------------------------------------------
[246]164
[252]165  void Object2D::addScan(Scan scan)
166  {
167    bool flagDone=false,flagChanged=false;;
168    long y = scan.itsY;
[541]169    unsigned int scanCount = 0;
[252]170    std::vector <Scan>::iterator iter;
[238]171
[252]172    while(!flagDone && (scanCount<this->scanlist.size()) ){
173      Scan existing = this->scanlist[scanCount];   
174      if(y==existing.itsY){ //ie. if the y value has a scan present
175        if(scan == existing) flagDone = true; // the scan is already there
176        else if(touching(scan,existing)){ // if it overlaps or is next to an existing scan
177          //    Scan joined = unite(scan,existing);
178          //    iter = this->scanlist.begin() + scanCount;
179          //    this->scanlist.erase(iter);
180          //    this->scanlist.push_back(joined);
181          //    flagDone = true;
182          flagChanged = true;
183        }
[238]184      }
[252]185      scanCount++;
[238]186    }
187
[252]188    // if it is unconnected with any existing scan, add it to the end of
189    // the list
190    if(!flagDone) this->scanlist.push_back(scan);
[238]191
[252]192    // if the scan has been added, we need to change the centres, mins,
193    // maxs etc. First add all the pixels from the scan. We then remove
194    // any doubled up ones later.
195    if( (!flagDone) || flagChanged ){
196      if(this->numPix==0){
197        this->ySum = y*scan.itsXLen;
198        this->ymin = this->ymax = y;
199        this->xmin = scan.itsX;
200        this->xmax = scan.getXmax();
201        this->xSum = scan.itsX;
202        for(int x=scan.itsX+1;x<=scan.getXmax();x++) this->xSum += x;
203        this->numPix = scan.itsXLen;
204      }
205      else{
206        this->ySum += y*scan.itsXLen;
207        for(int x=scan.itsX; x<=scan.getXmax(); x++) this->xSum += x;
208        if(y<this->ymin) this->ymin = y;
209        if(y>this->ymax) this->ymax = y;
210        if(scan.itsX<this->xmin)      this->xmin = scan.itsX;
211        if(scan.getXmax()>this->xmax) this->xmax = scan.getXmax();
212        this->numPix += scan.itsXLen;
213      }
[246]214    }
215
[252]216    if(flagChanged){
217      // this is true only if one of the pre-existing scans has changed
218      //
219      // In this case, we are adding a scan, and the possibility exists
220      // that more than one other scan could be affected. We therefore
221      // need to look over all scans, not just stopping at the first
222      // match we come across (as for addPixel() above).
[541]223      unsigned int count1=0;
[252]224      while(count1<this->scanlist.size()-1){
[541]225        unsigned int count2 = count1 + 1;
[252]226        do {
227          Scan first = this->scanlist[count1];
228          Scan second = this->scanlist[count2];
229          if(y==first.itsY && y==second.itsY){
230            // only look at the y-value where there would have been a change.
231            if(touching(first,second)){
232              Scan newOne = unite(first,second);
233              iter = this->scanlist.begin() + count2;
234              this->scanlist.erase(iter);
235              iter = this->scanlist.begin() + count1;
236              this->scanlist.erase(iter);
237              this->scanlist.push_back(newOne);
[244]238           
[252]239              count2 = count1 + 1;
[246]240
[252]241              // Need to remove the doubled-up pixels from the info
242              Scan overlap = intersect(first,second);
243              this->ySum -= overlap.itsY*overlap.itsXLen;
244              for(int x=overlap.itsX; x<=overlap.getXmax(); x++)
245                this->xSum -= x;
246              this->numPix -= overlap.itsXLen;
[246]247
[252]248            }
249            else count2++;
250          }     
[244]251          else count2++;
[252]252        } while(count2 < this->scanlist.size());
[244]253
[252]254        count1++;
255      }
[238]256    }
[252]257
[238]258  }
[252]259  //------------------------------------------------------
[238]260
[252]261  bool Object2D::isInObject(long x, long y)
262  {
[371]263
[534]264    unsigned long scanCount = 0;
[252]265    do{
[238]266
[252]267      if(y == this->scanlist[scanCount].itsY){
268        // if the y value is already in the list
[238]269
[371]270        if((x>=this->scanlist[scanCount].itsX)&&
271           (x<=this->scanlist[scanCount].getXmax())){
[252]272          // if the x value is already in the range, the pixel is
273          //  already stored, so return true
[371]274          return true;
[252]275        }
[238]276
277      }
278
[252]279      scanCount++;
[238]280
[371]281    }while( scanCount<this->scanlist.size() );
[238]282
[371]283    // if we get to here, we've looked at each pixel with no match.
284    return false;
[238]285
[252]286  }
287  //------------------------------------------------------
[238]288
[252]289  // long Object2D::getSize()
290  // {
291  //   long size=0;
292  //   for(int i=0;i<this->scanlist.size();i++){
293  //     size += this->scanlist[i].getXlen();
294  //   }
295  //   return size;
296  // }
297  //------------------------------------------------------
[238]298
[252]299  std::ostream& operator<< ( std::ostream& theStream, Object2D& obj)
300  {
[541]301    for(unsigned int i=0;i<obj.scanlist.size();i++)
[252]302      theStream << obj.scanlist[i] << "\n";
303    theStream<<"---\n";
[270]304    return theStream;
[238]305
[252]306  }
307  //------------------------------------------------------
[238]308
[252]309  void Object2D::calcParams()
310  {
311    this->xSum = 0;
312    this->ySum = 0;
[541]313    for(unsigned int s=0;s<this->scanlist.size();s++){
[238]314
[252]315      if(s==0){
316        this->ymin = this->ymax = this->scanlist[s].itsY;
317        this->xmin = this->scanlist[s].itsX;
318        this->xmax = this->scanlist[s].getXmax();
319      }
320      else{
321        if(this->ymin>this->scanlist[s].itsY)    this->ymin = this->scanlist[s].itsY;
322        if(this->xmin>this->scanlist[s].itsX)    this->xmin = this->scanlist[s].itsX;
323        if(this->ymax<this->scanlist[s].itsY)    this->ymax = this->scanlist[s].itsY;
324        if(this->xmax<this->scanlist[s].getXmax()) this->xmax = this->scanlist[s].getXmax();
325      }
[238]326
[252]327      this->ySum += this->scanlist[s].itsY*this->scanlist[s].getXlen();
[416]328      for(int x=this->scanlist[s].itsX;x<=this->scanlist[s].getXmax();x++)
[252]329        this->xSum += x;
[416]330//       this->xSum += (this->scanlist[s].getXmax()*(this->scanlist[s].getXmax()+1) -
331//                   this->scanlist[s].itsX*(this->scanlist[s].itsX-1) ) / 2;
[252]332
[238]333    }
334
335  }
[252]336  //------------------------------------------------------
[238]337
[252]338  void Object2D::cleanup()
339  {
[541]340    unsigned int counter=0, compCounter=1;
[252]341    std::vector<Scan>::iterator iter;
342    while(counter < this->scanlist.size())
343      {
344        compCounter = counter + 1;
[238]345     
[252]346        while( compCounter < this->scanlist.size() ) {
[238]347
[252]348          Scan scan1 = this->scanlist[counter];
349          Scan scan2 = this->scanlist[compCounter];
350          if(overlap(scan1,scan2)){
351            Scan newscan = unite(scan1,scan2);
352            iter = this->scanlist.begin()+compCounter;
353            this->scanlist.erase(iter);
354            iter = this->scanlist.begin()+counter;
355            this->scanlist.erase(iter);
356            this->scanlist.push_back(newscan);
357            compCounter = counter + 1;
358          }
359          else compCounter++;
[238]360
[252]361        }
[238]362
[252]363        counter++;
364      }
[238]365
[252]366    //   this->order();
[238]367
368  }
[252]369  //------------------------------------------------------
[238]370
[252]371  long Object2D::getNumDistinctY()
372  {
373    std::vector<long> ylist;
374    if(this->scanlist.size()==0) return 0;
375    if(this->scanlist.size()==1) return 1;
376    ylist.push_back(this->scanlist[0].itsY);
[541]377    for(unsigned int i=1;i<this->scanlist.size();i++){
[238]378      bool inList = false;
[541]379      unsigned int j=0;
[252]380      long y = this->scanlist[i].itsY;
381      while(!inList && j<ylist.size()){
382        if(y==ylist[j]) inList=true;
[238]383        j++;
384      };
[252]385      if(!inList) ylist.push_back(y);
[238]386    }
[252]387    return ylist.size();
[238]388  }
[252]389  //------------------------------------------------------
[238]390
[252]391  long Object2D::getNumDistinctX()
392  {
393    std::vector<long> xlist;
394    if(this->scanlist.size()==0) return 0;
395    if(this->scanlist.size()==1) return 1;
396    for(int x=this->scanlist[0].itsX;x<this->scanlist[0].getXmax();x++)
397      xlist.push_back(x);
[541]398    for(unsigned int i=1;i<this->scanlist.size();i++){
[252]399      for(int x=this->scanlist[0].itsX;x<this->scanlist[0].getXmax();x++){
400        bool inList = false;
[541]401        unsigned int j=0;
[252]402        while(!inList && j<xlist.size()){
403          if(x==xlist[j]) inList=true;
404          j++;
405        };
406        if(!inList) xlist.push_back(x);
407      }
408    }
409    return xlist.size();
[238]410  }
[252]411  //------------------------------------------------------
412
413  bool Object2D::scanOverlaps(Scan scan)
414  {
415    bool returnval = false;
[541]416    unsigned int scanCount=0;
[252]417    while(!returnval && scanCount<this->scanlist.size()){
418      returnval = returnval || overlap(scan,this->scanlist[scanCount++]);
419    }
420    return returnval;
421  }
422
[399]423  //------------------------------------------------------
424
425  void Object2D::addOffsets(long xoff, long yoff)
426  {
427    for(unsigned int i=0;i<this->scanlist.size();i++)
428      this->scanlist[i].addOffsets(xoff,yoff);
429    this->xSum += xoff*numPix;
430    this->xmin += xoff; xmax += xoff;
431    this->ySum += yoff*numPix;
432    this->ymin += yoff; ymax += yoff;
433  }
434
[469]435  //------------------------------------------------------
436
437  double Object2D::getPositionAngle()
438  {
439
440    int sumxx=0;
441    int sumyy=0;
442    int sumxy=0;
443    std::vector<Scan>::iterator scn=this->scanlist.begin();
444    for(;scn<this->scanlist.end();scn++){
445      sumyy += (scn->itsY*scn->itsY)*scn->itsXLen;
446      for(int x=scn->itsX;x<=scn->getXmax();x++){
447        sumxx += x*x;
448        sumxy += x*scn->itsY;
449      }
450    }
451
452    // Calculate net moments
453    double mxx = sumxx - this->xSum*this->xSum / double(this->numPix);
454    double myy = sumyy - this->ySum*this->ySum / double(this->numPix);
455    double mxy = sumxy - this->xSum*this->ySum / double(this->numPix);
456
[472]457    if(mxy==0){
458      if(mxx>myy) return M_PI/2.;
459      else return 0.;
460    }
[469]461
462    // Angle of the minimum moment
463    double tantheta = (mxx - myy + sqrt( (mxx-myy)*(mxx-myy) + 4.*mxy*mxy))/(2.*mxy);
464
465    return atan(tantheta);
466  }
467
468  //------------------------------------------------------
469
470  std::pair<double,double> Object2D::getPrincipleAxes()
471  {
472
[470]473    double theta = this->getPositionAngle();
[545]474    double x0 = this->getXaverage();
475    double y0 = this->getYaverage();
[469]476    std::vector<double> majorAxes, minorAxes;
477    std::vector<Scan>::iterator scn=this->scanlist.begin();
478    for(;scn<this->scanlist.end();scn++){
479      for(int x=scn->itsX;x<=scn->getXmax();x++){
[472]480        majorAxes.push_back((x-x0+0.5)*cos(theta) + (scn->itsY-y0+0.5)*sin(theta));
481        minorAxes.push_back((x-x0+0.5)*sin(theta) + (scn->itsY-y0+0.5)*cos(theta));
[469]482      }
483    }
484
485    std::sort(majorAxes.begin(),majorAxes.end());
486    std::sort(minorAxes.begin(),minorAxes.end());
487    int size = majorAxes.size();
488    std::pair<double,double> axes;
489    axes.first = fabs(majorAxes[0]-majorAxes[size-1]);
490    axes.second = fabs(minorAxes[0]-minorAxes[size-1]);
[472]491    if(axes.first<0.5) axes.first=0.5;
492    if(axes.second<0.5) axes.second=0.5;
[469]493    return axes;
494
495  }
496
[238]497}
Note: See TracBrowser for help on using the repository browser.