Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.