1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2016 Imperial College London
5  * Copyright 2016 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_DataSelection_H
21 #define MIRTK_DataSelection_H
22 
23 #include "mirtk/Object.h"
24 
25 #include "mirtk/UnorderedSet.h"
26 #include "mirtk/Algorithm.h"
27 
28 
29 namespace mirtk { namespace data {
30 
31 /// Set of selected data point IDs
32 typedef UnorderedSet<int> Selection;
33 
34 // -----------------------------------------------------------------------------
35 /// Base class of data selectors
36 class Selector : public Object
37 {
38   mirtkAbstractMacro(Selector);
39 
40 public:
41 
42   /// Destructor
~Selector()43   virtual ~Selector() {};
44 
45   /// Run selection query and return IDs of selected data points
46   ///
47   /// \param[in] values Values of the n data points.
48   ///
49   /// \returns Set of IDs of the selected data points.
50   virtual Selection Evaluate(const Array<double> &values) const = 0;
51 };
52 
53 // -----------------------------------------------------------------------------
54 /// Combine one or more data selection criteria using a logical operator
55 class LogicalOp : public Selector
56 {
57   mirtkAbstractMacro(LogicalOp);
58 
59   typedef SharedPtr<const Selector> SelectorPointer;
60   typedef List<SelectorPointer>     SelectorList;
61 
62 protected:
63 
64   /// Individual data selectors
65   mirtkAttributeMacro(SelectorList, Criteria);
66 
67 public:
68 
69   /// Number of data selection criteria
NumberOfCriteria()70   int NumberOfCriteria() const
71   {
72     return static_cast<int>(_Criteria.size());
73   }
74 
75   /// Get n-th data selection criterium
Criterium(int i)76   SelectorPointer Criterium(int i) const
77   {
78     auto it = _Criteria.begin();
79     for (int pos = 0; pos < i; ++pos) ++it;
80     return *it;
81   }
82 
83   /// Add data selection criterium
Push(const SelectorPointer & criterium)84   void Push(const SelectorPointer &criterium)
85   {
86     _Criteria.push_back(criterium);
87   }
88 };
89 
90 // -----------------------------------------------------------------------------
91 /// Combine one or more data selection criteria using a logical AND
92 class LogicalAnd : public LogicalOp
93 {
94   mirtkObjectMacro(LogicalAnd);
95 
96 public:
97 
98   /// Run selection query and return IDs of selected data points
Evaluate(const Array<double> & values)99   virtual Selection Evaluate(const Array<double> &values) const
100   {
101     if (_Criteria.empty()) return Selection();
102     auto criterium = _Criteria.begin();
103     auto selection = (*criterium)->Evaluate(values);
104     while (++criterium != _Criteria.end()) {
105       selection = Intersection(selection, (*criterium)->Evaluate(values));
106     }
107     return selection;
108   }
109 };
110 
111 // -----------------------------------------------------------------------------
112 /// Combine one or more data selection criteria using a logical OR
113 class LogicalOr : public LogicalOp
114 {
115   mirtkObjectMacro(LogicalOr);
116 
117 public:
118 
119   /// Run selection query and return IDs of selected data points
Evaluate(const Array<double> & values)120   virtual Selection Evaluate(const Array<double> &values) const
121   {
122     Selection selection;
123     for (auto criterium : _Criteria) {
124       auto ids = criterium->Evaluate(values);
125       for (auto id : ids) {
126         selection.insert(id);
127       }
128     }
129     return selection;
130   }
131 };
132 
133 // -----------------------------------------------------------------------------
134 /// Base class of data selection criteria
135 class SelectionCriterium : public Selector
136 {
137   mirtkAbstractMacro(SelectionCriterium);
138 
139 public:
140 
141   /// Run selection query and return IDs of selected data points
Evaluate(const Array<double> & values)142   virtual Selection Evaluate(const Array<double> &values) const
143   {
144     Selection selection;
145     selection.reserve(values.size());
146     const int n = static_cast<int>(values.size());
147     for (int id = 0; id < n; ++id) {
148       if (this->Select(values[id])) {
149         selection.insert(id);
150       }
151     }
152     return selection;
153   }
154 
155   /// Evaluate criterium for given data value
156   virtual bool Select(double) const = 0;
157 };
158 
159 // =============================================================================
160 // Data selection criteria
161 // =============================================================================
162 
163 namespace select {
164 
165 
166 // -----------------------------------------------------------------------------
167 /// Select data points with a value equal the specified value
168 class Equal : public SelectionCriterium
169 {
170   mirtkObjectMacro(Equal);
171 
172   /// Upper data value threshold
173   mirtkPublicAttributeMacro(double, Value);
174 
175 public:
176 
177   /// Constructor
Equal(double value)178   Equal(double value) : _Value(value) {}
179 
180   /// Evaluate criterium for given data value
Select(double value)181   virtual bool Select(double value) const
182   {
183     return fequal(value, _Value);
184   }
185 };
186 
187 // -----------------------------------------------------------------------------
188 /// Select data points a value different from the specified value
189 class NotEqual : public SelectionCriterium
190 {
191   mirtkObjectMacro(NotEqual);
192 
193   /// Upper data value threshold
194   mirtkPublicAttributeMacro(double, Value);
195 
196 public:
197 
198   /// Constructor
NotEqual(double value)199   NotEqual(double value) : _Value(value) {}
200 
201   /// Evaluate criterium for given data value
Select(double value)202   virtual bool Select(double value) const
203   {
204     return !fequal(value, _Value);
205   }
206 };
207 
208 // -----------------------------------------------------------------------------
209 /// Select data points with a value less than the specified threshold
210 class LessThan : public SelectionCriterium
211 {
212   mirtkObjectMacro(LessThan);
213 
214   /// Upper data value threshold
215   mirtkPublicAttributeMacro(double, Threshold);
216 
217 public:
218 
219   /// Constructor
LessThan(double threshold)220   LessThan(double threshold) : _Threshold(threshold) {}
221 
222   /// Evaluate criterium for given data value
Select(double value)223   virtual bool Select(double value) const
224   {
225     return value < _Threshold;
226   }
227 };
228 
229 // -----------------------------------------------------------------------------
230 /// Select data points with a value less than or equal the specified threshold
231 class LessOrEqual : public SelectionCriterium
232 {
233   mirtkObjectMacro(LessOrEqual);
234 
235   /// Upper data value threshold
236   mirtkPublicAttributeMacro(double, Threshold);
237 
238 public:
239 
240   /// Constructor
LessOrEqual(double threshold)241   LessOrEqual(double threshold) : _Threshold(threshold) {}
242 
243   /// Evaluate criterium for given data value
Select(double value)244   virtual bool Select(double value) const
245   {
246     return value <= _Threshold;
247   }
248 };
249 
250 // -----------------------------------------------------------------------------
251 /// Select data points with a value greater than the specified threshold
252 class GreaterThan : public SelectionCriterium
253 {
254   mirtkObjectMacro(GreaterThan);
255 
256   /// Lower data value threshold
257   mirtkPublicAttributeMacro(double, Threshold);
258 
259 public:
260 
261   /// Constructor
GreaterThan(double threshold)262   GreaterThan(double threshold) : _Threshold(threshold) {}
263 
264   /// Evaluate criterium for given data value
Select(double value)265   virtual bool Select(double value) const
266   {
267     return value > _Threshold;
268   }
269 };
270 
271 // -----------------------------------------------------------------------------
272 /// Select data points with a value greater than or equal the specified threshold
273 class GreaterOrEqual : public SelectionCriterium
274 {
275   mirtkObjectMacro(GreaterOrEqual);
276 
277   /// Lower data value threshold
278   mirtkPublicAttributeMacro(double, Threshold);
279 
280 public:
281 
282   /// Constructor
GreaterOrEqual(double threshold)283   GreaterOrEqual(double threshold) : _Threshold(threshold) {}
284 
285   /// Evaluate criterium for given data value
Select(double value)286   virtual bool Select(double value) const
287   {
288     return value >= _Threshold;
289   }
290 };
291 
292 
293 } } } // namespace mirtk::data::select
294 
295 #endif // MIRTK_DataSelection_H
296