Sampler.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef DRAIN_SAMPLER_H_
32 #define DRAIN_SAMPLER_H_
33 
34 
35 #include <vector>
36 #include <iostream>
37 #include <sstream>
38 #include <string>
39 
40 #include <drain/FlexibleVariable.h>
41 
42 
43 #include "drain/util/BeanLike.h"
44 #include "drain/util/IosFormat.h"
45 #include "drain/util/Range.h"
46 #include "drain/util/ReferenceMap.h"
47 #include "drain/util/StringMapper.h"
48 #include "drain/image/Image.h"
49 
50 namespace drain
51 {
52 
53 namespace image
54 {
55 
57 
61 struct SamplePicker {
62 
66  inline
67  //SamplePicker(ReferenceMap & variableMap) : variableMap(variableMap) {
69  infoMap["width"].link(width = 0);
70  infoMap["height"].link(height = 0);
71  }
72 
73  virtual inline
74  ~SamplePicker(){};
75 
76  void setSize(int w, int h){
77  width = w;
78  height = h;
79  }
80 
82  virtual
83  inline
84  void setPosition(int i, int j) const {
85  current_i = i;
86  current_j = j;
87  current_j2 = height-1 - j;
88  }
89 
90  // TODO: min/max coord control, like CoordHandler for checking min and max.
91  //bool checkPosition()
92 
94  //virtual
95  //void writeHeader(char commentPrefix, std::ostream & ostr) const {};
96 
97 
99  mutable int current_i = 0;
100 
102  mutable int current_j = 0;
103 
105  mutable int current_j2 = 0;
106 
107  int width = 0;
108  int height = 0;
109 
112 
116 
117 };
118 
120 
123 class ImageReader : public SamplePicker {
124 
125 public:
126 
127  inline
128  ImageReader(ReferenceMap2<> & ref) : SamplePicker(ref) {//static int dummy;
129  variableMap.link("i", current_i = 0);
130  variableMap.link("j", current_j = 0);
131  variableMap.link("j2", current_j2 = 0);
132  }
133 
134  inline
135  bool getValue(const ImageFrame & image, double & value) const {
136  //value = image.get<double>(current_i, current_j);
137  // if (mode==SCALED ?
138  value = image.getScaled(current_i, current_j);
139  //value = image.get<double>(current_i, current_j);
140  //std::cerr << current_i << ',' << current_j << '\t' << value << '\n';
141  return true;
142  }
143 
144 
145 };
146 
148 
152 class Sampler : public BeanLike {
153 
154 public:
155 
156  Sampler();
157 
158  inline
159  Sampler(const Sampler &sampler) : BeanLike(sampler){
160  parameters.copyStruct(sampler.getParameters(), sampler, *this);
161  };
162 
163  // Named conf, to separate ImageMod::parameters (BeanLike)
164  //ReferenceMap conf;
165 
166  int iStep = 10;
167  int jStep = 0;
168 
169  drain::Range<int> iRange = {-1,1};
170  drain::Range<int> jRange = {-1,1};
171 
173  std::string commentPrefix = "#";
174 
175 
176  // was already DEPRECATING...
178  bool skipVoid = false ;
179  //std::string skipVoid = "false";
180  std::string voidComment = "void";
181 
182  // NEW
183  std::string handleVoid = "null"; // "false","skip"
184 
185 
187  mutable
189 
191  char getCommentChar() const;
192 
194  std::string getFormat(const std::string & formatStr) const;
195 
196 
198 
209  template <class D, class P>
210  void sample(const std::map<std::string, D> & images, const P & picker, const std::string & formatStr, std::ostream & ostr = std::cout) const { // std::string format copy ok
211 
212  drain::Logger mout(__FUNCTION__, getName());
213 
214  if (images.empty()){
215  mout.error("no image data (channels) provided: " );
216  return;
217  }
218 
219  const bool SKIP_VOID = (handleVoid == "skip") || (skipVoid == true);
220 
221  const bool MARK_VOID = (handleVoid != "skip");
222 
223  double voidMarker = NAN;
224  if (handleVoid != "null"){
225  StringTools::convert(handleVoid, voidMarker);
226  }
227 
228  // Save initial formatting data
229 
230  //mout.special("fieldWidth: " , fieldWidth , ", fillChar=" , fillChar );
231  mout.debug2("variables (initially): " , variableMap.getKeys() );
232 
234  // Note: supports leading minus sign
235  drain::StringMapper formatter("-?[a-zA-Z0-9_]+"); // WAS: "-?[a-zA-Z0-9_]+" with odd "-?"
236  // format = drain::StringTools::replace(format, "\\n", "\n");
237  // format = drain::StringTools::replace(format, "\\t", "\t");
238  std::string format = getFormat(formatStr);
239  formatter.parse(format, true); // convert escaped, eg. "\\n" -> "\n"
240  formatter.iosFormat.copyFrom(ostr);
241  mout.special("iosFormat: " , formatter.iosFormat );
242 
243  // std::string format = getFormat(formatStr);
244 
245  // Service: associate file keys with data
246  // mout.debug("check minus" );
247  std::map<std::string, double> values;
248  static const std::string minusStr("-");
249  for (typename std::map<std::string, D>::const_iterator it = images.begin(); it != images.end(); ++it){
250  const std::string & key = it->first;
251  mout.debug2("referencing: " , key , ',' , minusStr , key );
252  variableMap.link(key, values[key]=0);
253  variableMap.link(minusStr+key, values[minusStr+key]=0);
254  }
255  mout.debug("variables: " , variableMap );
256 
257 
258 
259  const int iStep = this->iStep;
260  const int jStep = (this->jStep > 0) ? this->jStep : iStep;
261 
262  const char commentChar = getCommentChar();
263  if (commentChar){
265 
266  // ostr << commentChar << " TEST\n";
267  // picker.writeHeader(commentChar, ostr);
268  // ostr << commentChar << " size='" << picker.width << 'x' << picker.height << "'\n";
269 
270  ostr << commentChar << commentChar << " input properties " << '\n';
271 
272  for (const auto & entry: picker.infoMap){
273  ostr << commentChar << ' ' << entry.first << '=';
274  //it->second.valueToJSON(ostr);
275  Sprinter::toStream(ostr, entry.second, Sprinter::jsonLayout);
276  ostr << '\n';
277  }
278 
279  ostr << commentChar << commentChar << " sampling parameters " << '\n';
280 
281  for (const auto & entry: parameters){
282  ostr << commentChar << ' ' << entry.first << '=';
283  // it->second.valueToJSON(ostr);
284  Sprinter::toStream(ostr, entry.second, Sprinter::jsonLayout);
285  ostr << '\n';
286  }
287  if (!formatStr.empty())
288  ostr << commentChar << " format='" << formatStr << "'\n"; // formatStr instead of format, to save double slash \\n \\t
289  else
290  ostr << commentChar << " format='" << format << "'\n";
291 
292  ostr << commentChar << commentChar << " resulting geometry " << '\n';
293  const int iN = picker.width/iStep;
294  const int jN = picker.height/jStep;
295  ostr << commentChar << " rows=" << iN << "\n";
296  ostr << commentChar << " rols=" << jN << "\n";
297  ostr << commentChar << " samples=" << (iN*jN) << "\n";
298 
299 
300  }
301 
302 
303  int iStart = this->iRange.min; // this->iStart;
304  if (iStart < 0)
305  iStart = iStep/2;
306 
307  int jStart = this->jRange.min; //jStart;
308  if (jStart < 0)
309  jStart = jStep/2;
310 
311  int iEnd = this->iRange.max; // iEnd;
312  if (iEnd < iStart)
313  iEnd = picker.width-1;
314 
315  int jEnd = this->jRange.max; // jEnd;
316  if (jEnd < jStart)
317  jEnd = picker.height-1;
318 
319 
320  // Main loop: traverse image area with (i,j)
321  // SamplePicker has set variableMap references (ie. geographical coords j2=(height-1-j) ).
322  double x;
323  bool dataOk;
324  for (int j = jStart; j<=jEnd; j+=jStep){
325  for (int i = iStart; i<=iEnd; i+=iStep){
326 
327  picker.setPosition(i, j);
328 
329  // SLOW, but works... // TODO speedup with iterator
330  dataOk = true;
331  for (typename std::map<std::string, D>::const_iterator it = images.begin(); it != images.end(); ++it){
332  const std::string & quantity = it->first;
333  const D & data = it->second;
334  if (!picker.getValue(data, x)){
335  dataOk = false;
336  if (MARK_VOID){
337  x = voidMarker;
338  }
339  }
340  //else if (x != 0) std::cerr << x << '\t';
341 
342  values[quantity] = x;
343  values[minusStr+quantity] = -x;
344  }
345 
346  if (dataOk || !SKIP_VOID){
347  //if (dataOk || (skipVoid==0)){
348  //formatter.toStream(ostr, variableMap, true);
349  formatter.toStream(ostr, variableMap, -1); // leaves ${variable} ?
350  if ((!dataOk) && (commentChar))
351  ostr << ' ' << commentChar << voidComment;
352  ostr << '\n';
353  }
354  }
355  // formatter.expand(map, true);
356  }
357  mout.debug("last values: " , variableMap );
358  //mout.warn("formatter " , formatter );
359 
360  }
361 
362 
363 };
364 
365 
366 
367 }
368 }
369 
370 
371 #endif /*POINT_H_*/
372 
373 // Drain
Something which has a name, a description and possibly some parameters of varying type.
Definition: BeanLike.h:60
virtual const std::string & getName() const
Return the name of an instance.
Definition: BeanLike.h:69
A map of FlexVariable:s.
Definition: VariableMap.h:138
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & error(const TT &... args)
Echoes.
Definition: Log.h:412
Logger & special(const TT &... args)
Other useful information.
Definition: Log.h:527
Logger & debug(const TT &... args)
Public, yet typically used "internally", when TIMING=true.
Definition: Log.h:676
Logger & debug2(const TT &... args)
Debug information.
Definition: Log.h:686
A map of references to base type scalars, arrays or std::string; changing values in either are equiva...
Definition: ReferenceMap.h:67
ref_t & link(const std::string &key, F &x)
Associates a map entry with a variable.
Definition: ReferenceMap.h:82
void copyStruct(const ReferenceMap &m, const T &src, T &dst, extLinkPolicy policy=RESERVE)
Experimental. Copies references and values of a structure to another.
Definition: ReferenceMap.h:399
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition: Sprinter.h:420
static const SprinterLayout jsonLayout
Resembles JSON structure: {"a":1,"b":22,"c":3}.
Definition: Sprinter.h:221
A tool for expanding variables embedded in a std::string to literals.
Definition: StringMapper.h:275
StringMapper & parse(const std::string &s, bool convertEscaped=false)
Converts a std::string containing variables like in "Hello, ${NAME}!" to a list of StringLet's.
Definition: StringMapper.cpp:53
std::ostream & toStream(std::ostream &ostr) const
Output a concatenated chain of stringlets: literals as such and variables surrounded with "${" and "}...
Definition: StringMapper.h:364
static void convert(const std::string &s, T &dst)
Conversion from std::string to basic types, including std::string.
Definition: String.h:451
Image with static geometry.
Definition: ImageFrame.h:67
double getScaled(size_t i, size_t j) const
Get intensity in original physical scale.
Definition: ImageFrame.h:287
Reads image channels, returning scaled (physical) values.
Definition: Sampler.h:123
Utility for sampling images (2D data), outputting formatted text data.
Definition: Sampler.h:152
char getCommentChar() const
Returns character, also supporting numeric ASCII values between 32 and 128.
Definition: Sampler.cpp:58
std::string commentPrefix
Escape std::string for prefixing text no to be handled as data values.
Definition: Sampler.h:173
ReferenceMap2 variableMap
Interface that links coordinates and image data.
Definition: Sampler.h:188
std::string getFormat(const std::string &formatStr) const
Use given format or generate default "${var},${var2}, ...".
Definition: Sampler.cpp:90
bool skipVoid
Skip lines, if contain missing values.
Definition: Sampler.h:178
void sample(const std::map< std::string, D > &images, const P &picker, const std::string &formatStr, std::ostream &ostr=std::cout) const
Main function.
Definition: Sampler.h:210
Definition: DataSelector.cpp:1277
Interprets data values for Sampler.
Definition: Sampler.h:61
int current_j2
Vertical inversed coordinate.
Definition: Sampler.h:105
ReferenceMap2 & variableMap
Definition: Sampler.h:115
int current_i
Optional utility. Called prior to writing the actual data to output stream.
Definition: Sampler.h:99
SamplePicker(ReferenceMap2<> &variableMap)
Definition: Sampler.h:68
FlexVariableMap infoMap
Information to be should in output file header.
Definition: Sampler.h:111
int current_j
Vertical coordinate.
Definition: Sampler.h:102
virtual void setPosition(int i, int j) const
Sets current position in image coordinates. To be redefined to compute also geographical projections,...
Definition: Sampler.h:84