1 /*=========================================================================
\r
5 * Licensed under the Apache License, Version 2.0 (the "License");
\r
6 * you may not use this file except in compliance with the License.
\r
7 * You may obtain a copy of the License at
\r
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
\r
11 * Unless required by applicable law or agreed to in writing, software
\r
12 * distributed under the License is distributed on an "AS IS" BASIS,
\r
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
14 * See the License for the specific language governing permissions and
\r
15 * limitations under the License.
\r
17 *=========================================================================*/
\r
19 #ifndef itkFastMarchingQuadEdgeMeshFilterResultsBase_hxx
\r
20 #define itkFastMarchingQuadEdgeMeshFilterResultsBase_hxx
\r
22 #include "itkFastMarchingQuadEdgeMeshFilterResultsBase.h"
\r
24 #include "itkMath.h"
\r
25 #include "itkVector.h"
\r
26 #include "itkMatrix.h"
\r
30 template <typename TInput, typename TOutput>
\r
31 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::FastMarchingQuadEdgeMeshFilterResultsBase()
\r
34 this->m_InputMesh = nullptr;
\r
35 this->m_BackInputMesh = nullptr;
\r
38 template <typename TInput, typename TOutput>
\r
40 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::GetTotalNumberOfNodes() const
\r
42 return this->GetInput()->GetNumberOfPoints();
\r
45 template <typename TInput, typename TOutput>
\r
47 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::SetOutputValue(OutputMeshType * oMesh,
\r
48 const NodeType & iNode,
\r
49 const OutputPixelType & iValue)
\r
51 oMesh->SetPointData(iNode, iValue);
\r
54 template <typename TInput, typename TOutput>
\r
55 const typename FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::OutputPixelType
\r
56 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::GetOutputValue(OutputMeshType * oMesh,
\r
57 const NodeType & iNode) const
\r
59 OutputPixelType outputValue = NumericTraits<OutputPixelType>::ZeroValue();
\r
60 oMesh->GetPointData(iNode, &outputValue);
\r
65 template <typename TInput, typename TOutput>
\r
67 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::GetLabelValueForGivenNode(const NodeType & iNode) const
\r
69 auto it = m_Label.find(iNode);
\r
71 if (it != m_Label.end())
\r
81 template <typename TInput, typename TOutput>
\r
83 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::SetLabelValueForGivenNode(const NodeType & iNode,
\r
84 const LabelType & iLabel)
\r
86 m_Label[iNode] = iLabel;
\r
89 template <typename TInput, typename TOutput>
\r
91 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::UpdateNeighbors(OutputMeshType * oMesh, const NodeType & iNode)
\r
93 //printf("PG FastMarchingQuadEdgeMeshFilterResultsBase::UpdateNeighbors Start \n");
\r
95 oMesh->GetPoint(iNode, &p);
\r
97 OutputQEType * qe = p.GetEdge();
\r
101 OutputQEType * qe_it = qe;
\r
102 this->m_InputMesh = this->GetInput();
\r
107 OutputPointIdentifierType neigh_id = qe_it->GetDestination();
\r
109 const char label = this->GetLabelValueForGivenNode(neigh_id);
\r
111 if ((label != Traits::Alive) && (label != Traits::InitialTrial) && (label != Traits::Forbidden))
\r
113 this->UpdateValue(oMesh, neigh_id);
\r
118 itkGenericExceptionMacro(<< "qe_it is nullptr");
\r
120 qe_it = qe_it->GetOnext();
\r
121 } while (qe_it != qe);
\r
125 itkGenericExceptionMacro(<< "qe is nullptr");
\r
127 //printf("PG FastMarchingQuadEdgeMeshFilterResultsBase::UpdateNeighbors End \n");
\r
130 template <typename TInput, typename TOutput>
\r
132 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::UpdateValue(OutputMeshType * oMesh, const NodeType & iNode)
\r
135 oMesh->GetPoint(iNode, &p);
\r
137 InputPixelType F = NumericTraits<InputPixelType>::ZeroValue();
\r
138 //this->m_InputMesh->GetPointData(iNode, &F);
\r
142 itkGenericExceptionMacro(<< "F < 0.");
\r
145 OutputQEType * qe = p.GetEdge();
\r
147 OutputPixelType outputPixel = this->m_LargeValue;
\r
151 OutputQEType * qe_it = qe;
\r
152 qe_it = qe_it->GetOnext();
\r
156 OutputQEType * qe_it2 = qe_it->GetOnext();
\r
160 if (qe_it->GetLeft() != OutputMeshType::m_NoFace)
\r
162 OutputPointIdentifierType id1 = qe_it->GetDestination();
\r
163 OutputPointIdentifierType id2 = qe_it2->GetDestination();
\r
165 const auto label1 = static_cast<LabelType>(this->GetLabelValueForGivenNode(id1));
\r
166 const auto label2 = static_cast<LabelType>(this->GetLabelValueForGivenNode(id2));
\r
168 bool IsFar1 = (label1 != Traits::Far);
\r
169 bool IsFar2 = (label2 != Traits::Far);
\r
171 if (IsFar1 || IsFar2)
\r
173 OutputPointType q1 = oMesh->GetPoint(id1);
\r
174 OutputPointType q2 = oMesh->GetPoint(id2);
\r
176 auto val1 = static_cast<OutputVectorRealType>(this->GetOutputValue(oMesh, id1));
\r
177 auto val2 = static_cast<OutputVectorRealType>(this->GetOutputValue(oMesh, id2));
\r
181 OutputPointType temp_pt(q1);
\r
185 std::swap(val1, val2);
\r
186 std::swap(IsFar1, IsFar2);
\r
187 std::swap(id1, id2);
\r
190 const OutputVectorRealType temp =
\r
191 this->Solve(oMesh, iNode, p, F, id1, q1, IsFar1, val1, id2, q2, IsFar2, val2);
\r
193 outputPixel = std::min(outputPixel, static_cast<OutputPixelType>(temp));
\r
201 // throw one exception here
\r
202 itkGenericExceptionMacro(<< "qe_it2 is nullptr");
\r
204 } while (qe_it != qe);
\r
206 if (outputPixel < this->m_LargeValue)
\r
208 this->SetOutputValue(oMesh, iNode, outputPixel);
\r
210 this->SetLabelValueForGivenNode(iNode, Traits::Trial);
\r
212 this->m_Heap.push(NodePairType(iNode, outputPixel));
\r
217 // throw one exception
\r
218 itkGenericExceptionMacro(<< "qe_it is nullptr");
\r
222 template <typename TInput, typename TOutput>
\r
223 const typename FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::OutputVectorRealType
\r
224 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::Solve(OutputMeshType * oMesh,
\r
225 const NodeType & iId,
\r
226 const OutputPointType & iCurrentPoint,
\r
227 const OutputVectorRealType & iF,
\r
228 const NodeType & iId1,
\r
229 const OutputPointType & iP1,
\r
230 const bool & iIsFar1,
\r
231 const OutputVectorRealType iVal1,
\r
232 const NodeType & iId2,
\r
233 const OutputPointType & iP2,
\r
234 const bool & iIsFar2,
\r
235 const OutputVectorRealType & iVal2) const
\r
237 OutputVectorType Edge1 = iP1 - iCurrentPoint;
\r
238 OutputVectorType Edge2 = iP2 - iCurrentPoint;
\r
240 OutputVectorRealType sq_norm1 = Edge1.GetSquaredNorm();
\r
241 OutputVectorRealType norm1 = 0.;
\r
243 OutputVectorRealType epsilon = NumericTraits<OutputVectorRealType>::epsilon();
\r
245 if (sq_norm1 > epsilon)
\r
247 norm1 = std::sqrt(sq_norm1);
\r
249 OutputVectorRealType inv_norm1 = 1. / norm1;
\r
250 Edge1 *= inv_norm1;
\r
253 OutputVectorRealType sq_norm2 = Edge2.GetSquaredNorm();
\r
254 OutputVectorRealType norm2 = 0.;
\r
256 if (sq_norm2 > epsilon)
\r
258 norm2 = std::sqrt(sq_norm2);
\r
260 OutputVectorRealType inv_norm2 = 1. / norm2;
\r
261 Edge2 *= inv_norm2;
\r
264 if (!iIsFar1 && iIsFar2)
\r
266 // only one point is a contributor
\r
267 return iVal2 + norm2 * iF;
\r
269 if (iIsFar1 && !iIsFar2)
\r
271 // only one point is a contributor
\r
272 return iVal1 + norm1 * iF;
\r
275 if (iIsFar1 && iIsFar2)
\r
277 auto dot = static_cast<OutputVectorRealType>(Edge1 * Edge2);
\r
281 return ComputeUpdate(iVal1, iVal2, norm2, sq_norm2, norm1, sq_norm1, dot, iF);
\r
285 OutputVectorRealType sq_norm3, norm3, dot1, dot2;
\r
286 OutputPointIdentifierType new_id;
\r
289 UnfoldTriangle(oMesh, iId, iCurrentPoint, iId1, iP1, iId2, iP2, norm3, sq_norm3, dot1, dot2, new_id);
\r
293 OutputVectorRealType t_sq_norm3 = norm3 * norm3;
\r
295 auto val3 = static_cast<OutputVectorRealType>(this->GetOutputValue(oMesh, new_id));
\r
296 OutputVectorRealType t1 = ComputeUpdate(iVal1, val3, norm3, t_sq_norm3, norm1, sq_norm1, dot1, iF);
\r
297 OutputVectorRealType t2 = ComputeUpdate(iVal2, val3, norm3, t_sq_norm3, norm2, sq_norm2, dot2, iF);
\r
299 return std::min(t1, t2);
\r
303 return ComputeUpdate(iVal1, iVal2, norm2, sq_norm2, norm1, sq_norm1, dot, iF);
\r
308 return this->m_LargeValue;
\r
311 template <typename TInput, typename TOutput>
\r
312 const typename FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::OutputVectorRealType
\r
313 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::ComputeUpdate(const OutputVectorRealType & iVal1,
\r
314 const OutputVectorRealType & iVal2,
\r
315 const OutputVectorRealType & iNorm1,
\r
316 const OutputVectorRealType & iSqNorm1,
\r
317 const OutputVectorRealType & iNorm2,
\r
318 const OutputVectorRealType & iSqNorm2,
\r
319 const OutputVectorRealType & iDot,
\r
320 const OutputVectorRealType & iF) const
\r
322 auto large_value = static_cast<OutputVectorRealType>(this->m_LargeValue);
\r
324 OutputVectorRealType t = large_value;
\r
326 OutputVectorRealType CosAngle = iDot;
\r
327 OutputVectorRealType SinAngle = std::sqrt(1. - iDot * iDot);
\r
329 OutputVectorRealType u = iVal2 - iVal1;
\r
331 OutputVectorRealType sq_u = u * u;
\r
332 OutputVectorRealType f2 = iSqNorm1 + iSqNorm2 - 2. * iNorm1 * iNorm2 * CosAngle;
\r
333 OutputVectorRealType f1 = iNorm2 * u * (iNorm1 * CosAngle - iNorm2);
\r
334 OutputVectorRealType f0 = iSqNorm2 * (sq_u - iF * iF * iSqNorm1 * SinAngle * SinAngle);
\r
336 OutputVectorRealType delta = f1 * f1 - f0 * f2;
\r
338 OutputVectorRealType epsilon = NumericTraits<OutputVectorRealType>::epsilon();
\r
342 if (itk::Math::abs(f2) > epsilon)
\r
344 t = (-f1 - std::sqrt(delta)) / f2;
\r
346 // test if we must must choose the other solution
\r
347 if ((t < u) || (iNorm2 * (t - u) / t < iNorm1 * CosAngle) || (iNorm1 / CosAngle < iNorm2 * (t - u) / t))
\r
349 t = (-f1 + std::sqrt(delta)) / f2;
\r
354 if (itk::Math::abs(f1) > epsilon)
\r
369 // choose the update from the 2 vertex only if upwind criterion is met
\r
370 if ((u < t) && (iNorm1 * CosAngle < iNorm2 * (t - u) / t) && (iNorm2 * (t - u) / t < iNorm1 / CosAngle))
\r
376 return std::min(iNorm2 * iF + iVal1, iNorm1 * iF + iVal2);
\r
380 template <typename TInput, typename TOutput>
\r
382 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::UnfoldTriangle(OutputMeshType * oMesh,
\r
383 const OutputPointIdentifierType & iId,
\r
384 const OutputPointType & iP,
\r
385 const OutputPointIdentifierType & iId1,
\r
386 const OutputPointType & iP1,
\r
387 const OutputPointIdentifierType & iId2,
\r
388 const OutputPointType & iP2,
\r
389 OutputVectorRealType & oNorm,
\r
390 OutputVectorRealType & oSqNorm,
\r
391 OutputVectorRealType & oDot1,
\r
392 OutputVectorRealType & oDot2,
\r
393 OutputPointIdentifierType & oId) const
\r
397 OutputVectorType Edge1 = iP1 - iP;
\r
398 OutputVectorRealType Norm1 = Edge1.GetNorm();
\r
400 OutputVectorRealType epsilon = NumericTraits<OutputVectorRealType>::epsilon();
\r
402 if (Norm1 > epsilon)
\r
404 OutputVectorRealType inv_Norm = 1. / Norm1;
\r
408 OutputVectorType Edge2 = iP2 - iP;
\r
409 OutputVectorRealType Norm2 = Edge2.GetNorm();
\r
410 if (Norm2 > epsilon)
\r
412 OutputVectorRealType inv_Norm = 1. / Norm2;
\r
416 auto dot = static_cast<OutputVectorRealType>(Edge1 * Edge2);
\r
418 // the equation of the lines defining the unfolding region
\r
419 // [e.g. line 1 : {x ; <x,eq1>=0} ]
\r
420 using Vector2DType = Vector<OutputVectorRealType, 2>;
\r
421 using Matrix2DType = Matrix<OutputVectorRealType, 2, 2>;
\r
425 v1[1] = std::sqrt(1. - dot * dot);
\r
435 Vector2DType x2 = Norm2 * v1;
\r
437 // keep track of the starting point
\r
438 Vector2DType x_start1(x1);
\r
439 Vector2DType x_start2(x2);
\r
441 OutputPointIdentifierType id1 = iId1;
\r
442 OutputPointIdentifierType id2 = iId2;
\r
444 OutputQEType * qe = oMesh->FindEdge(id1, id2);
\r
447 OutputPointType t_pt1 = iP1;
\r
448 OutputPointType t_pt2 = iP2;
\r
449 OutputPointType t_pt = t_pt1;
\r
451 unsigned int nNum = 0;
\r
452 while (nNum < 50 && qe->GetLeft() != OutputMeshType::m_NoFace)
\r
454 OutputQEType * qe_Lnext = qe->GetLnext();
\r
455 OutputPointIdentifierType t_id = qe_Lnext->GetDestination();
\r
457 oMesh->GetPoint(t_id, &t_pt);
\r
459 Edge1 = t_pt2 - t_pt1;
\r
460 Norm1 = Edge1.GetNorm();
\r
461 if (Norm1 > epsilon)
\r
463 OutputVectorRealType inv_Norm = 1. / Norm1;
\r
467 Edge2 = t_pt - t_pt1;
\r
468 Norm2 = Edge2.GetNorm();
\r
469 if (Norm2 > epsilon)
\r
471 OutputVectorRealType inv_Norm = 1. / Norm2;
\r
475 /* compute the position of the new point x on the unfolding plane (via a rotation of -alpha on (x2-x1)/rNorm1 )
\r
476 | cos(alpha) sin(alpha)|
\r
477 x = |-sin(alpha) cos(alpha)| * [x2-x1]*rNorm2/rNorm1 + x1 where cos(alpha)=dot
\r
480 if (Norm1 > epsilon)
\r
482 vv = (x2 - x1) * Norm2 / Norm1;
\r
489 dot = Edge1 * Edge2;
\r
491 Matrix2DType rotation;
\r
492 rotation[0][0] = dot;
\r
493 rotation[0][1] = std::sqrt(1. - dot * dot);
\r
494 rotation[1][0] = -rotation[0][1];
\r
495 rotation[1][1] = dot;
\r
497 Vector2DType x = rotation * vv + x1;
\r
500 /* compute the intersection points.
\r
501 We look for x=x1+lambda*(x-x1) or x=x2+lambda*(x-x2) with <x,eqi>=0, so */
\r
502 OutputVectorRealType lambda11 = -(x1 * v1) / ((x - x1) * v1); // left most
\r
503 OutputVectorRealType lambda12 = -(x1 * v2) / ((x - x1) * v2); // right most
\r
504 OutputVectorRealType lambda21 = -(x2 * v1) / ((x - x2) * v1); // left most
\r
505 OutputVectorRealType lambda22 = -(x2 * v2) / ((x - x2) * v2); // right most
\r
506 bool bIntersect11 = (lambda11 >= 0.) && (lambda11 <= 1.);
\r
507 bool bIntersect12 = (lambda12 >= 0.) && (lambda12 <= 1.);
\r
508 bool bIntersect21 = (lambda21 >= 0.) && (lambda21 <= 1.);
\r
509 bool bIntersect22 = (lambda22 >= 0.) && (lambda22 <= 1.);
\r
511 if (bIntersect11 && bIntersect12)
\r
513 qe = oMesh->FindEdge(id1, t_id);
\r
521 if (bIntersect21 && bIntersect22)
\r
523 qe = oMesh->FindEdge(id2, t_id);
\r
530 { // bIntersect11 && !bIntersect12 && !bIntersect21 && bIntersect22
\r
532 // that's it, we have found the point
\r
533 oSqNorm = x.GetSquaredNorm();
\r
535 if (oSqNorm > epsilon)
\r
537 oNorm = std::sqrt(oSqNorm);
\r
538 OutputVectorRealType temp_norm = x_start1.GetNorm();
\r
539 if (temp_norm > epsilon)
\r
541 oDot1 = x * x_start1 / (oNorm * temp_norm);
\r
547 temp_norm = x_start2.GetNorm();
\r
548 if (temp_norm > epsilon)
\r
550 oDot2 = x * x_start2 / (oNorm * temp_norm);
\r
574 template <typename TInput, typename TOutput>
\r
576 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::CheckTopology(OutputMeshType * oMesh, const NodeType & iNode)
\r
584 template <typename TInput, typename TOutput>
\r
586 FastMarchingQuadEdgeMeshFilterResultsBase<TInput, TOutput>::InitializeOutput(OutputMeshType * oMesh)
\r
588 printf("PG FastMarchingQuadEdgeMeshFilterResultsBase::InitializeOutput Start \n");
\r
589 if(this->GetInput() != m_InputMesh || this->GetOutput() == NULL){
\r
590 this->CopyInputMeshToOutputMeshGeometry();
\r
593 printf("PG FastMarchingQuadEdgeMeshFilterResultsBase::InitializeOutput FLAG 0.5 \n");
\r
594 oMesh = this->GetOutput();
\r
596 printf("PG FastMarchingQuadEdgeMeshFilterResultsBase::InitializeOutput FLAG 1 \n");
\r
597 // Check that the input mesh is made of triangles
\r
598 //We already now it is made of triangles
\r
601 OutputCellsContainerPointer cells = oMesh->GetCells();
\r
602 OutputCellsContainerConstIterator c_it = cells->Begin();
\r
603 OutputCellsContainerConstIterator c_end = cells->End();
\r
605 while (c_it != c_end)
\r
607 OutputCellType * cell = c_it.Value();
\r
609 if (cell->GetNumberOfPoints() != 3)
\r
611 itkGenericExceptionMacro(<< "Input mesh has non triangular faces");
\r
617 OutputPointsContainerPointer points = oMesh->GetPoints();
\r
619 OutputPointDataContainerPointer pointdata = OutputPointDataContainer::New();
\r
620 pointdata->Reserve(points->Size());
\r
622 OutputPointsContainerIterator p_it = points->Begin();
\r
623 OutputPointsContainerIterator p_end = points->End();
\r
625 while (p_it != p_end)
\r
627 pointdata->SetElement(p_it->Index(), this->m_LargeValue);
\r
631 oMesh->SetPointData(pointdata);
\r
635 if (this->m_AlivePoints)
\r
637 NodePairContainerConstIterator pointsIter = this->m_AlivePoints->Begin();
\r
638 NodePairContainerConstIterator pointsEnd = this->m_AlivePoints->End();
\r
639 while (pointsIter != pointsEnd)
\r
641 // get node from alive points container
\r
642 NodeType idx = pointsIter->Value().GetNode();
\r
644 if (points->IndexExists(idx))
\r
646 OutputPixelType outputPixel = pointsIter->Value().GetValue();
\r
648 this->SetLabelValueForGivenNode(idx, Traits::Alive);
\r
649 this->SetOutputValue(oMesh, idx, outputPixel);
\r
655 if (this->m_ForbiddenPoints)
\r
657 NodePairContainerConstIterator pointsIter = this->m_ForbiddenPoints->Begin();
\r
658 NodePairContainerConstIterator pointsEnd = this->m_ForbiddenPoints->End();
\r
660 OutputPixelType zero = NumericTraits<OutputPixelType>::ZeroValue();
\r
662 while (pointsIter != pointsEnd)
\r
664 NodeType idx = pointsIter->Value().GetNode();
\r
666 if (points->IndexExists(idx))
\r
668 this->SetLabelValueForGivenNode(idx, Traits::Forbidden);
\r
669 this->SetOutputValue(oMesh, idx, zero);
\r
675 if (this->m_TrialPoints)
\r
677 NodePairContainerConstIterator pointsIter = this->m_TrialPoints->Begin();
\r
678 NodePairContainerConstIterator pointsEnd = this->m_TrialPoints->End();
\r
680 while (pointsIter != pointsEnd)
\r
682 NodeType idx = pointsIter->Value().GetNode();
\r
684 if (points->IndexExists(idx))
\r
686 OutputPixelType outputPixel = pointsIter->Value().GetValue();
\r
688 this->SetLabelValueForGivenNode(idx, Traits::InitialTrial);
\r
689 this->SetOutputValue(oMesh, idx, outputPixel);
\r
691 this->m_Heap.push(pointsIter->Value());
\r
696 }printf("PG FastMarchingQuadEdgeMeshFilterResultsBase::InitializeOutput ENDED \n");
\r
700 #endif // itkFastMarchingQuadEdgeMeshFilterResultsBase_hxx
\r