annotate Framework/Toolbox/CoordinateSystem3D.cpp @ 1327:4f8db2d202c8 broker

OrthancSeriesProgressiveLoader now has two modes that can be selected at object creation : - progressive (will first load jpeg50, then jpeg90 then PAM) - non-progressive (will directly load PAM (uncompressed)) Please note that the slice loading order remains dynamic and depending upon the slice that the client code wishes to extract from the volume.
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 25 Mar 2020 14:34:27 +0100
parents 7ec8fea061b9
children 30deba7bc8e2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
1 /**
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
2 * Stone of Orthanc
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
4 * Department, University Hospital of Liege, Belgium
1270
2d8ab34c8c91 upgrade to year 2020
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
6 *
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
7 * This program is free software: you can redistribute it and/or
47
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
8 * modify it under the terms of the GNU Affero General Public License
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
9 * as published by the Free Software Foundation, either version 3 of
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
10 * the License, or (at your option) any later version.
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
11 *
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
12 * This program is distributed in the hope that it will be useful, but
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
47
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
15 * Affero General Public License for more details.
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
16 *
28956ed68280 agpl license
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 40
diff changeset
17 * You should have received a copy of the GNU Affero General Public License
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
19 **/
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
20
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
21
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
22 #include "CoordinateSystem3D.h"
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
23
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
24 #include "LinearAlgebra.h"
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
25 #include "GeometryToolbox.h"
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
26
212
5412adf19980 resort to OrthancFramework
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 201
diff changeset
27 #include <Core/Logging.h>
5412adf19980 resort to OrthancFramework
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 201
diff changeset
28 #include <Core/Toolbox.h>
5412adf19980 resort to OrthancFramework
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 201
diff changeset
29 #include <Core/OrthancException.h>
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
30
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
31 namespace OrthancStone
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
32 {
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
33 void CoordinateSystem3D::CheckAndComputeNormal()
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
34 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
35 // DICOM expects normal vectors to define the axes: "The row and
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
36 // column direction cosine vectors shall be normal, i.e., the dot
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
37 // product of each direction cosine vector with itself shall be
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
38 // unity."
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
39 // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.2.html
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
40 if (!LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(axisX_), 1.0) ||
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
41 !LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(axisY_), 1.0))
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
42 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
43 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
44 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
45
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
46 // The vectors within "Image Orientation Patient" must be
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
47 // orthogonal, according to the DICOM specification: "The row and
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
48 // column direction cosine vectors shall be orthogonal, i.e.,
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
49 // their dot product shall be zero."
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
50 // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.2.html
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
51 if (!LinearAlgebra::IsCloseToZero(boost::numeric::ublas::inner_prod(axisX_, axisY_)))
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
52 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
53 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
54 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
55
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
56 LinearAlgebra::CrossProduct(normal_, axisX_, axisY_);
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
57
157
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
58 d_ = -(normal_[0] * origin_[0] + normal_[1] * origin_[1] + normal_[2] * origin_[2]);
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
59
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
60 // Just a sanity check, it should be useless by construction
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
61 assert(LinearAlgebra::IsNear(boost::numeric::ublas::norm_2(normal_), 1.0));
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
62 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
63
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
64
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
65 void CoordinateSystem3D::SetupCanonical()
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
66 {
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
67 LinearAlgebra::AssignVector(origin_, 0, 0, 0);
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
68 LinearAlgebra::AssignVector(axisX_, 1, 0, 0);
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
69 LinearAlgebra::AssignVector(axisY_, 0, 1, 0);
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
70 CheckAndComputeNormal();
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
71 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
72
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
73
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
74 CoordinateSystem3D::CoordinateSystem3D(const Vector& origin,
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
75 const Vector& axisX,
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
76 const Vector& axisY) :
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
77 origin_(origin),
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
78 axisX_(axisX),
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
79 axisY_(axisY)
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
80 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
81 CheckAndComputeNormal();
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
82 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
83
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
84
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
85 void CoordinateSystem3D::Setup(const std::string& imagePositionPatient,
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
86 const std::string& imageOrientationPatient)
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
87 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
88 std::string tmpPosition = Orthanc::Toolbox::StripSpaces(imagePositionPatient);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
89 std::string tmpOrientation = Orthanc::Toolbox::StripSpaces(imageOrientationPatient);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
90
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
91 Vector orientation;
158
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
92 if (!LinearAlgebra::ParseVector(origin_, tmpPosition) ||
a053ca7fa5c6 LinearAlgebra toolbox
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 157
diff changeset
93 !LinearAlgebra::ParseVector(orientation, tmpOrientation) ||
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
94 origin_.size() != 3 ||
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
95 orientation.size() != 6)
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
96 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
97 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
98 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
99
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
100 axisX_.resize(3);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
101 axisX_[0] = orientation[0];
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
102 axisX_[1] = orientation[1];
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
103 axisX_[2] = orientation[2];
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
104
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
105 axisY_.resize(3);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
106 axisY_[0] = orientation[3];
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
107 axisY_[1] = orientation[4];
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
108 axisY_[2] = orientation[5];
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
109
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
110 CheckAndComputeNormal();
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
111 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
112
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
113
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
114 CoordinateSystem3D::CoordinateSystem3D(const OrthancPlugins::IDicomDataset& dicom)
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
115 {
32
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 16
diff changeset
116 std::string a, b;
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 16
diff changeset
117
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 16
diff changeset
118 if (dicom.GetStringValue(a, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) &&
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 16
diff changeset
119 dicom.GetStringValue(b, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT))
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
120 {
32
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 16
diff changeset
121 Setup(a, b);
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
122 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
123 else
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
124 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
125 SetupCanonical();
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
126 }
122
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
127 }
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
128
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
129
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
130 CoordinateSystem3D::CoordinateSystem3D(const Orthanc::DicomMap& dicom)
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
131 {
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
132 std::string a, b;
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
133
994
1f74bc3459ba fix build due to rename in Orthanc::DicomMap
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 986
diff changeset
134 if (dicom.LookupStringValue(a, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) &&
1f74bc3459ba fix build due to rename in Orthanc::DicomMap
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 986
diff changeset
135 dicom.LookupStringValue(b, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false))
122
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
136 {
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
137 Setup(a, b);
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
138 }
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
139 else
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
140 {
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
141 SetupCanonical();
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
142 }
e3433dabfb8d refactoring DicomStructureSet
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 113
diff changeset
143 }
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
144
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
145
760
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
146 void CoordinateSystem3D::SetOrigin(const Vector& origin)
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
147 {
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
148 if (origin.size() != 3)
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
149 {
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
150 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
151 }
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
152 else
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
153 {
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
154 origin_ = origin;
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
155 }
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
156 }
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
157
1181e1ad98ec progressive loading working
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 757
diff changeset
158
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
159 Vector CoordinateSystem3D::MapSliceToWorldCoordinates(double x,
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
160 double y) const
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
161 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
162 return origin_ + x * axisX_ + y * axisY_;
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
163 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
164
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
165
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
166 double CoordinateSystem3D::ProjectAlongNormal(const Vector& point) const
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
167 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
168 return boost::numeric::ublas::inner_prod(point, normal_);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
169 }
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
170
1013
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
171 void CoordinateSystem3D::ProjectPoint2(double& offsetX, double& offsetY, const Vector& point) const
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
172 {
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
173 // Project the point onto the slice
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
174 double projectionX,projectionY,projectionZ;
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
175 GeometryToolbox::ProjectPointOntoPlane2(projectionX, projectionY, projectionZ, point, normal_, origin_);
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
176
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
177 // As the axes are orthonormal vectors thanks to
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
178 // CheckAndComputeNormal(), the following dot products give the
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
179 // offset of the origin of the slice wrt. the origin of the
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
180 // reference plane https://en.wikipedia.org/wiki/Vector_projection
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
181 offsetX = axisX_[0] * (projectionX - origin_[0]) + axisX_[1] * (projectionY - origin_[1]) + axisX_[2] * (projectionZ - origin_[2]);
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
182 offsetY = axisY_[0] * (projectionX - origin_[0]) + axisY_[1] * (projectionY - origin_[1]) + axisY_[2] * (projectionZ - origin_[2]);
53cc787bd7bc - Added an optimized ProjectPoint2 to CoordinateSystem3D. It has *not* replaced
Benjamin Golinvaux <bgo@osimis.io>
parents: 994
diff changeset
183 }
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
184
110
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
185 void CoordinateSystem3D::ProjectPoint(double& offsetX,
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
186 double& offsetY,
53025eecbc95 renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 89
diff changeset
187 const Vector& point) const
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
188 {
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
189 // Project the point onto the slice
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
190 Vector projection;
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
191 GeometryToolbox::ProjectPointOntoPlane(projection, point, normal_, origin_);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
192
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
193 // As the axes are orthonormal vectors thanks to
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
194 // CheckAndComputeNormal(), the following dot products give the
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
195 // offset of the origin of the slice wrt. the origin of the
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
196 // reference plane https://en.wikipedia.org/wiki/Vector_projection
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
197 offsetX = boost::numeric::ublas::inner_prod(axisX_, projection - origin_);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
198 offsetY = boost::numeric::ublas::inner_prod(axisY_, projection - origin_);
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
199 }
151
c5044bbfc303 CoordinateSystem3D::IntersectSegment()
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 135
diff changeset
200
152
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 151
diff changeset
201 bool CoordinateSystem3D::IntersectSegment(Vector& p,
151
c5044bbfc303 CoordinateSystem3D::IntersectSegment()
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 135
diff changeset
202 const Vector& edgeFrom,
c5044bbfc303 CoordinateSystem3D::IntersectSegment()
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 135
diff changeset
203 const Vector& edgeTo) const
c5044bbfc303 CoordinateSystem3D::IntersectSegment()
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 135
diff changeset
204 {
157
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
205 return GeometryToolbox::IntersectPlaneAndSegment(p, normal_, d_, edgeFrom, edgeTo);
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
206 }
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
207
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
208
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
209 bool CoordinateSystem3D::IntersectLine(Vector& p,
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
210 const Vector& origin,
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
211 const Vector& direction) const
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
212 {
2309e8d86efe IntersectPlaneAndLine
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 152
diff changeset
213 return GeometryToolbox::IntersectPlaneAndLine(p, normal_, d_, origin, direction);
151
c5044bbfc303 CoordinateSystem3D::IntersectSegment()
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 135
diff changeset
214 }
647
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
215
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
216
757
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 647
diff changeset
217 bool CoordinateSystem3D::ComputeDistance(double& distance,
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 647
diff changeset
218 const CoordinateSystem3D& a,
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 647
diff changeset
219 const CoordinateSystem3D& b)
647
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
220 {
986
4e2de6b8a70b Uninit. var.
Benjamin Golinvaux <bgo@osimis.io>
parents: 949
diff changeset
221 bool opposite = false; // Ignored
647
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
222
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
223 if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
224 opposite, a.GetNormal(), b.GetNormal()))
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
225 {
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
226 distance = std::abs(a.ProjectAlongNormal(a.GetOrigin()) -
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
227 a.ProjectAlongNormal(b.GetOrigin()));
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
228 return true;
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
229 }
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
230 else
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
231 {
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
232 return false;
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
233 }
6af3099ed8da uncoupling OrthancStone::SlicesSorter from OrthancStone::Slice
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 439
diff changeset
234 }
949
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
235
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
236 std::ostream& operator<< (std::ostream& s, const CoordinateSystem3D& that)
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
237 {
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
238 s << "origin: " << that.origin_ << " normal: " << that.normal_
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
239 << " axisX: " << that.axisX_ << " axisY: " << that.axisY_
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
240 << " D: " << that.d_;
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
241 return s;
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
242 }
32eaf4929b08 OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader now implement IGeometryProvider so that the geometry reference can be switched (CT or DOSE, for instance) + VolumeImageGeometry::SetSize renamed to VolumeImageGeometry::SetSizeInVoxels + prevent text layer update if text or properties do not change + a few stream operator<< for debug (Vector, Matrix,...) + fixed memory access aligment issues in ImageBuffer3D::ExtractSagittalSlice + fix for wrong screen Y offset of mpr slices in DicomVolumeImageMPRSlicer.
Benjamin Golinvaux <bgo@osimis.io>
parents: 760
diff changeset
243
1161
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
244
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
245 CoordinateSystem3D CoordinateSystem3D::NormalizeCuttingPlane(const CoordinateSystem3D& plane)
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
246 {
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
247 double ox, oy;
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
248 plane.ProjectPoint(ox, oy, LinearAlgebra::CreateVector(0, 0, 0));
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
249
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
250 CoordinateSystem3D normalized(plane);
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
251 normalized.SetOrigin(plane.MapSliceToWorldCoordinates(ox, oy));
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
252 return normalized;
19b1c8caade4 fix sagittal geometry
Sebastien Jodogne <s.jodogne@gmail.com>
parents: 1020
diff changeset
253 }
0
351ab0da0150 initial commit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff changeset
254 }