Mercurial > hg > orthanc-stl
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 } |