Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkTemporoSpatialStringProperty.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include <iterator>
18 
20 
21 #ifdef _MSC_VER
22 // has to be deactivated because of a bug in boost v1.59. see Boost bug ticket #11599
23 // as soon as MITK uses a boost version with a bug fix we can remove the disableling.
24 #pragma warning(push)
25 #pragma warning(disable : 4715)
26 #endif
27 
28 #include <boost/property_tree/json_parser.hpp>
29 #include <boost/property_tree/ptree.hpp>
30 #include <boost/type_traits/make_unsigned.hpp>
31 
33 {
34  if (s)
35  {
36  SliceMapType slices{{0, s}};
37 
38  m_Values.insert(std::make_pair(0, slices));
39  }
40 }
41 
43 {
44  SliceMapType slices{{0, s}};
45 
46  m_Values.insert(std::make_pair(0, slices));
47 }
48 
50  : BaseProperty(other), m_Values(other.m_Values)
51 {
52 }
53 
54 bool mitk::TemporoSpatialStringProperty::IsEqual(const BaseProperty &property) const
55 {
56  return this->m_Values == static_cast<const Self &>(property).m_Values;
57 }
58 
59 bool mitk::TemporoSpatialStringProperty::Assign(const BaseProperty &property)
60 {
61  this->m_Values = static_cast<const Self &>(property).m_Values;
62  return true;
63 }
64 
66 {
67  return GetValue();
68 }
69 
70 itk::LightObject::Pointer mitk::TemporoSpatialStringProperty::InternalClone() const
71 {
72  itk::LightObject::Pointer result(new Self(*this));
73  result->UnRegister();
74  return result;
75 }
76 
78 {
79  std::string result = "";
80 
81  if (!m_Values.empty())
82  {
83  if (!m_Values.begin()->second.empty())
84  {
85  result = m_Values.begin()->second.begin()->second;
86  }
87  }
88  return result;
89 };
90 
91 std::pair<bool, mitk::TemporoSpatialStringProperty::ValueType> mitk::TemporoSpatialStringProperty::CheckValue(
92  const TimeStepType &timeStep, const IndexValueType &zSlice, bool allowCloseTime, bool allowCloseSlice) const
93 {
94  std::string value = "";
95  bool found = false;
96 
97  TimeMapType::const_iterator timeIter = m_Values.find(timeStep);
98  TimeMapType::const_iterator timeEnd = m_Values.end();
99  if (timeIter == timeEnd && allowCloseTime)
100  { // search for closest time step (earlier preverd)
101  timeIter = m_Values.upper_bound(timeStep);
102  if (timeIter != m_Values.begin())
103  { // there is a key lower than time step
104  timeIter = std::prev(timeIter);
105  }
106  }
107 
108  if (timeIter != timeEnd)
109  {
110  const SliceMapType &slices = timeIter->second;
111 
112  SliceMapType::const_iterator sliceIter = slices.find(zSlice);
113  SliceMapType::const_iterator sliceEnd = slices.end();
114  if (sliceIter == sliceEnd && allowCloseSlice)
115  { // search for closest slice (earlier preverd)
116  sliceIter = slices.upper_bound(zSlice);
117  if (sliceIter != slices.begin())
118  { // there is a key lower than slice
119  sliceIter = std::prev(sliceIter);
120  }
121  }
122 
123  if (sliceIter != sliceEnd)
124  {
125  value = sliceIter->second;
126  found = true;
127  }
128  }
129 
130  return std::make_pair(found, value);
131 };
132 
134  const IndexValueType &zSlice,
135  bool allowCloseTime,
136  bool allowCloseSlice) const
137 {
138  return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).second;
139 };
140 
142  const IndexValueType &zSlice, bool allowClose) const
143 {
144  return GetValue(0, zSlice, true, allowClose);
145 };
146 
148  const TimeStepType &timeStep, bool allowClose) const
149 {
150  return GetValue(timeStep, 0, allowClose, true);
151 };
152 
154 {
155  return !m_Values.empty();
156 };
157 
159  const IndexValueType &zSlice,
160  bool allowCloseTime,
161  bool allowCloseSlice) const
162 {
163  return CheckValue(timeStep, zSlice, allowCloseTime, allowCloseSlice).first;
164 };
165 
166 bool mitk::TemporoSpatialStringProperty::HasValueBySlice(const IndexValueType &zSlice, bool allowClose) const
167 {
168  return HasValue(0, zSlice, true, allowClose);
169 };
170 
171 bool mitk::TemporoSpatialStringProperty::HasValueByTimeStep(const TimeStepType &timeStep, bool allowClose) const
172 {
173  return HasValue(timeStep, 0, allowClose, true);
174 };
175 
176 std::vector<mitk::TemporoSpatialStringProperty::IndexValueType> mitk::TemporoSpatialStringProperty::GetAvailableSlices(
177  const TimeStepType &timeStep) const
178 {
179  std::vector<IndexValueType> result;
180 
181  TimeMapType::const_iterator timeIter = m_Values.find(timeStep);
182  TimeMapType::const_iterator timeEnd = m_Values.end();
183 
184  if (timeIter != timeEnd)
185  {
186  for (auto const &element : timeIter->second)
187  {
188  result.push_back(element.first);
189  }
190  }
191 
192  return result;
193 };
194 
195 std::vector<mitk::TimeStepType> mitk::TemporoSpatialStringProperty::GetAvailableTimeSteps() const
196 {
197  std::vector<mitk::TimeStepType> result;
198 
199  for (auto const &element : m_Values)
200  {
201  result.push_back(element.first);
202  }
203 
204  return result;
205 };
206 
208  const IndexValueType &zSlice,
209  const ValueType &value)
210 {
211  TimeMapType::iterator timeIter = m_Values.find(timeStep);
212  TimeMapType::iterator timeEnd = m_Values.end();
213 
214  if (timeIter == timeEnd)
215  {
216  SliceMapType slices{{zSlice, value}};
217  m_Values.insert(std::make_pair(timeStep, slices));
218  }
219  else
220  {
221  timeIter->second[zSlice] = value;
222  }
223  this->Modified();
224 };
225 
227 {
228  this->Modified();
229  m_Values.clear();
230  this->SetValue(0, 0, value);
231 };
232 
233 // Create necessary escape sequences from illegal characters
234 // REMARK: This code is based upon code from boost::ptree::json_writer.
235 // The corresponding boost function was not used directly, because it is not part of
236 // the public interface of ptree::json_writer. :(
237 // A own serialization strategy was implemented instead of using boost::ptree::json_write because
238 // currently (<= boost 1.60) everything (even numbers) are converted into string representations
239 // by the writer, so e.g. it becomes "t":"2" instaed of "t":2
240 template <class Ch>
241 std::basic_string<Ch> CreateJSONEscapes(const std::basic_string<Ch> &s)
242 {
243  std::basic_string<Ch> result;
244  typename std::basic_string<Ch>::const_iterator b = s.begin();
245  typename std::basic_string<Ch>::const_iterator e = s.end();
246  while (b != e)
247  {
248  typedef typename boost::make_unsigned<Ch>::type UCh;
249  UCh c(*b);
250  // This assumes an ASCII superset.
251  // We escape everything outside ASCII, because this code can't
252  // handle high unicode characters.
253  if (c == 0x20 || c == 0x21 || (c >= 0x23 && c <= 0x2E) || (c >= 0x30 && c <= 0x5B) || (c >= 0x5D && c <= 0x7F))
254  result += *b;
255  else if (*b == Ch('\b'))
256  result += Ch('\\'), result += Ch('b');
257  else if (*b == Ch('\f'))
258  result += Ch('\\'), result += Ch('f');
259  else if (*b == Ch('\n'))
260  result += Ch('\\'), result += Ch('n');
261  else if (*b == Ch('\r'))
262  result += Ch('\\'), result += Ch('r');
263  else if (*b == Ch('\t'))
264  result += Ch('\\'), result += Ch('t');
265  else if (*b == Ch('/'))
266  result += Ch('\\'), result += Ch('/');
267  else if (*b == Ch('"'))
268  result += Ch('\\'), result += Ch('"');
269  else if (*b == Ch('\\'))
270  result += Ch('\\'), result += Ch('\\');
271  else
272  {
273  const char *hexdigits = "0123456789ABCDEF";
274  unsigned long u = (std::min)(static_cast<unsigned long>(static_cast<UCh>(*b)), 0xFFFFul);
275  int d1 = u / 4096;
276  u -= d1 * 4096;
277  int d2 = u / 256;
278  u -= d2 * 256;
279  int d3 = u / 16;
280  u -= d3 * 16;
281  int d4 = u;
282  result += Ch('\\');
283  result += Ch('u');
284  result += Ch(hexdigits[d1]);
285  result += Ch(hexdigits[d2]);
286  result += Ch(hexdigits[d3]);
287  result += Ch(hexdigits[d4]);
288  }
289  ++b;
290  }
291  return result;
292 }
293 
295  const mitk::BaseProperty *prop)
296 {
297  // REMARK: Implemented own serialization instead of using boost::ptree::json_write because
298  // currently (<= boost 1.60) everything (even numbers) are converted into string representations
299  // by the writer, so e.g. it becomes "t":"2" instaed of "t":2
300  // If this problem is fixed with boost, we shoud switch back to json_writer (and remove the custom
301  // implementation of CreateJSONEscapes (see above)).
302  const mitk::TemporoSpatialStringProperty *tsProp = dynamic_cast<const mitk::TemporoSpatialStringProperty *>(prop);
303 
304  if (!tsProp)
305  {
306  return "";
307  }
308 
309  std::ostringstream stream;
310  stream << "{\"values\":[";
311 
312  std::vector<mitk::TimeStepType> ts = tsProp->GetAvailableTimeSteps();
313  bool first = true;
314  for (auto t : ts)
315  {
316  std::vector<mitk::TemporoSpatialStringProperty::IndexValueType> zs = tsProp->GetAvailableSlices(t);
317  for (auto z : zs)
318  {
319  std::string value = CreateJSONEscapes(tsProp->GetValue(t, z));
320 
321  if (first)
322  {
323  first = false;
324  }
325  else
326  {
327  stream << ", ";
328  }
329 
330  stream << "{\"t\":" << t << ", \"z\":" << z << ", \"value\":\"" << value << "\"}";
331  }
332  }
333 
334  stream << "]}";
335 
336  return stream.str();
337 }
338 
340  const std::string &value)
341 {
343 
344  boost::property_tree::ptree root;
345 
346  std::istringstream stream(value);
347 
348  boost::property_tree::read_json(stream, root);
349 
350  // Iterator over all animals
351  for (boost::property_tree::ptree::value_type &element : root.get_child("values"))
352  {
353  std::string value = element.second.get("value", "");
355  element.second.get<mitk::TemporoSpatialStringProperty::IndexValueType>("z", 0);
356  TimeStepType t = element.second.get<TimeStepType>("t", 0);
357 
358  prop->SetValue(t, z, value);
359  }
360 
361  return prop.GetPointer();
362 }
363 
364 #ifdef _MSC_VER
365 #pragma warning(pop)
366 #endif
std::basic_string< Ch > CreateJSONEscapes(const std::basic_string< Ch > &s)
std::pair< bool, ValueType > CheckValue(const TimeStepType &timeStep, const IndexValueType &zSlice, bool allowCloseTime=false, bool allowCloseSlice=false) const
itk::SmartPointer< Self > Pointer
MITKCORE_EXPORT::std::string serializeTemporoSpatialStringPropertyToJSON(const mitk::BaseProperty *prop)
std::vector< TimeStepType > GetAvailableTimeSteps() const
ValueType GetValueByTimeStep(const TimeStepType &timeStep, bool allowClose=false) const
void SetValue(const TimeStepType &timeStep, const IndexValueType &zSlice, const ValueType &value)
std::vector< IndexValueType > GetAvailableSlices(const TimeStepType &timeStep) const
Abstract base class for properties.
std::vcl_size_t TimeStepType
virtual std::string GetValueAsString() const override
bool HasValueBySlice(const IndexValueType &zSlice, bool allowClose=false) const
static T min(T x, T y)
Definition: svm.cpp:67
bool HasValueByTimeStep(const TimeStepType &timeStep, bool allowClose=false) const
std::map< IndexValueType, std::string > SliceMapType
MITKCORE_EXPORT mitk::BaseProperty::Pointer deserializeJSONToTemporoSpatialStringProperty(const std::string &value)
ValueType GetValueBySlice(const IndexValueType &zSlice, bool allowClose=false) const
Property for time and space resolved string values.