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

Last change on this file since 927 was 927, checked in by MatthewWhiting, 12 years ago

Fixing #139 - making the spatial map a member of Object3D, so that adding a pixel to the Object3D also results in adding the x,y combination to the spatial map. We then just rapidly return the spatial map when needed instead of calculating it each time.

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