Medical Imaging Interaction Toolkit  2026.06.00
Medical Imaging Interaction Toolkit
PropertyAutoWrap.h
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 #ifndef PropertyAutoWrap_h
14 #define PropertyAutoWrap_h
15 
16 #include <mitkBaseProperty.h>
17 #include <mitkColorProperty.h>
18 #include <mitkIPropertyOwner.h>
19 #include <mitkProperties.h>
20 #include <mitkStringProperty.h>
21 #include <pybind11/pybind11.h>
22 
23 namespace py = pybind11;
24 
43 inline mitk::BaseProperty::Pointer pythonValueToProperty(py::object value)
44 {
45  if (py::isinstance<mitk::BaseProperty>(value))
46  return value.cast<mitk::BaseProperty::Pointer>();
47 
48  // bool before int: bool is a subclass of int in Python.
49  if (py::isinstance<py::bool_>(value))
50  return mitk::BoolProperty::New(value.cast<bool>());
51 
52  if (py::isinstance<py::int_>(value))
53  return mitk::IntProperty::New(value.cast<int>());
54 
55  // Python float is double-precision; use DoubleProperty to preserve it.
56  if (py::isinstance<py::float_>(value))
57  return mitk::DoubleProperty::New(value.cast<double>());
58 
59  if (py::isinstance<py::str>(value))
60  return mitk::StringProperty::New(value.cast<std::string>());
61 
62  if (py::isinstance<mitk::Color>(value))
63  return mitk::ColorProperty::New(value.cast<mitk::Color>());
64 
65  // A 3-element tuple is treated as an (r, g, b) colour shorthand.
66  // No other MITK property type uses a bare 3-tuple, so the mapping is unambiguous.
67  // Lists of 3 are deliberately NOT auto-wrapped here -- a list is more likely
68  // to be an accidental value than an intentional colour literal.
69  if (py::isinstance<py::tuple>(value))
70  {
71  auto t = value.cast<py::tuple>();
72  if (t.size() == 3)
73  {
74  mitk::Color c;
75  c[0] = t[0].cast<float>();
76  c[1] = t[1].cast<float>();
77  c[2] = t[2].cast<float>();
78  return mitk::ColorProperty::New(c);
79  }
80  }
81 
82  throw py::type_error("Cannot auto-convert " + std::string(py::str(py::type::of(value))) +
83  " to a property. Pass a mitk.BaseProperty subclass explicitly "
84  "(e.g. mitk.StringProperty(...), mitk.ColorProperty(...)).");
85 }
86 
93 inline mitk::BaseProperty::Pointer pythonValueToPropertyWithType(py::object value, const std::string &targetType)
94 {
95  if (py::isinstance<mitk::BaseProperty>(value))
96  return value.cast<mitk::BaseProperty::Pointer>();
97 
98  if (targetType.empty())
99  return pythonValueToProperty(value);
100 
101  if (targetType == "StringProperty")
102  return mitk::StringProperty::New(value.cast<std::string>());
103 
104  if (targetType == "BoolProperty")
105  return mitk::BoolProperty::New(value.cast<bool>());
106 
107  if (targetType == "IntProperty")
108  return mitk::IntProperty::New(value.cast<int>());
109 
110  if (targetType == "FloatProperty")
111  return mitk::FloatProperty::New(value.cast<float>());
112 
113  if (targetType == "DoubleProperty")
114  return mitk::DoubleProperty::New(value.cast<double>());
115 
116  if (targetType == "ColorProperty")
117  {
118  // Accept mitk.Color directly, or a plain (r, g, b) sequence as a shorthand.
119  // The target type is already known here, so any 3-element sequence is unambiguous.
120  if (py::isinstance<mitk::Color>(value))
121  return mitk::ColorProperty::New(value.cast<mitk::Color>());
122  if (py::isinstance<py::sequence>(value))
123  {
124  auto seq = value.cast<py::sequence>();
125  mitk::Color c;
126  c[0] = seq[0].cast<float>();
127  c[1] = seq[1].cast<float>();
128  c[2] = seq[2].cast<float>();
129  return mitk::ColorProperty::New(c);
130  }
131  throw py::type_error("ColorProperty requires a mitk.Color or a 3-element (r,g,b) sequence.");
132  }
133 
134  throw py::type_error("Cannot coerce " + std::string(py::str(py::type::of(value))) + " to " + targetType +
135  ". Pass the new property value as a mitk." + targetType + " instance explicitly.");
136 }
137 
141 inline mitk::BaseProperty::Pointer coerceToExistingType(const mitk::BaseProperty *existing, py::object value)
142 {
143  if (nullptr == existing)
144  throw std::runtime_error("Cannot coerce to existing type: no existing property");
145 
146  return pythonValueToPropertyWithType(value, existing->GetNameOfClass());
147 }
148 
157 inline mitk::BaseProperty::Pointer resolvePropertyValue(mitk::IPropertyOwner &owner,
158  const std::string &key,
159  py::object value)
160 {
161  if (py::isinstance<mitk::BaseProperty>(value))
162  return value.cast<mitk::BaseProperty::Pointer>();
163 
164  auto existing = owner.GetConstProperty(key);
165  if (existing)
166  return coerceToExistingType(existing, value);
167 
168  return pythonValueToProperty(value);
169 }
170 
171 #endif
mitk::BaseProperty::Pointer pythonValueToProperty(py::object value)
Converts a Python object to a BaseProperty, auto-wrapping common scalar types.
mitk::BaseProperty::Pointer coerceToExistingType(const mitk::BaseProperty *existing, py::object value)
Coerces a Python value to the class of an existing property.
mitk::BaseProperty::Pointer pythonValueToPropertyWithType(py::object value, const std::string &targetType)
Converts a Python object to a BaseProperty, coercing to a specific target class when given.
mitk::BaseProperty::Pointer resolvePropertyValue(mitk::IPropertyOwner &owner, const std::string &key, py::object value)
Resolves a Python value to a BaseProperty, respecting any existing property's type.
Abstract base class for properties.
static Pointer New()
Interface implemented by classes that provide write/read access to property information.
virtual BaseProperty::ConstPointer GetConstProperty(const std::string &propertyKey, const std::string &contextName="", bool fallBackOnDefaultContext=true) const =0
Get property by its key.
static Pointer New()
Declares commonly used GenericProperty specializations for MITK.
itk::RGBPixel< float > Color
Standard RGB color typedef using float components.