Mercurial > hg > orthanc-stone
annotate Framework/Toolbox/SlicesSorter.cpp @ 119:ba83e38cf3ff wasm
rendering of rt-dose
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 02 Oct 2017 22:01:41 +0200 |
parents | 2eca030792aa |
children | e2fe9352f240 |
rev | line source |
---|---|
73 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017 Osimis, Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "SlicesSorter.h" | |
23 | |
113
2eca030792aa
using the Orthanc Framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
110
diff
changeset
|
24 #include <Core/OrthancException.h> |
73 | 25 |
26 namespace OrthancStone | |
27 { | |
28 class SlicesSorter::SliceWithDepth : public boost::noncopyable | |
29 { | |
30 private: | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
31 std::auto_ptr<Slice> slice_; |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
32 double depth_; |
73 | 33 |
34 public: | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
35 SliceWithDepth(Slice* slice) : |
73 | 36 slice_(slice), |
37 depth_(0) | |
38 { | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
39 if (slice == NULL) |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
40 { |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
41 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
42 } |
73 | 43 } |
44 | |
45 void SetNormal(const Vector& normal) | |
46 { | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
47 assert(slice_.get() != NULL); |
73 | 48 depth_ = boost::numeric::ublas::inner_prod |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
49 (slice_->GetGeometry().GetOrigin(), normal); |
73 | 50 } |
51 | |
52 double GetDepth() const | |
53 { | |
54 return depth_; | |
55 } | |
56 | |
57 const Slice& GetSlice() const | |
58 { | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
59 assert(slice_.get() != NULL); |
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
60 return *slice_; |
73 | 61 } |
62 }; | |
63 | |
64 | |
65 struct SlicesSorter::Comparator | |
66 { | |
67 bool operator() (const SliceWithDepth* const& a, | |
68 const SliceWithDepth* const& b) const | |
69 { | |
70 return a->GetDepth() < b->GetDepth(); | |
71 } | |
72 }; | |
73 | |
74 | |
75 SlicesSorter::~SlicesSorter() | |
76 { | |
77 for (size_t i = 0; i < slices_.size(); i++) | |
78 { | |
79 assert(slices_[i] != NULL); | |
80 delete slices_[i]; | |
81 } | |
82 } | |
83 | |
84 | |
119
ba83e38cf3ff
rendering of rt-dose
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
113
diff
changeset
|
85 void SlicesSorter::AddSlice(Slice* slice) |
73 | 86 { |
87 slices_.push_back(new SliceWithDepth(slice)); | |
88 } | |
89 | |
90 | |
91 const Slice& SlicesSorter::GetSlice(size_t i) const | |
92 { | |
93 if (i >= slices_.size()) | |
94 { | |
95 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
96 } | |
97 | |
98 assert(slices_[i] != NULL); | |
99 return slices_[i]->GetSlice(); | |
100 } | |
101 | |
102 | |
103 void SlicesSorter::SetNormal(const Vector& normal) | |
104 { | |
105 for (size_t i = 0; i < slices_.size(); i++) | |
106 { | |
107 slices_[i]->SetNormal(normal); | |
108 } | |
109 | |
110 hasNormal_ = true; | |
111 } | |
112 | |
113 | |
114 void SlicesSorter::Sort() | |
115 { | |
116 if (!hasNormal_) | |
117 { | |
118 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
119 } | |
120 | |
121 Comparator comparator; | |
122 std::sort(slices_.begin(), slices_.end(), comparator); | |
123 } | |
124 | |
125 | |
126 void SlicesSorter::FilterNormal(const Vector& normal) | |
127 { | |
128 size_t pos = 0; | |
129 | |
130 for (size_t i = 0; i < slices_.size(); i++) | |
131 { | |
132 if (GeometryToolbox::IsParallel(normal, slices_[i]->GetSlice().GetGeometry().GetNormal())) | |
133 { | |
134 // This slice is compatible with the selected normal | |
135 slices_[pos] = slices_[i]; | |
136 pos += 1; | |
137 } | |
138 else | |
139 { | |
140 delete slices_[i]; | |
141 slices_[i] = NULL; | |
142 } | |
143 } | |
144 | |
145 slices_.resize(pos); | |
146 } | |
147 | |
148 | |
149 bool SlicesSorter::SelectNormal(Vector& normal) const | |
150 { | |
151 std::vector<Vector> normalCandidates; | |
152 std::vector<unsigned int> normalCount; | |
153 | |
154 bool found = false; | |
155 | |
156 for (size_t i = 0; !found && i < GetSliceCount(); i++) | |
157 { | |
158 const Vector& normal = GetSlice(i).GetGeometry().GetNormal(); | |
159 | |
160 bool add = true; | |
161 for (size_t j = 0; add && j < normalCandidates.size(); j++) // (*) | |
162 { | |
163 if (GeometryToolbox::IsParallel(normal, normalCandidates[j])) | |
164 { | |
165 normalCount[j] += 1; | |
166 add = false; | |
167 } | |
168 } | |
169 | |
170 if (add) | |
171 { | |
172 if (normalCount.size() > 2) | |
173 { | |
174 // To get linear-time complexity in (*). This heuristics | |
175 // allows the series to have one single frame that is | |
176 // not parallel to the others (such a frame could be a | |
177 // generated preview) | |
178 found = false; | |
179 } | |
180 else | |
181 { | |
182 normalCandidates.push_back(normal); | |
183 normalCount.push_back(1); | |
184 } | |
185 } | |
186 } | |
187 | |
188 for (size_t i = 0; !found && i < normalCandidates.size(); i++) | |
189 { | |
190 unsigned int count = normalCount[i]; | |
191 if (count == GetSliceCount() || | |
192 count + 1 == GetSliceCount()) | |
193 { | |
194 normal = normalCandidates[i]; | |
195 found = true; | |
196 } | |
197 } | |
198 | |
199 return found; | |
200 } | |
77 | 201 |
202 | |
203 bool SlicesSorter::LookupSlice(size_t& index, | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
77
diff
changeset
|
204 const CoordinateSystem3D& slice) const |
77 | 205 { |
206 // TODO Turn this linear-time lookup into a log-time lookup, | |
207 // keeping track of whether the slices are sorted along the normal | |
208 | |
209 for (size_t i = 0; i < slices_.size(); i++) | |
210 { | |
211 if (slices_[i]->GetSlice().ContainsPlane(slice)) | |
212 { | |
213 index = i; | |
214 return true; | |
215 } | |
216 } | |
217 | |
218 return false; | |
219 } | |
73 | 220 } |