source: tags/release-1.1.7/src/PixelMap/Object2D.cc @ 533

Last change on this file since 533 was 528, checked in by MatthewWhiting, 15 years ago

Changing the documentation comments to match the askapsoft style. Also have split ChanMap? and Object3D into separate files.

File size: 14.8 KB
Line 
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// -----------------------------------------------------------------------
28#include <duchamp/PixelMap/Scan.hh>
29#include <duchamp/PixelMap/Object2D.hh>
30#include <duchamp/PixelMap/Voxel.hh>
31#include <iostream>
32#include <vector>
33#include <algorithm>
34#include <math.h>
35
36namespace PixelInfo
37{
38
39  Object2D::Object2D()
40  {
41    this->numPix = 0;
42  }
43
44  Object2D::Object2D(const Object2D& o)
45  {
46    operator=(o);
47  } 
48
49  Object2D& Object2D::operator= (const Object2D& o)
50  {
51    if(this == &o) return *this;
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;
60    return *this;
61  } 
62  //------------------------------------------------------
63
64  void Object2D::addPixel(long x, long y)
65  {
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>
79
80
81    bool flagDone=false,flagChanged=false, isNew=false;
82
83    int scanCount = 0;
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;
96          }
97        }     
98      }
99      scanCount++;
100    }
101
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.
117
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
143    }
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++;
160    }
161
162  }
163  //------------------------------------------------------
164
165  void Object2D::addScan(Scan scan)
166  {
167    bool flagDone=false,flagChanged=false;;
168    long y = scan.itsY;
169    int scanCount = 0;
170    std::vector <Scan>::iterator iter;
171
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        }
184      }
185      scanCount++;
186    }
187
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);
191
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      }
214    }
215
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).
223      int count1=0;
224      while(count1<this->scanlist.size()-1){
225        int count2 = count1 + 1;
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);
238           
239              count2 = count1 + 1;
240
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;
247
248            }
249            else count2++;
250          }     
251          else count2++;
252        } while(count2 < this->scanlist.size());
253
254        count1++;
255      }
256    }
257
258  }
259  //------------------------------------------------------
260
261  bool Object2D::isInObject(long x, long y)
262  {
263
264    long scanCount = 0;
265    do{
266
267      if(y == this->scanlist[scanCount].itsY){
268        // if the y value is already in the list
269
270        if((x>=this->scanlist[scanCount].itsX)&&
271           (x<=this->scanlist[scanCount].getXmax())){
272          // if the x value is already in the range, the pixel is
273          //  already stored, so return true
274          return true;
275        }
276
277      }
278
279      scanCount++;
280
281    }while( scanCount<this->scanlist.size() );
282
283    // if we get to here, we've looked at each pixel with no match.
284    return false;
285
286  }
287  //------------------------------------------------------
288
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  //------------------------------------------------------
298
299  std::ostream& operator<< ( std::ostream& theStream, Object2D& obj)
300  {
301    for(int i=0;i<obj.scanlist.size();i++)
302      theStream << obj.scanlist[i] << "\n";
303    theStream<<"---\n";
304    return theStream;
305
306  }
307  //------------------------------------------------------
308
309  void Object2D::calcParams()
310  {
311    this->xSum = 0;
312    this->ySum = 0;
313    for(int s=0;s<this->scanlist.size();s++){
314
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      }
326
327      this->ySum += this->scanlist[s].itsY*this->scanlist[s].getXlen();
328      for(int x=this->scanlist[s].itsX;x<=this->scanlist[s].getXmax();x++)
329        this->xSum += x;
330//       this->xSum += (this->scanlist[s].getXmax()*(this->scanlist[s].getXmax()+1) -
331//                   this->scanlist[s].itsX*(this->scanlist[s].itsX-1) ) / 2;
332
333    }
334
335  }
336  //------------------------------------------------------
337
338  void Object2D::cleanup()
339  {
340    int counter=0, compCounter=1;
341    std::vector<Scan>::iterator iter;
342    while(counter < this->scanlist.size())
343      {
344        compCounter = counter + 1;
345     
346        while( compCounter < this->scanlist.size() ) {
347
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++;
360
361        }
362
363        counter++;
364      }
365
366    //   this->order();
367
368  }
369  //------------------------------------------------------
370
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);
377    for(int i=1;i<this->scanlist.size();i++){
378      bool inList = false;
379      int j=0;
380      long y = this->scanlist[i].itsY;
381      while(!inList && j<ylist.size()){
382        if(y==ylist[j]) inList=true;
383        j++;
384      };
385      if(!inList) ylist.push_back(y);
386    }
387    return ylist.size();
388  }
389  //------------------------------------------------------
390
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);
398    for(int i=1;i<this->scanlist.size();i++){
399      for(int x=this->scanlist[0].itsX;x<this->scanlist[0].getXmax();x++){
400        bool inList = false;
401        int j=0;
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();
410  }
411  //------------------------------------------------------
412
413  bool Object2D::scanOverlaps(Scan scan)
414  {
415    bool returnval = false;
416    int scanCount=0;
417    while(!returnval && scanCount<this->scanlist.size()){
418      returnval = returnval || overlap(scan,this->scanlist[scanCount++]);
419    }
420    return returnval;
421  }
422
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
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
457    if(mxy==0){
458      if(mxx>myy) return M_PI/2.;
459      else return 0.;
460    }
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
473    double theta = this->getPositionAngle();
474    double x0 = this->getXcentre();
475    double y0 = this->getYcentre();
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++){
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));
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]);
491    if(axes.first<0.5) axes.first=0.5;
492    if(axes.second<0.5) axes.second=0.5;
493    return axes;
494
495  }
496
497}
Note: See TracBrowser for help on using the repository browser.