Mercurial > hg > orthanc-stone
comparison OrthancStone/Resources/Graveyard/RTStructTentativeReimplementation-BGO/DicomStructureSetUtils.cpp @ 1908:affde38b84de
moved tentative bgo reimplementation of rt-struct into graveyard
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 01 Feb 2022 08:38:32 +0100 |
parents | OrthancStone/Sources/Toolbox/DicomStructureSetUtils.cpp@14c8f339d480 |
children | 07964689cb0b |
comparison
equal
deleted
inserted
replaced
1907:0208f99b8bde | 1908:affde38b84de |
---|---|
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-2022 Osimis S.A., Belgium | |
6 * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium | |
7 * | |
8 * This program is free software: you can redistribute it and/or | |
9 * modify it under the terms of the GNU Lesser General Public License | |
10 * as published by the Free Software Foundation, either version 3 of | |
11 * the License, or (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, but | |
14 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 * Lesser General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU Lesser General Public | |
19 * License along with this program. If not, see | |
20 * <http://www.gnu.org/licenses/>. | |
21 **/ | |
22 | |
23 #include "DicomStructureSetUtils.h" | |
24 | |
25 namespace OrthancStone | |
26 { | |
27 | |
28 #if 0 | |
29 void DicomStructure2::PartitionRectangleList(std::vector< std::vector<size_t> > & sets, const std::vector<RtStructRectanglesInSlab> slabCuts) | |
30 { | |
31 // map position ( <slabIndex,rectIndex> )--> disjoint set index | |
32 std::map<std::pair<size_t, size_t>, size_t> posToIndex; | |
33 | |
34 // disjoint set index --> position | |
35 std::map<size_t, std::pair<size_t, size_t> > indexToPos; | |
36 | |
37 size_t nextIndex = 0; | |
38 for (size_t i = 0; i < slabCuts.size(); ++i) | |
39 { | |
40 for (size_t j = 0; j < slabCuts[i].size(); ++j) | |
41 { | |
42 std::pair<size_t, size_t> pos(i, j); | |
43 posToIndex<pos> = nextIndex; | |
44 indexToPos<nextIndex> = pos; | |
45 } | |
46 } | |
47 // nextIndex is now the total rectangle count | |
48 DisjointDataSet ds(nextIndex); | |
49 | |
50 // we loop on all slabs (except the last one) and we connect all rectangles | |
51 if (slabCuts.size() < 2) | |
52 { | |
53 #error write special case | |
54 } | |
55 else | |
56 { | |
57 for (size_t i = 0; i < slabCuts.size() - 1; ++i) | |
58 { | |
59 for (size_t j = 0; j < slabCuts[i].size(); ++j) | |
60 { | |
61 const RtStructRectangleInSlab& r1 = slabCuts[i][j]; | |
62 const size_t r1i = posToIndex(std::pair<size_t, size_t>(i, j)); | |
63 for (size_t k = 0; k < slabCuts[i + 1].size(); ++k) | |
64 { | |
65 const RtStructRectangleInSlab& r2 = slabCuts[i + 1][k]; | |
66 const size_t r2i = posToIndex(std::pair<size_t, size_t>(i, j)); | |
67 // rect.xmin <= rectBottom.xmax && rectBottom.xmin <= rect.xmax | |
68 if ((r1.xmin <= r2.xmax) && (r2.xmin <= r1.xmax)) | |
69 { | |
70 #error now go! | |
71 } | |
72 | |
73 } | |
74 } | |
75 } | |
76 } | |
77 #endif | |
78 | |
79 /* | |
80 | |
81 compute list of segments : | |
82 | |
83 numberOfRectsFromHereOn = 0 | |
84 possibleNext = {in_k,in_kplus1} | |
85 | |
86 for all boundaries: | |
87 - we create a vertical segment and we push it | |
88 - if boundary is a start, numberOfRectsFromHereOn += 1. | |
89 - if we switch from 0 to 1, we start a segment | |
90 - if we switch from 1 to 2, we end the current segment and we record it | |
91 - if boundary is an end, numberOfRectsFromHereOn -= 1. | |
92 - if we switch from 1 to 0, we end the current segment and we record it | |
93 - if we switch from 2 to 1, we start a segment | |
94 */ | |
95 | |
96 // static | |
97 void AddSlabBoundaries( | |
98 std::vector<std::pair<double, RectangleBoundaryKind> > & boundaries, | |
99 const std::vector<RtStructRectanglesInSlab> & slabCuts, size_t iSlab) | |
100 { | |
101 if (iSlab < slabCuts.size()) | |
102 { | |
103 const RtStructRectanglesInSlab& slab = slabCuts[iSlab]; | |
104 for (size_t iRect = 0; iRect < slab.size(); ++iRect) | |
105 { | |
106 const RtStructRectangleInSlab& rect = slab[iRect]; | |
107 { | |
108 std::pair<double, RectangleBoundaryKind> boundary(rect.xmin, RectangleBoundaryKind_Start); | |
109 boundaries.insert(std::lower_bound(boundaries.begin(), boundaries.end(), boundary), boundary); | |
110 } | |
111 { | |
112 std::pair<double, RectangleBoundaryKind> boundary(rect.xmax, RectangleBoundaryKind_End); | |
113 boundaries.insert(std::lower_bound(boundaries.begin(), boundaries.end(), boundary), boundary); | |
114 } | |
115 } | |
116 } | |
117 } | |
118 | |
119 // static | |
120 void ProcessBoundaryList( | |
121 std::vector< std::pair<ScenePoint2D, ScenePoint2D> > & segments, | |
122 const std::vector<std::pair<double, RectangleBoundaryKind> > & boundaries, | |
123 double y) | |
124 { | |
125 ScenePoint2D start; | |
126 ScenePoint2D end; | |
127 int curNumberOfSegments = 0; // we count the number of segments. we only draw if it is 1 (not 0 or 2) | |
128 for (size_t i = 0; i < boundaries.size(); ++i) | |
129 { | |
130 switch (boundaries[i].second) | |
131 { | |
132 case RectangleBoundaryKind_Start: | |
133 curNumberOfSegments += 1; | |
134 switch (curNumberOfSegments) | |
135 { | |
136 case 0: | |
137 assert(false); | |
138 break; | |
139 case 1: | |
140 // a new segment has begun! | |
141 start = ScenePoint2D(boundaries[i].first, y); | |
142 break; | |
143 case 2: | |
144 // an extra segment has begun : stop the current one (we don't draw overlaps) | |
145 end = ScenePoint2D(boundaries[i].first, y); | |
146 segments.push_back(std::pair<ScenePoint2D, ScenePoint2D>(start, end)); | |
147 break; | |
148 default: | |
149 //assert(false); // seen IRL ! | |
150 break; | |
151 } | |
152 break; | |
153 case RectangleBoundaryKind_End: | |
154 curNumberOfSegments -= 1; | |
155 switch (curNumberOfSegments) | |
156 { | |
157 case 0: | |
158 // a lone (thus active) segment has ended. | |
159 end = ScenePoint2D(boundaries[i].first, y); | |
160 segments.push_back(std::pair<ScenePoint2D, ScenePoint2D>(start, end)); | |
161 break; | |
162 case 1: | |
163 // an extra segment has ended : start a new one one | |
164 start = ScenePoint2D(boundaries[i].first, y); | |
165 break; | |
166 default: | |
167 // this should not happen! | |
168 //assert(false); | |
169 break; | |
170 } | |
171 break; | |
172 default: | |
173 assert(false); | |
174 break; | |
175 } | |
176 } | |
177 } | |
178 | |
179 #if 0 | |
180 void ConvertListOfSlabsToSegments( | |
181 std::vector< std::pair<ScenePoint2D, ScenePoint2D> >& segments, | |
182 const std::vector<RtStructRectanglesInSlab>& slabCuts, | |
183 const size_t totalRectCount) | |
184 { | |
185 #error to delete | |
186 } | |
187 #else | |
188 // See https://www.dropbox.com/s/bllco6q8aazxk44/2019-09-18-rtstruct-cut-algorithm-rect-merge.png | |
189 void ConvertListOfSlabsToSegments( | |
190 std::vector< std::pair<ScenePoint2D, ScenePoint2D> > & segments, | |
191 const std::vector<RtStructRectanglesInSlab> & slabCuts, | |
192 const size_t totalRectCount) | |
193 { | |
194 if (slabCuts.size() == 0) | |
195 return; | |
196 | |
197 if (totalRectCount > 0) | |
198 segments.reserve(4 * totalRectCount); // worst case, but common. | |
199 | |
200 /* | |
201 VERTICAL | |
202 */ | |
203 for (size_t iSlab = 0; iSlab < slabCuts.size(); ++iSlab) | |
204 { | |
205 for (size_t iRect = 0; iRect < slabCuts[iSlab].size(); ++iRect) | |
206 { | |
207 const RtStructRectangleInSlab& rect = slabCuts[iSlab][iRect]; | |
208 { | |
209 ScenePoint2D p1(rect.xmin, rect.ymin); | |
210 ScenePoint2D p2(rect.xmin, rect.ymax); | |
211 segments.push_back(std::pair<ScenePoint2D, ScenePoint2D>(p1, p2)); | |
212 } | |
213 { | |
214 ScenePoint2D p1(rect.xmax, rect.ymin); | |
215 ScenePoint2D p2(rect.xmax, rect.ymax); | |
216 segments.push_back(std::pair<ScenePoint2D, ScenePoint2D>(p1, p2)); | |
217 } | |
218 } | |
219 } | |
220 | |
221 /* | |
222 HORIZONTAL | |
223 */ | |
224 | |
225 // if we have N slabs, we have N+1 potential vertical positions for horizontal segments | |
226 // - one for top of slab 0 | |
227 // - N-1 for all positions between two slabs | |
228 // - one for bottom of slab N-1 | |
229 | |
230 // this adds all the horizontal segments for the tops of 3the rectangles | |
231 // in row 0 | |
232 if (slabCuts[0].size() > 0) | |
233 { | |
234 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; | |
235 AddSlabBoundaries(boundaries, slabCuts, 0); | |
236 | |
237 ProcessBoundaryList(segments, boundaries, slabCuts[0][0].ymin); | |
238 } | |
239 | |
240 // this adds all the horizontal segments belonging to two slabs | |
241 for (size_t iSlab = 0; iSlab < slabCuts.size() - 1; ++iSlab) | |
242 { | |
243 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; | |
244 AddSlabBoundaries(boundaries, slabCuts, iSlab); | |
245 AddSlabBoundaries(boundaries, slabCuts, iSlab + 1); | |
246 double curY = 0; | |
247 if (slabCuts[iSlab].size() > 0) | |
248 { | |
249 curY = slabCuts[iSlab][0].ymax; | |
250 ProcessBoundaryList(segments, boundaries, curY); | |
251 } | |
252 else if (slabCuts[iSlab + 1].size() > 0) | |
253 { | |
254 curY = slabCuts[iSlab + 1][0].ymin; | |
255 ProcessBoundaryList(segments, boundaries, curY); | |
256 } | |
257 else | |
258 { | |
259 // nothing to do!! : both slab lists are empty! | |
260 } | |
261 } | |
262 | |
263 // this adds all the horizontal segments for the BOTTOM of the rectangles | |
264 // on last row | |
265 if (slabCuts[slabCuts.size() - 1].size() > 0) | |
266 { | |
267 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; | |
268 AddSlabBoundaries(boundaries, slabCuts, slabCuts.size() - 1); | |
269 | |
270 ProcessBoundaryList(segments, boundaries, slabCuts[slabCuts.size() - 1][0].ymax); | |
271 } | |
272 } | |
273 #endif | |
274 } |