From 5498ecd35b63e5afba3505cb4cf53dd575041ba5 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 19 Feb 2020 10:34:24 -0700 Subject: [PATCH] Properly handle global (whole mesh) fields in data set filters Generally, fields that have a WHOLE_MESH association might be valid even if the structure of the mesh changes. Thus, it makes sense for filters to pass this data pretty much all the time. Also cleaned up some code and comments to make the relationship between `MapFieldOntoOutput` and `DoMapField` more clear. --- vtkm/cont/Field.h | 1 + vtkm/filter/ClipWithField.cxx | 25 ------------------------ vtkm/filter/ClipWithField.h | 22 ++++++++++++++++----- vtkm/filter/ClipWithImplicitFunction.cxx | 24 ----------------------- vtkm/filter/ClipWithImplicitFunction.h | 21 +++++++++++++++----- vtkm/filter/Contour.cxx | 25 ------------------------ vtkm/filter/Contour.h | 22 ++++++++++++++++----- vtkm/filter/ExternalFaces.cxx | 11 +++++++++-- vtkm/filter/ExtractGeometry.cxx | 5 +++++ vtkm/filter/ExtractPoints.hxx | 13 +++++++++--- vtkm/filter/ExtractStructured.cxx | 14 +++++++++---- vtkm/filter/GhostCellRemove.hxx | 5 +++++ vtkm/filter/Lagrangian.hxx | 14 ++++++++++--- vtkm/filter/LagrangianStructures.hxx | 14 ++++++++++--- vtkm/filter/Mask.hxx | 2 +- vtkm/filter/MaskPoints.hxx | 13 +++++++++--- vtkm/filter/Probe.hxx | 19 ++++++++++++------ vtkm/filter/SplitSharpEdges.hxx | 2 +- vtkm/filter/Tetrahedralize.hxx | 18 +++++++++++------ vtkm/filter/Threshold.cxx | 11 ++++++----- vtkm/filter/ThresholdPoints.hxx | 13 +++++++++--- vtkm/filter/Triangulate.hxx | 18 +++++++++++------ vtkm/filter/Tube.hxx | 14 +++++++++---- vtkm/filter/VertexClustering.hxx | 14 +++++++++---- 24 files changed, 197 insertions(+), 143 deletions(-) diff --git a/vtkm/cont/Field.h b/vtkm/cont/Field.h index 661624924..20396905d 100644 --- a/vtkm/cont/Field.h +++ b/vtkm/cont/Field.h @@ -84,6 +84,7 @@ public: VTKM_CONT bool IsFieldCell() const { return this->FieldAssociation == Association::CELL_SET; } VTKM_CONT bool IsFieldPoint() const { return this->FieldAssociation == Association::POINTS; } + VTKM_CONT bool IsFieldGlobal() const { return this->FieldAssociation == Association::WHOLE_MESH; } VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Data.GetNumberOfValues(); } diff --git a/vtkm/filter/ClipWithField.cxx b/vtkm/filter/ClipWithField.cxx index eee6e4d2b..017fe3259 100644 --- a/vtkm/filter/ClipWithField.cxx +++ b/vtkm/filter/ClipWithField.cxx @@ -11,35 +11,10 @@ #include -#include - namespace vtkm { namespace filter { - -VTKM_FILTER_EXPORT bool ClipWithField::MapFieldOntoOutput(vtkm::cont::DataSet& result, - const vtkm::cont::Field& field) -{ - if (field.IsFieldPoint()) - { - // Handled by DoMapField, which the superclass will call. - // Actually already done by other version of MapFieldOntoOutput. (Stupid policies.) - //return this->FilterDataSetWithField::MapFieldOntoOutput(result, field, policy); - VTKM_ASSERT(false && "Should not be here"); - return false; - } - else if (field.IsFieldCell()) - { - vtkm::cont::ArrayHandle permutation = this->Worklet.GetCellMapOutputToInput(); - return vtkm::filter::MapFieldPermutation(field, permutation, result); - } - else - { - return false; - } -} - //----------------------------------------------------------------------------- VTKM_FILTER_INSTANTIATE_EXECUTE_METHOD(ClipWithField); } diff --git a/vtkm/filter/ClipWithField.h b/vtkm/filter/ClipWithField.h index e8eba9e63..5477b2504 100644 --- a/vtkm/filter/ClipWithField.h +++ b/vtkm/filter/ClipWithField.h @@ -14,6 +14,8 @@ #include #include +#include + #include namespace vtkm @@ -46,9 +48,6 @@ public: const vtkm::filter::FieldMetadata& fieldMeta, vtkm::filter::PolicyBase policy); - VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, - const vtkm::cont::Field& field); - template VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm::cont::Field& field, @@ -56,12 +55,25 @@ public: { if (field.IsFieldPoint()) { - // DIE, POLICIES, DIE! + // If the field is a point field, then we need to do a custom interpolation of the points. + // In this case, we need to call the superclass's MapFieldOntoOutput, which will in turn + // call our DoMapField. return this->FilterDataSetWithField::MapFieldOntoOutput(result, field, policy); } + else if (field.IsFieldCell()) + { + // Use the precompiled field permutation function. + vtkm::cont::ArrayHandle permutation = this->Worklet.GetCellMapOutputToInput(); + return vtkm::filter::MapFieldPermutation(field, permutation, result); + } + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } else { - return this->MapFieldOntoOutput(result, field); + return false; } } diff --git a/vtkm/filter/ClipWithImplicitFunction.cxx b/vtkm/filter/ClipWithImplicitFunction.cxx index be9603a1e..a5c4aa2a2 100644 --- a/vtkm/filter/ClipWithImplicitFunction.cxx +++ b/vtkm/filter/ClipWithImplicitFunction.cxx @@ -11,34 +11,10 @@ #define vtkm_filter_ClipWithImplicitFunction_cxx #include -#include - namespace vtkm { namespace filter { - -VTKM_FILTER_EXPORT bool ClipWithImplicitFunction::MapFieldOntoOutput(vtkm::cont::DataSet& result, - const vtkm::cont::Field& field) -{ - if (field.IsFieldPoint()) - { - // Handled by DoMapField, which the superclass will call. - // Actually already done by other version of MapFieldOntoOutput. (Stupid policies.) - //return this->FilterDataSet::MapFieldOntoOutput(result, field, policy); - VTKM_ASSERT(false && "Should not be here"); - return false; - } - else if (field.IsFieldCell()) - { - vtkm::cont::ArrayHandle permutation = this->Worklet.GetCellMapOutputToInput(); - return vtkm::filter::MapFieldPermutation(field, permutation, result); - } - else - { - return false; - } -} //----------------------------------------------------------------------------- VTKM_FILTER_INSTANTIATE_EXECUTE_METHOD(ClipWithImplicitFunction); } diff --git a/vtkm/filter/ClipWithImplicitFunction.h b/vtkm/filter/ClipWithImplicitFunction.h index 75300b985..087c6e159 100644 --- a/vtkm/filter/ClipWithImplicitFunction.h +++ b/vtkm/filter/ClipWithImplicitFunction.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace vtkm @@ -43,9 +44,6 @@ public: vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input, vtkm::filter::PolicyBase policy); - VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, - const vtkm::cont::Field& field); - template VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm::cont::Field& field, @@ -53,13 +51,26 @@ public: { if (field.IsFieldPoint()) { - // DIE, POLICIES, DIE! + // If the field is a point field, then we need to do a custom interpolation of the points. + // In this case, we need to call the superclass's MapFieldOntoOutput, which will in turn + // call our DoMapField. return this->FilterDataSet::MapFieldOntoOutput( result, field, policy); } + else if (field.IsFieldCell()) + { + // Use the precompiled field permutation function. + vtkm::cont::ArrayHandle permutation = this->Worklet.GetCellMapOutputToInput(); + return vtkm::filter::MapFieldPermutation(field, permutation, result); + } + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } else { - return this->MapFieldOntoOutput(result, field); + return false; } } diff --git a/vtkm/filter/Contour.cxx b/vtkm/filter/Contour.cxx index cb2293694..c52ca1a15 100644 --- a/vtkm/filter/Contour.cxx +++ b/vtkm/filter/Contour.cxx @@ -10,8 +10,6 @@ #define vtkm_filter_Contour_cxx #include -#include - namespace vtkm { namespace filter @@ -69,28 +67,5 @@ VTKM_FILTER_EXPORT vtkm::Float64 Contour::GetIsoValue(vtkm::Id index) const { return this->IsoValues[static_cast(index)]; } - -//----------------------------------------------------------------------------- -VTKM_FILTER_EXPORT bool Contour::MapFieldOntoOutput(vtkm::cont::DataSet& result, - const vtkm::cont::Field& field) -{ - if (field.IsFieldPoint()) - { - // Handled by DoMapField, which the superclass will call. - // Actually already done by other version of MapFieldOntoOutput. (Stupid policies.) - //return this->FilterDataSetWithField::MapFieldOntoOutput(result, field, policy); - VTKM_ASSERT(false && "Should not be here"); - return false; - } - else if (field.IsFieldCell()) - { - vtkm::cont::ArrayHandle permutation = this->Worklet.GetCellIdMap(); - return vtkm::filter::MapFieldPermutation(field, permutation, result); - } - else - { - return false; - } -} } } diff --git a/vtkm/filter/Contour.h b/vtkm/filter/Contour.h index 917f8ea40..5ea89fc9d 100644 --- a/vtkm/filter/Contour.h +++ b/vtkm/filter/Contour.h @@ -14,6 +14,8 @@ #include #include +#include + #include namespace vtkm @@ -111,9 +113,6 @@ public: const vtkm::filter::FieldMetadata& fieldMeta, vtkm::filter::PolicyBase policy); - VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, - const vtkm::cont::Field& field); - template VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm::cont::Field& field, @@ -121,12 +120,25 @@ public: { if (field.IsFieldPoint()) { - // DIE, POLICIES, DIE! + // If the field is a point field, then we need to do a custom interpolation of the points. + // In this case, we need to call the superclass's MapFieldOntoOutput, which will in turn + // call our DoMapField. return this->FilterDataSetWithField::MapFieldOntoOutput(result, field, policy); } + else if (field.IsFieldCell()) + { + // Use the precompiled field permutation function. + vtkm::cont::ArrayHandle permutation = this->Worklet.GetCellIdMap(); + return vtkm::filter::MapFieldPermutation(field, permutation, result); + } + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } else { - return this->MapFieldOntoOutput(result, field); + return false; } } diff --git a/vtkm/filter/ExternalFaces.cxx b/vtkm/filter/ExternalFaces.cxx index 2edb74a7b..9a61b92f4 100644 --- a/vtkm/filter/ExternalFaces.cxx +++ b/vtkm/filter/ExternalFaces.cxx @@ -82,8 +82,15 @@ bool ExternalFaces::MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm:: { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIdMap(), result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } //----------------------------------------------------------------------------- diff --git a/vtkm/filter/ExtractGeometry.cxx b/vtkm/filter/ExtractGeometry.cxx index 9901d1cd8..b54bc7152 100644 --- a/vtkm/filter/ExtractGeometry.cxx +++ b/vtkm/filter/ExtractGeometry.cxx @@ -39,6 +39,11 @@ VTKM_FILTER_EXPORT bool ExtractGeometry::MapFieldOntoOutput(vtkm::cont::DataSet& vtkm::cont::ArrayHandle permutation = this->Worklet.GetValidCellIds(); return vtkm::filter::MapFieldPermutation(field, permutation, result); } + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } else { return false; diff --git a/vtkm/filter/ExtractPoints.hxx b/vtkm/filter/ExtractPoints.hxx index b657da9a9..1d3f4b0a4 100644 --- a/vtkm/filter/ExtractPoints.hxx +++ b/vtkm/filter/ExtractPoints.hxx @@ -84,9 +84,16 @@ inline VTKM_CONT bool ExtractPoints::MapFieldOntoOutput( return true; } } - - // cell data does not apply - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + // cell data does not apply + return false; + } } } } diff --git a/vtkm/filter/ExtractStructured.cxx b/vtkm/filter/ExtractStructured.cxx index 4fd57c6d4..9aee477b4 100644 --- a/vtkm/filter/ExtractStructured.cxx +++ b/vtkm/filter/ExtractStructured.cxx @@ -36,13 +36,19 @@ bool ExtractStructured::MapFieldOntoOutput(vtkm::cont::DataSet& result, { return vtkm::filter::MapFieldPermutation(field, this->PointFieldMap, result); } - - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { return vtkm::filter::MapFieldPermutation(field, this->CellFieldMap, result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } //----------------------------------------------------------------------------- diff --git a/vtkm/filter/GhostCellRemove.hxx b/vtkm/filter/GhostCellRemove.hxx index 923664a43..c64e0bd1d 100644 --- a/vtkm/filter/GhostCellRemove.hxx +++ b/vtkm/filter/GhostCellRemove.hxx @@ -376,6 +376,11 @@ VTKM_CONT bool GhostCellRemove::MapFieldOntoOutput(vtkm::cont::DataSet& result, { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetValidCellIds(), result); } + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } else { return false; diff --git a/vtkm/filter/Lagrangian.hxx b/vtkm/filter/Lagrangian.hxx index 3050e649a..e6bfeb489 100644 --- a/vtkm/filter/Lagrangian.hxx +++ b/vtkm/filter/Lagrangian.hxx @@ -327,11 +327,19 @@ inline VTKM_CONT vtkm::cont::DataSet Lagrangian::DoExecute( //--------------------------------------------------------------------------- template -inline VTKM_CONT bool Lagrangian::MapFieldOntoOutput(vtkm::cont::DataSet&, - const vtkm::cont::Field&, +inline VTKM_CONT bool Lagrangian::MapFieldOntoOutput(vtkm::cont::DataSet& result, + const vtkm::cont::Field& field, vtkm::filter::PolicyBase) { - return false; + if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } } } // namespace vtkm::filter diff --git a/vtkm/filter/LagrangianStructures.hxx b/vtkm/filter/LagrangianStructures.hxx index 0d18a41ec..22deda787 100644 --- a/vtkm/filter/LagrangianStructures.hxx +++ b/vtkm/filter/LagrangianStructures.hxx @@ -157,11 +157,19 @@ inline VTKM_CONT vtkm::cont::DataSet LagrangianStructures::DoExecute( //----------------------------------------------------------------------------- template inline VTKM_CONT bool LagrangianStructures::MapFieldOntoOutput( - vtkm::cont::DataSet&, - const vtkm::cont::Field&, + vtkm::cont::DataSet& result, + const vtkm::cont::Field& field, vtkm::filter::PolicyBase) { - return false; + if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } } } // namespace vtkm::filter diff --git a/vtkm/filter/Mask.hxx b/vtkm/filter/Mask.hxx index ee97c5e98..e5b240e40 100644 --- a/vtkm/filter/Mask.hxx +++ b/vtkm/filter/Mask.hxx @@ -73,7 +73,7 @@ inline VTKM_CONT bool Mask::MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm::cont::Field& field, vtkm::filter::PolicyBase) { - if (field.IsFieldPoint()) + if (field.IsFieldPoint() || field.IsFieldGlobal()) { result.AddField(field); // pass through return true; diff --git a/vtkm/filter/MaskPoints.hxx b/vtkm/filter/MaskPoints.hxx index 0dd877e5c..2b15775eb 100644 --- a/vtkm/filter/MaskPoints.hxx +++ b/vtkm/filter/MaskPoints.hxx @@ -76,9 +76,16 @@ inline VTKM_CONT bool MaskPoints::MapFieldOntoOutput(vtkm::cont::DataSet& result return true; } } - - // cell data does not apply - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + // cell data does not apply + return false; + } } } } diff --git a/vtkm/filter/Probe.hxx b/vtkm/filter/Probe.hxx index 96d343b35..e7266f3e5 100644 --- a/vtkm/filter/Probe.hxx +++ b/vtkm/filter/Probe.hxx @@ -54,17 +54,24 @@ VTKM_CONT inline bool Probe::MapFieldOntoOutput(vtkm::cont::DataSet& result, { if (field.IsFieldPoint()) { - // This is a special interpolation that is handled by DoMapField. The superclass' - // MapFieldOntoOutput will handle this. + // If the field is a point field, then we need to do a custom interpolation of the points. + // In this case, we need to call the superclass's MapFieldOntoOutput, which will in turn + // call our DoMapField. return this->FilterDataSet::MapFieldOntoOutput(result, field, policy); } - - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIds(), result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } template diff --git a/vtkm/filter/SplitSharpEdges.hxx b/vtkm/filter/SplitSharpEdges.hxx index 9da6c989f..7f28b0b55 100644 --- a/vtkm/filter/SplitSharpEdges.hxx +++ b/vtkm/filter/SplitSharpEdges.hxx @@ -68,7 +68,7 @@ inline VTKM_CONT bool SplitSharpEdges::MapFieldOntoOutput(vtkm::cont::DataSet& r { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetNewPointsIdArray(), result); } - else if (field.IsFieldCell()) + else if (field.IsFieldCell() || field.IsFieldGlobal()) { result.AddField(field); // pass through return true; diff --git a/vtkm/filter/Tetrahedralize.hxx b/vtkm/filter/Tetrahedralize.hxx index cbe0c233f..64398c658 100644 --- a/vtkm/filter/Tetrahedralize.hxx +++ b/vtkm/filter/Tetrahedralize.hxx @@ -68,22 +68,28 @@ inline VTKM_CONT bool Tetrahedralize::MapFieldOntoOutput(vtkm::cont::DataSet& re const vtkm::cont::Field& field, vtkm::filter::PolicyBase) { - // point data is copied as is because it was not collapsed if (field.IsFieldPoint()) { + // point data is copied as is because it was not collapsed result.AddField(field); return true; } - - // cell data must be scattered to the cells created per input cell - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { + // cell data must be scattered to the cells created per input cell vtkm::cont::ArrayHandle permutation = this->Worklet.GetOutCellScatter().GetOutputToInputMap(); return vtkm::filter::MapFieldPermutation(field, permutation, result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } } } diff --git a/vtkm/filter/Threshold.cxx b/vtkm/filter/Threshold.cxx index 19c0f3448..595bf70d7 100644 --- a/vtkm/filter/Threshold.cxx +++ b/vtkm/filter/Threshold.cxx @@ -20,19 +20,20 @@ namespace filter VTKM_FILTER_EXPORT bool Threshold::MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm::cont::Field& field) { - if (field.IsFieldPoint()) + if (field.IsFieldPoint() || field.IsFieldGlobal()) { //we copy the input handle to the result dataset, reusing the metadata result.AddField(field); return true; } - - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetValidCellIds(), result); } - - return false; + else + { + return false; + } } //----------------------------------------------------------------------------- diff --git a/vtkm/filter/ThresholdPoints.hxx b/vtkm/filter/ThresholdPoints.hxx index 4ebddbdde..97f2f08c3 100644 --- a/vtkm/filter/ThresholdPoints.hxx +++ b/vtkm/filter/ThresholdPoints.hxx @@ -206,9 +206,16 @@ inline VTKM_CONT bool ThresholdPoints::MapFieldOntoOutput( return true; } } - - // cell data does not apply - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + // cell data does not apply + return false; + } } } } diff --git a/vtkm/filter/Triangulate.hxx b/vtkm/filter/Triangulate.hxx index f5e0a23fa..bd1ae667d 100644 --- a/vtkm/filter/Triangulate.hxx +++ b/vtkm/filter/Triangulate.hxx @@ -90,22 +90,28 @@ inline VTKM_CONT bool Triangulate::MapFieldOntoOutput(vtkm::cont::DataSet& resul const vtkm::cont::Field& field, vtkm::filter::PolicyBase) { - // point data is copied as is because it was not collapsed if (field.IsFieldPoint()) { + // point data is copied as is because it was not collapsed result.AddField(field); return true; } - - // cell data must be scattered to the cells created per input cell - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { + // cell data must be scattered to the cells created per input cell vtkm::cont::ArrayHandle permutation = this->Worklet.GetOutCellScatter().GetOutputToInputMap(); return vtkm::filter::MapFieldPermutation(field, permutation, result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } } } diff --git a/vtkm/filter/Tube.hxx b/vtkm/filter/Tube.hxx index 43c3848cb..3d94c038f 100644 --- a/vtkm/filter/Tube.hxx +++ b/vtkm/filter/Tube.hxx @@ -64,14 +64,20 @@ inline VTKM_CONT bool Tube::MapFieldOntoOutput(vtkm::cont::DataSet& result, return vtkm::filter::MapFieldPermutation( field, this->Worklet.GetOutputPointSourceIndex(), result); } - - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { return vtkm::filter::MapFieldPermutation( field, this->Worklet.GetOutputCellSourceIndex(), result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } } } // namespace vtkm::filter diff --git a/vtkm/filter/VertexClustering.hxx b/vtkm/filter/VertexClustering.hxx index ff1da429c..f1fce0943 100644 --- a/vtkm/filter/VertexClustering.hxx +++ b/vtkm/filter/VertexClustering.hxx @@ -56,13 +56,19 @@ inline VTKM_CONT bool VertexClustering::MapFieldOntoOutput(vtkm::cont::DataSet& { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetPointIdMap(), result); } - - if (field.IsFieldCell()) + else if (field.IsFieldCell()) { return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIdMap(), result); } - - return false; + else if (field.IsFieldGlobal()) + { + result.AddField(field); + return true; + } + else + { + return false; + } } } }