comparison Sources/StructurePolygon.cpp @ 33:2460b376d3f7

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 04 Apr 2024 18:50:11 +0200
parents
children
comparison
equal deleted inserted replaced
32:976da5476810 33:2460b376d3f7
1 /**
2 * SPDX-FileCopyrightText: 2023-2024 Sebastien Jodogne, UCLouvain, Belgium
3 * SPDX-License-Identifier: GPL-3.0-or-later
4 */
5
6 /**
7 * STL plugin for Orthanc
8 * Copyright (C) 2023-2024 Sebastien Jodogne, UCLouvain, Belgium
9 *
10 * This program is free software: you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, either version 3 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 **/
23
24
25 #include "StructurePolygon.h"
26
27 #include "STLToolbox.h"
28
29 #include <OrthancException.h>
30 #include <SerializationToolbox.h>
31
32 #include <dcmtk/dcmdata/dcfilefo.h>
33 #include <dcmtk/dcmdata/dcdeftag.h>
34
35
36 StructurePolygon::StructurePolygon(Orthanc::ParsedDicomFile& dicom,
37 unsigned long roiIndex,
38 unsigned long contourIndex)
39 {
40 DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset();
41
42 DcmItem* structure = NULL;
43 DcmItem* roi = NULL;
44 DcmItem* contour = NULL;
45 DcmSequenceOfItems* referenced = NULL;
46
47 if (!dataset.findAndGetSequenceItem(DCM_StructureSetROISequence, structure, roiIndex).good() ||
48 structure == NULL ||
49 !dataset.findAndGetSequenceItem(DCM_ROIContourSequence, roi, roiIndex).good() ||
50 roi == NULL ||
51 !roi->findAndGetSequenceItem(DCM_ContourSequence, contour, contourIndex).good() ||
52 contour == NULL ||
53 !contour->findAndGetSequence(DCM_ContourImageSequence, referenced).good() ||
54 referenced == NULL ||
55 referenced->card() != 1)
56 {
57 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
58 }
59
60 roiName_ = STLToolbox::GetStringValue(*structure, DCM_ROIName);
61 referencedSopInstanceUid_ = STLToolbox::GetStringValue(*referenced->getItem(0), DCM_ReferencedSOPInstanceUID);
62
63 if (STLToolbox::GetStringValue(*contour, DCM_ContourGeometricType) != "CLOSED_PLANAR")
64 {
65 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
66 }
67
68 {
69 std::vector<std::string> tokens;
70 Orthanc::Toolbox::TokenizeString(tokens, STLToolbox::GetStringValue(*roi, DCM_ROIDisplayColor), '\\');
71
72 uint32_t r, g, b;
73 if (tokens.size() != 3 ||
74 !Orthanc::SerializationToolbox::ParseFirstUnsignedInteger32(r, tokens[0]) ||
75 !Orthanc::SerializationToolbox::ParseFirstUnsignedInteger32(g, tokens[1]) ||
76 !Orthanc::SerializationToolbox::ParseFirstUnsignedInteger32(b, tokens[2]) ||
77 r > 255 ||
78 g > 255 ||
79 b > 255)
80 {
81 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
82 }
83
84 red_ = r;
85 green_ = g;
86 blue_ = b;
87 }
88
89 {
90 std::vector<std::string> tokens;
91 Orthanc::Toolbox::TokenizeString(tokens, STLToolbox::GetStringValue(*contour, DCM_ContourData), '\\');
92
93 const std::string s = STLToolbox::GetStringValue(*contour, DCM_NumberOfContourPoints);
94
95 uint32_t countPoints;
96 if (!Orthanc::SerializationToolbox::ParseUnsignedInteger32(countPoints, s) ||
97 tokens.size() != 3 * countPoints)
98 {
99 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
100 }
101
102 points_.reserve(countPoints);
103
104 for (size_t i = 0; i < tokens.size(); i += 3)
105 {
106 double x, y, z;
107 if (!STLToolbox::MyParseDouble(x, tokens[i]) ||
108 !STLToolbox::MyParseDouble(y, tokens[i + 1]) ||
109 !STLToolbox::MyParseDouble(z, tokens[i + 2]))
110 {
111 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
112 }
113
114 points_.push_back(Vector3D(x, y, z));
115 }
116
117 assert(points_.size() == countPoints);
118 }
119 }
120
121
122 const Vector3D& StructurePolygon::GetPoint(size_t i) const
123 {
124 if (i >= points_.size())
125 {
126 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
127 }
128 else
129 {
130 return points_[i];
131 }
132 }
133
134
135 bool StructurePolygon::IsCoplanar(Vector3D& normal) const
136 {
137 if (points_.size() < 3)
138 {
139 return false;
140 }
141
142 bool hasNormal = false;
143
144 for (size_t i = 0; i < points_.size(); i++)
145 {
146 normal = Vector3D::CrossProduct(Vector3D(points_[1], points_[0]),
147 Vector3D(points_[2], points_[0]));
148 if (!STLToolbox::IsNear(normal.ComputeNorm(), 0))
149 {
150 normal.Normalize();
151 hasNormal = true;
152 }
153 }
154
155 if (!hasNormal)
156 {
157 return false;
158 }
159
160 double a = Vector3D::DotProduct(points_[0], normal);
161
162 for (size_t i = 1; i < points_.size(); i++)
163 {
164 double b = Vector3D::DotProduct(points_[i], normal);
165 if (!STLToolbox::IsNear(a, b))
166 {
167 return false;
168 }
169 }
170
171 return true;
172 }
173
174
175 void StructurePolygon::Add(Extent2D& extent,
176 const Vector3D& axisX,
177 const Vector3D& axisY) const
178 {
179 assert(STLToolbox::IsNear(1, axisX.ComputeNorm()));
180 assert(STLToolbox::IsNear(1, axisY.ComputeNorm()));
181
182 for (size_t i = 0; i < points_.size(); i++)
183 {
184 extent.Add(Vector3D::DotProduct(axisX, points_[i]),
185 Vector3D::DotProduct(axisY, points_[i]));
186 }
187 }