source: trunk/src/PixelMap/Object2D.cc @ 623

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

Changing references of unsigned ints to size_t, or to use of iterators. Also fixing one bug in Object2D::getNumDistinctX, where we weren't looking at all scans. This
should fix ticket #63.

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