source: tags/release-1.1.10/src/PixelMap/Object2D.cc @ 1339

Last change on this file since 1339 was 747, checked in by MatthewWhiting, 14 years ago

More improvements based on some profiling with Shark. Tara's test case down to just over a minute!

File size: 11.7 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, size=this->scanlist.size();
92    while(!flagDone && (scanCount<size) ){
93      if(y == this->scanlist[scanCount].itsY){ // if the y value is already in the list
94        if(this->scanlist[scanCount].isInScan(x,y)) flagDone = true; // pixel already here.
95        else{ // it's a new pixel!
96          if((x==(this->scanlist[scanCount].itsX-1)) || (x == (this->scanlist[scanCount].getXmax()+1)) ){
97            // if it is adjacent to the existing range, add to that range
98            if(x==(this->scanlist[scanCount].itsX-1)) this->scanlist[scanCount].growLeft();
99            else                                      this->scanlist[scanCount].growRight();
100            flagDone = true;
101            flagChanged = true;
102            isNew = true;
103          }
104        }     
105      }
106      scanCount++;
107    }
108
109    if(!flagDone){
110      // we got to the end of the scanlist, so there is no pre-existing scan with this y value
111      // add a new scan consisting of just this pixel
112      Scan newOne(y,x,1);
113      this->scanlist.push_back(newOne);
114      if(this->scanlist.size()>1) this->order();
115      isNew = true;
116    }
117    else 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. Only need to look at scans with matching
122      // y-value
123      //
124      // because there has been only one pixel added, only 2 AT MOST
125      // scans will need to be combined, so once we meet a pair that
126      // overlap, we can finish.
127
128      std::vector <Scan>::iterator iter;
129      bool combined = false;
130      int size = this->scanlist.size();
131      int count1=0;
132      while(!combined && count1<size){
133        if(this->scanlist[count1].itsY==y){
134          int count2 = count1 + 1;
135          while(!combined && count2<size){
136            if(this->scanlist[count2].itsY==y){
137              combined = touching(this->scanlist[count1], this->scanlist[count2]);
138              if(combined){
139                for(int i=0;i<this->scanlist[count2].getXlen();i++) this->scanlist[count1].growRight();
140                iter = this->scanlist.begin() + count2;
141                this->scanlist.erase(iter);
142              }
143            }   
144            count2++;
145          }
146        }
147        count1++;
148      }
149
150    }
151
152    if(isNew){ 
153      // update the centres, mins, maxs and increment the pixel counter
154      if(this->numPix==0){
155        this->xSum = this->xmin = this->xmax = x;
156        this->ySum = this->ymin = this->ymax = y;
157      }
158      else{
159        this->xSum += x;
160        this->ySum += y;
161        if(x<this->xmin) this->xmin = x;
162        if(x>this->xmax) this->xmax = x;
163        if(y<this->ymin) this->ymin = y;
164        if(y>this->ymax) this->ymax = y;
165      }
166      this->numPix++;
167    }
168
169  }
170  //------------------------------------------------------
171
172  void Object2D::addScan(Scan scan)
173  {
174
175    for(int x=scan.getX();x<=scan.getXmax();x++) this->addPixel(x,scan.getY());
176
177  }
178  //------------------------------------------------------
179
180  bool Object2D::isInObject(long x, long y)
181  {
182
183    std::vector<Scan>::iterator scn;
184    bool returnval=false;
185    for(scn=this->scanlist.begin();scn<this->scanlist.end()&&!returnval;scn++){
186
187      returnval = ((y == scn->itsY) && (x>= scn->itsX) && (x<=scn->getXmax()));
188
189    }
190       
191    return returnval;
192
193  }
194  //------------------------------------------------------
195
196  std::ostream& operator<< ( std::ostream& theStream, Object2D& obj)
197  {
198    for(size_t i=0;i<obj.scanlist.size();i++)
199      theStream << obj.scanlist[i] << "\n";
200    theStream<<"---\n";
201    return theStream;
202
203  }
204  //------------------------------------------------------
205
206  void Object2D::calcParams()
207  {
208    this->xSum = 0;
209    this->ySum = 0;
210    std::vector<Scan>::iterator s;
211    for(s=this->scanlist.begin();s<this->scanlist.end();s++){
212
213      if(s==this->scanlist.begin()){
214        this->ymin = this->ymax = s->itsY;
215        this->xmin = s->itsX;
216        this->xmax = s->getXmax();
217      }
218      else{
219        if(this->ymin>s->itsY)    this->ymin = s->itsY;
220        if(this->xmin>s->itsX)    this->xmin = s->itsX;
221        if(this->ymax<s->itsY)    this->ymax = s->itsY;
222        if(this->xmax<s->getXmax()) this->xmax = s->getXmax();
223      }
224
225      this->ySum += s->itsY*s->getXlen();
226      for(int x=s->itsX;x<=s->getXmax();x++)
227        this->xSum += x;
228
229    }
230
231  }
232  //------------------------------------------------------
233
234  void Object2D::cleanup()
235  {
236    size_t counter=0, compCounter=1;
237    std::vector<Scan>::iterator iter;
238    while(counter < this->scanlist.size())
239      {
240        compCounter = counter + 1;
241     
242        while( compCounter < this->scanlist.size() ) {
243
244          Scan scan1 = this->scanlist[counter];
245          Scan scan2 = this->scanlist[compCounter];
246          if(overlap(scan1,scan2)){
247            Scan newscan = unite(scan1,scan2);
248            iter = this->scanlist.begin()+compCounter;
249            this->scanlist.erase(iter);
250            iter = this->scanlist.begin()+counter;
251            this->scanlist.erase(iter);
252            this->scanlist.push_back(newscan);
253            compCounter = counter + 1;
254          }
255          else compCounter++;
256
257        }
258
259        counter++;
260      }
261
262  }
263  //------------------------------------------------------
264
265  long Object2D::getNumDistinctY()
266  {
267    std::vector<long> ylist;
268    if(this->scanlist.size()==0) return 0;
269    if(this->scanlist.size()==1) return 1;
270    ylist.push_back(this->scanlist[0].itsY);
271    std::vector<Scan>::iterator scn;
272    for(scn=this->scanlist.begin();scn<this->scanlist.end();scn++){
273      bool inList = false;
274      unsigned int j=0;
275      long y = scn->itsY;
276      while(!inList && j<ylist.size()){
277        if(y==ylist[j]) inList=true;
278        j++;
279      };
280      if(!inList) ylist.push_back(y);
281    }
282    return ylist.size();
283  }
284  //------------------------------------------------------
285
286  long Object2D::getNumDistinctX()
287  {
288    std::vector<long> xlist;
289    if(this->scanlist.size()==0) return 0;
290    if(this->scanlist.size()==1) return 1;
291    for(int x=this->scanlist[0].itsX;x<this->scanlist[0].getXmax();x++)
292      xlist.push_back(x);
293    std::vector<Scan>::iterator scn;
294    for(scn=this->scanlist.begin();scn<this->scanlist.end();scn++){
295      for(int x=scn->itsX;x<scn->getXmax();x++){
296        bool inList = false;
297        unsigned int j=0;
298        while(!inList && j<xlist.size()){
299          if(x==xlist[j]) inList=true;
300          j++;
301        };
302        if(!inList) xlist.push_back(x);
303      }
304    }
305    return xlist.size();
306  }
307  //------------------------------------------------------
308
309  bool Object2D::scanOverlaps(Scan scan)
310  {
311    bool returnval = false;
312    unsigned int scanCount=0;
313    while(!returnval && scanCount<this->scanlist.size()){
314      returnval = returnval || overlap(scan,this->scanlist[scanCount++]);
315    }
316    return returnval;
317  }
318
319  //------------------------------------------------------
320
321  void Object2D::addOffsets(long xoff, long yoff)
322  {
323    std::vector<Scan>::iterator scn;
324    for(scn=this->scanlist.begin();scn<this->scanlist.end();scn++)
325      scn->addOffsets(xoff,yoff);
326    this->xSum += xoff*numPix;
327    this->xmin += xoff; xmax += xoff;
328    this->ySum += yoff*numPix;
329    this->ymin += yoff; ymax += yoff;
330  }
331
332  //------------------------------------------------------
333
334  double Object2D::getPositionAngle()
335  {
336
337    int sumxx=0;
338    int sumyy=0;
339    int sumxy=0;
340    std::vector<Scan>::iterator scn=this->scanlist.begin();
341    for(;scn<this->scanlist.end();scn++){
342      sumyy += (scn->itsY*scn->itsY)*scn->itsXLen;
343      for(int x=scn->itsX;x<=scn->getXmax();x++){
344        sumxx += x*x;
345        sumxy += x*scn->itsY;
346      }
347    }
348
349    // Calculate net moments
350    double mxx = sumxx - this->xSum*this->xSum / double(this->numPix);
351    double myy = sumyy - this->ySum*this->ySum / double(this->numPix);
352    double mxy = sumxy - this->xSum*this->ySum / double(this->numPix);
353
354    if(mxy==0){
355      if(mxx>myy) return M_PI/2.;
356      else return 0.;
357    }
358
359    // Angle of the minimum moment
360    double tantheta = (mxx - myy + sqrt( (mxx-myy)*(mxx-myy) + 4.*mxy*mxy))/(2.*mxy);
361
362    return atan(tantheta);
363  }
364
365  //------------------------------------------------------
366
367  std::pair<double,double> Object2D::getPrincipleAxes()
368  {
369
370    double theta = this->getPositionAngle();
371    double x0 = this->getXaverage();
372    double y0 = this->getYaverage();
373    std::vector<double> majorAxes, minorAxes;
374    std::vector<Scan>::iterator scn=this->scanlist.begin();
375    for(;scn<this->scanlist.end();scn++){
376      for(int x=scn->itsX;x<=scn->getXmax();x++){
377        majorAxes.push_back((x-x0+0.5)*cos(theta) + (scn->itsY-y0+0.5)*sin(theta));
378        minorAxes.push_back((x-x0+0.5)*sin(theta) + (scn->itsY-y0+0.5)*cos(theta));
379      }
380    }
381
382    std::sort(majorAxes.begin(),majorAxes.end());
383    std::sort(minorAxes.begin(),minorAxes.end());
384    int size = majorAxes.size();
385    std::pair<double,double> axes;
386    axes.first = fabs(majorAxes[0]-majorAxes[size-1]);
387    axes.second = fabs(minorAxes[0]-minorAxes[size-1]);
388    if(axes.first<0.5) axes.first=0.5;
389    if(axes.second<0.5) axes.second=0.5;
390    return axes;
391
392  }
393
394}
Note: See TracBrowser for help on using the repository browser.