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

Last change on this file since 1455 was 1443, checked in by MatthewWhiting, 7 years ago

Fixing some build errors to make 1.6.2 more widely useful.

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