1 /*
2 * Medical Image Registration ToolKit (MIRTK)
3 *
4 * Copyright 2016 Imperial College London
5 * Copyright 2016 Andreas Schuh
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #include "mirtk/BoundarySegment.h"
21
22 #include "mirtk/Assert.h"
23 #include "mirtk/Algorithm.h"
24
25
26 namespace mirtk {
27
28
29 // =============================================================================
30 // Construction/destruction
31 // =============================================================================
32
33 // -----------------------------------------------------------------------------
CopyAttributes(const BoundarySegment & other)34 void BoundarySegment::CopyAttributes(const BoundarySegment &other)
35 {
36 _Surface = other._Surface;
37 _PointIds = other._PointIds;
38 _Index = other._Index;
39 _Selection = other._Selection;
40 _EdgeLengths = other._EdgeLengths;
41 _Length = other._Length;
42 }
43
44 // -----------------------------------------------------------------------------
BoundarySegment()45 BoundarySegment::BoundarySegment()
46 :
47 _Length(0.)
48 {
49 }
50
51 // -----------------------------------------------------------------------------
BoundarySegment(vtkPolyData * surface,const Array<int> & ptIds)52 BoundarySegment::BoundarySegment(vtkPolyData *surface, const Array<int> &ptIds)
53 :
54 _Surface(surface),
55 _PointIds(ptIds),
56 _Length(0.)
57 {
58 }
59
60 // -----------------------------------------------------------------------------
BoundarySegment(const BoundarySegment & other)61 BoundarySegment::BoundarySegment(const BoundarySegment &other)
62 :
63 Object(other)
64 {
65 CopyAttributes(other);
66 }
67
68 // -----------------------------------------------------------------------------
operator =(const BoundarySegment & other)69 BoundarySegment &BoundarySegment::operator =(const BoundarySegment &other)
70 {
71 if (this != &other) {
72 Object::operator =(other);
73 CopyAttributes(other);
74 }
75 return *this;
76 }
77
78 // -----------------------------------------------------------------------------
~BoundarySegment()79 BoundarySegment::~BoundarySegment()
80 {
81 }
82
83 // =============================================================================
84 // Initialization
85 // =============================================================================
86
87 // -----------------------------------------------------------------------------
InitializeIndex()88 void BoundarySegment::InitializeIndex()
89 {
90 if (_Index.empty()) {
91 int i = 0;
92 _Index.reserve(_PointIds.size());
93 for (auto it = _PointIds.begin(); it != _PointIds.end(); ++it, ++i) {
94 _Index[*it] = i;
95 }
96 }
97 }
98
99 // -----------------------------------------------------------------------------
InitializeLengths()100 void BoundarySegment::InitializeLengths()
101 {
102 if (!_EdgeLengths) {
103 _EdgeLengths = ComputeEdgeLengths();
104 _Length = _EdgeLengths.Sum();
105 } else if (_Length == 0.) {
106 _Length = _EdgeLengths.Sum();
107 }
108 }
109
110 // -----------------------------------------------------------------------------
ComputeEdgeLengths() const111 Vector BoundarySegment::ComputeEdgeLengths() const
112 {
113 const int npoints = NumberOfPoints();
114 if (npoints == 0) return Vector();
115
116 const class Point p0 = Point(0);
117
118 class Point p1, p2;
119 Vector l(npoints);
120
121 p1 = p0;
122 for (int i = 1; i < npoints; ++i) {
123 p2 = Point(i);
124 l(i-1) = p1.Distance(p2);
125 p1 = p2;
126 }
127 l(npoints-1) = p1.Distance(p0);
128
129 return l;
130 }
131
132 // =============================================================================
133 // Boundary points
134 // =============================================================================
135
136 // -----------------------------------------------------------------------------
Find(int ptId) const137 int BoundarySegment::Find(int ptId) const
138 {
139 if (_Index.empty()) {
140 auto it = find(_PointIds.begin(), _PointIds.end(), ptId);
141 if (it == _PointIds.end()) return -1;
142 return distance(_PointIds.begin(), it);
143 } else {
144 auto it = _Index.find(ptId);
145 if (it == _Index.end()) return -1;
146 return it->second;
147 }
148 }
149
150 // -----------------------------------------------------------------------------
FindClosestPoint(const class Point & x,double * dist2) const151 int BoundarySegment::FindClosestPoint(const class Point &x, double *dist2) const
152 {
153 int min_index = -1;
154 double min_dist2 = inf;
155 double d;
156
157 for (int i = 0; i < NumberOfPoints(); ++i) {
158 d = Point(i).SquaredDistance(x);
159 if (d < min_dist2) {
160 min_dist2 = d;
161 min_index = i;
162 }
163 }
164
165 if (dist2 != nullptr) *dist2 = min_dist2;
166 return min_index;
167 }
168
169 // =============================================================================
170 // Selected points
171 // =============================================================================
172
173 // -----------------------------------------------------------------------------
ReserveSelection(int n)174 void BoundarySegment::ReserveSelection(int n)
175 {
176 _Selection.reserve(n);
177 }
178
179 // -----------------------------------------------------------------------------
RemoveSelection(int i)180 void BoundarySegment::RemoveSelection(int i)
181 {
182 mirtkAssert(i >= 0 && i < static_cast<int>(_Selection.size()), "valid selection index");
183 _Selection.erase(_Selection.begin() + i);
184 }
185
186 // -----------------------------------------------------------------------------
ClearSelection()187 void BoundarySegment::ClearSelection()
188 {
189 _Selection.clear();
190 }
191
192 // -----------------------------------------------------------------------------
SelectPoint(int i)193 void BoundarySegment::SelectPoint(int i)
194 {
195 mirtkAssert(i >= 0 && i < NumberOfPoints(), "valid boundary segment point index");
196 if (find(_Selection.begin(), _Selection.end(), i) == _Selection.end()) {
197 _Selection.push_back(i);
198 }
199 }
200
201 // -----------------------------------------------------------------------------
DeselectPoint(int i)202 void BoundarySegment::DeselectPoint(int i)
203 {
204 auto it = find(_Selection.begin(), _Selection.end(), i);
205 if (it != _Selection.end()) _Selection.erase(it);
206 }
207
208
209 } // namespace mirtk
210