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