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.
This commit is contained in:
Kenneth Moreland 2020-02-19 10:34:24 -07:00
parent f8fd0ce316
commit 5498ecd35b
24 changed files with 197 additions and 143 deletions

@ -84,6 +84,7 @@ public:
VTKM_CONT bool IsFieldCell() const { return this->FieldAssociation == Association::CELL_SET; } VTKM_CONT bool IsFieldCell() const { return this->FieldAssociation == Association::CELL_SET; }
VTKM_CONT bool IsFieldPoint() const { return this->FieldAssociation == Association::POINTS; } 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(); } VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Data.GetNumberOfValues(); }

@ -11,35 +11,10 @@
#include <vtkm/filter/ClipWithField.h> #include <vtkm/filter/ClipWithField.h>
#include <vtkm/filter/MapFieldPermutation.h>
namespace vtkm namespace vtkm
{ {
namespace filter 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<ClipWithField>::MapFieldOntoOutput(result, field, policy);
VTKM_ASSERT(false && "Should not be here");
return false;
}
else if (field.IsFieldCell())
{
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetCellMapOutputToInput();
return vtkm::filter::MapFieldPermutation(field, permutation, result);
}
else
{
return false;
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
VTKM_FILTER_INSTANTIATE_EXECUTE_METHOD(ClipWithField); VTKM_FILTER_INSTANTIATE_EXECUTE_METHOD(ClipWithField);
} }

@ -14,6 +14,8 @@
#include <vtkm/filter/vtkm_filter_export.h> #include <vtkm/filter/vtkm_filter_export.h>
#include <vtkm/filter/FilterDataSetWithField.h> #include <vtkm/filter/FilterDataSetWithField.h>
#include <vtkm/filter/MapFieldPermutation.h>
#include <vtkm/worklet/Clip.h> #include <vtkm/worklet/Clip.h>
namespace vtkm namespace vtkm
@ -46,9 +48,6 @@ public:
const vtkm::filter::FieldMetadata& fieldMeta, const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<DerivedPolicy> policy); vtkm::filter::PolicyBase<DerivedPolicy> policy);
VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field);
template <typename DerivedPolicy> template <typename DerivedPolicy>
VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field, const vtkm::cont::Field& field,
@ -56,12 +55,25 @@ public:
{ {
if (field.IsFieldPoint()) 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<ClipWithField>::MapFieldOntoOutput(result, field, policy); return this->FilterDataSetWithField<ClipWithField>::MapFieldOntoOutput(result, field, policy);
} }
else if (field.IsFieldCell())
{
// Use the precompiled field permutation function.
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetCellMapOutputToInput();
return vtkm::filter::MapFieldPermutation(field, permutation, result);
}
else if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else else
{ {
return this->MapFieldOntoOutput(result, field); return false;
} }
} }

@ -11,34 +11,10 @@
#define vtkm_filter_ClipWithImplicitFunction_cxx #define vtkm_filter_ClipWithImplicitFunction_cxx
#include <vtkm/filter/ClipWithImplicitFunction.h> #include <vtkm/filter/ClipWithImplicitFunction.h>
#include <vtkm/filter/MapFieldPermutation.h>
namespace vtkm namespace vtkm
{ {
namespace filter 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<ClipWithImplicitFunction>::MapFieldOntoOutput(result, field, policy);
VTKM_ASSERT(false && "Should not be here");
return false;
}
else if (field.IsFieldCell())
{
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetCellMapOutputToInput();
return vtkm::filter::MapFieldPermutation(field, permutation, result);
}
else
{
return false;
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
VTKM_FILTER_INSTANTIATE_EXECUTE_METHOD(ClipWithImplicitFunction); VTKM_FILTER_INSTANTIATE_EXECUTE_METHOD(ClipWithImplicitFunction);
} }

