Orfeo Toolbox  3.16
itkSimplexMeshAdaptTopologyFilter.txx
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Insight Segmentation & Registration Toolkit
4  Module: $RCSfile: itkSimplexMeshAdaptTopologyFilter.txx,v $
5  Language: C++
6  Date: $Date: 2009-09-17 11:14:56 $
7  Version: $Revision: 1.19 $
8 
9  Copyright (c) Insight Software Consortium. All rights reserved.
10  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
11 
12  Portions of this code are covered under the VTK copyright.
13  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.
14 
15  This software is distributed WITHOUT ANY WARRANTY; without even
16  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
17  PURPOSE. See the above copyright notices for more information.
18 
19 =========================================================================*/
20 #ifndef __itkSimplexMeshAdaptTopologyFilter_txx
21 #define __itkSimplexMeshAdaptTopologyFilter_txx
22 
24 
25 namespace itk
26 {
27 
28 template <typename TInputMesh, typename TOutputMesh>
30 {
31  m_Output = TOutputMesh::New();
33  this->ProcessObject::SetNthOutput(0, m_Output.GetPointer());
34  m_ModifiedCount = 0;
35  m_SelectionMethod = 0;
36  m_Threshold = 0.5;
37 }
38 
39 template <typename TInputMesh, typename TOutputMesh>
42 {
43 }
44 
45 
46 template <typename TInputMesh, typename TOutputMesh>
49 {
50  this->Initialize();
51  this->ComputeCellParameters();
52  this->InsertNewCells();
53 }
54 
55 //
56 template <typename TInputMesh, typename TOutputMesh>
59 {
60  m_ModifiedCount = 0;
61 }
62 
63 template <typename TInputMesh, typename TOutputMesh>
66 {
67  const InputMeshType * inputMesh = this->GetInput(0);
68 
69  // A filter shouldn't modify its input.
70  // There is a design flaw here...
71  InputMeshType * nonConstInput = const_cast< InputMeshType * >( inputMesh );
72 
73  // Ensure that cells will be deallocated by the Mesh.
74  nonConstInput->SetCellsAllocationMethod( TInputMesh::CellsAllocatedDynamicallyCellByCell );
75 
76  SimplexVisitorInterfacePointer simplexVisitor = SimplexVisitorInterfaceType::New();
77  simplexVisitor->mesh = nonConstInput;
78  CellMultiVisitorPointer mv = CellMultiVisitorType::New();
79  mv->AddVisitor(simplexVisitor);
80  this->GetInput(0)->Accept(mv);
81 
82 
83  DoubleValueMapType::Pointer areas = simplexVisitor->GetAreaMap();
84  DoubleContainerIterator areaIt = areas->Begin();
85  DoubleValueMapType::Pointer curvatures = simplexVisitor->GetCurvatureMap();
86  DoubleContainerIterator curvatureIt = curvatures->Begin();
87 
88  double averageCurvature = simplexVisitor->GetTotalMeanCurvature();
89 
90  double rangeCellSize = simplexVisitor->GetMaximumCellSize() - simplexVisitor->GetMinimumCellSize();
91  double rangeCurvature = simplexVisitor->GetMaximumCurvature() - simplexVisitor->GetMinimumCurvature();
92 
93  while ( curvatureIt != curvatures->End())
94  {
95  bool doRefinement = false;
96 
97  const bool conditionA1 = ( m_SelectionMethod == 0 );
98  const bool conditionA2 = ( curvatureIt.Value() > averageCurvature );
99 
100  const double limit1 = 0.05 * rangeCellSize + simplexVisitor->GetMinimumCellSize();
101  const double limit2 = m_Threshold * rangeCellSize + simplexVisitor->GetMinimumCellSize();
102 
103  const bool conditionA3 = ( areaIt.Value() > limit1 );
104  const bool conditionA4 = ( areaIt.Value() > limit2 );
105 
106  if( conditionA1 && ( ( conditionA2 && conditionA3 ) || conditionA4 ) )
107  {
108  doRefinement = true;
109  }
110  else
111  {
112  const bool conditionB1 = ( m_SelectionMethod == 1 );
113  const bool conditionB2 = curvatureIt.Value() > m_Threshold * rangeCurvature;
114  const bool conditionB3 = areaIt.Value() > 0.05 * rangeCellSize;
115  const bool conditionB4 = areaIt.Value() > m_Threshold * rangeCellSize;
116 
117  if( conditionB1 && ( ( conditionB2 && conditionB3 ) || conditionB4 ) )
118  {
119  doRefinement = true;
120  }
121  }
122 
123  if (doRefinement)
124  {
125  m_ModifiedCount++;
126 
128  inputMesh->GetCell(curvatureIt.Index(), poly);
129 
130  InputPointType cellCenter = this->ComputeCellCenter( poly );
131 
132  typename InputPolygonType::PointIdIterator pointIds = poly->PointIdsBegin();
133 
134  unsigned long lineOneFirstIdx = *pointIds;
135  pointIds++;
136  unsigned long lineOneSecondIdx = *pointIds;
137 
138  unsigned short cnt = 0;
139 
140  while (cnt < poly->GetNumberOfPoints()/2 - 1)
141  {
142  pointIds++;
143  cnt++;
144  }
145  unsigned long lineTwoFirstIdx = *pointIds;
146  pointIds++;
147  unsigned long lineTwoSecondIdx = *pointIds;
148 
149  unsigned long newPointId = inputMesh->GetNumberOfPoints();
150  unsigned long firstNewIndex = newPointId;
151  unsigned long secondNewIndex = newPointId+1;
152 
153  //create first new point
154  InputPointType newMidPoint, helperPoint;
155  InputPointType p1, p2;
156  p1.Fill(0);
157  p2.Fill(0);
158  inputMesh->GetPoint(lineOneFirstIdx, &p1);
159  inputMesh->GetPoint(lineOneSecondIdx, &p2);
160 
161  helperPoint.SetToMidPoint(p1,p2);
162  newMidPoint.SetToMidPoint( helperPoint, cellCenter );
163 
164 
165  nonConstInput->SetPoint( firstNewIndex , newMidPoint);
166  nonConstInput->SetGeometryData( firstNewIndex , new itk::SimplexMeshGeometry() );
167 
168  nonConstInput->ReplaceNeighbor( lineOneFirstIdx, lineOneSecondIdx, firstNewIndex);
169  nonConstInput->ReplaceNeighbor( lineOneSecondIdx, lineOneFirstIdx, firstNewIndex);
170 
171 
172  //create second new point
173  inputMesh->GetPoint(lineTwoFirstIdx, &p1);
174  inputMesh->GetPoint(lineTwoSecondIdx, &p2);
175 
176  helperPoint.SetToMidPoint(p1,p2);
177  newMidPoint.SetToMidPoint( helperPoint, cellCenter );
178 
179  nonConstInput->SetPoint( secondNewIndex , newMidPoint );
180  nonConstInput->SetGeometryData( secondNewIndex , new itk::SimplexMeshGeometry() );
181 
182  nonConstInput->ReplaceNeighbor( lineTwoFirstIdx, lineTwoSecondIdx, secondNewIndex);
183  nonConstInput->ReplaceNeighbor( lineTwoSecondIdx, lineTwoFirstIdx, secondNewIndex);
184 
185  nonConstInput->AddNeighbor(firstNewIndex, secondNewIndex);
186  nonConstInput->AddNeighbor(firstNewIndex, lineOneFirstIdx);
187  nonConstInput->AddNeighbor(firstNewIndex, lineOneSecondIdx);
188 
189  nonConstInput->AddNeighbor(secondNewIndex, lineTwoSecondIdx);
190  nonConstInput->AddNeighbor(secondNewIndex, firstNewIndex);
191  nonConstInput->AddNeighbor(secondNewIndex, lineTwoFirstIdx);
192 
193  CovariantVectorType lineOneFirstNormal = inputMesh->ComputeNormal(lineOneFirstIdx);
194  CovariantVectorType firstNewNormal = inputMesh->ComputeNormal(firstNewIndex);
195 
196  CovariantVectorType lineTwoFirstNormal = inputMesh->ComputeNormal(lineTwoFirstIdx);
197  CovariantVectorType secondNewNormal = inputMesh->ComputeNormal(secondNewIndex);
198 
199 
200  double prod;
201 
202 
203  prod = dot_product( firstNewNormal.GetVnlVector() , lineOneFirstNormal.GetVnlVector() );
204 
205  if (prod < 0)
206  {
207  nonConstInput->SwapNeighbors( firstNewIndex, lineOneFirstIdx, lineOneSecondIdx);
208  firstNewNormal = inputMesh->ComputeNormal(firstNewIndex);
209  }
210 
211  prod = dot_product(secondNewNormal.GetVnlVector(), lineTwoFirstNormal.GetVnlVector());
212  if (prod < 0)
213  {
214  nonConstInput->SwapNeighbors( secondNewIndex, lineTwoFirstIdx, lineTwoSecondIdx);
215  secondNewNormal = inputMesh->ComputeNormal(secondNewIndex);
216  }
217 
218  nonConstInput->AddEdge( firstNewIndex, secondNewIndex );
219 
220  // splitting cell
221  unsigned long newPointIndex = 0;
222  OutputPolygonType * polygon = new OutputPolygonType;
223  m_NewSimplexCellPointer.TakeOwnership( polygon );
224 
225  pointIds = poly->PointIdsBegin();
226  unsigned long firstPointId = *pointIds++;
227 
228  while (*pointIds != lineTwoSecondIdx )
229  {
230  m_NewSimplexCellPointer->SetPointId( newPointIndex++, *pointIds++ );
231  }
232 
233  m_NewSimplexCellPointer->SetPointId( newPointIndex++, secondNewIndex );
234  m_NewSimplexCellPointer->SetPointId( newPointIndex++, firstNewIndex );
235  nonConstInput->ReplaceFace( curvatureIt.Index(), m_NewSimplexCellPointer );
236 
237  OutputPolygonType * polygon2 = new OutputPolygonType;
238  m_NewSimplexCellPointer.TakeOwnership( polygon2 );
239  newPointIndex = 0;
240 
241  while ( pointIds != poly->PointIdsEnd() )
242  {
243  m_NewSimplexCellPointer->SetPointId( newPointIndex++, *pointIds++ );
244  }
245  m_NewSimplexCellPointer->SetPointId( newPointIndex++, firstPointId );
246  m_NewSimplexCellPointer->SetPointId( newPointIndex++, firstNewIndex );
247  m_NewSimplexCellPointer->SetPointId( newPointIndex++, secondNewIndex );
248  nonConstInput->AddFace( m_NewSimplexCellPointer );
249 
250  nonConstInput->BuildCellLinks();
251 
252  this->ModifyNeighborCells(lineOneFirstIdx, lineOneSecondIdx, firstNewIndex);
253  this->ModifyNeighborCells(lineTwoFirstIdx, lineTwoSecondIdx, secondNewIndex);
254 
255  if( inputMesh->GetCellsAllocationMethod() == TInputMesh::CellsAllocatedDynamicallyCellByCell )
256  {
257  delete poly.GetPointer();
258  }
259  } // end if cell must be modified
260  areaIt++;
261  curvatureIt++;
262  }
263 
264 
265 }
266 
267 template <typename TInputMesh, typename TOutputMesh>
270 {
271  typename TOutputMesh::Pointer output = TOutputMesh::New();
272  this->CopyInputMeshToOutputMeshPoints();
273  this->CopyInputMeshToOutputMeshPointData();
274  this->CopyInputMeshToOutputMeshCellData();
275  this->CopyInputMeshToOutputMeshCells();
276  output->SetGeometryData(this->GetInput(0)->GetGeometryData());
277  output->SetLastCellId( this->GetInput(0)->GetLastCellId() );
278  this->ProcessObject::SetNthOutput(0, output.GetPointer());
279 }
280 
281 template <typename TInputMesh, typename TOutputMesh>
282 void
284 ::ModifyNeighborCells(unsigned long id1, unsigned long id2, unsigned long insertPointId)
285 {
286  std::set<unsigned long> cells1 = this->GetInput(0)->GetCellLinks()->GetElement(id1);
287  std::set<unsigned long> cells2 = this->GetInput(0)->GetCellLinks()->GetElement(id2);
288  std::set<unsigned long>::iterator cellIt = cells1.begin();
289 
290  std::set<unsigned long> result;
291 
292  const InputMeshType * inputMesh = this->GetInput(0);
293 
294  // A filter shouldn't modify its input.
295  // There is a design flaw here...
296  InputMeshType * nonConstInput = const_cast< InputMeshType * >( inputMesh );
297 
298  while (cellIt != cells1.end() )
299  {
300  std::set<unsigned long>::iterator found = std::find(cells2.begin(), cells2.end(), *cellIt);
301  if ( found != cells2.end() )
302  {
303  result.insert(*cellIt);
304  }
305  cellIt++;
306  }
307 
308  cellIt = result.begin();
309 
310  while ( cellIt != result.end() )
311  {
312  InputCellAutoPointer nextCell;
313  this->GetInput(0)->GetCell(*cellIt, nextCell );
314 
315  if ( nextCell->GetNumberOfPoints() == 2 )
316  {
317  InputCellPointIdIterator lineIt = nextCell->PointIdsBegin();
318  unsigned long first= *lineIt++;
319  unsigned long second= *lineIt;
320 
321  nonConstInput->AddEdge( first, insertPointId );
322  nonConstInput->AddEdge( insertPointId, second );
323  nonConstInput->GetCells()->DeleteIndex( *cellIt );
324  }
325  else if ( nextCell->GetNumberOfPoints() > 3 )
326  {
327  m_NewSimplexCellPointer.TakeOwnership( new OutputPolygonType );
328  InputPolygonPointIdIterator pointIt = nextCell->PointIdsBegin();
329  unsigned long cnt = 0;
330  unsigned long first = *pointIt++;
331  unsigned long startId = first;
332 
333  unsigned long second = 0;
334 
335  while ( pointIt != nextCell->PointIdsEnd() )
336  {
337  m_NewSimplexCellPointer->SetPointId( cnt++, first );
338  second = *pointIt;
339 
340  if ( ( id1 == first && id2 == second ) || ( id2 == first && id1 == second ) )
341  {
342  m_NewSimplexCellPointer->SetPointId( cnt++, insertPointId );
343  }
344  first = second;
345  pointIt++;
346  }
347 
348  m_NewSimplexCellPointer->SetPointId( cnt++, second );
349  if ( ( id1 == second && id2 == startId ) || ( id2 == second && id1 == startId ) )
350  {
351  m_NewSimplexCellPointer->SetPointId( cnt++, insertPointId );
352  }
353 
354  nonConstInput->ReplaceFace( *cellIt, m_NewSimplexCellPointer );
355 
356  }
357  cellIt++;
358  }
359 
360  this->GetInput(0)->BuildCellLinks();
361 }
362 
363 /* PrintSelf. */
364 template <typename TInputMesh, typename TOutputMesh>
365 void
367 ::PrintSelf(std::ostream& os, Indent indent) const
368 {
369  Superclass::PrintSelf(os,indent);
370  os << indent << "Threshold: " << m_Threshold << std::endl;
371  os << indent << "SelectionMethod: " << m_SelectionMethod << std::endl;
372  os << indent << "ModifiedCount: " << m_ModifiedCount << std::endl;
373 
374 }
375 
376 
377 template <typename TInputMesh, typename TOutputMesh>
381 {
382  InputPolygonPointIdIterator pointIt = simplexCell->PointIdsBegin();
383 
384  InputVectorType tmp;
385  InputPointType p1, p2, cellCenter;
386  p1.Fill(0);
387  cellCenter.Fill(0);
388 
389  // compute the cell center first
390  while ( pointIt != simplexCell->PointIdsEnd() )
391  {
392  this->GetInput(0)->GetPoint(*pointIt, &p1);
393  cellCenter += p1.GetVectorFromOrigin();
394  pointIt++;
395  }
396 
397  tmp.SetVnlVector( cellCenter.GetVnlVector()/simplexCell->GetNumberOfPoints() );
398  cellCenter.Fill(0.0);
399  cellCenter += tmp;
400 
401  return cellCenter;
402 }
403 
404 
405 } // end of namspace itk
406 
407 #endif // __itkSimplexMeshAdaptTopologyFilter_txx

Generated at Sun May 19 2013 00:08:04 for Orfeo Toolbox with doxygen 1.8.3.1