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