source: trunk/src/PixelMap/Object3D.cc @ 822

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

Some fixes for a couple of bugs in the adjacency tests, and streamlining a couple of other functions.

File size: 13.6 KB
RevLine 
[301]1// -----------------------------------------------------------------------
[528]2// Object3D.cc: Member functions for Object3D class.
[301]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// -----------------------------------------------------------------------
[244]28#include <iostream>
[658]29#include <sstream>
[393]30#include <duchamp/PixelMap/Voxel.hh>
31#include <duchamp/PixelMap/Scan.hh>
32#include <duchamp/PixelMap/Object2D.hh>
33#include <duchamp/PixelMap/Object3D.hh>
[238]34#include <vector>
[570]35#include <map>
[238]36
[252]37namespace PixelInfo
38{
[365]39  Object3D::Object3D()
40  {
41    this->numVox=0;
[570]42    this->xSum = 0;
43    this->ySum = 0;
44    this->zSum = 0;
45    this->xmin = this->xmax = this->ymin = this->ymax = this->zmin = this->zmax = -1;
[365]46  }
[570]47  //--------------------------------------------
[365]48
[270]49  Object3D::Object3D(const Object3D& o)
50  {
[365]51    operator=(o);
[252]52  }
53  //--------------------------------------------
54
[270]55  Object3D& Object3D::operator= (const Object3D& o)
56  {
57    if(this == &o) return *this;
[570]58    this->chanlist = o.chanlist;
[252]59    this->numVox  = o.numVox;
60    this->xSum    = o.xSum;
61    this->ySum    = o.ySum;
62    this->zSum    = o.zSum;
63    this->xmin    = o.xmin;
64    this->ymin    = o.ymin;
65    this->zmin    = o.zmin;
66    this->xmax    = o.xmax;
67    this->ymax    = o.ymax;
68    this->zmax    = o.zmax;
[270]69    return *this;
[252]70  }
71  //--------------------------------------------
[570]72
73  Object3D operator+ (Object3D lhs, Object3D rhs)
74  {
75    Object3D output = lhs;
76    for(std::map<long, Object2D>::iterator it = rhs.chanlist.begin(); it!=rhs.chanlist.end();it++)
77      output.addChannel(it->first, it->second);
[770]78      //      output.addChannel(*it);
[570]79    return output;
80  }
81
82  //--------------------------------------------
83  float Object3D::getXaverage()
84  {
85    if(numVox>0) return xSum/float(numVox);
86    else return 0.;
87  }
88  //--------------------------------------------
89
90  float Object3D::getYaverage()
91  {
92    if(numVox>0) return ySum/float(numVox);
93    else return 0.;
94  }
95  //--------------------------------------------
96
97  float Object3D::getZaverage()
98  {
99    if(numVox>0) return zSum/float(numVox);
100    else return 0.;
101  }
102  //--------------------------------------------
[243]103 
[252]104  bool Object3D::isInObject(long x, long y, long z)
105  {
[570]106    std::map<long,Object2D>::iterator it=this->chanlist.begin();
107    while(it!=this->chanlist.end() && it->first!=z) it++;
108
109    if(it==this->chanlist.end()) return false;
110    else                         return it->second.isInObject(x,y);
[238]111  }
[252]112  //--------------------------------------------
[238]113
[252]114  void Object3D::addPixel(long x, long y, long z)
115  {
[570]116 
117    std::map<long,Object2D>::iterator it=this->chanlist.begin();
118    while(it!=this->chanlist.end() && it->first!=z) it++;
[238]119
[570]120    if(it==this->chanlist.end()){ //new channel
121      Object2D obj;
122      obj.addPixel(x,y);
123      chanlist.insert( std::pair<int,Object2D>(z,obj) );
[252]124      // update the centres, min & max, as well as the number of voxels
125      if(this->numVox==0){
126        this->xSum = this->xmin = this->xmax = x;
127        this->ySum = this->ymin = this->ymax = y;
128        this->zSum = this->zmin = this->zmax = z;
129      }
130      else{
131        this->xSum += x;
132        this->ySum += y;
133        this->zSum += z;
134        if(x<this->xmin) this->xmin = x;
135        if(x>this->xmax) this->xmax = x;
136        if(y<this->ymin) this->ymin = y;
137        if(y>this->ymax) this->ymax = y;
[570]138        // since we've ordered the maplist, the min & max z fall out naturally
139        this->zmin = this->chanlist.begin()->first;
140        this->zmax = this->chanlist.rbegin()->first;
[252]141      }
142      this->numVox++;   
[246]143    }
[570]144    else{ // existing channel
145      // This method deals with the case of a new pixel being added AND
146      // with the new pixel already existing in the Object2D
147 
[252]148      // Remove that channel's information from the Object's information
[570]149      this->xSum -= it->second.xSum;
150      this->ySum -= it->second.ySum;
[776]151      this->zSum -= z*it->second.numPix;
152      this->numVox -= it->second.numPix;
[252]153
[570]154      // Add the pixel
155      it->second.addPixel(x,y);
[252]156   
[776]157      this->numVox += it->second.numPix;
[570]158      this->xSum += it->second.xSum;
159      this->ySum += it->second.ySum;
[776]160      this->zSum += z*it->second.numPix;
[246]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;
[252]165      // don't need to do anything to zmin/zmax -- the z-value is
166      // already in the list
[246]167    }
168
[238]169  }
[252]170  //--------------------------------------------
[238]171
[472]172  void Object3D::addScan(Scan s, long z)
173  {
174    long y=s.getY();
175    for(int x=s.getX(); x<=s.getXmax(); x++)
176      this->addPixel(x,y,z);
177  }
178
179  //--------------------------------------------
180
[770]181  // void Object3D::addChannel(const std::pair<long, Object2D> *chan)
182  // {
183  //   long z = chan->first;
184  //   Object2D
185  // }
186
187
[570]188  void Object3D::addChannel(const long &z, Object2D &obj)
[252]189  {
[238]190
[570]191    std::map<long,Object2D>::iterator it=this->chanlist.begin();
192    while(it!=this->chanlist.end() && it->first!=z) it++;
193
[577]194    if(it == this->chanlist.end()){ // channel z is not already in object, so add it.
[570]195      this->chanlist.insert(std::pair<long,Object2D>(z,obj));
[577]196      if(this->numVox == 0){ // if there are no other pixels, so initialise mins,maxs,sums
[570]197        this->xmin = obj.xmin;
198        this->xmax = obj.xmax;
199        this->ymin = obj.ymin;
200        this->ymax = obj.ymax;
201        this->zmin = this->zmax = z;
202        this->xSum = obj.xSum;
203        this->ySum = obj.ySum;
204        this->zSum = z * obj.getSize();
[252]205      }
[577]206      else{ // there are other pixels in other channels, so update mins, maxs, sums
[570]207        if(obj.xmin<this->xmin) this->xmin = obj.xmin;
208        if(obj.xmax>this->xmax) this->xmax = obj.xmax;
209        if(obj.ymin<this->ymin) this->ymin = obj.ymin;
210        if(obj.ymax>this->ymax) this->ymax = obj.ymax;
211        if(z<this->zmin) this->zmin = z;
212        if(z>this->zmax) this->zmax = z;
213        this->xSum += obj.xSum;
214        this->ySum += obj.ySum;
215        this->zSum += z * obj.getSize();
[252]216      }
[570]217      this->numVox += obj.getSize();
[246]218    }
[577]219    else{ // channel is already present, so need to combine objects.
[570]220      this->xSum -= it->second.xSum;
221      this->ySum -= it->second.ySum;
222      this->zSum -= z*it->second.getSize();
223      this->numVox -= it->second.getSize();
[577]224      it->second = it->second + obj;
[570]225      this->xSum += it->second.xSum;
226      this->ySum += it->second.ySum;
227      this->zSum += z*it->second.getSize();
228      this->numVox += it->second.getSize();
229      if(obj.xmin<this->xmin) this->xmin = obj.xmin;
230      if(obj.xmax>this->xmax) this->xmax = obj.xmax;
231      if(obj.ymin<this->ymin) this->ymin = obj.ymin;
232      if(obj.ymax>this->ymax) this->ymax = obj.ymax;
[252]233    }
[240]234  }
[419]235
[252]236  //--------------------------------------------
[238]237
[577]238  unsigned long Object3D::getSpatialSize()
[252]239  {
[570]240    Object2D spatialMap = this->getSpatialMap();
[252]241    return spatialMap.getSize();
[238]242  }
[252]243  //--------------------------------------------
[238]244
[252]245  Object2D Object3D::getSpatialMap()
246  {
[570]247    Object2D spatialMap;
248    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
249        it!=this->chanlist.end();it++){
250      spatialMap = spatialMap + it->second;
[252]251    }
252    return spatialMap;
[238]253  }
[252]254  //--------------------------------------------
[238]255 
[252]256  void Object3D::calcParams()
257  {
258    this->xSum = 0;
259    this->ySum = 0;
260    this->zSum = 0;
[570]261    this->numVox = 0;
[238]262
[570]263    this->zmin = this->chanlist.begin()->first;
264    this->zmax = this->chanlist.rbegin()->first;
265    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
266        it!=this->chanlist.end();it++){
[238]267
[570]268      it->second.calcParams();
269
270      if(it==this->chanlist.begin()){
271        this->xmin = it->second.getXmin();
272        this->xmax = it->second.getXmax();
273        this->ymin = it->second.getYmin();
274        this->ymax = it->second.getYmax();
[252]275      }
276      else{
[570]277        if(it->second.xmin<this->xmin) this->xmin = it->second.xmin;
278        if(it->second.xmax>this->xmax) this->xmax = it->second.xmax;
279        if(it->second.ymin<this->ymin) this->ymin = it->second.ymin;
280        if(it->second.ymax>this->ymax) this->ymax = it->second.ymax;
[252]281      }
282
[570]283      this->xSum += it->second.xSum;
284      this->ySum += it->second.ySum;
285      this->zSum += it->first * it->second.getSize();
286      this->numVox += it->second.getSize();
[252]287
[238]288    }
289
290  }
[252]291  //------------------------------------------------------
[238]292
[773]293  void Object3D::print(std::ostream& theStream)
[252]294  {
[773]295    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
296        it!=this->chanlist.end();it++){
297      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
298        theStream << *s << "," << it->first << "\n";
[244]299      }
[252]300    } 
301    theStream << "\n";
[773]302  }
303
304
305  std::ostream& operator<< ( std::ostream& theStream, Object3D& obj)
306  {
307    obj.print(theStream);
[270]308    return theStream;
[252]309  }
310  //--------------------------------------------
[241]311
[252]312  std::vector<Voxel> Object3D::getPixelSet()
313  {
[724]314    /// @details Returns a vector of the Voxels in the object. All
315    /// flux values are set to 0.
316
[252]317    std::vector<Voxel> voxList(this->numVox);
318    long count = 0;
[570]319    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
320        it!=this->chanlist.end();it++){
321      long z = it->first;
[773]322      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
323        long y = s->getY();
324        for(long x=s->getX(); x<=s->getXmax(); x++){
[252]325          voxList[count].setXYZF(x,y,z,0);
326          count++;
[241]327        }
[252]328      }
[241]329    }
[252]330    return voxList;
[243]331
332  }
333
[399]334  //--------------------------------------------------------------------
335
[724]336  std::vector<Voxel> Object3D::getPixelSet(float *array, long *dim)
337  {
338    /// @details Returns a vector of Voxels with the flux values for each voxel
339    /// taken from the array provided. No check is made as to whether
340    /// the pixels fall in the array boundaries
341    /// @param array Array of pixel values
342    /// @param dim Array of axis dimensions
343
344    std::vector<Voxel> voxList(this->numVox);
345    long count = 0;
346    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
347        it!=this->chanlist.end();it++){
348      long z = it->first;
[773]349      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
350        long y = s->getY();
351        for(long x=s->getX(); x<=s->getXmax(); x++){
[724]352          voxList[count].setXYZF(x,y,z,array[x+dim[0]*y+dim[0]*dim[1]*z]);
353          count++;
354        }
355      }
356    }
357    return voxList;
358
359  }
360
361  //--------------------------------------------------------------------
362
[570]363  std::vector<long> Object3D::getChannelList()
[399]364  {
[570]365
366    std::vector<long> chanlist;
367    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
368        it != this->chanlist.end(); it++){
369      chanlist.push_back(it->first);
370    }
371    return chanlist;
[399]372  }
[570]373
[399]374  //--------------------------------------------------------------------
375
[570]376  Object2D Object3D::getChanMap(long z)
377  {
378    Object2D obj;
379    std::map<long,Object2D>::iterator it=this->chanlist.begin();
380    while(it!=this->chanlist.end() && it->first!=z) it++;
381
382    if(it==this->chanlist.end()) obj = Object2D();
383    else obj = it->second;
384
385    return obj;
386  }
387
388  //--------------------------------------------------------------------
389
390  int Object3D::getMaxAdjacentChannels()
391  {
[691]392    /// @details Find the maximum number of contiguous channels in the
393    /// object. Since there can be gaps in the channels included in an
394    /// object, we run through the list of channels and keep track of
395    /// sizes of contiguous segments. Then return the largest size.
396
[570]397    int maxnumchan=0;
[691]398    int zcurrent=0, zprevious,zcount=0;
399    std::map<long, Object2D>::iterator it;
400    for(it = this->chanlist.begin(); it!=this->chanlist.end();it++)
[570]401      {
[691]402        if(it==this->chanlist.begin()){
403          zcount++;
404          zcurrent = it->first;
[570]405        }
[691]406        else{
407          zprevious = zcurrent;
408          zcurrent = it->first;
409          if(zcurrent-zprevious>1){
410            maxnumchan = std::max(maxnumchan, zcount);
411            zcount=1;
412          }
413          else zcount++;
414        }
[570]415      }
416    maxnumchan = std::max(maxnumchan,zcount);
417    return maxnumchan;
418  }
419
420  //--------------------------------------------------------------------
421
[399]422  void Object3D::addOffsets(long xoff, long yoff, long zoff)
[419]423  {
[658]424    std::map<long,Object2D> newmap;
425    for(std::map<long, Object2D>::iterator it = this->chanlist.begin(); it!=this->chanlist.end();it++){
426      std::pair<long,Object2D> newOne(it->first+zoff, it->second);
427      newOne.second.addOffsets(xoff,yoff);
428      newmap.insert(newOne);
429    }
430    this->chanlist.clear();
431    this->chanlist = newmap;
[570]432    if(this->numVox>0){
433      this->xSum += xoff*numVox;
434      this->xmin += xoff; this->xmax += xoff;
435      this->ySum += yoff*numVox;
436      this->ymin += yoff; this->ymax += yoff;
437      this->zSum += zoff*numVox;
438      this->zmin += zoff; this->zmax += zoff;
439    }
[419]440  }
[399]441
[658]442
443  duchamp::Section Object3D::getBoundingSection(int boundary)
444  {
445    std::stringstream ss;
446    ss << "[" << this->xmin-boundary <<":"<<this->xmax+boundary<<","<< this->ymin-boundary <<":"<<this->ymax+boundary<<","<< this->zmin-boundary <<":"<<this->zmax+boundary<<"]";
447    std::string sec=ss.str();
448    duchamp::Section section(sec);
449    return section;
450  }
451
[243]452}
Note: See TracBrowser for help on using the repository browser.