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

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

Only order the 2D object if it has more than one scan.

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(unsigned int 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    unsigned int 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    unsigned long 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(unsigned int 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    for(unsigned int s=0;s<this->scanlist.size();s++){
335
336      if(s==0){
337        this->ymin = this->ymax = this->scanlist[s].itsY;
338        this->xmin = this->scanlist[s].itsX;
339        this->xmax = this->scanlist[s].getXmax();
340      }
341      else{
342        if(this->ymin>this->scanlist[s].itsY)    this->ymin = this->scanlist[s].itsY;
343        if(this->xmin>this->scanlist[s].itsX)    this->xmin = this->scanlist[s].itsX;
344        if(this->ymax<this->scanlist[s].itsY)    this->ymax = this->scanlist[s].itsY;
345        if(this->xmax<this->scanlist[s].getXmax()) this->xmax = this->scanlist[s].getXmax();
346      }
347
348      this->ySum += this->scanlist[s].itsY*this->scanlist[s].getXlen();
349      for(int x=this->scanlist[s].itsX;x<=this->scanlist[s].getXmax();x++)
350        this->xSum += x;
351//       this->xSum += (this->scanlist[s].getXmax()*(this->scanlist[s].getXmax()+1) -
352//                   this->scanlist[s].itsX*(this->scanlist[s].itsX-1) ) / 2;
353
354    }
355
356  }
357  //------------------------------------------------------
358
359  void Object2D::cleanup()
360  {
361    unsigned int counter=0, compCounter=1;
362    std::vector<Scan>::iterator iter;
363    while(counter < this->scanlist.size())
364      {
365        compCounter = counter + 1;
366     
367        while( compCounter < this->scanlist.size() ) {
368
369          Scan scan1 = this->scanlist[counter];
370          Scan scan2 = this->scanlist[compCounter];
371          if(overlap(scan1,scan2)){
372            Scan newscan = unite(scan1,scan2);
373            iter = this->scanlist.begin()+compCounter;
374            this->scanlist.erase(iter);
375            iter = this->scanlist.begin()+counter;
376            this->scanlist.erase(iter);
377            this->scanlist.push_back(newscan);
378            compCounter = counter + 1;
379          }
380          else compCounter++;
381
382        }
383
384        counter++;
385      }
386
387    //   this->order();
388
389  }
390  //------------------------------------------------------
391
392  long Object2D::getNumDistinctY()
393  {
394    std::vector<long> ylist;
395    if(this->scanlist.size()==0) return 0;
396    if(this->scanlist.size()==1) return 1;
397    ylist.push_back(this->scanlist[0].itsY);
398    for(unsigned int i=1;i<this->scanlist.size();i++){
399      bool inList = false;
400      unsigned int j=0;
401      long y = this->scanlist[i].itsY;
402      while(!inList && j<ylist.size()){
403        if(y==ylist[j]) inList=true;
404        j++;
405      };
406      if(!inList) ylist.push_back(y);
407    }
408    return ylist.size();
409  }
410  //------------------------------------------------------
411
412  long Object2D::getNumDistinctX()
413  {
414    std::vector<long> xlist;
415    if(this->scanlist.size()==0) return 0;
416    if(this->scanlist.size()==1) return 1;
417    for(int x=this->scanlist[0].itsX;x<this->scanlist[0].getXmax();x++)
418      xlist.push_back(x);
419    for(unsigned int i=1;i<this->scanlist.size();i++){
420      for(int x=this->scanlist[0].itsX;x<this->scanlist[0].getXmax();x++){
421        bool inList = false;
422        unsigned int j=0;
423        while(!inList && j<xlist.size()){
424          if(x==xlist[j]) inList=true;
425          j++;
426        };
427        if(!inList) xlist.push_back(x);
428      }
429    }
430    return xlist.size();
431  }
432  //------------------------------------------------------
433
434  bool Object2D::scanOverlaps(Scan scan)
435  {
436    bool returnval = false;
437    unsigned int scanCount=0;
438    while(!returnval && scanCount<this->scanlist.size()){
439      returnval = returnval || overlap(scan,this->scanlist[scanCount++]);
440    }
441    return returnval;
442  }
443
444  //------------------------------------------------------
445
446  void Object2D::addOffsets(long xoff, long yoff)
447  {
448    for(unsigned int i=0;i<this->scanlist.size();i++)
449      this->scanlist[i].addOffsets(xoff,yoff);
450    this->xSum += xoff*numPix;
451    this->xmin += xoff; xmax += xoff;
452    this->ySum += yoff*numPix;
453    this->ymin += yoff; ymax += yoff;
454  }
455
456  //------------------------------------------------------
457
458  double Object2D::getPositionAngle()
459  {
460
461    int sumxx=0;
462    int sumyy=0;
463    int sumxy=0;
464    std::vector<Scan>::iterator scn=this->scanlist.begin();
465    for(;scn<this->scanlist.end();scn++){
466      sumyy += (scn->itsY*scn->itsY)*scn->itsXLen;
467      for(int x=scn->itsX;x<=scn->getXmax();x++){
468        sumxx += x*x;
469        sumxy += x*scn->itsY;
470      }
471    }
472
473    // Calculate net moments
474    double mxx = sumxx - this->xSum*this->xSum / double(this->numPix);
475    double myy = sumyy - this->ySum*this->ySum / double(this->numPix);
476    double mxy = sumxy - this->xSum*this->ySum / double(this->numPix);
477
478    if(mxy==0){
479      if(mxx>myy) return M_PI/2.;
480      else return 0.;
481    }
482
483    // Angle of the minimum moment
484    double tantheta = (mxx - myy + sqrt( (mxx-myy)*(mxx-myy) + 4.*mxy*mxy))/(2.*mxy);
485
486    return atan(tantheta);
487  }
488
489  //------------------------------------------------------
490
491  std::pair<double,double> Object2D::getPrincipleAxes()
492  {
493
494    double theta = this->getPositionAngle();
495    double x0 = this->getXaverage();
496    double y0 = this->getYaverage();
497    std::vector<double> majorAxes, minorAxes;
498    std::vector<Scan>::iterator scn=this->scanlist.begin();
499    for(;scn<this->scanlist.end();scn++){
500      for(int x=scn->itsX;x<=scn->getXmax();x++){
501        majorAxes.push_back((x-x0+0.5)*cos(theta) + (scn->itsY-y0+0.5)*sin(theta));
502        minorAxes.push_back((x-x0+0.5)*sin(theta) + (scn->itsY-y0+0.5)*cos(theta));
503      }
504    }
505
506    std::sort(majorAxes.begin(),majorAxes.end());
507    std::sort(minorAxes.begin(),minorAxes.end());
508    int size = majorAxes.size();
509    std::pair<double,double> axes;
510    axes.first = fabs(majorAxes[0]-majorAxes[size-1]);
511    axes.second = fabs(minorAxes[0]-minorAxes[size-1]);
512    if(axes.first<0.5) axes.first=0.5;
513    if(axes.second<0.5) axes.second=0.5;
514    return axes;
515
516  }
517
518}
Note: See TracBrowser for help on using the repository browser.