comparison OrthancStone/UnitTestsSources/ComputationalGeometryTests.cpp @ 1877:a2955abe4c2e

skeleton for the RenderingPlugin
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 12 Jan 2022 08:23:38 +0100
parents UnitTestsSources/ComputationalGeometryTests.cpp@b1f510e601d2
children 6ce81914f7e4
comparison
equal deleted inserted replaced
1876:b1f510e601d2 1877:a2955abe4c2e
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
24 #include <gtest/gtest.h>
25
26 #include "../Sources/Toolbox/Internals/OrientedIntegerLine2D.h"
27 #include "../Sources/Toolbox/Internals/RectanglesIntegerProjection.h"
28 #include "../Sources/Toolbox/SegmentTree.h"
29 #include "../Sources/Toolbox/UnionOfRectangles.h"
30
31 #include <Logging.h>
32 #include <OrthancException.h>
33
34
35 namespace
36 {
37 typedef Orthanc::SingleValueObject<int> Counter;
38
39 class CounterFactory : public OrthancStone::SegmentTree::IPayloadFactory
40 {
41 private:
42 int value_;
43
44 public:
45 CounterFactory(int value) :
46 value_(value)
47 {
48 }
49
50 virtual Orthanc::IDynamicObject* Create() ORTHANC_OVERRIDE
51 {
52 return new Counter(value_);
53 }
54 };
55
56 class IncrementVisitor : public OrthancStone::SegmentTree::IVisitor
57 {
58 private:
59 int increment_;
60
61 public:
62 IncrementVisitor(int increment) :
63 increment_(increment)
64 {
65 }
66
67 virtual void Visit(const OrthancStone::SegmentTree& node,
68 bool fullyInside) ORTHANC_OVERRIDE
69 {
70 if (fullyInside)
71 {
72 Counter& payload = node.GetTypedPayload<Counter>();
73
74 if (payload.GetValue() + increment_ < 0)
75 {
76 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
77 }
78 else
79 {
80 payload.SetValue(payload.GetValue() + increment_);
81 }
82 }
83 }
84 };
85 }
86
87
88 TEST(SegmentTree, Create)
89 {
90 CounterFactory factory(42);
91 OrthancStone::SegmentTree root(4u, 15u, factory); // Check out Figure 1.1 (page 14) from textbook
92
93 ASSERT_EQ(4u, root.GetLowBound());
94 ASSERT_EQ(15u, root.GetHighBound());
95 ASSERT_FALSE(root.IsLeaf());
96 ASSERT_EQ(42, root.GetTypedPayload<Counter>().GetValue());
97 ASSERT_EQ(21u, root.CountNodes());
98
99 const OrthancStone::SegmentTree* n = &root.GetLeftChild();
100 ASSERT_EQ(4u, n->GetLowBound());
101 ASSERT_EQ(9u, n->GetHighBound());
102 ASSERT_FALSE(n->IsLeaf());
103 ASSERT_EQ(9u, n->CountNodes());
104
105 n = &root.GetLeftChild().GetLeftChild();
106 ASSERT_EQ(4u, n->GetLowBound());
107 ASSERT_EQ(6u, n->GetHighBound());
108 ASSERT_FALSE(n->IsLeaf());
109 ASSERT_EQ(3u, n->CountNodes());
110
111 n = &root.GetLeftChild().GetLeftChild().GetLeftChild();
112 ASSERT_EQ(4u, n->GetLowBound());
113 ASSERT_EQ(5u, n->GetHighBound());
114 ASSERT_TRUE(n->IsLeaf());
115 ASSERT_THROW(n->GetLeftChild(), Orthanc::OrthancException);
116 ASSERT_THROW(n->GetRightChild(), Orthanc::OrthancException);
117 ASSERT_EQ(1u, n->CountNodes());
118
119 n = &root.GetLeftChild().GetLeftChild().GetRightChild();
120 ASSERT_EQ(5u, n->GetLowBound());
121 ASSERT_EQ(6u, n->GetHighBound());
122 ASSERT_TRUE(n->IsLeaf());
123 ASSERT_EQ(1u, n->CountNodes());
124
125 n = &root.GetLeftChild().GetRightChild();
126 ASSERT_EQ(6u, n->GetLowBound());
127 ASSERT_EQ(9u, n->GetHighBound());
128 ASSERT_FALSE(n->IsLeaf());
129 ASSERT_EQ(5u, n->CountNodes());
130
131 n = &root.GetLeftChild().GetRightChild().GetLeftChild();
132 ASSERT_EQ(6u, n->GetLowBound());
133 ASSERT_EQ(7u, n->GetHighBound());
134 ASSERT_TRUE(n->IsLeaf());
135 ASSERT_EQ(1u, n->CountNodes());
136
137 n = &root.GetLeftChild().GetRightChild().GetRightChild();
138 ASSERT_EQ(7u, n->GetLowBound());
139 ASSERT_EQ(9u, n->GetHighBound());
140 ASSERT_FALSE(n->IsLeaf());
141 ASSERT_EQ(3u, n->CountNodes());
142
143 n = &root.GetLeftChild().GetRightChild().GetRightChild().GetLeftChild();
144 ASSERT_EQ(7u, n->GetLowBound());
145 ASSERT_EQ(8u, n->GetHighBound());
146 ASSERT_TRUE(n->IsLeaf());
147 ASSERT_EQ(1u, n->CountNodes());
148
149 n = &root.GetLeftChild().GetRightChild().GetRightChild().GetRightChild();
150 ASSERT_EQ(8u, n->GetLowBound());
151 ASSERT_EQ(9u, n->GetHighBound());
152 ASSERT_TRUE(n->IsLeaf());
153 ASSERT_EQ(1u, n->CountNodes());
154
155 n = &root.GetRightChild();
156 ASSERT_EQ(9u, n->GetLowBound());
157 ASSERT_EQ(15u, n->GetHighBound());
158 ASSERT_FALSE(n->IsLeaf());
159 ASSERT_EQ(11u, n->CountNodes());
160
161 n = &root.GetRightChild().GetLeftChild();
162 ASSERT_EQ(9u, n->GetLowBound());
163 ASSERT_EQ(12u, n->GetHighBound());
164 ASSERT_FALSE(n->IsLeaf());
165 ASSERT_EQ(5u, n->CountNodes());
166
167 n = &root.GetRightChild().GetLeftChild().GetLeftChild();
168 ASSERT_EQ(9u, n->GetLowBound());
169 ASSERT_EQ(10u, n->GetHighBound());
170 ASSERT_TRUE(n->IsLeaf());
171 ASSERT_EQ(1u, n->CountNodes());
172
173 n = &root.GetRightChild().GetLeftChild().GetRightChild();
174 ASSERT_EQ(10u, n->GetLowBound());
175 ASSERT_EQ(12u, n->GetHighBound());
176 ASSERT_FALSE(n->IsLeaf());
177 ASSERT_EQ(3u, n->CountNodes());
178
179 n = &root.GetRightChild().GetLeftChild().GetRightChild().GetLeftChild();
180 ASSERT_EQ(10u, n->GetLowBound());
181 ASSERT_EQ(11u, n->GetHighBound());
182 ASSERT_TRUE(n->IsLeaf());
183 ASSERT_EQ(1u, n->CountNodes());
184
185 n = &root.GetRightChild().GetLeftChild().GetRightChild().GetRightChild();
186 ASSERT_EQ(11u, n->GetLowBound());
187 ASSERT_EQ(12u, n->GetHighBound());
188 ASSERT_TRUE(n->IsLeaf());
189 ASSERT_EQ(1u, n->CountNodes());
190
191 n = &root.GetRightChild().GetRightChild();
192 ASSERT_EQ(12u, n->GetLowBound());
193 ASSERT_EQ(15u, n->GetHighBound());
194 ASSERT_FALSE(n->IsLeaf());
195 ASSERT_EQ(5u, n->CountNodes());
196
197 n = &root.GetRightChild().GetRightChild().GetLeftChild();
198 ASSERT_EQ(12u, n->GetLowBound());
199 ASSERT_EQ(13u, n->GetHighBound());
200 ASSERT_TRUE(n->IsLeaf());
201 ASSERT_EQ(1u, n->CountNodes());
202
203 n = &root.GetRightChild().GetRightChild().GetRightChild();
204 ASSERT_EQ(13u, n->GetLowBound());
205 ASSERT_EQ(15u, n->GetHighBound());
206 ASSERT_FALSE(n->IsLeaf());
207 ASSERT_EQ(3u, n->CountNodes());
208
209 n = &root.GetRightChild().GetRightChild().GetRightChild().GetLeftChild();
210 ASSERT_EQ(13u, n->GetLowBound());
211 ASSERT_EQ(14u, n->GetHighBound());
212 ASSERT_TRUE(n->IsLeaf());
213 ASSERT_EQ(1u, n->CountNodes());
214
215 n = &root.GetRightChild().GetRightChild().GetRightChild().GetRightChild();
216 ASSERT_EQ(14u, n->GetLowBound());
217 ASSERT_EQ(15u, n->GetHighBound());
218 ASSERT_TRUE(n->IsLeaf());
219 ASSERT_EQ(1u, n->CountNodes());
220
221 ASSERT_TRUE(root.FindLeaf(3) == NULL);
222 for (size_t i = 4; i < 15; i++)
223 {
224 n = root.FindLeaf(i);
225 ASSERT_TRUE(n != NULL);
226 ASSERT_TRUE(n->IsLeaf());
227 ASSERT_EQ(i, n->GetLowBound());
228 ASSERT_EQ(i + 1, n->GetHighBound());
229 ASSERT_EQ(42, n->GetTypedPayload<Counter>().GetValue());
230 }
231 ASSERT_TRUE(root.FindLeaf(15) == NULL);
232 }
233
234
235 static bool CheckCounter(const OrthancStone::SegmentTree& node,
236 int expectedValue)
237 {
238 if (node.GetTypedPayload<Counter>().GetValue() != expectedValue)
239 {
240 return false;
241 }
242 else if (node.IsLeaf())
243 {
244 return true;
245 }
246 else
247 {
248 return (CheckCounter(node.GetLeftChild(), expectedValue) &&
249 CheckCounter(node.GetRightChild(), expectedValue));
250 }
251 }
252
253
254 #if 0
255 static void Print(const OrthancStone::SegmentTree& node,
256 unsigned int indent)
257 {
258 for (size_t i = 0; i < indent; i++)
259 printf(" ");
260 printf("(%lu,%lu): %d\n", node.GetLowBound(), node.GetHighBound(), node.GetTypedPayload<Counter>().GetValue());
261 if (!node.IsLeaf())
262 {
263 Print(node.GetLeftChild(), indent + 1);
264 Print(node.GetRightChild(), indent + 1);
265 }
266 }
267 #endif
268
269
270 TEST(SegmentTree, Visit)
271 {
272 CounterFactory factory(0);
273 OrthancStone::SegmentTree root(4u, 15u, factory); // Check out Figure 1.1 (page 14) from textbook
274
275 ASSERT_TRUE(CheckCounter(root, 0));
276
277 IncrementVisitor plus(1);
278 IncrementVisitor minus(-1);
279
280 root.VisitSegment(0, 20, plus);
281 ASSERT_EQ(1, root.GetTypedPayload<Counter>().GetValue());
282 ASSERT_TRUE(CheckCounter(root.GetLeftChild(), 0));
283 ASSERT_TRUE(CheckCounter(root.GetRightChild(), 0));
284
285 root.VisitSegment(0, 20, plus);
286 ASSERT_EQ(2, root.GetTypedPayload<Counter>().GetValue());
287 ASSERT_TRUE(CheckCounter(root.GetLeftChild(), 0));
288 ASSERT_TRUE(CheckCounter(root.GetRightChild(), 0));
289
290 root.VisitSegment(0, 20, minus);
291 root.VisitSegment(0, 20, minus);
292 ASSERT_TRUE(CheckCounter(root, 0));
293
294 root.VisitSegment(8, 11, plus);
295 ASSERT_EQ(0, root.FindNode(4, 15)->GetTypedPayload<Counter>().GetValue());
296 ASSERT_EQ(0, root.FindNode(4, 9)->GetTypedPayload<Counter>().GetValue());
297 ASSERT_EQ(0, root.FindNode(4, 6)->GetTypedPayload<Counter>().GetValue());
298 ASSERT_EQ(0, root.FindNode(4, 5)->GetTypedPayload<Counter>().GetValue());
299 ASSERT_EQ(0, root.FindNode(5, 6)->GetTypedPayload<Counter>().GetValue());
300 ASSERT_EQ(0, root.FindNode(6, 9)->GetTypedPayload<Counter>().GetValue());
301 ASSERT_EQ(0, root.FindNode(6, 7)->GetTypedPayload<Counter>().GetValue());
302 ASSERT_EQ(0, root.FindNode(7, 9)->GetTypedPayload<Counter>().GetValue());
303 ASSERT_EQ(0, root.FindNode(7, 8)->GetTypedPayload<Counter>().GetValue());
304 ASSERT_EQ(1, root.FindNode(8, 9)->GetTypedPayload<Counter>().GetValue());
305 ASSERT_EQ(0, root.FindNode(9, 15)->GetTypedPayload<Counter>().GetValue());
306 ASSERT_EQ(0, root.FindNode(9, 12)->GetTypedPayload<Counter>().GetValue());
307 ASSERT_EQ(1, root.FindNode(9, 10)->GetTypedPayload<Counter>().GetValue());
308 ASSERT_EQ(0, root.FindNode(10, 12)->GetTypedPayload<Counter>().GetValue());
309 ASSERT_EQ(1, root.FindNode(10, 11)->GetTypedPayload<Counter>().GetValue());
310 ASSERT_EQ(0, root.FindNode(11, 12)->GetTypedPayload<Counter>().GetValue());
311 ASSERT_EQ(0, root.FindNode(12, 15)->GetTypedPayload<Counter>().GetValue());
312 ASSERT_EQ(0, root.FindNode(12, 13)->GetTypedPayload<Counter>().GetValue());
313 ASSERT_EQ(0, root.FindNode(13, 15)->GetTypedPayload<Counter>().GetValue());
314 ASSERT_EQ(0, root.FindNode(13, 14)->GetTypedPayload<Counter>().GetValue());
315 ASSERT_EQ(0, root.FindNode(14, 15)->GetTypedPayload<Counter>().GetValue());
316
317 root.VisitSegment(9, 11, minus);
318 ASSERT_EQ(0, root.FindNode(4, 15)->GetTypedPayload<Counter>().GetValue());
319 ASSERT_EQ(0, root.FindNode(4, 9)->GetTypedPayload<Counter>().GetValue());
320 ASSERT_EQ(0, root.FindNode(4, 6)->GetTypedPayload<Counter>().GetValue());
321 ASSERT_EQ(0, root.FindNode(4, 5)->GetTypedPayload<Counter>().GetValue());
322 ASSERT_EQ(0, root.FindNode(5, 6)->GetTypedPayload<Counter>().GetValue());
323 ASSERT_EQ(0, root.FindNode(6, 9)->GetTypedPayload<Counter>().GetValue());
324 ASSERT_EQ(0, root.FindNode(6, 7)->GetTypedPayload<Counter>().GetValue());
325 ASSERT_EQ(0, root.FindNode(7, 9)->GetTypedPayload<Counter>().GetValue());
326 ASSERT_EQ(0, root.FindNode(7, 8)->GetTypedPayload<Counter>().GetValue());
327 ASSERT_EQ(1, root.FindNode(8, 9)->GetTypedPayload<Counter>().GetValue());
328 ASSERT_TRUE(CheckCounter(root.GetRightChild(), 0));
329
330 root.VisitSegment(8, 9, minus);
331 ASSERT_TRUE(CheckCounter(root, 0));
332 }
333
334
335 TEST(UnionOfRectangles, RectanglesIntegerProjection)
336 {
337 std::list<OrthancStone::Extent2D> rectangles;
338 rectangles.push_back(OrthancStone::Extent2D(10, 20, 30, 40));
339
340 {
341 OrthancStone::Internals::RectanglesIntegerProjection h(rectangles, true);
342 ASSERT_EQ(2u, h.GetEndpointsCount());
343 ASSERT_EQ(10, h.GetEndpointCoordinate(0));
344 ASSERT_EQ(30, h.GetEndpointCoordinate(1));
345 ASSERT_EQ(1u, h.GetProjectedRectanglesCount());
346 ASSERT_EQ(0u, h.GetProjectedRectangleLow(0));
347 ASSERT_EQ(1u, h.GetProjectedRectangleHigh(0));
348
349 ASSERT_THROW(h.GetEndpointCoordinate(2), Orthanc::OrthancException);
350 ASSERT_THROW(h.GetProjectedRectangleLow(1), Orthanc::OrthancException);
351 ASSERT_THROW(h.GetProjectedRectangleHigh(1), Orthanc::OrthancException);
352 }
353
354 {
355 OrthancStone::Internals::RectanglesIntegerProjection h(rectangles, false);
356 ASSERT_EQ(2u, h.GetEndpointsCount());
357 ASSERT_EQ(20, h.GetEndpointCoordinate(0));
358 ASSERT_EQ(40, h.GetEndpointCoordinate(1));
359 ASSERT_EQ(1u, h.GetProjectedRectanglesCount());
360 ASSERT_EQ(0u, h.GetProjectedRectangleLow(0));
361 ASSERT_EQ(1u, h.GetProjectedRectangleHigh(0));
362 }
363
364 rectangles.push_back(OrthancStone::Extent2D(20, 30, 40, 50));
365
366 {
367 OrthancStone::Internals::RectanglesIntegerProjection h(rectangles, true);
368 ASSERT_EQ(4u, h.GetEndpointsCount());
369 ASSERT_EQ(10, h.GetEndpointCoordinate(0));
370 ASSERT_EQ(20, h.GetEndpointCoordinate(1));
371 ASSERT_EQ(30, h.GetEndpointCoordinate(2));
372 ASSERT_EQ(40, h.GetEndpointCoordinate(3));
373 ASSERT_EQ(2u, h.GetProjectedRectanglesCount());
374 ASSERT_EQ(0u, h.GetProjectedRectangleLow(0));
375 ASSERT_EQ(2u, h.GetProjectedRectangleHigh(0));
376 ASSERT_EQ(1u, h.GetProjectedRectangleLow(1));
377 ASSERT_EQ(3u, h.GetProjectedRectangleHigh(1));
378 }
379
380 {
381 OrthancStone::Internals::RectanglesIntegerProjection h(rectangles, false);
382 ASSERT_EQ(4u, h.GetEndpointsCount());
383 ASSERT_EQ(20, h.GetEndpointCoordinate(0));
384 ASSERT_EQ(30, h.GetEndpointCoordinate(1));
385 ASSERT_EQ(40, h.GetEndpointCoordinate(2));
386 ASSERT_EQ(50, h.GetEndpointCoordinate(3));
387 ASSERT_EQ(2u, h.GetProjectedRectanglesCount());
388 ASSERT_EQ(0u, h.GetProjectedRectangleLow(0));
389 ASSERT_EQ(2u, h.GetProjectedRectangleHigh(0));
390 ASSERT_EQ(1u, h.GetProjectedRectangleLow(1));
391 ASSERT_EQ(3u, h.GetProjectedRectangleHigh(1));
392 }
393 }
394
395
396 static void Convert(std::vector<size_t>& horizontal,
397 std::vector<size_t>& vertical,
398 const OrthancStone::Internals::OrientedIntegerLine2D::Chain& chain)
399 {
400 horizontal.clear();
401 vertical.clear();
402
403 for (OrthancStone::Internals::OrientedIntegerLine2D::Chain::const_iterator
404 it = chain.begin(); it != chain.end(); ++it)
405 {
406 horizontal.push_back(it->first);
407 vertical.push_back(it->second);
408 }
409 }
410
411
412 TEST(UnionOfRectangles, ExtractChains)
413 {
414 std::vector<OrthancStone::Internals::OrientedIntegerLine2D> edges;
415 edges.push_back(OrthancStone::Internals::OrientedIntegerLine2D(0, 0, 10, 0));
416 edges.push_back(OrthancStone::Internals::OrientedIntegerLine2D(10, 0, 10, 20));
417 edges.push_back(OrthancStone::Internals::OrientedIntegerLine2D(10, 20, 0, 20));
418
419 std::list<OrthancStone::Internals::OrientedIntegerLine2D::Chain> chains;
420 OrthancStone::Internals::OrientedIntegerLine2D::ExtractChains(chains, edges);
421
422 std::vector<size_t> h, v;
423
424 ASSERT_EQ(1u, chains.size());
425
426 Convert(h, v, chains.front());
427 ASSERT_EQ(4u, h.size());
428 ASSERT_EQ(0u, h[0]);
429 ASSERT_EQ(10u, h[1]);
430 ASSERT_EQ(10u, h[2]);
431 ASSERT_EQ(0u, h[3]);
432 ASSERT_EQ(4u, v.size());
433 ASSERT_EQ(0u, v[0]);
434 ASSERT_EQ(0u, v[1]);
435 ASSERT_EQ(20u, v[2]);
436 ASSERT_EQ(20u, v[3]);
437
438 edges.push_back(OrthancStone::Internals::OrientedIntegerLine2D(5, 5, 10, 5));
439 OrthancStone::Internals::OrientedIntegerLine2D::ExtractChains(chains, edges);
440
441 ASSERT_EQ(2u, chains.size());
442
443 Convert(h, v, chains.front());
444 ASSERT_EQ(4u, h.size());
445 ASSERT_EQ(0u, h[0]);
446 ASSERT_EQ(10u, h[1]);
447 ASSERT_EQ(10u, h[2]);
448 ASSERT_EQ(0u, h[3]);
449 ASSERT_EQ(4u, v.size());
450 ASSERT_EQ(0u, v[0]);
451 ASSERT_EQ(0u, v[1]);
452 ASSERT_EQ(20u, v[2]);
453 ASSERT_EQ(20u, v[3]);
454
455 Convert(h, v, chains.back());
456 ASSERT_EQ(2u, h.size());
457 ASSERT_EQ(5u, h[0]);
458 ASSERT_EQ(10u, h[1]);
459 ASSERT_EQ(2u, v.size());
460 ASSERT_EQ(5u, v[0]);
461 ASSERT_EQ(5u, v[1]);
462
463 edges.push_back(OrthancStone::Internals::OrientedIntegerLine2D(0, 20, 5, 5));
464 OrthancStone::Internals::OrientedIntegerLine2D::ExtractChains(chains, edges);
465
466 ASSERT_EQ(1u, chains.size());
467
468 Convert(h, v, chains.front());
469 ASSERT_EQ(6u, h.size());
470 ASSERT_EQ(0u, h[0]);
471 ASSERT_EQ(10u, h[1]);
472 ASSERT_EQ(10u, h[2]);
473 ASSERT_EQ(0u, h[3]);
474 ASSERT_EQ(5u, h[4]);
475 ASSERT_EQ(10u, h[5]);
476 ASSERT_EQ(6u, v.size());
477 ASSERT_EQ(0u, v[0]);
478 ASSERT_EQ(0u, v[1]);
479 ASSERT_EQ(20u, v[2]);
480 ASSERT_EQ(20u, v[3]);
481 ASSERT_EQ(5u, v[4]);
482 ASSERT_EQ(5u, v[5]);
483 }
484
485
486 TEST(UnionOfRectangles, Textbook)
487 {
488 // This is Figure 8.12 from textbook
489
490 std::list<OrthancStone::Extent2D> rectangles;
491 rectangles.push_back(OrthancStone::Extent2D(1, 3, 13, 5));
492 rectangles.push_back(OrthancStone::Extent2D(3, 1, 7, 12));
493 rectangles.push_back(OrthancStone::Extent2D(5, 7, 11, 10));
494 rectangles.push_back(OrthancStone::Extent2D(10, 2, 14, 8));
495 rectangles.push_back(OrthancStone::Extent2D(3, 3, 4, 3)); // empty rectangle
496
497 for (unsigned int fillHole = 0; fillHole < 2; fillHole++)
498 {
499 if (fillHole)
500 {
501 rectangles.push_back(OrthancStone::Extent2D(6.5, 4.5, 10.5, 7.5));
502 }
503
504 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
505 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
506
507 ASSERT_EQ(fillHole ? 1u : 2u, contours.size());
508 ASSERT_EQ(17u, contours.front().size());
509 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(3, 12)));
510 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 12)));
511 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 10)));
512 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(11, 10)));
513 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(11, 8)));
514 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(14, 8)));
515 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(14, 2)));
516 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(10, 2)));
517 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(10, 3)));
518 ASSERT_TRUE(contours.front()[9].IsEqual(OrthancStone::ScenePoint2D(7, 3)));
519 ASSERT_TRUE(contours.front()[10].IsEqual(OrthancStone::ScenePoint2D(7, 1)));
520 ASSERT_TRUE(contours.front()[11].IsEqual(OrthancStone::ScenePoint2D(3, 1)));
521 ASSERT_TRUE(contours.front()[12].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
522 ASSERT_TRUE(contours.front()[13].IsEqual(OrthancStone::ScenePoint2D(1, 3)));
523 ASSERT_TRUE(contours.front()[14].IsEqual(OrthancStone::ScenePoint2D(1, 5)));
524 ASSERT_TRUE(contours.front()[15].IsEqual(OrthancStone::ScenePoint2D(3, 5)));
525 ASSERT_TRUE(contours.front()[16].IsEqual(OrthancStone::ScenePoint2D(3, 12)));
526
527 if (!fillHole)
528 {
529 ASSERT_EQ(5u, contours.back().size());
530 ASSERT_TRUE(contours.back()[0].IsEqual(OrthancStone::ScenePoint2D(10, 7)));
531 ASSERT_TRUE(contours.back()[1].IsEqual(OrthancStone::ScenePoint2D(7, 7)));
532 ASSERT_TRUE(contours.back()[2].IsEqual(OrthancStone::ScenePoint2D(7, 5)));
533 ASSERT_TRUE(contours.back()[3].IsEqual(OrthancStone::ScenePoint2D(10, 5)));
534 ASSERT_TRUE(contours.back()[4].IsEqual(OrthancStone::ScenePoint2D(10, 7)));
535 }
536 }
537 }
538
539
540 #if 0
541 static void SaveSvg(const std::list< std::vector<OrthancStone::ScenePoint2D> >& contours)
542 {
543 float ww = 15;
544 float hh = 13;
545
546 FILE* fp = fopen("test.svg", "w");
547 fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
548 fprintf(fp, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
549 fprintf(fp, "<svg width=\"%f\" height=\"%f\" viewBox=\"0 0 %f %f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", 100.0f*ww, 100.0f*hh, ww, hh);
550
551 // http://thenewcode.com/1068/Making-Arrows-in-SVG
552 fprintf(fp, "<defs>\n");
553 fprintf(fp, "<marker id=\"arrowhead\" markerWidth=\"2\" markerHeight=\"3\" \n");
554 fprintf(fp, "refX=\"2\" refY=\"1.5\" orient=\"auto\">\n");
555 fprintf(fp, "<polygon points=\"0 0, 2 1.5, 0 3\" />\n");
556 fprintf(fp, "</marker>\n");
557 fprintf(fp, "</defs>\n");
558
559 fprintf(fp, "<rect fill=\"#fff\" stroke=\"#000\" x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"/>\n", ww, hh);
560
561 for (std::list< std::vector<OrthancStone::ScenePoint2D> >::const_iterator
562 it = contours.begin(); it != contours.end(); ++it)
563 {
564 for (size_t i = 0; i + 1 < it->size(); i++)
565 {
566 float x1 = (*it)[i].GetX();
567 float x2 = (*it)[i + 1].GetX();
568 float y1 = (*it)[i].GetY();
569 float y2 = (*it)[i + 1].GetY();
570
571 fprintf(fp, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" stroke=\"blue\" stroke-width=\"0.05\" marker-end=\"url(#arrowhead)\"/>\n", x1, y1, x2, y2);
572 }
573 }
574 fprintf(fp, "</svg>\n");
575
576 fclose(fp);
577 }
578 #endif
579
580
581 TEST(UnionOfRectangles, EdgeCases)
582 {
583 {
584 std::list<OrthancStone::Extent2D> rectangles;
585
586 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
587 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
588
589 ASSERT_EQ(0u, contours.size());
590 }
591
592 {
593 std::list<OrthancStone::Extent2D> rectangles;
594 rectangles.push_back(OrthancStone::Extent2D(3, 3, 4, 3)); // empty rectangle
595
596 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
597 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
598
599 ASSERT_EQ(0u, contours.size());
600 }
601
602 {
603 std::list<OrthancStone::Extent2D> rectangles;
604 rectangles.push_back(OrthancStone::Extent2D(1, 1, 2, 2));
605
606 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
607 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
608
609 ASSERT_EQ(1u, contours.size());
610 ASSERT_EQ(5u, contours.front().size());
611 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
612 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
613 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(2, 1)));
614 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
615 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
616 }
617
618 {
619 std::list<OrthancStone::Extent2D> rectangles;
620 rectangles.push_back(OrthancStone::Extent2D(1, 1, 2, 2));
621 rectangles.push_back(OrthancStone::Extent2D(1, 3, 2, 4));
622
623 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
624 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
625
626 ASSERT_EQ(2u, contours.size());
627
628 ASSERT_EQ(5u, contours.front().size());
629 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
630 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
631 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
632 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(1, 3)));
633 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
634
635 ASSERT_EQ(5u, contours.back().size());
636 ASSERT_TRUE(contours.back()[0].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
637 ASSERT_TRUE(contours.back()[1].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
638 ASSERT_TRUE(contours.back()[2].IsEqual(OrthancStone::ScenePoint2D(2, 1)));
639 ASSERT_TRUE(contours.back()[3].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
640 ASSERT_TRUE(contours.back()[4].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
641 }
642
643 {
644 std::list<OrthancStone::Extent2D> rectangles;
645 rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
646 rectangles.push_back(OrthancStone::Extent2D(4, 6, 7, 8));
647 rectangles.push_back(OrthancStone::Extent2D(4, 2, 7, 4));
648 rectangles.push_back(OrthancStone::Extent2D(7, 4, 10, 6));
649
650 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
651 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
652
653 ASSERT_EQ(1u, contours.size());
654 ASSERT_EQ(17u, contours.front().size());
655 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
656 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 8)));
657 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
658 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(10, 6)));
659 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(10, 4)));
660 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
661 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(7, 2)));
662 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
663 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
664 ASSERT_TRUE(contours.front()[9].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
665 ASSERT_TRUE(contours.front()[10].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
666 ASSERT_TRUE(contours.front()[11].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
667 ASSERT_TRUE(contours.front()[12].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
668 ASSERT_TRUE(contours.front()[13].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
669 ASSERT_TRUE(contours.front()[14].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
670 ASSERT_TRUE(contours.front()[15].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
671 ASSERT_TRUE(contours.front()[16].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
672 }
673
674 {
675 std::list<OrthancStone::Extent2D> rectangles;
676 rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
677 rectangles.push_back(OrthancStone::Extent2D(4, 4, 7, 6));
678
679 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
680 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
681
682 ASSERT_EQ(1u, contours.size());
683 ASSERT_EQ(5u, contours.front().size());
684 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
685 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
686 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
687 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
688 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
689 }
690
691 {
692 std::list<OrthancStone::Extent2D> rectangles;
693 rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
694 rectangles.push_back(OrthancStone::Extent2D(1, 6, 4, 8));
695
696 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
697 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
698
699 ASSERT_EQ(1u, contours.size());
700 ASSERT_EQ(5u, contours.front().size());
701 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(1, 8)));
702 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
703 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
704 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
705 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(1, 8)));
706 }
707
708 {
709 std::list<OrthancStone::Extent2D> rectangles;
710 rectangles.push_back(OrthancStone::Extent2D(1, 1, 2, 2));
711 rectangles.push_back(OrthancStone::Extent2D(4, 4, 7, 6));
712 rectangles.push_back(OrthancStone::Extent2D(4, 6, 7, 8));
713
714 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
715 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
716
717 ASSERT_EQ(2u, contours.size());
718
719 ASSERT_EQ(5u, contours.front().size());
720 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
721 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 8)));
722 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
723 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
724 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
725
726 ASSERT_EQ(5u, contours.back().size());
727 ASSERT_TRUE(contours.back()[0].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
728 ASSERT_TRUE(contours.back()[1].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
729 ASSERT_TRUE(contours.back()[2].IsEqual(OrthancStone::ScenePoint2D(2, 1)));
730 ASSERT_TRUE(contours.back()[3].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
731 ASSERT_TRUE(contours.back()[4].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
732 }
733
734 {
735 std::list<OrthancStone::Extent2D> rectangles;
736 rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
737 rectangles.push_back(OrthancStone::Extent2D(6, 4, 9, 6));
738 rectangles.push_back(OrthancStone::Extent2D(4, 6, 7, 8));
739 rectangles.push_back(OrthancStone::Extent2D(4, 2, 7, 6));
740
741 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
742 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
743
744 ASSERT_EQ(1u, contours.size());
745 ASSERT_EQ(13u, contours.front().size());
746 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
747 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 8)));
748 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 6)));
749 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(9, 6)));
750 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(9, 4)));
751 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(7, 4)));
752 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(7, 2)));
753 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
754 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
755 ASSERT_TRUE(contours.front()[9].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
756 ASSERT_TRUE(contours.front()[10].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
757 ASSERT_TRUE(contours.front()[11].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
758 ASSERT_TRUE(contours.front()[12].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
759 }
760
761 {
762 std::list<OrthancStone::Extent2D> rectangles;
763 rectangles.push_back(OrthancStone::Extent2D(1, 4, 4, 6));
764 rectangles.push_back(OrthancStone::Extent2D(4, 6, 7, 8));
765 rectangles.push_back(OrthancStone::Extent2D(4, 2, 7, 6));
766
767 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
768 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
769
770 ASSERT_EQ(1u, contours.size());
771 ASSERT_EQ(9u, contours.front().size());
772 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
773 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(7, 8)));
774 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(7, 2)));
775 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
776 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
777 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
778 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(1, 6)));
779 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(4, 6)));
780 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(4, 8)));
781 }
782
783 {
784 std::list<OrthancStone::Extent2D> rectangles;
785 rectangles.push_back(OrthancStone::Extent2D(2, 2, 4, 4));
786 rectangles.push_back(OrthancStone::Extent2D(3, 3, 5, 5));
787
788 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
789 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
790
791 ASSERT_EQ(1u, contours.size());
792 ASSERT_EQ(9u, contours.front().size());
793 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(3, 5)));
794 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(5, 5)));
795 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(5, 3)));
796 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(4, 3)));
797 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
798 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
799 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
800 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
801 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(3, 5)));
802 }
803
804 {
805 std::list<OrthancStone::Extent2D> rectangles;
806 rectangles.push_back(OrthancStone::Extent2D(2, 2, 4, 4));
807 rectangles.push_back(OrthancStone::Extent2D(3, 1, 5, 3));
808
809 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
810 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
811
812 ASSERT_EQ(1u, contours.size());
813 ASSERT_EQ(9u, contours.front().size());
814 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
815 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
816 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(4, 3)));
817 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(5, 3)));
818 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(5, 1)));
819 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(3, 1)));
820 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
821 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
822 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
823 }
824
825 {
826 std::list<OrthancStone::Extent2D> rectangles;
827 rectangles.push_back(OrthancStone::Extent2D(2, 2, 4, 4));
828 rectangles.push_back(OrthancStone::Extent2D(1, 1, 3, 3));
829
830 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
831 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
832
833 ASSERT_EQ(1u, contours.size());
834 ASSERT_EQ(9u, contours.front().size());
835 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
836 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
837 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
838 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
839 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(3, 1)));
840 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
841 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(1, 3)));
842 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
843 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
844 }
845
846 {
847 std::list<OrthancStone::Extent2D> rectangles;
848 rectangles.push_back(OrthancStone::Extent2D(2, 2, 4, 4));
849 rectangles.push_back(OrthancStone::Extent2D(1, 3, 3, 5));
850
851 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
852 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
853
854 ASSERT_EQ(1u, contours.size());
855 ASSERT_EQ(9u, contours.front().size());
856 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(1, 5)));
857 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(3, 5)));
858 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
859 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
860 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
861 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
862 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
863 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(1, 3)));
864 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(1, 5)));
865 }
866
867 {
868 std::list<OrthancStone::Extent2D> rectangles;
869 rectangles.push_back(OrthancStone::Extent2D(2, 2, 3, 3));
870 rectangles.push_back(OrthancStone::Extent2D(3, 1, 4, 2));
871
872 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
873 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
874
875 ASSERT_EQ(1u, contours.size());
876 ASSERT_EQ(9u, contours.front().size());
877 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
878 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
879 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
880 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(4, 2)));
881 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(4, 1)));
882 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(3, 1)));
883 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
884 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
885 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
886 }
887
888 {
889 std::list<OrthancStone::Extent2D> rectangles;
890 rectangles.push_back(OrthancStone::Extent2D(2, 2, 3, 3));
891 rectangles.push_back(OrthancStone::Extent2D(3, 3, 4, 4));
892
893 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
894 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
895
896 ASSERT_EQ(1u, contours.size());
897 ASSERT_EQ(9u, contours.front().size());
898 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
899 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
900 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(4, 3)));
901 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
902 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
903 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
904 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
905 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
906 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
907 }
908
909 {
910 std::list<OrthancStone::Extent2D> rectangles;
911 rectangles.push_back(OrthancStone::Extent2D(2, 2, 3, 3));
912 rectangles.push_back(OrthancStone::Extent2D(1, 3, 2, 4));
913
914 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
915 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
916
917 ASSERT_EQ(1u, contours.size());
918 ASSERT_EQ(9u, contours.front().size());
919 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
920 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
921 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
922 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
923 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
924 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
925 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
926 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(1, 3)));
927 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
928 }
929
930 {
931 std::list<OrthancStone::Extent2D> rectangles;
932 rectangles.push_back(OrthancStone::Extent2D(2, 2, 3, 3));
933 rectangles.push_back(OrthancStone::Extent2D(1, 1, 2, 2));
934
935 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
936 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
937
938 ASSERT_EQ(1u, contours.size());
939 ASSERT_EQ(9u, contours.front().size());
940 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
941 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
942 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
943 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
944 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(2, 1)));
945 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(1, 1)));
946 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(1, 2)));
947 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
948 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
949 }
950
951 {
952 std::list<OrthancStone::Extent2D> rectangles;
953 rectangles.push_back(OrthancStone::Extent2D(2, 2, 3, 5));
954 rectangles.push_back(OrthancStone::Extent2D(1, 3, 4, 4));
955
956 std::list< std::vector<OrthancStone::ScenePoint2D> > contours;
957 OrthancStone::UnionOfRectangles::Apply(contours, rectangles);
958
959 ASSERT_EQ(1u, contours.size());
960 ASSERT_EQ(13u, contours.front().size());
961 ASSERT_TRUE(contours.front()[0].IsEqual(OrthancStone::ScenePoint2D(2, 5)));
962 ASSERT_TRUE(contours.front()[1].IsEqual(OrthancStone::ScenePoint2D(3, 5)));
963 ASSERT_TRUE(contours.front()[2].IsEqual(OrthancStone::ScenePoint2D(3, 4)));
964 ASSERT_TRUE(contours.front()[3].IsEqual(OrthancStone::ScenePoint2D(4, 4)));
965 ASSERT_TRUE(contours.front()[4].IsEqual(OrthancStone::ScenePoint2D(4, 3)));
966 ASSERT_TRUE(contours.front()[5].IsEqual(OrthancStone::ScenePoint2D(3, 3)));
967 ASSERT_TRUE(contours.front()[6].IsEqual(OrthancStone::ScenePoint2D(3, 2)));
968 ASSERT_TRUE(contours.front()[7].IsEqual(OrthancStone::ScenePoint2D(2, 2)));
969 ASSERT_TRUE(contours.front()[8].IsEqual(OrthancStone::ScenePoint2D(2, 3)));
970 ASSERT_TRUE(contours.front()[9].IsEqual(OrthancStone::ScenePoint2D(1, 3)));
971 ASSERT_TRUE(contours.front()[10].IsEqual(OrthancStone::ScenePoint2D(1, 4)));
972 ASSERT_TRUE(contours.front()[11].IsEqual(OrthancStone::ScenePoint2D(2, 4)));
973 ASSERT_TRUE(contours.front()[12].IsEqual(OrthancStone::ScenePoint2D(2, 5)));
974 }
975 }