@ -14,6 +14,7 @@
#include <vtkm/cont/ImplicitFunctionHandle.h> #include <vtkm/cont/ImplicitFunctionHandle.h>
#include <vtkm/filter/FilterDataSet.h> #include <vtkm/filter/FilterDataSet.h>
#include <vtkm/filter/MapFieldPermutation.h>
#include <vtkm/worklet/Clip.h> #include <vtkm/worklet/Clip.h>
namespace vtkm namespace vtkm
@ -43,9 +44,6 @@ public:
vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input, vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input,
vtkm::filter::PolicyBase<DerivedPolicy> policy); vtkm::filter::PolicyBase<DerivedPolicy> policy);
VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field);
template <typename DerivedPolicy> template <typename DerivedPolicy>
VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field, const vtkm::cont::Field& field,
@ -53,13 +51,26 @@ public:
{ {
if (field.IsFieldPoint()) 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<ClipWithImplicitFunction>::MapFieldOntoOutput( return this->FilterDataSet<ClipWithImplicitFunction>::MapFieldOntoOutput(
result, field, policy); result, field, policy);
} }
else if (field.IsFieldCell())
{
// Use the precompiled field permutation function.
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetCellMapOutputToInput();
return vtkm::filter::MapFieldPermutation(field, permutation, result);
}
else if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else else
{ {
return this->MapFieldOntoOutput(result, field); return false;
} }
} }

@ -10,8 +10,6 @@
#define vtkm_filter_Contour_cxx #define vtkm_filter_Contour_cxx
#include <vtkm/filter/Contour.h> #include <vtkm/filter/Contour.h>
#include <vtkm/filter/MapFieldPermutation.h>
namespace vtkm namespace vtkm
{ {
namespace filter namespace filter
@ -69,28 +67,5 @@ VTKM_FILTER_EXPORT vtkm::Float64 Contour::GetIsoValue(vtkm::Id index) const
{ {
return this->IsoValues[static_cast<std::size_t>(index)]; return this->IsoValues[static_cast<std::size_t>(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<Contour>::MapFieldOntoOutput(result, field, policy);
VTKM_ASSERT(false && "Should not be here");
return false;
}
else if (field.IsFieldCell())
{
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetCellIdMap();
return vtkm::filter::MapFieldPermutation(field, permutation, result);
}
else
{
return false;
}
}
} }
} }

@ -14,6 +14,8 @@
#include <vtkm/filter/vtkm_filter_export.h> #include <vtkm/filter/vtkm_filter_export.h>
#include <vtkm/filter/FilterDataSetWithField.h> #include <vtkm/filter/FilterDataSetWithField.h>
#include <vtkm/filter/MapFieldPermutation.h>
#include <vtkm/worklet/Contour.h> #include <vtkm/worklet/Contour.h>
namespace vtkm namespace vtkm
@ -111,9 +113,6 @@ public:
const vtkm::filter::FieldMetadata& fieldMeta, const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<DerivedPolicy> policy); vtkm::filter::PolicyBase<DerivedPolicy> policy);
VTKM_FILTER_EXPORT VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field);
template <typename DerivedPolicy> template <typename DerivedPolicy>
VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result, VTKM_CONT bool MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field, const vtkm::cont::Field& field,
@ -121,12 +120,25 @@ public:
{ {
if (field.IsFieldPoint()) 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<Contour>::MapFieldOntoOutput(result, field, policy); return this->FilterDataSetWithField<Contour>::MapFieldOntoOutput(result, field, policy);
} }
else if (field.IsFieldCell())
{
// Use the precompiled field permutation function.
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetCellIdMap();
return vtkm::filter::MapFieldPermutation(field, permutation, result);
}
else if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else else
{ {
return this->MapFieldOntoOutput(result, field); return false;
} }
} }

@ -82,8 +82,15 @@ bool ExternalFaces::MapFieldOntoOutput(vtkm::cont::DataSet& result, const vtkm::
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIdMap(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIdMap(), result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

@ -39,6 +39,11 @@ VTKM_FILTER_EXPORT bool ExtractGeometry::MapFieldOntoOutput(vtkm::cont::DataSet&
vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetValidCellIds(); vtkm::cont::ArrayHandle<vtkm::Id> permutation = this->Worklet.GetValidCellIds();
return vtkm::filter::MapFieldPermutation(field, permutation, result); return vtkm::filter::MapFieldPermutation(field, permutation, result);
} }
else if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else else
{ {
return false; return false;

@ -84,9 +84,16 @@ inline VTKM_CONT bool ExtractPoints::MapFieldOntoOutput(
return true; return true;
} }
} }
else if (field.IsFieldGlobal())
// cell data does not apply {
return false; result.AddField(field);
return true;
}
else
{
// cell data does not apply
return false;
}
} }
} }
} }

