source: trunk/src/Utils/Section.cc @ 880

Last change on this file since 880 was 879, checked in by MatthewWhiting, 12 years ago
  • New operator * for Section, to apply a subsection of a subsection (used by Cube::slice)
  • Adding a flagParsed member, so we can easily track whether a Section has been parsed.
File size: 10.9 KB
Line 
1// -----------------------------------------------------------------------
2// Section.cc: Member functions for the Section class, particularly
3//             how to interpret the subsection string.
4// -----------------------------------------------------------------------
5// Copyright (C) 2006, Matthew Whiting, ATNF
6//
7// This program is free software; you can redistribute it and/or modify it
8// under the terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 2 of the License, or (at your
10// option) any later version.
11//
12// Duchamp is distributed in the hope that it will be useful, but WITHOUT
13// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15// for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with Duchamp; if not, write to the Free Software Foundation,
19// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20//
21// Correspondence concerning Duchamp may be directed to:
22//    Internet email: Matthew.Whiting [at] atnf.csiro.au
23//    Postal address: Dr. Matthew Whiting
24//                    Australia Telescope National Facility, CSIRO
25//                    PO Box 76
26//                    Epping NSW 1710
27//                    AUSTRALIA
28// -----------------------------------------------------------------------
29#include <string>
30#include <vector>
31#include <iostream>
32#include <sstream>
33#include <duchamp/Utils/Section.hh>
34#include <duchamp/duchamp.hh>
35
36namespace duchamp
37{
38
39  Section::Section()
40  {
41    this->numSections = 0;
42    this->flagParsed = false;
43  }
44
45  Section::Section(const Section& s)
46  {
47    operator=(s);
48  }
49  //--------------------------------------------
50 
51  Section& Section::operator= (const Section& s)
52  {
53    if(this == &s) return *this;
54    this->flagParsed    = s.flagParsed;
55    this->subsection  = s.subsection;
56    this->sections    = s.sections;
57    this->numSections = s.numSections;
58    this->starts      = s.starts;
59    this->dims        = s.dims;
60    return *this;
61  }
62  //--------------------------------------------
63
64  OUTCOME Section::parse(long *dimAxes, int size)
65  {
66    std::vector<long> vecDim(size);
67    for(int i=0;i<size;i++) vecDim[i] = dimAxes[i];
68    return this->parse(vecDim);
69  }
70
71  OUTCOME Section::parse(std::vector<int> dimAxes)
72  {
73    std::vector<long> vecDim(dimAxes.size());
74    for(size_t i=0;i<dimAxes.size();i++) vecDim[i] = long(dimAxes[i]);
75    return this->parse(vecDim);
76  }
77
78  OUTCOME Section::parse(std::vector<long> dimAxes)
79  {
80    /// @details
81    /// This function reads the subsection string, and registers the
82    /// starting values and lengths for each dimension. The array of axis
83    /// dimensions is needed to know how long each axis really is, and
84    /// whether we have strayed over the limit or not.
85    ///
86    /// Note that steps in the subsection string are not dealt with -- a
87    /// warning message is written to the screen, and the step values are
88    /// removed from the subsection string.
89    ///
90    /// The function also does basic checks to make sure it is of the
91    /// correct format (ie. has square brackets delimiting it) and the
92    /// correct number of sections, returning a FAILURE if either of
93    /// these checks fail.
94    ///
95    /// \param dimAxes The array of axis dimensions, of which the
96    ///                 Section is a subsection.
97    /// \return SUCCESS/FAILURE (from duchamp.hh)
98
99    std::stringstream errmsg;
100
101    // First Make sure subsection has [ and ] at ends
102    if((this->subsection[0]!='[') ||
103       (this->subsection[this->subsection.size()-1]!=']')){
104      errmsg.str("");
105      errmsg << "Subsection needs to be delimited by square brackets\n"
106             << "You provided: " << this->subsection << std::endl;
107      duchampError("Section parsing",errmsg.str());
108      return FAILURE;
109    }
110
111    this->starts.clear();
112    this->dims.clear();
113 
114    this->numSections=1;
115    for(size_t i=0;i<this->subsection.size();i++)
116      if(this->subsection[i]==',') this->numSections++;
117
118    if(numSections!=dimAxes.size()){
119      errmsg.str("");
120      errmsg << "Subsection has "<<numSections
121             <<" sections, compared to a cube with "
122             << dimAxes.size() << " axes\n"
123             << "Subsection provided was: " << this->subsection << std::endl;
124      duchampError("Section parsing",errmsg.str());
125      return FAILURE;
126    }
127
128    this->starts.resize(this->numSections);
129    this->dims.resize(this->numSections);
130    this->sections.resize(this->numSections);
131
132    std::vector<std::string> tempsections(numSections);
133    // this will hold the section strings for each dimension
134    std::stringstream ss;
135    ss.str(this->subsection);
136    bool removeStep = false;
137    bool doingBorders = false;
138    std::string temp;
139
140    getline(ss,temp,'[');
141    for(size_t i=0;i<numSections-1;i++){
142      getline(ss,temp,',');
143      tempsections[i]=temp;
144    }
145    getline(ss,temp,']');
146    tempsections[numSections-1]=temp;
147
148    for(size_t str=0;str<numSections;str++){
149      if(tempsections[str]=="*"){
150        this->starts[str] = 0;
151        this->dims[str]= dimAxes[str];
152        this->sections[str] = tempsections[str];
153      }
154      else{
155        int numColon=0;
156        for(size_t i=0;i<tempsections[str].size();i++){
157          if(tempsections[str][i]==':'){
158            tempsections[str][i]=' ';
159            numColon++;
160          }
161        }
162        int a,b,c;
163        std::stringstream readString,fixedString;
164        readString.str(tempsections[str]);
165        switch(numColon){
166        case 1: // usual case
167          readString >> a >> b;
168          this->starts[str] = a-1;
169          this->dims[str] = b-a+1;
170          fixedString << a << ":" << b;
171          this->sections[str] = fixedString.str();
172          break;
173        case 0: // borders case -- so many off each border
174          readString >> a;
175          if(a>=dimAxes[str]/2){
176            errmsg.str("");
177            errmsg<< "You requested the subsection " << this->subsection
178                  << " but axis #" << str+1
179                  <<" has zero size, since its dimension is " << dimAxes[str]
180                  <<".\nI'm not going to parse this! Go and fix it.\n";
181            duchampError("Section parsing", errmsg.str());
182            return FAILURE;
183          }
184          this->starts[str] = a;
185          this->dims[str] = dimAxes[str]-2*a;
186          fixedString << this->starts[str]+1 << ":"
187                      << this->getEnd(str)+1;
188          this->sections[str] = fixedString.str();
189          doingBorders=true;
190          break;
191        case 2: // subsection involves a step
192        default:
193          readString>> a >> b >> c;
194          this->starts[str] = a-1;
195          this->dims[str] = b-a+1;
196          fixedString << a << ":" << b;
197          this->sections[str] = fixedString.str();
198          removeStep=true;
199          break;
200        }
201
202      }
203    }
204
205    if(removeStep){  // if there was a step present
206      errmsg.str("");
207      errmsg << "The subsection given is " << this->subsection <<".\n"
208             << "Duchamp is currently unable to deal with pixel steps"
209             << " in the subsection.\n"
210             << "These have been ignored, and so the subection used is ";
211    }
212
213    if(removeStep || doingBorders){
214      // rewrite subsection without any step sizes and with correct borders.
215      this->subsection = "[" + this->sections[0];
216      for(size_t str=1;str<numSections;str++)
217        this->subsection += ',' + this->sections[str];
218      this->subsection += "]";
219    }
220
221    if(removeStep){
222      errmsg << this->subsection << std::endl;
223      duchampWarning("Section parsing", errmsg.str());
224    }
225
226    this->flagParsed = true;
227    return SUCCESS;
228 
229  }
230
231  std::string nullSection(int ndim)
232  {
233    std::stringstream ss;
234    ss << "[";
235    for(int i=0;i<ndim-1;i++) ss << "*,";
236    ss << "*]";
237    return ss.str();
238  }
239
240  bool Section::isValid()
241  {
242    /// @details A test to see whether each of the axis sections have
243    /// a positive length. If at least one of them has zero or
244    /// negative length, or if the section has not yet been parsed,
245    /// then false is returned. If everything is OK, then we get true.
246
247    bool valid = (this->numSections>0);
248    for(size_t i=0;i<this->dims.size()&&valid;i++){
249      valid = valid && dims[i]>0;
250    }
251    return valid;
252  }
253
254  Section Section::intersect(Section &other)
255  {
256    /// @details Return a Section object that is the intersection
257    /// between the current section and another. The returned section
258    /// only has its section string set, so it will need to be parsed
259    /// afterwards.
260   
261    if(this->numSections != other.numSections){
262      duchampError("Section::intersect", "Sizes of sections not equal - returning initial section");
263      return *this;
264    }
265
266    std::vector<std::string> outputsections(this->numSections);
267    for(size_t i=0;i<this->numSections;i++){
268      std::stringstream ss;
269      ss << std::max(this->starts[i],other.starts[i])+1 << ":" << std::min(this->getEnd(i),other.getEnd(i))+1;
270      outputsections[i] = ss.str();
271    }
272         
273    std::stringstream section;
274    section << "[" << outputsections[0];
275    for(size_t i=1;i<this->numSections;i++) section<<"," << outputsections[i];
276    section << "]";
277    duchamp::Section output;
278    output.setSection(section.str());
279    return output;
280
281  }
282
283  Section Section::intersect(long *dimAxes, int size)
284  {
285    std::vector<long> vecDim(size);
286    for(int i=0;i<size;i++) vecDim[i] = dimAxes[i];
287    return this->intersect(vecDim);
288  }
289
290  Section Section::intersect(std::vector<int> dimAxes)
291  {
292    std::vector<long> vecDim(dimAxes.size());
293    for(size_t i=0;i<dimAxes.size();i++) vecDim[i] = long(dimAxes[i]);
294    return this->intersect(vecDim);
295  }
296
297  Section Section::intersect(std::vector<long> dimAxes)
298  {
299   
300    std::string nullSec = nullSection(dimAxes.size());
301    Section null(nullSec);
302    null.parse(dimAxes);
303    return this->intersect(null);
304
305  }
306
307  Section operator* (Section &lhs, Section &rhs)
308  {
309    /// @details Return a Section object that is the combination of two subsections. The second subsection indicates the pixel ranges *within* the ranges of the first, and the output is in the same global units as the first (this).
310    /// So, [10:20,20:40] * [4:7,12:15] = [13:16,31:34]
311    /// Note this is not commutative!
312   
313    if(lhs.numSections != rhs.numSections){
314      std::stringstream ss;
315      ss << "Sizes of sections not equal - you requested " << lhs.subsection << " * " << rhs.subsection << ", with " << lhs.numSections << " and " << rhs.numSections << " sections each.\n";
316      duchampError("Section::operator*", ss.str());
317      return lhs;
318    }
319
320    std::vector<std::string> outputsections(lhs.numSections);
321    for(size_t i=0;i<lhs.numSections;i++){
322      std::stringstream ss;
323      int minval=std::min(lhs.starts[i]+rhs.starts[i],lhs.starts[i]+lhs.dims[i])+1;
324      int maxval=std::min(lhs.starts[i]+rhs.starts[i]+rhs.dims[i],lhs.starts[i]+lhs.dims[i]);
325      //      ss << lhs.starts[i]+rhs.starts[i]+1 << ":" << lhs.starts[i]+rhs.starts[i]+rhs.dims[i];
326      ss << minval << ":"<<maxval;
327      outputsections[i] = ss.str();
328    }
329         
330    std::stringstream section;
331    section << "[" << outputsections[0];
332    for(size_t i=1;i<lhs.numSections;i++) section<<"," << outputsections[i];
333    section << "]";
334    duchamp::Section output;
335    output.setSection(section.str());
336    return output;
337
338  }
339
340
341}
Note: See TracBrowser for help on using the repository browser.