/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkLevelSetEquationTermContainer_hxx #define itkLevelSetEquationTermContainer_hxx #include "itkMath.h" #include "itkObject.h" namespace itk { // ---------------------------------------------------------------------------- template LevelSetEquationTermContainer::LevelSetEquationTermContainer() { this->m_CurrentLevelSetId = LevelSetIdentifierType(); } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::Begin() -> Iterator { return Iterator(this->m_Container.begin()); } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::End() -> Iterator { return Iterator(this->m_Container.end()); } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::Begin() const -> ConstIterator { return ConstIterator(this->m_Container.begin()); } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::End() const -> ConstIterator { return ConstIterator(this->m_Container.end()); } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::AddTerm(const TermIdType & iId, TermType * iTerm) { if (iTerm) { if (!iTerm->GetInput()) { if (m_Input.IsNotNull()) { iTerm->SetInput(m_Input); } else { itkGenericExceptionMacro("m_Input and iTerm->GetInput are nullptr"); } } iTerm->SetCurrentLevelSetId(this->m_CurrentLevelSetId); if (this->m_LevelSetContainer.IsNotNull()) { iTerm->SetLevelSetContainer(this->m_LevelSetContainer); } else { if (!iTerm->GetLevelSetContainer()) { itkGenericExceptionMacro("m_LevelSetContainer and iTerm->GetLevelSetContainer() are nullptr"); } } m_Container[iId] = iTerm; m_TermContribution[iId] = LevelSetOutputPixelType{}; m_NameContainer[iTerm->GetTermName()] = iTerm; RequiredDataType termRequiredData = iTerm->GetRequiredData(); typename RequiredDataType::const_iterator dIt = termRequiredData.begin(); typename RequiredDataType::const_iterator dEnd = termRequiredData.end(); while (dIt != dEnd) { m_RequiredData.insert(*dIt); ++dIt; } this->Modified(); } else { itkGenericExceptionMacro("Term supplied is null"); } } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::PushTerm(TermType * iTerm) { if (iTerm) { if (!iTerm->GetInput()) { if (m_Input.IsNotNull()) { iTerm->SetInput(m_Input); } else { itkGenericExceptionMacro("m_Input and iTerm->GetInput are nullptr"); } } iTerm->SetCurrentLevelSetId(this->m_CurrentLevelSetId); if (this->m_LevelSetContainer.isNotNull()) { iTerm->SetLevelSetContainer(this->m_LevelSetContainer); } else { if (!iTerm->GetLevelSetContainer()) { itkGenericExceptionMacro("m_LevelSetContainer and iTerm->GetLevelSetContainer() are nullptr"); } } TermIdType id = (m_Container.rbegin())->first; ++id; m_Container[id] = iTerm; m_TermContribution[id] = LevelSetOutputPixelType{}; m_NameContainer[iTerm->GetTermName()] = iTerm; RequiredDataType termRequiredData = iTerm->GetRequiredData(); typename RequiredDataType::const_iterator dIt = termRequiredData.begin(); typename RequiredDataType::const_iterator dEnd = termRequiredData.end(); while (dIt != dEnd) { m_RequiredData.insert(*dIt); ++dIt; } this->Modified(); } else { itkGenericExceptionMacro("Term supplied is null"); } } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::GetTerm(const std::string & iName) -> TermType * { MapTermContainerIteratorType it = m_Container.find(iName); if (it == m_Container.end()) { itkGenericExceptionMacro("the term " << iName.c_str() << " is not present in the container"); } return it->second; } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::GetTerm(const TermIdType & iId) -> TermType * { auto it = m_Container.find(iId); if (it == m_Container.end()) { itkGenericExceptionMacro("the term " << iId << " is not present in the container"); } return it->second; } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::Initialize(const LevelSetInputIndexType & iP) { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); while (term_it != term_end) { (term_it->second)->Initialize(iP); ++term_it; } } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::UpdatePixel(const LevelSetInputIndexType & iP, const LevelSetOutputRealType & oldValue, const LevelSetOutputRealType & newValue) { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); while (term_it != term_end) { (term_it->second)->UpdatePixel(iP, oldValue, newValue); ++term_it; } } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::InitializeParameters() { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); while (term_it != term_end) { (term_it->second)->InitializeParameters(); ++term_it; } } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::Evaluate(const LevelSetInputIndexType & iP) -> LevelSetOutputRealType { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); auto cfl_it = m_TermContribution.begin(); LevelSetOutputRealType oValue{}; while (term_it != term_end) { LevelSetOutputRealType temp_val = (term_it->second)->Evaluate(iP); LevelSetOutputRealType abs_temp_value = itk::Math::abs(temp_val); // This is a thread-safe equivalent of: // cfl_it->second = std::max(abs_temp_value, cfl_it->second); LevelSetOutputRealType previous_value = cfl_it->second; while ((abs_temp_value > previous_value) && !cfl_it->second.compare_exchange_strong(previous_value, abs_temp_value)) { } oValue += temp_val; ++term_it; ++cfl_it; } return oValue; } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::Evaluate(const LevelSetInputIndexType & iP, const LevelSetDataType & iData) -> LevelSetOutputRealType { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); auto cfl_it = m_TermContribution.begin(); LevelSetOutputRealType oValue{}; while (term_it != term_end) { LevelSetOutputRealType temp_val = (term_it->second)->Evaluate(iP, iData); LevelSetOutputRealType abs_temp_value = itk::Math::abs(temp_val); // This is a thread-safe equivalent of: // cfl_it->second = std::max(abs_temp_value, cfl_it->second); LevelSetOutputRealType previous_value = cfl_it->second; while ((abs_temp_value > previous_value) && !cfl_it->second.compare_exchange_strong(previous_value, abs_temp_value)) { } oValue += temp_val; ++term_it; ++cfl_it; } return oValue; } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::Update() { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); auto cfl_it = m_TermContribution.begin(); while (term_it != term_end) { (term_it->second)->Update(); (cfl_it->second) = LevelSetOutputPixelType{}; ++term_it; ++cfl_it; } } // ---------------------------------------------------------------------------- template auto LevelSetEquationTermContainer::ComputeCFLContribution() const -> LevelSetOutputRealType { auto term_it = m_Container.begin(); auto term_end = m_Container.end(); auto cfl_it = m_TermContribution.begin(); LevelSetOutputRealType oValue{}; while (term_it != term_end) { LevelSetOutputRealType cfl = (term_it->second)->GetCFLContribution(); if (Math::AlmostEquals(cfl, LevelSetOutputRealType{})) { cfl = (cfl_it->second); } oValue += cfl; ++term_it; ++cfl_it; } return oValue; } // ---------------------------------------------------------------------------- template void LevelSetEquationTermContainer::ComputeRequiredData(const LevelSetInputIndexType & iP, LevelSetDataType & ioData) { typename RequiredDataType::const_iterator dIt = m_RequiredData.begin(); typename RequiredDataType::const_iterator dEnd = m_RequiredData.end(); auto tIt = m_Container.begin(); LevelSetPointer levelset = (tIt->second)->GetModifiableCurrentLevelSetPointer(); while (dIt != dEnd) { if (*dIt == "Value") { levelset->Evaluate(iP, ioData); } if (*dIt == "Gradient") { levelset->EvaluateGradient(iP, ioData); } if (*dIt == "Hessian") { levelset->EvaluateHessian(iP, ioData); } if (*dIt == "Laplacian") { levelset->EvaluateLaplacian(iP, ioData); } if (*dIt == "GradientNorm") { levelset->EvaluateGradientNorm(iP, ioData); } if (*dIt == "MeanCurvature") { levelset->EvaluateMeanCurvature(iP, ioData); } if (*dIt == "ForwardGradient") { levelset->EvaluateForwardGradient(iP, ioData); } if (*dIt == "BackwardGradient") { levelset->EvaluateBackwardGradient(iP, ioData); } // here add new characteristics ++dIt; } } } // namespace itk #endif // itkLevelSetEquationTermContainer_hxx