comparison OrthancStone/UnitTestsSources/TestStructureSet.cpp @ 1894:438071a29f77

xor polygon filler for holes in rt-struct
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 19 Jan 2022 14:25:59 +0100
parents 90b5e116a5f9
children 14c8f339d480
comparison
equal deleted inserted replaced
1893:90b5e116a5f9 1894:438071a29f77
29 // warning C4748: /GS can not protect parameters and local variables from 29 // warning C4748: /GS can not protect parameters and local variables from
30 // local buffer overrun because optimizations are disabled in function 30 // local buffer overrun because optimizations are disabled in function
31 # pragma warning(disable: 4748) 31 # pragma warning(disable: 4748)
32 #endif 32 #endif
33 33
34 #include "../Sources/Toolbox/DicomStructureSet.h"
34 #include "../Sources/Toolbox/DicomStructureSet2.h" 35 #include "../Sources/Toolbox/DicomStructureSet2.h"
35 #include "../Sources/Toolbox/DicomStructureSetUtils.h" 36 #include "../Sources/Toolbox/DicomStructureSetUtils.h"
36 #include "../Sources/Toolbox/DisjointDataSet.h" 37 #include "../Sources/Toolbox/DisjointDataSet.h"
37 38
38 #include <EmbeddedResources.h> 39 #include <EmbeddedResources.h>
85 } 86 }
86 87
87 88
88 #include <Toolbox.h> 89 #include <Toolbox.h>
89 90
90 TEST(StructureSet, ReadFromJsonThatsAll) 91 TEST(StructureSet2, ReadFromJsonThatsAll)
91 { 92 {
92 /* 93 /*
93 The "RT_STRUCT_00" string is the reply to the following Orthanc request: 94 The "RT_STRUCT_00" string is the reply to the following Orthanc request:
94 95
95 http://localhost:8042/instances/1aa5f84b-c32a03b4-3c1857da-da2e69f3-3ef6e2b3/tags?ignore-length=3006-0050 96 http://localhost:8042/instances/1aa5f84b-c32a03b4-3c1857da-da2e69f3-3ef6e2b3/tags?ignore-length=3006-0050
97 The tag hierarchy can be found here: https://dicom.innolitics.com/ciods/rt-dose 98 The tag hierarchy can be found here: https://dicom.innolitics.com/ciods/rt-dose
98 */ 99 */
99 100
100 DicomStructureSet2 structureSet; 101 DicomStructureSet2 structureSet;
101 102
102 Json::Value test; 103 FullOrthancDataset dicom(Orthanc::EmbeddedResources::GetFileResourceBuffer(Orthanc::EmbeddedResources::RT_STRUCT_00),
103 Orthanc::Toolbox::ReadJson(test, Orthanc::EmbeddedResources::GetFileResourceBuffer(Orthanc::EmbeddedResources::RT_STRUCT_00), 104 Orthanc::EmbeddedResources::GetFileResourceSize(Orthanc::EmbeddedResources::RT_STRUCT_00));
104 Orthanc::EmbeddedResources::GetFileResourceSize(Orthanc::EmbeddedResources::RT_STRUCT_00));
105
106 FullOrthancDataset dicom(test);
107 structureSet.Clear(); 105 structureSet.Clear();
108 106
109 structureSet.FillStructuresFromDataset(dicom); 107 structureSet.FillStructuresFromDataset(dicom);
110 structureSet.ComputeDependentProperties(); 108 structureSet.ComputeDependentProperties();
111 109
218 #endif 216 #endif
219 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2 217 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2
220 218
221 #if 0 219 #if 0
222 220
223 TEST(StructureSet, ReadFromJsonAndCompute1) 221 TEST(StructureSet2, ReadFromJsonAndCompute1)
224 { 222 {
225 DicomStructureSet2 structureSet; 223 DicomStructureSet2 structureSet;
226 224
227 OrthancPlugins::FullOrthancDataset dicom(GetTestJson()); 225 OrthancPlugins::FullOrthancDataset dicom(GetTestJson());
228 structureSet.Clear(); 226 structureSet.Clear();
230 structureSet.FillStructuresFromDataset(dicom); 228 structureSet.FillStructuresFromDataset(dicom);
231 229
232 structureSet.ComputeDependentProperties(); 230 structureSet.ComputeDependentProperties();
233 } 231 }
234 232
235 TEST(StructureSet, ReadFromJsonAndCompute2) 233 TEST(StructureSet2, ReadFromJsonAndCompute2)
236 { 234 {
237 DicomStructureSet2 structureSet; 235 DicomStructureSet2 structureSet;
238 236
239 OrthancPlugins::FullOrthancDataset dicom(GetTestJson()); 237 OrthancPlugins::FullOrthancDataset dicom(GetTestJson());
240 structureSet.Clear(); 238 structureSet.Clear();
299 } 297 }
300 structure.ComputeDependentProperties(); 298 structure.ComputeDependentProperties();
301 } 299 }
302 300
303 301
304 TEST(StructureSet, CutAxialOutsideTop) 302 TEST(StructureSet2, CutAxialOutsideTop)
305 { 303 {
306 DicomStructure2 structure; 304 DicomStructure2 structure;
307 CreateBasicStructure(structure); 305 CreateBasicStructure(structure);
308 std::vector< std::pair<Point2D, Point2D> > segments; 306 std::vector< std::pair<Point2D, Point2D> > segments;
309 307
315 0, 1, 0); 313 0, 1, 0);
316 EXPECT_FALSE(ok); 314 EXPECT_FALSE(ok);
317 } 315 }
318 316
319 317
320 TEST(StructureSet, CutAxialOutsideBottom) 318 TEST(StructureSet2, CutAxialOutsideBottom)
321 { 319 {
322 DicomStructure2 structure; 320 DicomStructure2 structure;
323 CreateBasicStructure(structure); 321 CreateBasicStructure(structure);
324 std::vector< std::pair<Point2D, Point2D> > segments; 322 std::vector< std::pair<Point2D, Point2D> > segments;
325 323
330 1, 0, 0, 328 1, 0, 0,
331 0, 1, 0); 329 0, 1, 0);
332 EXPECT_FALSE(ok); 330 EXPECT_FALSE(ok);
333 } 331 }
334 332
335 TEST(StructureSet, CutAxialInsideClose) 333 TEST(StructureSet2, CutAxialInsideClose)
336 { 334 {
337 DicomStructure2 structure; 335 DicomStructure2 structure;
338 CreateBasicStructure(structure); 336 CreateBasicStructure(structure);
339 std::vector< std::pair<Point2D, Point2D> > segments; 337 std::vector< std::pair<Point2D, Point2D> > segments;
340 338
359 EXPECT_NEAR(pt.y, pointsCoord2[i], DELTA_MAX); 357 EXPECT_NEAR(pt.y, pointsCoord2[i], DELTA_MAX);
360 } 358 }
361 } 359 }
362 360
363 361
364 TEST(StructureSet, CutAxialInsideFar) 362 TEST(StructureSet2, CutAxialInsideFar)
365 { 363 {
366 DicomStructure2 structure; 364 DicomStructure2 structure;
367 CreateBasicStructure(structure); 365 CreateBasicStructure(structure);
368 std::vector< std::pair<Point2D, Point2D> > segments; 366 std::vector< std::pair<Point2D, Point2D> > segments;
369 367
392 EXPECT_NEAR(pt.x, pointsCoord1[i], DELTA_MAX); 390 EXPECT_NEAR(pt.x, pointsCoord1[i], DELTA_MAX);
393 EXPECT_NEAR(pt.y, pointsCoord2[i], DELTA_MAX); 391 EXPECT_NEAR(pt.y, pointsCoord2[i], DELTA_MAX);
394 } 392 }
395 } 393 }
396 394
397 TEST(StructureSet, CutCoronalOutsideClose) 395 TEST(StructureSet2, CutCoronalOutsideClose)
398 { 396 {
399 DicomStructure2 structure; 397 DicomStructure2 structure;
400 CreateBasicStructure(structure); 398 CreateBasicStructure(structure);
401 std::vector< std::pair<Point2D, Point2D> > segments; 399 std::vector< std::pair<Point2D, Point2D> > segments;
402 400
410 // compute intersection 408 // compute intersection
411 bool ok = structure.Project(segments, cuttingPlane); 409 bool ok = structure.Project(segments, cuttingPlane);
412 EXPECT_FALSE(ok); 410 EXPECT_FALSE(ok);
413 } 411 }
414 412
415 TEST(StructureSet, CutCoronalInsideClose1DTest) 413 TEST(StructureSet2, CutCoronalInsideClose1DTest)
416 { 414 {
417 DicomStructure2 structure; 415 DicomStructure2 structure;
418 CreateBasicStructure(structure); 416 CreateBasicStructure(structure);
419 417
420 // create an X,Z cutting plane, outside of the volume 418 // create an X,Z cutting plane, outside of the volume
449 EXPECT_NEAR(polygonZ, intersects[i].y, DELTA_MAX); 447 EXPECT_NEAR(polygonZ, intersects[i].y, DELTA_MAX);
450 } 448 }
451 } 449 }
452 } 450 }
453 451
454 TEST(StructureSet, CutCoronalInsideClose) 452 TEST(StructureSet2, CutCoronalInsideClose)
455 { 453 {
456 DicomStructure2 structure; 454 DicomStructure2 structure;
457 CreateBasicStructure(structure); 455 CreateBasicStructure(structure);
458 std::vector< std::pair<Point2D, Point2D> > segments; 456 std::vector< std::pair<Point2D, Point2D> > segments;
459 457
547 } 545 }
548 } 546 }
549 547
550 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2 548 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
551 549
552 TEST(StructureSet, CutSagittalInsideClose) 550 TEST(StructureSet2, CutSagittalInsideClose)
553 { 551 {
554 DicomStructure2 structure; 552 DicomStructure2 structure;
555 CreateBasicStructure(structure); 553 CreateBasicStructure(structure);
556 std::vector< std::pair<Point2D, Point2D> > segments; 554 std::vector< std::pair<Point2D, Point2D> > segments;
557 555
635 const std::vector<std::pair<double, RectangleBoundaryKind> >& boundaries, 633 const std::vector<std::pair<double, RectangleBoundaryKind> >& boundaries,
636 double y) 634 double y)
637 */ 635 */
638 636
639 637
640 TEST(StructureSet, ProcessBoundaryList_Empty) 638 TEST(StructureSet2, ProcessBoundaryList_Empty)
641 { 639 {
642 std::vector< RtStructRectanglesInSlab > slabCuts; 640 std::vector< RtStructRectanglesInSlab > slabCuts;
643 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 641 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
644 642
645 boundaries.clear(); 643 boundaries.clear();
646 EXPECT_NO_THROW(AddSlabBoundaries(boundaries, slabCuts, 0)); 644 EXPECT_NO_THROW(AddSlabBoundaries(boundaries, slabCuts, 0));
647 ASSERT_EQ(0u, boundaries.size()); 645 ASSERT_EQ(0u, boundaries.size());
648 } 646 }
649 647
650 TEST(StructureSet, ProcessBoundaryListTopRow) 648 TEST(StructureSet2, ProcessBoundaryListTopRow)
651 { 649 {
652 std::vector< RtStructRectanglesInSlab > slabCuts; 650 std::vector< RtStructRectanglesInSlab > slabCuts;
653 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 651 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
654 FillTestRectangleList(slabCuts); 652 FillTestRectangleList(slabCuts);
655 653
676 ASSERT_NEAR(50, boundaries[i].first, DELTA_MAX); 674 ASSERT_NEAR(50, boundaries[i].first, DELTA_MAX);
677 i++; 675 i++;
678 } 676 }
679 } 677 }
680 678
681 TEST(StructureSet, ProcessBoundaryListRows_0_and_1) 679 TEST(StructureSet2, ProcessBoundaryListRows_0_and_1)
682 { 680 {
683 std::vector< RtStructRectanglesInSlab > slabCuts; 681 std::vector< RtStructRectanglesInSlab > slabCuts;
684 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 682 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
685 FillTestRectangleList(slabCuts); 683 FillTestRectangleList(slabCuts);
686 684
725 ASSERT_NEAR(70, boundaries[i].first, DELTA_MAX); 723 ASSERT_NEAR(70, boundaries[i].first, DELTA_MAX);
726 i++; 724 i++;
727 } 725 }
728 } 726 }
729 727
730 TEST(StructureSet, ConvertListOfSlabsToSegments_EmptyBoundaries) 728 TEST(StructureSet2, ConvertListOfSlabsToSegments_EmptyBoundaries)
731 { 729 {
732 std::vector< RtStructRectanglesInSlab > slabCuts; 730 std::vector< RtStructRectanglesInSlab > slabCuts;
733 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 731 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
734 FillTestRectangleList(slabCuts); 732 FillTestRectangleList(slabCuts);
735 boundaries.clear(); 733 boundaries.clear();
736 std::vector< std::pair<Point2D, Point2D> > segments; 734 std::vector< std::pair<Point2D, Point2D> > segments;
737 ASSERT_NO_THROW(ProcessBoundaryList(segments, boundaries, 42.0)); 735 ASSERT_NO_THROW(ProcessBoundaryList(segments, boundaries, 42.0));
738 ASSERT_EQ(0u, segments.size()); 736 ASSERT_EQ(0u, segments.size());
739 } 737 }
740 738
741 TEST(StructureSet, ConvertListOfSlabsToSegments_TopRow_Horizontal) 739 TEST(StructureSet2, ConvertListOfSlabsToSegments_TopRow_Horizontal)
742 { 740 {
743 std::vector< RtStructRectanglesInSlab > slabCuts; 741 std::vector< RtStructRectanglesInSlab > slabCuts;
744 FillTestRectangleList(slabCuts); 742 FillTestRectangleList(slabCuts);
745 743
746 // top row 744 // top row
762 ASSERT_NEAR( 0.0, segments[1].first.y, DELTA_MAX); 760 ASSERT_NEAR( 0.0, segments[1].first.y, DELTA_MAX);
763 ASSERT_NEAR( 0.0, segments[1].second.y, DELTA_MAX); 761 ASSERT_NEAR( 0.0, segments[1].second.y, DELTA_MAX);
764 } 762 }
765 } 763 }
766 764
767 TEST(StructureSet, ConvertListOfSlabsToSegments_All_Horizontal) 765 TEST(StructureSet2, ConvertListOfSlabsToSegments_All_Horizontal)
768 { 766 {
769 std::vector< RtStructRectanglesInSlab > slabCuts; 767 std::vector< RtStructRectanglesInSlab > slabCuts;
770 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 768 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
771 FillTestRectangleList(slabCuts); 769 FillTestRectangleList(slabCuts);
772 770
829 ASSERT_NEAR(10.0, segments[1].second.y, DELTA_MAX); 827 ASSERT_NEAR(10.0, segments[1].second.y, DELTA_MAX);
830 } 828 }
831 829
832 } 830 }
833 831
834 TEST(StructureSet, ConvertListOfSlabsToSegments_Complete_Empty) 832 TEST(StructureSet2, ConvertListOfSlabsToSegments_Complete_Empty)
835 { 833 {
836 std::vector< RtStructRectanglesInSlab > slabCuts; 834 std::vector< RtStructRectanglesInSlab > slabCuts;
837 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 835 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
838 836
839 std::vector< std::pair<Point2D, Point2D> > segments; 837 std::vector< std::pair<Point2D, Point2D> > segments;
840 838
841 ASSERT_NO_THROW(ConvertListOfSlabsToSegments(segments, slabCuts, 0)); 839 ASSERT_NO_THROW(ConvertListOfSlabsToSegments(segments, slabCuts, 0));
842 ASSERT_EQ(0u, segments.size()); 840 ASSERT_EQ(0u, segments.size());
843 } 841 }
844 842
845 TEST(StructureSet, ConvertListOfSlabsToSegments_Complete_Regular) 843 TEST(StructureSet2, ConvertListOfSlabsToSegments_Complete_Regular)
846 { 844 {
847 std::vector< RtStructRectanglesInSlab > slabCuts; 845 std::vector< RtStructRectanglesInSlab > slabCuts;
848 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries; 846 std::vector<std::pair<double, RectangleBoundaryKind> > boundaries;
849 size_t totalRectCount = FillTestRectangleList(slabCuts); 847 size_t totalRectCount = FillTestRectangleList(slabCuts);
850 848
1158 1156
1159 #if defined(BGO_ENABLE_DICOMSTRUCTURESETLOADER2) && (ORTHANC_SANDBOXED != 1) 1157 #if defined(BGO_ENABLE_DICOMSTRUCTURESETLOADER2) && (ORTHANC_SANDBOXED != 1)
1160 1158
1161 #include <SystemToolbox.h> 1159 #include <SystemToolbox.h>
1162 1160
1163 TEST(StructureSet, ReadFromJsonPart2) 1161 TEST(StructureSet2, ReadFromJsonPart2)
1164 { 1162 {
1165 DicomStructureSet2 structureSet; 1163 DicomStructureSet2 structureSet;
1166 std::string jsonText; 1164 std::string jsonText;
1167 1165
1168 Orthanc::SystemToolbox::ReadFile(jsonText, "72c773ac-5059f2c4-2e6a9120-4fd4bca1-45701661.json"); 1166 Orthanc::SystemToolbox::ReadFile(jsonText, "72c773ac-5059f2c4-2e6a9120-4fd4bca1-45701661.json");
1176 //const std::vector<DicomStructure2>& structures = structureSet.structures_; 1174 //const std::vector<DicomStructure2>& structures = structureSet.structures_;
1177 } 1175 }
1178 1176
1179 #endif 1177 #endif
1180 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2 1178 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2
1179
1180
1181 TEST(StructureSet, ReadFromJson)
1182 {
1183 FullOrthancDataset dicom(Orthanc::EmbeddedResources::GetFileResourceBuffer(Orthanc::EmbeddedResources::RT_STRUCT_00),
1184 Orthanc::EmbeddedResources::GetFileResourceSize(Orthanc::EmbeddedResources::RT_STRUCT_00));
1185
1186 DicomStructureSet rtstruct(dicom);
1187
1188 ASSERT_DOUBLE_EQ(0.0, rtstruct.GetEstimatedNormal() [0]);
1189 ASSERT_DOUBLE_EQ(0.0, rtstruct.GetEstimatedNormal() [1]);
1190 ASSERT_DOUBLE_EQ(1.0, rtstruct.GetEstimatedNormal() [2]);
1191 ASSERT_DOUBLE_EQ(3.0, rtstruct.GetEstimatedSliceThickness());
1192
1193 // (0x3006, 0x0080) seq. size
1194 ASSERT_EQ(7u, rtstruct.GetStructuresCount());
1195
1196 // (0x3006, 0x0080)[i]/(0x3006, 0x00a4)
1197 for (size_t i = 0; i < 5; ++i)
1198 {
1199 ASSERT_EQ("ORGAN", rtstruct.GetStructureInterpretation(i));
1200 }
1201
1202 ASSERT_EQ("EXTERNAL", rtstruct.GetStructureInterpretation(5));
1203 ASSERT_EQ("PTV", rtstruct.GetStructureInterpretation(6));
1204
1205 // (0x3006, 0x0020)[i]/(0x3006, 0x0026)
1206 ASSERT_EQ("LN300", rtstruct.GetStructureName(0));
1207 ASSERT_EQ("Cortical Bone", rtstruct.GetStructureName(1));
1208 ASSERT_EQ("Adipose", rtstruct.GetStructureName(2));
1209 ASSERT_EQ("CB2-50%", rtstruct.GetStructureName(3));
1210 ASSERT_EQ("Water", rtstruct.GetStructureName(4));
1211 ASSERT_EQ("External", rtstruct.GetStructureName(5));
1212 ASSERT_EQ("PTV", rtstruct.GetStructureName(6));
1213
1214 // (0x3006, 0x0039)[i]/(0x3006, 0x002a)
1215 ASSERT_EQ(255, rtstruct.GetStructureColor(0).GetRed());
1216 ASSERT_EQ(0, rtstruct.GetStructureColor(0).GetGreen());
1217 ASSERT_EQ(0, rtstruct.GetStructureColor(0).GetBlue());
1218
1219 ASSERT_EQ(0, rtstruct.GetStructureColor(1).GetRed());
1220 ASSERT_EQ(255, rtstruct.GetStructureColor(1).GetGreen());
1221 ASSERT_EQ(255, rtstruct.GetStructureColor(1).GetBlue());
1222
1223 ASSERT_EQ(255, rtstruct.GetStructureColor(2).GetRed());
1224 ASSERT_EQ(0, rtstruct.GetStructureColor(2).GetGreen());
1225 ASSERT_EQ(255, rtstruct.GetStructureColor(2).GetBlue());
1226
1227 ASSERT_EQ(0, rtstruct.GetStructureColor(3).GetRed());
1228 ASSERT_EQ(0, rtstruct.GetStructureColor(3).GetGreen());
1229 ASSERT_EQ(255, rtstruct.GetStructureColor(3).GetBlue());
1230
1231 ASSERT_EQ(0, rtstruct.GetStructureColor(4).GetRed());
1232 ASSERT_EQ(128, rtstruct.GetStructureColor(4).GetGreen());
1233 ASSERT_EQ(255, rtstruct.GetStructureColor(4).GetBlue());
1234
1235 ASSERT_EQ(0, rtstruct.GetStructureColor(5).GetRed());
1236 ASSERT_EQ(128, rtstruct.GetStructureColor(5).GetGreen());
1237 ASSERT_EQ(0, rtstruct.GetStructureColor(5).GetBlue());
1238
1239 ASSERT_EQ(255, rtstruct.GetStructureColor(6).GetRed());
1240 ASSERT_EQ(0, rtstruct.GetStructureColor(6).GetGreen());
1241 ASSERT_EQ(255, rtstruct.GetStructureColor(6).GetBlue());
1242 }