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

Last change on this file since 1155 was 1155, checked in by MatthewWhiting, 11 years ago

Fixing issues with having moved the findShape function. Solving allocation bugs, and making sure the flags are worked out correctly.

File size: 14.3 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    this->majorAxis = o.majorAxis;
62    this->minorAxis = o.minorAxis;
63    this->posAngle  = o.posAngle;
64    return *this;
65  } 
66  //------------------------------------------------------
67
68  Object2D operator+ (Object2D lhs, Object2D rhs)
69  {
70    Object2D output = lhs;
71    for(std::vector<Scan>::iterator s=rhs.scanlist.begin();s!=rhs.scanlist.end();s++)
72      output.addScan(*s);
73    return output;
74  }
75
76  //------------------------------------------------------
77  void Object2D::addPixel(long x, long y)
78  {
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>
92
93
94    bool flagDone=false,flagChanged=false, isNew=false;
95
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.
99        else{ // it's a new pixel!
100          if((x==(scan->itsX-1)) || (x == (scan->itsX+scan->itsXLen)) ){
101            // if it is adjacent to the existing range, add to that range
102            if(x==(scan->itsX-1)) scan->growLeft();
103            else                  scan->growRight();
104            flagDone = true;
105            flagChanged = true;
106            isNew = true;
107          }
108        }     
109      }
110    }
111
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
115      Scan newOne(y,x,1);
116      this->scanlist.push_back(newOne);
117      isNew = true;
118    }
119    else if(flagChanged){
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
123      // there should be one. Only need to look at scans with matching
124      // y-value
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.
129
130      bool combined = false;
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){
138              combined = scan1->addScan(*scan2);
139              if(combined){
140                this->scanlist.erase(scan2);
141              }
142            }   
143          }
144        }
145      }
146
147    }
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++;
164    }
165
166  }
167  //------------------------------------------------------
168
169  void Object2D::addScan(Scan &scan)
170  {
171    long y=scan.getY();
172    for(long x=scan.getX();x<=scan.getXmax();x++) this->addPixel(x,y);
173
174  }
175  //------------------------------------------------------
176
177  bool Object2D::isInObject(long x, long y)
178  {
179
180    std::vector<Scan>::iterator scn;
181    bool returnval=false;
182    for(scn=this->scanlist.begin();scn!=this->scanlist.end()&&!returnval;scn++){
183
184      returnval = ((y == scn->itsY) && (x>= scn->itsX) && (x<=scn->getXmax()));
185
186    }
187       
188    return returnval;
189
190  }
191  //------------------------------------------------------
192
193  std::ostream& operator<< ( std::ostream& theStream, Object2D& obj)
194  {
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";
198    theStream<<"---\n";
199    return theStream;
200
201  }
202  //------------------------------------------------------
203
204  void Object2D::calcParams()
205  {
206    this->xSum = 0;
207    this->ySum = 0;
208    std::vector<Scan>::iterator s;
209    for(s=this->scanlist.begin();s!=this->scanlist.end();s++){
210
211      if(s==this->scanlist.begin()){
212        this->ymin = this->ymax = s->itsY;
213        this->xmin = s->itsX;
214        this->xmax = s->getXmax();
215      }
216      else{
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();
221      }
222
223      this->ySum += s->itsY*s->getXlen();
224      for(int x=s->itsX;x<=s->getXmax();x++)
225        this->xSum += x;
226
227    }
228
229  }
230  //------------------------------------------------------
231
232  void Object2D::cleanup()
233  {
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
239        if(overlap(*s1,*s2)){
240          s1->addScan(*s2);
241          this->scanlist.erase(s2);
242        }
243      }
244    }
245
246  }
247  //------------------------------------------------------
248
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;
254    std::vector<Scan>::iterator scn;
255    for(scn=this->scanlist.begin();scn!=this->scanlist.end();scn++){
256      bool inList = false;
257      unsigned int j=0;
258      long y = scn->itsY;
259      while(!inList && j<ylist.size()){
260        if(y==ylist[j]) inList=true;
261        j++;
262      };
263      if(!inList) ylist.push_back(y);
264    }
265    return ylist.size();
266  }
267  //------------------------------------------------------
268
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;
274    std::vector<Scan>::iterator scn;
275    for(scn=this->scanlist.begin();scn!=this->scanlist.end();scn++){
276      for(int x=scn->itsX;x<scn->getXmax();x++){
277        bool inList = false;
278        unsigned int j=0;
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();
287  }
288  //------------------------------------------------------
289
290  bool Object2D::scanOverlaps(Scan &scan)
291  {
292    bool returnval = false;
293    for(std::vector<Scan>::iterator s=this->scanlist.begin();!returnval&&s!=this->scanlist.end();s++){
294      returnval = returnval || s->overlaps(scan);
295    }
296    return returnval;
297  }
298
299  //------------------------------------------------------
300
301  void Object2D::addOffsets(long xoff, long yoff)
302  {
303    std::vector<Scan>::iterator scn;
304    for(scn=this->scanlist.begin();scn!=this->scanlist.end();scn++)
305      scn->addOffsets(xoff,yoff);
306    this->xSum += xoff*numPix;
307    this->xmin += xoff; xmax += xoff;
308    this->ySum += yoff*numPix;
309    this->ymin += yoff; ymax += yoff;
310  }
311
312  //------------------------------------------------------
313
314  bool Object2D::findEllipse(bool weightByFlux, float *array, size_t xdim, size_t ydim, int xzero, int yzero, float x0, float y0)
315  {
316    bool result=true;
317    double sumxx=0.,sumyy=0.,sumxy=0.,sumflux=0.;
318    std::vector<Scan>::iterator scn=this->scanlist.begin();
319    for(;scn!=this->scanlist.end();scn++){
320      int y = scn->itsY;
321      float yoff=scn->itsY - y0;
322      for(int x=scn->itsX;x<=scn->getXmax();x++){
323        float xoff=x-x0;
324        float flux = weightByFlux ? array[(x-xzero)+xdim*(y-yzero)] : 1;
325        sumxx += (xoff*xoff*flux);
326        sumyy += (yoff*yoff*flux);
327        sumxy += (xoff*yoff*flux);
328        sumflux += flux;
329      }
330    }
331
332    sumxx /= sumflux;
333    sumxy /= sumflux;
334    sumyy /= sumflux;
335
336    this->posAngle = 0.5 * atan2( 2*sumxy , (sumxx-sumyy) ) + M_PI/2.;
337    this->posAngle = fmod(this->posAngle, 2.*M_PI);
338    if(this->posAngle > M_PI) this->posAngle -= 2.*M_PI;
339    double plusroot = sumxx + sumyy + sqrt((sumxx-sumyy)*(sumxx-sumyy) + 4.*sumxy*sumxy);
340    result = ( plusroot > 0 );
341    double minusroot = sumxx + sumyy - sqrt((sumxx-sumyy)*(sumxx-sumyy) + 4.*sumxy*sumxy);
342    result = result && ( minusroot > 0 );
343    if(result){
344      this->majorAxis = sqrt( 2. * plusroot );
345      this->minorAxis = sqrt( 2. * minusroot );
346      this->minorAxis = std::max(this->minorAxis,0.1);
347    }
348    else this->majorAxis = this->minorAxis = 0.;
349    return result;
350  }
351
352
353  //------------------------------------------------------
354
355  double Object2D::getPositionAngle()
356  {
357
358    int sumxx=0;
359    int sumyy=0;
360    int sumxy=0;
361    std::vector<Scan>::iterator scn=this->scanlist.begin();
362    for(;scn!=this->scanlist.end();scn++){
363      sumyy += (scn->itsY*scn->itsY)*scn->itsXLen;
364      for(int x=scn->itsX;x<=scn->getXmax();x++){
365        sumxx += x*x;
366        sumxy += x*scn->itsY;
367      }
368    }
369
370    // Calculate net moments
371    double mxx = sumxx - this->xSum*this->xSum / double(this->numPix);
372    double myy = sumyy - this->ySum*this->ySum / double(this->numPix);
373    double mxy = sumxy - this->xSum*this->ySum / double(this->numPix);
374
375    if(mxy==0){
376      if(mxx>myy) return M_PI/2.;
377      else return 0.;
378    }
379
380    // Angle of the minimum moment
381    double tantheta = (mxx - myy + sqrt( (mxx-myy)*(mxx-myy) + 4.*mxy*mxy))/(2.*mxy);
382
383    return atan(tantheta);
384  }
385
386  //------------------------------------------------------
387
388  std::pair<double,double> Object2D::getPrincipleAxes()
389  {
390
391    double theta = this->getPositionAngle();
392    double x0 = this->getXaverage();
393    double y0 = this->getYaverage();
394    std::vector<double> majorAxes, minorAxes;
395    std::vector<Scan>::iterator scn=this->scanlist.begin();
396    for(;scn!=this->scanlist.end();scn++){
397      for(int x=scn->itsX;x<=scn->getXmax();x++){
398        majorAxes.push_back((x-x0+0.5)*cos(theta) + (scn->itsY-y0+0.5)*sin(theta));
399        minorAxes.push_back((x-x0+0.5)*sin(theta) + (scn->itsY-y0+0.5)*cos(theta));
400      }
401    }
402
403    std::sort(majorAxes.begin(),majorAxes.end());
404    std::sort(minorAxes.begin(),minorAxes.end());
405    int size = majorAxes.size();
406    std::pair<double,double> axes;
407    axes.first = fabs(majorAxes[0]-majorAxes[size-1]);
408    axes.second = fabs(minorAxes[0]-minorAxes[size-1]);
409    if(axes.first<0.5) axes.first=0.5;
410    if(axes.second<0.5) axes.second=0.5;
411    return axes;
412
413  }
414
415
416  //------------------------------------------------------
417
418
419  bool Object2D::canMerge(Object2D &other, float threshS, bool flagAdj)
420  {
421    long gap;
422    if(flagAdj) gap = 1;
423    else gap = long( ceil(threshS) );
424    bool near = this->isNear(other,gap);
425    if(near) return this->isClose(other,threshS,flagAdj);
426    else return near;
427  }
428
429  //------------------------------------------------------
430
431  bool Object2D::isNear(Object2D &other, long gap)
432  {
433    bool areNear;
434    // Test X ranges
435    if((this->xmin-gap)<other.xmin) areNear=((this->xmax+gap)>=other.xmin);
436    else areNear=(other.xmax>=(this->xmin-gap));
437    // Test Y ranges
438    if(areNear){
439      if((this->ymin-gap)<other.ymin) areNear=areNear&&((this->ymax+gap)>=other.ymin);
440      else areNear=areNear&&(other.ymax>=(this->ymin-gap));
441    }
442    return areNear;
443  }
444
445  //------------------------------------------------------
446
447  bool Object2D::isClose(Object2D &other, float threshS, bool flagAdj)
448  {
449
450    long gap = long(ceil(threshS));
451    if(flagAdj) gap=1;
452
453    bool close = false;
454
455    long ycommonMin=std::max(this->ymin-gap,other.ymin)-gap;
456    long ycommonMax=std::min(this->ymax+gap,other.ymax)+gap;
457
458    std::vector<Scan>::iterator iter1,iter2;
459    for(iter1=this->scanlist.begin();!close && iter1!=this->scanlist.end();iter1++){
460      if(iter1->itsY >= ycommonMin && iter1->itsY<=ycommonMax){
461        for(iter2=other.scanlist.begin();!close && iter2!=other.scanlist.end();iter2++){
462          if(iter2->itsY >= ycommonMin && iter2->itsY<=ycommonMax){
463             
464            if(abs(iter1->itsY-iter2->itsY)<=gap){
465              if(flagAdj) {
466                if((iter1->itsX-gap)>iter2->itsX) close=((iter2->itsX+iter2->itsXLen-1)>=(iter1->itsX-gap));
467                else close = ( (iter1->itsX+iter1->itsXLen+gap-1)>=iter2->itsX);
468              }
469              else close = (minSep(*iter1,*iter2) <= threshS);
470            }
471
472          }
473        }
474      }
475    }
476           
477    return close;
478   
479  }
480
481
482
483}
Note: See TracBrowser for help on using the repository browser.