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

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

A better way of initialising the Section - the subsection string is set to the null string, and checks are made against that in the parsing.

File size: 11.3 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->subsection = "";
42    this->numSections = 0;
43    this->flagParsed = false;
44  }
45
46  Section::Section(const Section& s)
47  {
48    operator=(s);
49  }
50  //--------------------------------------------
51 
52  Section& Section::operator= (const Section& s)
53  {
54    if(this == &s) return *this;
55    this->flagParsed    = s.flagParsed;
56    this->subsection  = s.subsection;
57    this->sections    = s.sections;
58    this->numSections = s.numSections;
59    this->starts      = s.starts;
60    this->dims        = s.dims;
61    return *this;
62  }
63  //--------------------------------------------
64
65  OUTCOME Section::parse(long *dimAxes, int size)
66  {
67    std::vector<size_t> vecDim(size);
68    for(int i=0;i<size;i++) vecDim[i] = dimAxes[i];
69    return this->parse(vecDim);
70  }
71
72  OUTCOME Section::parse(size_t *dimAxes, int size)
73  {
74    std::vector<size_t> vecDim(size);
75    for(int i=0;i<size;i++) vecDim[i] = dimAxes[i];
76    return this->parse(vecDim);
77  }
78
79  OUTCOME Section::parse(std::vector<int> dimAxes)
80  {
81    std::vector<size_t> vecDim(dimAxes.size());
82    for(size_t i=0;i<dimAxes.size();i++) vecDim[i] = long(dimAxes[i]);
83    return this->parse(vecDim);
84  }
85
86  OUTCOME Section::parse(std::vector<long> dimAxes)
87  {
88    std::vector<size_t> vecDim(dimAxes.size());
89    for(size_t i=0;i<dimAxes.size();i++) vecDim[i] = long(dimAxes[i]);
90    return this->parse(vecDim);
91  }
92
93  OUTCOME Section::parse(std::vector<size_t> dimAxes)
94  {
95    /// @details
96    /// This function reads the subsection string, and registers the
97    /// starting values and lengths for each dimension. The array of axis
98    /// dimensions is needed to know how long each axis really is, and
99    /// whether we have strayed over the limit or not.
100    ///
101    /// Note that steps in the subsection string are not dealt with -- a
102    /// warning message is written to the screen, and the step values are
103    /// removed from the subsection string.
104    ///
105    /// The function also does basic checks to make sure it is of the
106    /// correct format (ie. has square brackets delimiting it) and the
107    /// correct number of sections, returning a FAILURE if either of
108    /// these checks fail.
109    ///
110    /// \param dimAxes The array of axis dimensions, of which the
111    ///                 Section is a subsection.
112    /// \return SUCCESS/FAILURE (from duchamp.hh)
113
114    std::stringstream errmsg;
115
116    // Return an error if we haven't set the subsection yet.
117    if(this->subsection == ""){
118        DUCHAMPERROR("Section parsing", "Subsection has not yet been defined.");
119        return FAILURE;
120    }
121
122    // First Make sure subsection has [ and ] at ends
123    if((this->subsection[0]!='[') ||
124       (this->subsection[this->subsection.size()-1]!=']')){
125      DUCHAMPERROR("Section parsing","Subsection needs to be delimited by square brackets -- You provided: " << this->subsection);
126      return FAILURE;
127    }
128
129    this->starts.clear();
130    this->dims.clear();
131 
132    this->numSections=1;
133    for(size_t i=0;i<this->subsection.size();i++)
134      if(this->subsection[i]==',') this->numSections++;
135
136    if(numSections!=dimAxes.size()){
137      DUCHAMPERROR("Section parsing","Subsection " << this->subsection << " has "<<numSections <<" sections, compared to a cube with " << dimAxes.size() << " axes");
138      return FAILURE;
139    }
140
141    this->starts.resize(this->numSections);
142    this->dims.resize(this->numSections);
143    this->sections.resize(this->numSections);
144
145    std::vector<std::string> tempsections(numSections);
146    // this will hold the section strings for each dimension
147    std::stringstream ss;
148    ss.str(this->subsection);
149    bool removeStep = false;
150    bool doingBorders = false;
151    std::string temp;
152
153    getline(ss,temp,'[');
154    for(size_t i=0;i<numSections-1;i++){
155      getline(ss,temp,',');
156      tempsections[i]=temp;
157    }
158    getline(ss,temp,']');
159    tempsections[numSections-1]=temp;
160
161    for(size_t str=0;str<numSections;str++){
162      if(tempsections[str]=="*"){
163        this->starts[str] = 0;
164        this->dims[str]= dimAxes[str];
165        this->sections[str] = tempsections[str];
166      }
167      else{
168        int numColon=0;
169        for(size_t i=0;i<tempsections[str].size();i++){
170          if(tempsections[str][i]==':'){
171            tempsections[str][i]=' ';
172            numColon++;
173          }
174        }
175        int a,b,c;
176        std::stringstream readString,fixedString;
177        readString.str(tempsections[str]);
178        switch(numColon){
179        case 1: // usual case
180          readString >> a >> b;
181          this->starts[str] = a-1;
182          this->dims[str] = b-a+1;
183          fixedString << a << ":" << b;
184          this->sections[str] = fixedString.str();
185          break;
186        case 0: // borders case -- so many off each border
187          readString >> a;
188          if(a>=int(dimAxes[str])/2){
189            DUCHAMPERROR("Section parsing", "You requested the subsection " << this->subsection << " but axis #" << str+1 <<" has zero size, since its dimension is " << dimAxes[str]);
190            return FAILURE;
191          }
192          this->starts[str] = a;
193          this->dims[str] = dimAxes[str]-2*a;
194          fixedString << this->starts[str]+1 << ":"
195                      << this->getEnd(str)+1;
196          this->sections[str] = fixedString.str();
197          doingBorders=true;
198          break;
199        case 2: // subsection involves a step
200        default:
201          readString>> a >> b >> c;
202          this->starts[str] = a-1;
203          this->dims[str] = b-a+1;
204          fixedString << a << ":" << b;
205          this->sections[str] = fixedString.str();
206          removeStep=true;
207          break;
208        }
209
210      }
211    }
212
213    if(removeStep){  // if there was a step present
214      errmsg.str("");
215      errmsg << "The subsection given is " << this->subsection <<".\n"
216             << "Duchamp is currently unable to deal with pixel steps"
217             << " in the subsection.\n"
218             << "These have been ignored, and so the subection used is ";
219    }
220
221    if(removeStep || doingBorders){
222      // rewrite subsection without any step sizes and with correct borders.
223      this->subsection = "[" + this->sections[0];
224      for(size_t str=1;str<numSections;str++)
225        this->subsection += ',' + this->sections[str];
226      this->subsection += "]";
227    }
228
229    if(removeStep){
230      errmsg << this->subsection;
231      DUCHAMPWARN("Section parsing", errmsg);
232    }
233
234    this->flagParsed = true;
235    return SUCCESS;
236 
237  }
238
239  std::string nullSection(int ndim)
240  {
241    std::stringstream ss;
242    ss << "[";
243    for(int i=0;i<ndim-1;i++) ss << "*,";
244    ss << "*]";
245    return ss.str();
246  }
247
248  bool Section::isValid()
249  {
250    /// @details A test to see whether each of the axis sections have
251    /// a positive length. If at least one of them has zero or
252    /// negative length, or if the section has not yet been parsed,
253    /// then false is returned. If everything is OK, then we get true.
254
255    bool valid = (this->numSections>0);
256    for(size_t i=0;i<this->dims.size()&&valid;i++){
257      valid = valid && dims[i]>0;
258    }
259    return valid;
260  }
261
262  Section Section::intersect(Section &other)
263  {
264    /// @details Return a Section object that is the intersection
265    /// between the current section and another. The returned section
266    /// only has its section string set, so it will need to be parsed
267    /// afterwards.
268   
269    if(this->numSections != other.numSections){
270      DUCHAMPERROR("Section::intersect", "Sizes of sections not equal - returning initial section");
271      return *this;
272    }
273
274    std::vector<std::string> outputsections(this->numSections);
275    for(size_t i=0;i<this->numSections;i++){
276      std::stringstream ss;
277      ss << std::max(this->starts[i],other.starts[i])+1 << ":" << std::min(this->getEnd(i),other.getEnd(i))+1;
278      outputsections[i] = ss.str();
279    }
280         
281    std::stringstream section;
282    section << "[" << outputsections[0];
283    for(size_t i=1;i<this->numSections;i++) section<<"," << outputsections[i];
284    section << "]";
285    duchamp::Section output;
286    output.setSection(section.str());
287    return output;
288
289  }
290
291  Section Section::intersect(long *dimAxes, int size)
292  {
293    std::vector<long> vecDim(size);
294    for(int i=0;i<size;i++) vecDim[i] = dimAxes[i];
295    return this->intersect(vecDim);
296  }
297
298  Section Section::intersect(std::vector<int> dimAxes)
299  {
300    std::vector<long> vecDim(dimAxes.size());
301    for(size_t i=0;i<dimAxes.size();i++) vecDim[i] = long(dimAxes[i]);
302    return this->intersect(vecDim);
303  }
304
305  Section Section::intersect(std::vector<long> dimAxes)
306  {
307   
308    std::string nullSec = nullSection(dimAxes.size());
309    Section null(nullSec);
310    null.parse(dimAxes);
311    return this->intersect(null);
312
313  }
314
315  Section operator* (Section &lhs, Section &rhs)
316  {
317    /// @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).
318    /// So, [10:20,20:40] * [4:7,12:15] = [13:16,31:34]
319    /// Note this is not commutative!
320   
321    if(lhs.numSections != rhs.numSections){
322      std::stringstream ss;
323      ss << "Sizes of sections not equal - you requested " << lhs.subsection << " * " << rhs.subsection << ", with " << lhs.numSections << " and " << rhs.numSections << " sections each.\n";
324      DUCHAMPERROR("Section::operator*", "Sizes of sections not equal - you requested " << lhs.subsection << " * " << rhs.subsection << ", with " << lhs.numSections << " and " << rhs.numSections << " sections each.");
325      return lhs;
326    }
327
328    std::vector<std::string> outputsections(lhs.numSections);
329    for(size_t i=0;i<lhs.numSections;i++){
330      std::stringstream ss;
331      int minval=std::min(lhs.starts[i]+rhs.starts[i],lhs.starts[i]+lhs.dims[i])+1;
332      int maxval=std::min(lhs.starts[i]+rhs.starts[i]+rhs.dims[i],lhs.starts[i]+lhs.dims[i]);
333      //      ss << lhs.starts[i]+rhs.starts[i]+1 << ":" << lhs.starts[i]+rhs.starts[i]+rhs.dims[i];
334      ss << minval << ":"<<maxval;
335      outputsections[i] = ss.str();
336    }
337         
338    std::stringstream section;
339    section << "[" << outputsections[0];
340    for(size_t i=1;i<lhs.numSections;i++) section<<"," << outputsections[i];
341    section << "]";
342    duchamp::Section output;
343    output.setSection(section.str());
344    return output;
345
346  }
347
348
349}
Note: See TracBrowser for help on using the repository browser.