@ -36,13 +36,19 @@ bool ExtractStructured::MapFieldOntoOutput(vtkm::cont::DataSet& result,
{ {
return vtkm::filter::MapFieldPermutation(field, this->PointFieldMap, result); return vtkm::filter::MapFieldPermutation(field, this->PointFieldMap, result);
} }
else if (field.IsFieldCell())
if (field.IsFieldCell())
{ {
return vtkm::filter::MapFieldPermutation(field, this->CellFieldMap, result); return vtkm::filter::MapFieldPermutation(field, this->CellFieldMap, result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

@ -376,6 +376,11 @@ VTKM_CONT bool GhostCellRemove::MapFieldOntoOutput(vtkm::cont::DataSet& result,
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetValidCellIds(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetValidCellIds(), result);
} }
else if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else else
{ {
return false; return false;

@ -327,11 +327,19 @@ inline VTKM_CONT vtkm::cont::DataSet Lagrangian::DoExecute(
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
template <typename DerivedPolicy> template <typename DerivedPolicy>
inline VTKM_CONT bool Lagrangian::MapFieldOntoOutput(vtkm::cont::DataSet&, inline VTKM_CONT bool Lagrangian::MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field&, const vtkm::cont::Field& field,
vtkm::filter::PolicyBase<DerivedPolicy>) vtkm::filter::PolicyBase<DerivedPolicy>)
{ {
return false; if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else
{
return false;
}
} }
} }
} // namespace vtkm::filter } // namespace vtkm::filter

@ -157,11 +157,19 @@ inline VTKM_CONT vtkm::cont::DataSet LagrangianStructures::DoExecute(
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename DerivedPolicy> template <typename DerivedPolicy>
inline VTKM_CONT bool LagrangianStructures::MapFieldOntoOutput( inline VTKM_CONT bool LagrangianStructures::MapFieldOntoOutput(
vtkm::cont::DataSet&, vtkm::cont::DataSet& result,
const vtkm::cont::Field&, const vtkm::cont::Field& field,
vtkm::filter::PolicyBase<DerivedPolicy>) vtkm::filter::PolicyBase<DerivedPolicy>)
{ {
return false; if (field.IsFieldGlobal())
{
result.AddField(field);
return true;
}
else
{
return false;
}
} }
} }
} // namespace vtkm::filter } // namespace vtkm::filter

@ -73,7 +73,7 @@ inline VTKM_CONT bool Mask::MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field, const vtkm::cont::Field& field,
vtkm::filter::PolicyBase<DerivedPolicy>) vtkm::filter::PolicyBase<DerivedPolicy>)
{ {
if (field.IsFieldPoint()) if (field.IsFieldPoint() || field.IsFieldGlobal())
{ {
result.AddField(field); // pass through result.AddField(field); // pass through
return true; return true;

@ -76,9 +76,16 @@ inline VTKM_CONT bool MaskPoints::MapFieldOntoOutput(vtkm::cont::DataSet& result
return true; return true;
} }
} }
else if (field.IsFieldGlobal())
// cell data does not apply {
return false; result.AddField(field);
return true;
}
else
{
// cell data does not apply
return false;
}
} }
} }
} }

