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

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

A large number of changes made to the use of scanlist in Object2D. We now don't keep it sorted until it is printed out. We've made more use of iterators - this was to explore using a std::list instead of std::vector, but that seemed to be a lot slower. A new function in Scan, and better use of references in function calls as well.

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