Shapeworks Studio  2.1
Shape analysis software suite
itkPSMParticleSystem.hxx
1 /*=========================================================================
2  *
3  * Copyright Insight Software Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef __itkPSMParticleSystem_hxx
19 #define __itkPSMParticleSystem_hxx
20 #include "itkPSMParticleSystem.h"
21 
22 #include "itkCommand.h"
23 
24 namespace itk
25 {
26 
27 template <unsigned int VDimension>
28 PSMParticleSystem<VDimension>::PSMParticleSystem()
29 {
30 }
31 
32 template <unsigned int VDimension>
33 void
35 ::SetNumberOfDomains(unsigned int num)
36 {
37  // in case nothing has changed.
38  if (num == m_Domains.size())
39  {
40  return;
41  }
42  m_Domains.resize(num);
43  m_Transforms.resize(num);
44  m_InverseTransforms.resize(num);
45  m_PrefixTransforms.resize(num);
46  m_InversePrefixTransforms.resize(num);
47  m_Positions.resize(num);
48  m_IndexCounters.resize(num);
49  m_Neighborhoods.resize(num);
50  m_DomainFlags.resize(num);
51  this->Modified();
52 }
53 
54 template <unsigned int VDimension>
56 {
57  this->Modified();
58 
59  for (unsigned int idx = 0; idx < m_Domains.size(); ++idx)
60  {
61  if (!m_Domains[idx])
62  {
63  m_Domains[idx] = input;
64  m_Positions[idx] = PointContainerType::New();
65  m_IndexCounters[idx] = 0;
66  return;
67  }
68  }
69 
70  this->SetNumberOfDomains(static_cast<int>(m_Domains.size() + 1));
71  m_Domains[ static_cast<int>( m_Domains.size() ) - 1] = input;
72  m_Positions[static_cast<int>( m_Domains.size() ) - 1] = PointContainerType::New();
73  m_IndexCounters[static_cast<int>( m_Domains.size() -1)] = 0;
74  m_Neighborhoods[static_cast<int>( m_Domains.size() -1)] = NeighborhoodType::New();
75  m_Transforms[static_cast<int>( m_Domains.size() -1)].set_identity();
76  m_InverseTransforms[static_cast<int>( m_Domains.size() -1)].set_identity();
77  m_PrefixTransforms[static_cast<int>( m_Domains.size() -1)].set_identity();
78  m_InversePrefixTransforms[static_cast<int>( m_Domains.size() -1)].set_identity();
79  m_DomainFlags[static_cast<int>( m_Domains.size() -1)] = false;
80 
81  // Notify any observers.
82  ParticleDomainAddEvent e;
83  e.SetDomainIndex(m_Domains.size() - 1);
84  e.SetPositionIndex(0);
85  e.SetThreadID(threadId);
86  this->InvokeEvent(e);
87 }
88 
89 template <unsigned int VDimension>
91 ::PrintSelf(std::ostream& os, Indent indent) const
92 {
93  Superclass::PrintSelf(os, indent);
94 
95  os << indent << "m_IndexCounters.size(): " << m_IndexCounters.size() << std::endl;
96  os << indent << "m_Positions.size() : " << m_Positions.size() << std::endl;
97  os << indent << "m_Domains.size() : " << m_Domains.size() << std::endl;
98 }
99 
100 template <unsigned int VDimension>
102 ::SetTransform(unsigned int i, const TransformType& T, int threadId)
103 {
104  m_Transforms[i] = T;
105  m_InverseTransforms[i] = this->InvertTransform(T);
106 
107  // Notify any observers.
108  ParticleTransformSetEvent e;
109  e.SetThreadID(threadId);
110  e.SetDomainIndex(i);
111  this->InvokeEvent(e);
112 }
113 
114 template <unsigned int VDimension>
116 ::SetPrefixTransform(unsigned int i, const TransformType& T, int threadId)
117 {
118  m_PrefixTransforms[i] = T;
119  m_InversePrefixTransforms[i] = this->InvertTransform(T);
120 
121  // Notify any observers.
122  ParticlePrefixTransformSetEvent e;
123  e.SetThreadID(threadId);
124  e.SetDomainIndex(i);
125  this->InvokeEvent(e);
126 }
127 
128 template <unsigned int VDimension>
130 ::SetNeighborhood(unsigned int i, NeighborhoodType* N, int threadId)
131 {
132  m_Neighborhoods[i] = N;
133  m_Neighborhoods[i]->SetDomain(m_Domains[i]);
134  m_Neighborhoods[i]->SetPointContainer(m_Positions[i]);
135 
136  // Notify any observers.
137  ParticleNeighborhoodSetEvent e;
138  e.SetThreadID(threadId);
139  e.SetDomainIndex(i);
140  this->InvokeEvent(e);
141 }
142 
143 template <unsigned int VDimension>
145 PSMParticleSystem<VDimension>::AddPosition( const PointType &p, unsigned int d, int threadId)
146 {
147  m_Positions[d]->operator[](m_IndexCounters[d]) = p;
148 
149  // Apply constraints to the given position. Note that the following
150  // operation potentially modifes that position.
151  m_Domains[d]->ApplyConstraints( m_Positions[d]->operator[](m_IndexCounters[d]));
152 
153  m_Neighborhoods[d]->AddPosition( m_Positions[d]->operator[](m_IndexCounters[d]),
154  m_IndexCounters[d], threadId);
155 
156  // Increase the FixedParticleFlag list size if necessary.
157  if (m_IndexCounters[0] >= m_FixedParticleFlags.size())
158  {
159  m_FixedParticleFlags.push_back(false);
160  }
161 
162  // Notify any observers.
163  ParticlePositionAddEvent e;
164  e.SetThreadID(threadId);
165  e.SetDomainIndex(d);
166  e.SetPositionIndex(m_IndexCounters[d]);
167  this->InvokeEvent(e);
168  m_IndexCounters[d]++;
169 
170  return m_Positions[d]->operator[](m_IndexCounters[d]-1);
171 }
172 
173 template <unsigned int VDimension>
175 PSMParticleSystem<VDimension>::SetPosition(const PointType &p, unsigned long int k,
176  unsigned int d, int threadId)
177 {
178  if (m_FixedParticleFlags[k] == false)
179  {
180  m_Positions[d]->operator[](k) = p;
181 
182  // Apply constraints to the given position. Note that the following
183  // operation potentially modifes that position.
184  m_Domains[d]->ApplyConstraints( m_Positions[d]->operator[](k));
185 
186  m_Neighborhoods[d]->SetPosition( m_Positions[d]->operator[](k), k,
187  threadId);
188  }
189 
190  // Notify any observers.
191  ParticlePositionSetEvent e;
192  e.SetThreadID(threadId);
193  e.SetDomainIndex(d);
194  e.SetPositionIndex(k);
195 
196  this->InvokeEvent(e);
197 
198  return m_Positions[d]->operator[](k);
199 }
200 
201 template <unsigned int VDimension>
202 void
204  unsigned int d, int threadId)
205 {
206  m_Positions[d]->Erase(k);
207 
208  m_Neighborhoods[d]->RemovePosition(k, threadId);
209 
210  // Notify any observers.
211  ParticlePositionRemoveEvent e;
212  e.SetThreadID(threadId);
213  e.SetDomainIndex(d);
214  e.SetPositionIndex(k);
215 
216  this->InvokeEvent(e);
217 }
218 
219 template <unsigned int VDimension>
220 void
221 PSMParticleSystem<VDimension>::AddPositionList(const std::vector<PointType> &p,
222  unsigned int d, int threadId )
223 {
224  // Traverse the list and add each point to the domain.
225  for (typename std::vector<PointType>::const_iterator it= p.begin();
226  it != p.end(); it++)
227  {
228  this->AddPosition(*it, d, threadId);
229  }
230 }
231 
232 template <unsigned int VDimension>
233 void
234 PSMParticleSystem<VDimension>::SplitParticle(double epsilon, unsigned int idx, unsigned int domain, int threadId)
235 {
236  // Find a random direction.
237  vnl_vector_fixed<double, VDimension> random;
238 
239  for (unsigned int i = 0; i < VDimension; i++)
240  { random[i] = static_cast<double>(rand()); }
241  double norm = random.magnitude();
242 
243  // Normalize the random vector.
244  random /= norm;
245 
246  // Add epsilon times random direction to existing point and apply domain
247  // constraints to generate a new particle position. Add the new position.
248  PointType newpos;
249  for (unsigned int i = 0; i < VDimension; i++)
250  {
251  newpos[i] = this->GetPosition(idx,domain)[i] + epsilon * random[i];
252  }
253  this->GetDomain(domain)->ApplyConstraints(newpos);
254  this->AddPosition(newpos, domain, threadId);
255 }
256 
257 template <unsigned int VDimension>
258 void
259 PSMParticleSystem<VDimension>::SplitAllParticlesInDomain(const vnl_vector_fixed<double, VDimension> &random,
260  double epsilon, unsigned int domain, int threadId)
261 {
262  // Loop through all particle positions in the domain and add a new position
263  // at an epsilon distance and random direction. Since we are going to add
264  // positions to the list, we need to first copy the list.
265  std::vector<PointType> list;
266  typename PointContainerType::ConstIterator endIt = GetPositions(domain)->GetEnd();
267  for (typename PointContainerType::ConstIterator it = GetPositions(domain)->GetBegin();
268  it != endIt; it++)
269  { list.push_back(*it); }
270 
271  for (typename std::vector<PointType>::const_iterator it = list.begin();
272  it != list.end(); it++)
273  {
274  // Add epsilon times random direction to existing point and apply domain
275  // constraints to generate a new particle position. Add the new position.
276  PointType newpos;
277  for (unsigned int i = 0; i < VDimension; i++)
278  {
279  newpos[i] = (*it)[i] + epsilon * random[i];
280  }
281  this->GetDomain(domain)->ApplyConstraints(newpos);
282  this->AddPosition(newpos, domain, threadId);
283  } // end for std::vector::iterator
284 }
285 
286 template <unsigned int VDimension>
287 void
289 {
290  // Find a random direction.
291  vnl_vector_fixed<double, VDimension> random;
292 
293  for (unsigned int i = 0; i < VDimension; i++)
294  { random[i] = static_cast<double>(rand()); }
295  double norm = random.magnitude();
296 
297  // Normalize the random vector.
298  random /= norm;
299 
300  // Loop through all particle positions in the domain and add a new position
301  // at an epsilon distance and random direction.
302  for (unsigned i = 0; i < this->GetNumberOfDomains(); i++)
303  {
304  this->SplitAllParticlesInDomain(random, epsilon, i, threadId);
305  }
306 }
307 
308 template <unsigned int VDimension>
309 void
311 {
312  // Register any methods defined by the attribute as observers of this
313  // PSMParticleSystem with appropriate events.
314  if (attr->m_DefinedCallbacks.Event == true)
315  {
316  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
317  = MemberCommand< PSMAttribute<VDimension> >::New();
318  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::EventCallback);
319  this->AddObserver(ParticleEvent(), tmpcmd);
320  }
321  if (attr->m_DefinedCallbacks.EventWithIndex == true)
322  {
323  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
324  = MemberCommand< PSMAttribute<VDimension> >::New();
325  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::EventWithIndexCallback);
326  this->AddObserver(ParticleEventWithIndex(), tmpcmd);
327  }
328  if (attr->m_DefinedCallbacks.DomainAddEvent == true)
329  {
330  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
331  = MemberCommand< PSMAttribute<VDimension> >::New();
332  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::DomainAddEventCallback);
333  this->AddObserver(ParticleDomainAddEvent(), tmpcmd);
334  }
335  if (attr->m_DefinedCallbacks.TransformSetEvent == true)
336  {
337  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
338  = MemberCommand< PSMAttribute<VDimension> >::New();
339  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::TransformSetEventCallback);
340  this->AddObserver(ParticleTransformSetEvent(), tmpcmd);
341  }
342  if (attr->m_DefinedCallbacks.PrefixTransformSetEvent == true)
343  {
344  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
345  = MemberCommand< PSMAttribute<VDimension> >::New();
346  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::PrefixTransformSetEventCallback);
347  this->AddObserver(ParticlePrefixTransformSetEvent(), tmpcmd);
348  }
349  if (attr->m_DefinedCallbacks.NeighborhoodSetEvent == true)
350  {
351  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
352  = MemberCommand< PSMAttribute<VDimension> >::New();
353  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::NeighborhoodSetEventCallback);
354  this->AddObserver(ParticleNeighborhoodSetEvent(), tmpcmd);
355  }
356  if (attr->m_DefinedCallbacks.PositionSetEvent == true)
357  {
358  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
359  = MemberCommand< PSMAttribute<VDimension> >::New();
360  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::PositionSetEventCallback);
361  this->AddObserver(ParticlePositionSetEvent(), tmpcmd);
362  }
363  if (attr->m_DefinedCallbacks.PositionAddEvent == true)
364  {
365  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
366  = MemberCommand< PSMAttribute<VDimension> >::New();
367  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::PositionAddEventCallback);
368  this->AddObserver(ParticlePositionAddEvent(), tmpcmd);
369  }
370  if (attr->m_DefinedCallbacks.PositionRemoveEvent == true)
371  {
372  typename MemberCommand< PSMAttribute<VDimension> >::Pointer tmpcmd
373  = MemberCommand< PSMAttribute<VDimension> >::New();
374  tmpcmd->SetCallbackFunction(attr, &PSMAttribute<VDimension>::PositionRemoveEventCallback);
375  this->AddObserver(ParticlePositionRemoveEvent(), tmpcmd);
376  }
377 }
378 
379 
380 } // end namespace
381 
382 #endif //__itkPSMParticleSystem_hxx
void AddDomain(DomainType *, int threadId=0)
void SetNeighborhood(unsigned int, NeighborhoodType *, int threadId=0)
void RegisterAttribute(PSMAttribute< VDimension > *)
void AddPositionList(const std::vector< PointType > &, unsigned int d, int threadId=0)
void SetTransform(unsigned int i, const TransformType &, int threadId=0)
const PointType & AddPosition(const PointType &, unsigned int d=0, int threadId=0)
A facade class that manages interactions with a particle system.
void SetNumberOfDomains(unsigned int)
Base class for defining the domain in which a particle system exists.
Definition: itkPSMDomain.h:48
void SplitAllParticles(double epsilon, int threadId=0)
An event class that specializes EventObject for the PSMParticleSystem class.
Definition: itkPSMEvents.h:42
Base class for PSMParticleSystem attribute classes.
Definition: Shape.h:14
vnl_matrix_fixed< double, VDimension+1, VDimension+1 > TransformType