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

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

Ticket #181 - Implementing the new catalogue writing, with new functions in Cube to handle the overall reading & writing. Briefly tested and seems to work OK. A couple of minor bug fixes as well, one in particular with the baseline-writing.

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