source: trunk/src/PixelMap/Object3D.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: 14.9 KB
Line 
1// -----------------------------------------------------------------------
2// Object3D.cc: Member functions for Object3D 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 <iostream>
29#include <sstream>
30#include <duchamp/PixelMap/Voxel.hh>
31#include <duchamp/PixelMap/Scan.hh>
32#include <duchamp/PixelMap/Object2D.hh>
33#include <duchamp/PixelMap/Object3D.hh>
34#include <vector>
35#include <map>
36
37namespace PixelInfo
38{
39  Object3D::Object3D()
40  {
41    this->numVox=0;
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;
46  }
47  //--------------------------------------------
48
49  Object3D::Object3D(const Object3D& o)
50  {
51    operator=(o);
52  }
53  //--------------------------------------------
54
55  Object3D& Object3D::operator= (const Object3D& o)
56  {
57    if(this == &o) return *this;
58    this->chanlist = o.chanlist;
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;
69    return *this;
70  }
71  //--------------------------------------------
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);
78      //      output.addChannel(*it);
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  //--------------------------------------------
103 
104  bool Object3D::isInObject(long x, long y, long z)
105  {
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);
111  }
112  //--------------------------------------------
113
114  void Object3D::addPixel(long x, long y, long z)
115  {
116 
117    std::map<long,Object2D>::iterator it=this->chanlist.begin();
118    while(it!=this->chanlist.end() && it->first!=z) it++;
119
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) );
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;
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;
141      }
142      this->numVox++;   
143    }
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 
148      // Remove that channel's information from the Object's information
149      long oldChanSize = it->second.numPix;
150      this->xSum -= it->second.xSum;
151      this->ySum -= it->second.ySum;
152      this->zSum -= z*oldChanSize;
153
154      // Add the pixel
155      it->second.addPixel(x,y);
156   
157      // and update the information...
158     long newChanSize = it->second.numPix;
159   
160      this->numVox += (newChanSize - oldChanSize);
161      this->xSum += it->second.xSum;
162      this->ySum += it->second.ySum;
163      this->zSum += z*newChanSize;
164      if(x<this->xmin) this->xmin = x;
165      if(x>this->xmax) this->xmax = x;
166      if(y<this->ymin) this->ymin = y;
167      if(y>this->ymax) this->ymax = y;
168      // don't need to do anything to zmin/zmax -- the z-value is
169      // already in the list
170    }
171
172  }
173  //--------------------------------------------
174
175  void Object3D::addScan(Scan s, long z)
176  {
177    long y=s.getY();
178    for(int x=s.getX(); x<=s.getXmax(); x++)
179      this->addPixel(x,y,z);
180  }
181
182  //--------------------------------------------
183
184  // void Object3D::addChannel(const std::pair<long, Object2D> *chan)
185  // {
186  //   long z = chan->first;
187  //   Object2D
188  // }
189
190
191  void Object3D::addChannel(const long &z, Object2D &obj)
192  {
193
194    std::map<long,Object2D>::iterator it=this->chanlist.begin();
195    while(it!=this->chanlist.end() && it->first!=z) it++;
196
197    if(it == this->chanlist.end()){ // channel z is not already in object, so add it.
198      this->chanlist.insert(std::pair<long,Object2D>(z,obj));
199      if(this->numVox == 0){ // if there are no other pixels, so initialise mins,maxs,sums
200        this->xmin = obj.xmin;
201        this->xmax = obj.xmax;
202        this->ymin = obj.ymin;
203        this->ymax = obj.ymax;
204        this->zmin = this->zmax = z;
205        this->xSum = obj.xSum;
206        this->ySum = obj.ySum;
207        this->zSum = z * obj.getSize();
208      }
209      else{ // there are other pixels in other channels, so update mins, maxs, sums
210        if(obj.xmin<this->xmin) this->xmin = obj.xmin;
211        if(obj.xmax>this->xmax) this->xmax = obj.xmax;
212        if(obj.ymin<this->ymin) this->ymin = obj.ymin;
213        if(obj.ymax>this->ymax) this->ymax = obj.ymax;
214        if(z<this->zmin) this->zmin = z;
215        if(z>this->zmax) this->zmax = z;
216        this->xSum += obj.xSum;
217        this->ySum += obj.ySum;
218        this->zSum += z * obj.getSize();
219      }
220      this->numVox += obj.getSize();
221    }
222    else{ // channel is already present, so need to combine objects.
223      this->xSum -= it->second.xSum;
224      this->ySum -= it->second.ySum;
225      this->zSum -= z*it->second.getSize();
226      this->numVox -= it->second.getSize();
227      it->second = it->second + obj;
228      this->xSum += it->second.xSum;
229      this->ySum += it->second.ySum;
230      this->zSum += z*it->second.getSize();
231      this->numVox += it->second.getSize();
232      if(obj.xmin<this->xmin) this->xmin = obj.xmin;
233      if(obj.xmax>this->xmax) this->xmax = obj.xmax;
234      if(obj.ymin<this->ymin) this->ymin = obj.ymin;
235      if(obj.ymax>this->ymax) this->ymax = obj.ymax;
236    }
237  }
238
239  //--------------------------------------------
240
241  unsigned long Object3D::getSpatialSize()
242  {
243    Object2D spatialMap = this->getSpatialMap();
244    return spatialMap.getSize();
245  }
246  //--------------------------------------------
247
248  Object2D Object3D::getSpatialMap()
249  {
250    Object2D spatialMap;
251    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
252        it!=this->chanlist.end();it++){
253      spatialMap = spatialMap + it->second;
254    }
255    return spatialMap;
256  }
257  //--------------------------------------------
258 
259  void Object3D::calcParams()
260  {
261    this->xSum = 0;
262    this->ySum = 0;
263    this->zSum = 0;
264    this->numVox = 0;
265
266    this->zmin = this->chanlist.begin()->first;
267    this->zmax = this->chanlist.rbegin()->first;
268    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
269        it!=this->chanlist.end();it++){
270
271      it->second.calcParams();
272
273      if(it==this->chanlist.begin()){
274        this->xmin = it->second.getXmin();
275        this->xmax = it->second.getXmax();
276        this->ymin = it->second.getYmin();
277        this->ymax = it->second.getYmax();
278      }
279      else{
280        if(it->second.xmin<this->xmin) this->xmin = it->second.xmin;
281        if(it->second.xmax>this->xmax) this->xmax = it->second.xmax;
282        if(it->second.ymin<this->ymin) this->ymin = it->second.ymin;
283        if(it->second.ymax>this->ymax) this->ymax = it->second.ymax;
284      }
285
286      this->xSum += it->second.xSum;
287      this->ySum += it->second.ySum;
288      this->zSum += it->first * it->second.getSize();
289      this->numVox += it->second.getSize();
290
291    }
292
293  }
294  //------------------------------------------------------
295
296  void Object3D::print(std::ostream& theStream)
297  {
298    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
299        it!=this->chanlist.end();it++){
300      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
301        theStream << *s << "," << it->first << "\n";
302      // for(int s=0;s<it->second.getNumScan();s++){
303      //        Scan tempscan = it->second.getScan(s);
304      //        theStream << tempscan << ", " << it->first << "\n";
305      }
306    } 
307    theStream << "\n";
308  }
309
310
311  std::ostream& operator<< ( std::ostream& theStream, Object3D& obj)
312  {
313    // for(std::map<long, Object2D>::iterator it = obj.chanlist.begin();
314    //  it!=obj.chanlist.end();it++){
315    //   for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
316    //  theStream << *s << "," << it->first << "\n";
317    //   // for(int s=0;s<it->second.getNumScan();s++){
318    //   //     Scan tempscan = it->second.getScan(s);
319    //   //     theStream << tempscan << ", " << it->first << "\n";
320    //   }
321    // } 
322    // theStream << "\n";
323    obj.print(theStream);
324    return theStream;
325  }
326  //--------------------------------------------
327
328  std::vector<Voxel> Object3D::getPixelSet()
329  {
330    /// @details Returns a vector of the Voxels in the object. All
331    /// flux values are set to 0.
332
333    std::vector<Voxel> voxList(this->numVox);
334    long count = 0;
335    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
336        it!=this->chanlist.end();it++){
337      long z = it->first;
338      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
339        long y = s->getY();
340        for(long x=s->getX(); x<=s->getXmax(); x++){
341          voxList[count].setXYZF(x,y,z,0);
342          count++;
343        }
344      // for(int s=0;s<it->second.getNumScan();s++){
345      //        Scan scn = it->second.getScan(s);
346      //        long y = scn.getY();
347      //        for(long x=scn.getX(); x<=scn.getXmax(); x++){
348      //          voxList[count].setXYZF(x,y,z,0);
349      //          count++;
350      //        }
351      }
352    }
353    return voxList;
354
355  }
356
357  //--------------------------------------------------------------------
358
359  std::vector<Voxel> Object3D::getPixelSet(float *array, long *dim)
360  {
361    /// @details Returns a vector of Voxels with the flux values for each voxel
362    /// taken from the array provided. No check is made as to whether
363    /// the pixels fall in the array boundaries
364    /// @param array Array of pixel values
365    /// @param dim Array of axis dimensions
366
367    std::vector<Voxel> voxList(this->numVox);
368    long count = 0;
369    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
370        it!=this->chanlist.end();it++){
371      long z = it->first;
372      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
373        long y = s->getY();
374        for(long x=s->getX(); x<=s->getXmax(); x++){
375          voxList[count].setXYZF(x,y,z,array[x+dim[0]*y+dim[0]*dim[1]*z]);
376          count++;
377        }
378      // for(int s=0;s<it->second.getNumScan();s++){
379      //        Scan scn = it->second.getScan(s);
380      //        long y = scn.getY();
381      //        for(long x=scn.getX(); x<=scn.getXmax(); x++){
382      //          voxList[count].setXYZF(x,y,z,array[x+dim[0]*y+dim[0]*dim[1]*z]);
383      //          count++;
384      //        }
385      }
386    }
387    return voxList;
388
389  }
390
391  //--------------------------------------------------------------------
392
393  std::vector<long> Object3D::getChannelList()
394  {
395
396    std::vector<long> chanlist;
397    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
398        it != this->chanlist.end(); it++){
399      chanlist.push_back(it->first);
400    }
401    return chanlist;
402  }
403
404  //--------------------------------------------------------------------
405
406  Object2D Object3D::getChanMap(long z)
407  {
408    Object2D obj;
409    std::map<long,Object2D>::iterator it=this->chanlist.begin();
410    while(it!=this->chanlist.end() && it->first!=z) it++;
411
412    if(it==this->chanlist.end()) obj = Object2D();
413    else obj = it->second;
414
415    return obj;
416  }
417
418  //--------------------------------------------------------------------
419
420  int Object3D::getMaxAdjacentChannels()
421  {
422    /// @details Find the maximum number of contiguous channels in the
423    /// object. Since there can be gaps in the channels included in an
424    /// object, we run through the list of channels and keep track of
425    /// sizes of contiguous segments. Then return the largest size.
426
427    int maxnumchan=0;
428    int zcurrent=0, zprevious,zcount=0;
429    std::map<long, Object2D>::iterator it;
430    for(it = this->chanlist.begin(); it!=this->chanlist.end();it++)
431      {
432        if(it==this->chanlist.begin()){
433          zcount++;
434          zcurrent = it->first;
435        }
436        else{
437          zprevious = zcurrent;
438          zcurrent = it->first;
439          if(zcurrent-zprevious>1){
440            maxnumchan = std::max(maxnumchan, zcount);
441            zcount=1;
442          }
443          else zcount++;
444        }
445      }
446    maxnumchan = std::max(maxnumchan,zcount);
447    return maxnumchan;
448  }
449
450  //--------------------------------------------------------------------
451
452  void Object3D::addOffsets(long xoff, long yoff, long zoff)
453  {
454    std::map<long,Object2D> newmap;
455    for(std::map<long, Object2D>::iterator it = this->chanlist.begin(); it!=this->chanlist.end();it++){
456      std::pair<long,Object2D> newOne(it->first+zoff, it->second);
457      newOne.second.addOffsets(xoff,yoff);
458      newmap.insert(newOne);
459    }
460    this->chanlist.clear();
461    this->chanlist = newmap;
462    if(this->numVox>0){
463      this->xSum += xoff*numVox;
464      this->xmin += xoff; this->xmax += xoff;
465      this->ySum += yoff*numVox;
466      this->ymin += yoff; this->ymax += yoff;
467      this->zSum += zoff*numVox;
468      this->zmin += zoff; this->zmax += zoff;
469    }
470  }
471
472
473  duchamp::Section Object3D::getBoundingSection(int boundary)
474  {
475    std::stringstream ss;
476    ss << "[" << this->xmin-boundary <<":"<<this->xmax+boundary<<","<< this->ymin-boundary <<":"<<this->ymax+boundary<<","<< this->zmin-boundary <<":"<<this->zmax+boundary<<"]";
477    std::string sec=ss.str();
478    duchamp::Section section(sec);
479    return section;
480  }
481
482}
Note: See TracBrowser for help on using the repository browser.