@ -54,17 +54,24 @@ VTKM_CONT inline bool Probe::MapFieldOntoOutput(vtkm::cont::DataSet& result,
{ {
if (field.IsFieldPoint()) if (field.IsFieldPoint())
{ {
// This is a special interpolation that is handled by DoMapField. The superclass' // If the field is a point field, then we need to do a custom interpolation of the points.
// MapFieldOntoOutput will handle this. // In this case, we need to call the superclass's MapFieldOntoOutput, which will in turn
// call our DoMapField.
return this->FilterDataSet<Probe>::MapFieldOntoOutput(result, field, policy); return this->FilterDataSet<Probe>::MapFieldOntoOutput(result, field, policy);
} }
else if (field.IsFieldCell())
if (field.IsFieldCell())
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIds(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIds(), result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
template <typename T, typename StorageType, typename DerivedPolicy> template <typename T, typename StorageType, typename DerivedPolicy>

@ -68,7 +68,7 @@ inline VTKM_CONT bool SplitSharpEdges::MapFieldOntoOutput(vtkm::cont::DataSet& r
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetNewPointsIdArray(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetNewPointsIdArray(), result);
} }
else if (field.IsFieldCell()) else if (field.IsFieldCell() || field.IsFieldGlobal())
{ {
result.AddField(field); // pass through result.AddField(field); // pass through
return true; return true;

@ -68,22 +68,28 @@ inline VTKM_CONT bool Tetrahedralize::MapFieldOntoOutput(vtkm::cont::DataSet& re
const vtkm::cont::Field& field, const vtkm::cont::Field& field,
vtkm::filter::PolicyBase<DerivedPolicy>) vtkm::filter::PolicyBase<DerivedPolicy>)
{ {
// point data is copied as is because it was not collapsed
if (field.IsFieldPoint()) if (field.IsFieldPoint())
{ {
// point data is copied as is because it was not collapsed
result.AddField(field); result.AddField(field);
return true; return true;
} }
else if (field.IsFieldCell())
// cell data must be scattered to the cells created per input cell
if (field.IsFieldCell())
{ {
// cell data must be scattered to the cells created per input cell
vtkm::cont::ArrayHandle<vtkm::Id> permutation = vtkm::cont::ArrayHandle<vtkm::Id> permutation =
this->Worklet.GetOutCellScatter().GetOutputToInputMap(); this->Worklet.GetOutCellScatter().GetOutputToInputMap();
return vtkm::filter::MapFieldPermutation(field, permutation, result); return vtkm::filter::MapFieldPermutation(field, permutation, result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
} }
} }

@ -20,19 +20,20 @@ namespace filter
VTKM_FILTER_EXPORT bool Threshold::MapFieldOntoOutput(vtkm::cont::DataSet& result, VTKM_FILTER_EXPORT bool Threshold::MapFieldOntoOutput(vtkm::cont::DataSet& result,
const vtkm::cont::Field& field) 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 //we copy the input handle to the result dataset, reusing the metadata
result.AddField(field); result.AddField(field);
return true; return true;
} }
else if (field.IsFieldCell())
if (field.IsFieldCell())
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetValidCellIds(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetValidCellIds(), result);
} }
else
return false; {
return false;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

@ -206,9 +206,16 @@ inline VTKM_CONT bool ThresholdPoints::MapFieldOntoOutput(
return true; return true;
} }
} }
else if (field.IsFieldGlobal())
// cell data does not apply {
return false; result.AddField(field);
return true;
}
else
{
// cell data does not apply
return false;
}
} }
} }
} }

@ -90,22 +90,28 @@ inline VTKM_CONT bool Triangulate::MapFieldOntoOutput(vtkm::cont::DataSet& resul
const vtkm::cont::Field& field, const vtkm::cont::Field& field,
vtkm::filter::PolicyBase<DerivedPolicy>) vtkm::filter::PolicyBase<DerivedPolicy>)
{ {
// point data is copied as is because it was not collapsed
if (field.IsFieldPoint()) if (field.IsFieldPoint())
{ {
// point data is copied as is because it was not collapsed
result.AddField(field); result.AddField(field);
return true; return true;
} }
else if (field.IsFieldCell())
// cell data must be scattered to the cells created per input cell
if (field.IsFieldCell())
{ {
// cell data must be scattered to the cells created per input cell
vtkm::cont::ArrayHandle<vtkm::Id> permutation = vtkm::cont::ArrayHandle<vtkm::Id> permutation =
this->Worklet.GetOutCellScatter().GetOutputToInputMap(); this->Worklet.GetOutCellScatter().GetOutputToInputMap();
return vtkm::filter::MapFieldPermutation(field, permutation, result); return vtkm::filter::MapFieldPermutation(field, permutation, result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
} }
} }

@ -64,14 +64,20 @@ inline VTKM_CONT bool Tube::MapFieldOntoOutput(vtkm::cont::DataSet& result,
return vtkm::filter::MapFieldPermutation( return vtkm::filter::MapFieldPermutation(
field, this->Worklet.GetOutputPointSourceIndex(), result); field, this->Worklet.GetOutputPointSourceIndex(), result);
} }
else if (field.IsFieldCell())
if (field.IsFieldCell())
{ {
return vtkm::filter::MapFieldPermutation( return vtkm::filter::MapFieldPermutation(
field, this->Worklet.GetOutputCellSourceIndex(), result); field, this->Worklet.GetOutputCellSourceIndex(), result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
} }
} // namespace vtkm::filter } // namespace vtkm::filter

@ -56,13 +56,19 @@ inline VTKM_CONT bool VertexClustering::MapFieldOntoOutput(vtkm::cont::DataSet&
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetPointIdMap(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetPointIdMap(), result);
} }
else if (field.IsFieldCell())
if (field.IsFieldCell())
{ {
return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIdMap(), result); return vtkm::filter::MapFieldPermutation(field, this->Worklet.GetCellIdMap(), result);
} }
else if (field.IsFieldGlobal())
return false; {
result.AddField(field);
return true;
}
else
{
return false;
}
} }
} }
} }