libvisiontransfer  10.6.0
parameter.cpp
1 /*******************************************************************************
2  * Copyright (c) 2023 Allied Vision Technologies GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #include <string>
16 #include <vector>
17 #include <cstring>
18 #include <sstream>
19 #include <set>
20 
21 #include <iostream>
22 
23 #include <visiontransfer/parameter.h>
24 
25 namespace visiontransfer {
26 namespace param {
27 
28 using namespace internal;
29 
30 Parameter::Parameter(const std::string& uid)
31 : uid(uid), name(uid), governorType(GOVERNOR_NONE), invokeGovernorOnInit(false), accessForConfig(ACCESS_NONE), accessForApi(ACCESS_NONE), interactionHint(INTERACTION_ACTIVE), isModified(false) {
32 }
33 
34 std::string Parameter::interpolateCommandLine(const ParameterValue& newVal) {
35  std::string result = governorString;
36  std::set<char> subst{'P', 'O', 'N', 'E', 'D'};
37  std::ostringstream ss;
38  char what;
39  size_t where = -1;
40  while (true) {
41  int foundAt = -1;
42  int foundRightmost = -1;
43  what = 0;
44  for (auto ch: subst) {
45  std::string lookfor = "%";
46  lookfor += ch;
47  foundAt = result.rfind(lookfor, where);
48  if (foundAt > foundRightmost) {
49  foundRightmost = foundAt;
50  what = ch;
51  }
52  }
53  if (foundRightmost >= 0) {
54  ss.str("");
55  switch(what) {
56  case 'P':
57  ss << "\"" << getUid() << "\"";
58  break;
59  case 'O':
60  if (isScalar()) {
61  ss << "\"" << getCurrent<std::string>() << "\"";
62  } else {
63  bool first = true;
64  for (auto e: getTensorData()) {
65  if (first) first = false;
66  else ss << " ";
67  ss << e;
68  }
69  }
70  break;
71  case 'E':
72  ss << getTensorDimension();
73  if (isTensor()) {
74  auto sh = getTensorShape();
75  for (auto d: sh) {
76  ss << " " << d;
77  }
78  }
79  break;
80  case 'D':
81  ss << newVal.getTensorDimension();
82  if (isTensor()) {
83  auto sh = newVal.getTensorShape();
84  for (auto d: sh) {
85  ss << " " << d;
86  }
87  }
88  break;
89  case 'N':
90  default:
91  if (newVal.isScalar()) {
92  ss << "\"" << newVal.getValue<std::string>() << "\"";
93  } else {
94  bool first = true;
95  for (auto e: newVal.getTensorData()) {
96  if (first) first = false;
97  else ss << " ";
98  ss << e;
99  }
100  }
101  break;
102  }
103  result.replace(foundRightmost, 2, ss.str());
104  }
105  if (where == 0) break; // cannot go further left
106  where = (foundRightmost > 0) ? foundRightmost-1 : 0;
107  }
108  return result;
109 }
110 
111 Parameter& Parameter::setCurrentFrom(const Parameter& from) {
112  if (isTensor()) {
113  if(currentValue.getTensorShape() != from.getTensorShape()) {
114  throw std::runtime_error("Cannot assign tensors with unequal shape");
115  }
116  setTensorData(from.getTensorData());
117  } else {
118  currentValue.setType(getType());
119  // always cache string
120  switch (getType()) {
121  case ParameterValue::ParameterType::TYPE_INT:
122  currentValue.setValue(from.getCurrent<int>()); break;
123  case ParameterValue::ParameterType::TYPE_DOUBLE:
124  currentValue.setValue(from.getCurrent<double>()); break;
125  case ParameterValue::ParameterType::TYPE_STRING:
126  case ParameterValue::ParameterType::TYPE_SAFESTRING:
127  case ParameterValue::ParameterType::TYPE_COMMAND:
128  currentValue.setValue(from.getCurrent<std::string>()); break;
129  break;
130  case ParameterValue::ParameterType::TYPE_BOOL:
131  currentValue.setValue(from.getCurrent<bool>()); break;
132  break;
133  case ParameterValue::ParameterType::TYPE_TENSOR:
134  break; // (handled above)
135  case ParameterValue::ParameterType::TYPE_UNDEFINED:
136  throw std::runtime_error("Cannot assign a value to an undefined parameter");
137  }
139  }
140  return *this;
141 }
142 
144  if (!hasDefault()) {
145  throw std::runtime_error(std::string("Cannot set current value from default - no default value set for ") + getUid());
146  }
147  switch (getType()) {
148  case ParameterValue::ParameterType::TYPE_INT:
149  currentValue.setType(getType());
150  currentValue.setValue(getDefault<int>());
151  break;
152  case ParameterValue::ParameterType::TYPE_DOUBLE:
153  currentValue.setType(getType());
154  currentValue.setValue(getDefault<double>());
155  break;
156  case ParameterValue::ParameterType::TYPE_STRING:
157  case ParameterValue::ParameterType::TYPE_SAFESTRING:
158  currentValue.setType(getType());
159  currentValue.setValue(getDefault<std::string>());
160  break;
161  case ParameterValue::ParameterType::TYPE_BOOL:
162  currentValue.setType(getType());
163  currentValue.setValue(getDefault<bool>());
164  break;
165  case ParameterValue::ParameterType::TYPE_TENSOR:
166  if (hasCurrent() && (currentValue.getTensorNumElements() != defaultValue.getTensorNumElements())) {
167  throw std::runtime_error(std::string("Mismatching current and default tensor sizes for ") + getUid());
168  }
169  currentValue.setType(getType());
170  currentValue.setTensorData(defaultValue.getTensorData());
171  break;
172  case ParameterValue::ParameterType::TYPE_COMMAND:
173  // Ignore commands for resetting to default value
174  break;
175  case ParameterValue::ParameterType::TYPE_UNDEFINED:
176  throw std::runtime_error("Cannot assign a value to an undefined parameter");
177  }
178  return *this;
179 }
180 
181 template<> VT_EXPORT bool Parameter::enforceIncrement(bool t) {
182  return t;
183 }
184 
185 template<> VT_EXPORT int Parameter::enforceIncrement(int t) {
186  if (hasIncrement() && ((getType()==ParameterValue::TYPE_INT) || (getType()==ParameterValue::TYPE_DOUBLE))) {
187  double val = t;
188  double inc = getIncrement<double>();
189  if (hasRange()) {
190  double min = getMin<double>();
191  return (int) (min + inc * ((int) (val-min)/inc));
192  } else {
193  return (int) (inc * ((int) val/inc));
194  }
195  } else {
196  return t;
197  }
198 }
199 
200 template<> VT_EXPORT double Parameter::enforceIncrement(double t) {
201  if (hasIncrement() && ((getType()==ParameterValue::TYPE_INT) || (getType()==ParameterValue::TYPE_DOUBLE))) {
202  double val = t;
203  double inc = getIncrement<double>();
204  if (hasRange()) {
205  double min = getMin<double>();
206  return min + inc * ((int) (val-min)/inc);
207  } else {
208  return inc * ((int) val/inc);
209  }
210  } else {
211  return t;
212  }
213 }
214 
215 template<> VT_EXPORT std::string Parameter::enforceIncrement(std::string t) {
216  if (hasIncrement() && ((getType()==ParameterValue::TYPE_INT) || (getType()==ParameterValue::TYPE_DOUBLE))) {
217  double val = ConversionHelpers::anyToDouble(t);
218  double inc = getIncrement<double>();
219  if (hasRange()) {
220  double min = getMin<double>();
221  return ConversionHelpers::anyToString(min + inc * ((int) (val-min)/inc));
222  } else {
223  return ConversionHelpers::anyToString(inc * ((int) val/inc));
224  }
225  } else {
226  return t;
227  }
228 }
229 
230 std::vector<double>& Parameter::getTensorDataReference() {
231  if (hasCurrent()) {
232  return currentValue.getTensorDataReference();
233  } else {
234  if (hasDefault()) {
235  return defaultValue.getTensorDataReference();
236  } else {
237  throw std::runtime_error("Tried getTensorDataReference(), but no value set and no default defined");
238  }
239  }
240 }
241 
242 std::vector<double> Parameter::getTensorData() const {
243  if (hasCurrent()) {
244  return currentValue.getTensorData();
245  } else {
246  if (hasDefault()) {
247  return defaultValue.getTensorData();
248  } else {
249  throw std::runtime_error("Tried getTensorData(), but no value set and no default defined");
250  }
251  }
252 }
253 
255  if (hasDefault()) {
256  return defaultValue.getTensorDataReference();
257  } else {
258  throw std::runtime_error("Tried getTensorDefaultDataReference(), but no value set and no default defined");
259  }
260 }
261 
262 std::vector<double> Parameter::getTensorDefaultData() const {
263  if (hasDefault()) {
264  return defaultValue.getTensorData();
265  } else {
266  throw std::runtime_error("Tried getTensorDefaultData(), but no default defined");
267  }
268 }
269 
271  if (!hasDefault()) return false; // Not set yet
272  if (isTensor() || isCommand()) return false; // Revision unsupported or not required
273  if (hasOptions()) {
274  std::string val = defaultValue.getValue<std::string>();
275  for (auto& o: validOptions) {
276  if (val == o.getValue<std::string>()) {
277  return false; // Valid value -> no revision needed
278  }
279  }
280  // Invalid default: select first enum option as a fallback
281  defaultValue.setValue<std::string>(validOptions[0].getValue<std::string>());
282  return true;
283  } else {
284  if ((type==ParameterValue::ParameterType::TYPE_INT) || (type==ParameterValue::ParameterType::TYPE_DOUBLE)) {
285  if (hasRange()) {
286  // Limited range, must check
287  double minVal = minValue.getValue<double>();
288  double maxVal = maxValue.getValue<double>();
289  double val = defaultValue.getValue<double>();
290  double incVal = enforceIncrement(val);
291  if (val < minVal) {
292  defaultValue.setValue<double>(minVal);
293  return true;
294  } else if (val > maxVal) {
295  defaultValue.setValue<double>(maxVal);
296  return true;
297  } else if (val != incVal) {
298  // Did not adhere to increment
299  defaultValue.setValue<double>(incVal);
300  return true;
301  }
302  return false;
303  } else {
304  // Unlimited range, no revision
305  return false;
306  }
307  } else {
308  // No range check for non-numerical parameter
309  return false;
310  }
311  }
312 }
313 
315  if (!hasCurrent()) return false; // Not set yet
316  if (isTensor() || isCommand()) return false; // Revision unsupported or not required
317  if (hasOptions()) {
318  std::string val = currentValue.getValue<std::string>();
319  for (auto& o: validOptions) {
320  if (val == o.getValue<std::string>()) {
321  return false; // Valid value -> no revision needed
322  }
323  }
324  // Invalid current value: copy default if available and valid
325  if (hasDefault()) {
326  std::string defVal = defaultValue.getValue<std::string>();
327  for (auto& o: validOptions) {
328  if (defVal == o.getValue<std::string>()) {
329  currentValue.setValue<std::string>(defVal);
330  return true; // Default value is still valid for current option set
331  }
332  }
333  }
334  // The only venue left is to fall back to the first entry
335  currentValue.setValue<std::string>(validOptions[0].getValue<std::string>());
336  return true;
337  } else {
338  if ((type==ParameterValue::ParameterType::TYPE_INT) || (type==ParameterValue::ParameterType::TYPE_DOUBLE)) {
339  if (hasRange()) {
340  // Limited range, must check
341  double minVal = minValue.getValue<double>();
342  double maxVal = maxValue.getValue<double>();
343  double val = currentValue.getValue<double>();
344  double incVal = enforceIncrement(val);
345  if (val < minVal) {
346  currentValue.setValue<double>(minVal);
347  return true;
348  } else if (val > maxVal) {
349  currentValue.setValue<double>(maxVal);
350  return true;
351  } else if (val != incVal) {
352  // Did not adhere to increment
353  currentValue.setValue<double>(incVal);
354  return true;
355  }
356  return false;
357  } else {
358  // Unlimited range, no revision
359  return false;
360  }
361  } else {
362  // No range check for non-numerical parameter
363  return false;
364  }
365  }
366 }
367 
368 } // namespace param
369 } // namespace visiontransfer
370 
371 
visiontransfer::param::Parameter::enforceIncrement
T enforceIncrement(T t)
visiontransfer::param::Parameter::getType
ParameterValue::ParameterType getType() const
Definition: parameter.h:120
visiontransfer::param::Parameter::setCurrentFromDefault
Parameter & setCurrentFromDefault()
Definition: parameter.cpp:167
visiontransfer::param::Parameter::getTensorDimension
unsigned int getTensorDimension() const
Definition: parameter.h:158
visiontransfer::param::Parameter::isTensor
bool isTensor() const
Definition: parameter.h:152
visiontransfer::internal::ConversionHelpers::anyToDouble
static double anyToDouble(T val)
Converts any type to a double.
Definition: conversionhelpers.h:71
visiontransfer::param::Parameter::hasRange
bool hasRange() const
Definition: parameter.h:463
visiontransfer::param::Parameter::hasIncrement
bool hasIncrement() const
Definition: parameter.h:467
visiontransfer::param::Parameter::getTensorDefaultData
std::vector< double > getTensorDefaultData() const
Definition: parameter.cpp:286
visiontransfer::param::Parameter::getTensorDataReference
std::vector< double > & getTensorDataReference()
Definition: parameter.cpp:254
visiontransfer::param::Parameter::isScalar
bool isScalar() const
Definition: parameter.h:154
visiontransfer::param::Parameter::setCurrentFrom
Parameter & setCurrentFrom(const Parameter &from)
Definition: parameter.cpp:135
visiontransfer::param::Parameter::isCommand
bool isCommand() const
Definition: parameter.h:156
visiontransfer::param::Parameter::getTensorShape
std::vector< unsigned int > getTensorShape() const
Definition: parameter.h:161
visiontransfer::param::Parameter::setTensorData
Parameter & setTensorData(const std::vector< double > &data)
Definition: parameter.h:175
visiontransfer::param::ParameterValue::getTensorData
std::vector< double > getTensorData() const
Return a copy of the internal tensor data.
Definition: parametervalue.cpp:121
visiontransfer::param::Parameter::hasDefault
bool hasDefault() const
Definition: parameter.h:454
visiontransfer::param::Parameter::getTensorData
std::vector< double > getTensorData() const
Definition: parameter.cpp:266
visiontransfer::param::Parameter::interpolateCommandLine
std::string interpolateCommandLine(const ParameterValue &newVal)
Definition: parameter.cpp:58
visiontransfer::param::Parameter::getTensorDefaultDataReference
std::vector< double > & getTensorDefaultDataReference()
Definition: parameter.cpp:278
visiontransfer::param::Parameter::hasOptions
bool hasOptions() const
Definition: parameter.h:441
visiontransfer::param::Parameter::getUid
std::string getUid() const
Definition: parameter.h:108
visiontransfer::param::Parameter::Parameter
Parameter()
Definition: parameter.h:104
visiontransfer::param::ParameterValue::getTensorDataReference
std::vector< double > & getTensorDataReference()
Return a reference to the internal tensor data (caution)
Definition: parametervalue.h:97
visiontransfer::param::Parameter::ensureValidCurrent
bool ensureValidCurrent()
Definition: parameter.cpp:338
visiontransfer::param::Parameter::ensureValidDefault
bool ensureValidDefault()
Definition: parameter.cpp:294
visiontransfer::internal::ConversionHelpers::anyToString
static std::string anyToString(T val)
Converts any type to a string.
Definition: conversionhelpers.h:63
visiontransfer::param::Parameter::hasCurrent
bool hasCurrent() const
Definition: parameter.h:445
Allied Vision