diff --git a/Infovis/vtkDelimitedTextReader.cxx b/Infovis/vtkDelimitedTextReader.cxx index 6c8aef7e51344f7ccc60320efa4f157fb6a5fb68..c36435cdefe41afd12d7be61b8550e0ea776e7a2 100644 --- a/Infovis/vtkDelimitedTextReader.cxx +++ b/Infovis/vtkDelimitedTextReader.cxx @@ -399,6 +399,9 @@ vtkDelimitedTextReader::vtkDelimitedTextReader() : this->UseStringDelimiter = true; this->DetectNumericColumns = false; this->ForceDouble = false; + this->DefaultIntegerValue = 0; + this->DefaultDoubleValue = 0.0; + this->TrimWhitespacePriorToNumericConversion = false; } vtkDelimitedTextReader::~vtkDelimitedTextReader() @@ -439,6 +442,12 @@ void vtkDelimitedTextReader::PrintSelf(ostream& os, vtkIndent indent) << (this->DetectNumericColumns? "true" : "false") << endl; os << indent << "ForceDouble: " << (this->ForceDouble ? "true" : "false") << endl; + os << indent << "DefaultIntegerValue: " + << this->DefaultIntegerValue << endl; + os << indent << "DefaultDoubleValue: " + << this->DefaultDoubleValue << endl; + os << indent << "TrimWhitespacePriorToNumericConversion: " + << (this->TrimWhitespacePriorToNumericConversion ? "true" : "false") << endl; os << indent << "GeneratePedigreeIds: " << this->GeneratePedigreeIds << endl; os << indent << "PedigreeIdArrayName: " @@ -641,15 +650,18 @@ int vtkDelimitedTextReader::RequestData( if (this->DetectNumericColumns && !this->UnicodeOutputArrays) { - vtkStringToNumeric* convertor = vtkStringToNumeric::New(); - convertor->SetForceDouble(this->ForceDouble); + vtkStringToNumeric* converter = vtkStringToNumeric::New(); + converter->SetForceDouble(this->ForceDouble); + converter->SetDefaultIntegerValue(this->DefaultIntegerValue); + converter->SetDefaultDoubleValue(this->DefaultDoubleValue); + converter->SetTrimWhitespacePriorToNumericConversion(this->TrimWhitespacePriorToNumericConversion); vtkTable* clone = output_table->NewInstance(); clone->ShallowCopy(output_table); - convertor->SetInput(clone); - convertor->Update(); + converter->SetInput(clone); + converter->Update(); clone->Delete(); - output_table->ShallowCopy(convertor->GetOutputDataObject(0)); - convertor->Delete(); + output_table->ShallowCopy(converter->GetOutputDataObject(0)); + converter->Delete(); } } diff --git a/Infovis/vtkDelimitedTextReader.h b/Infovis/vtkDelimitedTextReader.h index 00f8f257710a1243b3614aa9b2d666b79221b363..0289174a96f6c19a5d0b74f8141baf34fea153ae 100644 --- a/Infovis/vtkDelimitedTextReader.h +++ b/Infovis/vtkDelimitedTextReader.h @@ -171,6 +171,36 @@ public: vtkGetMacro(ForceDouble, bool); vtkBooleanMacro(ForceDouble, bool); + // Description: + // When DetectNumericColumns is set to true, whether to trim whitespace from + // strings prior to conversion to a numeric. + // Default is false to preserve backward compatibility. + // + // vtkVariant handles whitespace inconsistently, so trim it before we try to + // convert it. For example: + // + // vtkVariant(" 2.0").ToDouble() == 2.0 <-- leading whitespace is not a problem + // vtkVariant(" 2.0 ").ToDouble() == NaN <-- trailing whitespace is a problem + // vtkVariant(" infinity ").ToDouble() == NaN <-- any whitespace is a problem + // + // In these cases, trimming the whitespace gives us the result we expect: + // 2.0 and INF respectively. + vtkSetMacro(TrimWhitespacePriorToNumericConversion, bool); + vtkGetMacro(TrimWhitespacePriorToNumericConversion, bool); + vtkBooleanMacro(TrimWhitespacePriorToNumericConversion, bool); + + // Description: + // When DetectNumericColumns is set to true, the reader use this value to populate + // the vtkIntArray where empty strings are found. Default is 0. + vtkSetMacro(DefaultIntegerValue, int); + vtkGetMacro(DefaultIntegerValue, int); + + // Description: + // When DetectNumericColumns is set to true, the reader use this value to populate + // the vtkDoubleArray where empty strings are found. Default is 0.0 + vtkSetMacro(DefaultDoubleValue, double); + vtkGetMacro(DefaultDoubleValue, double); + // Description: // The name of the array for generating or assigning pedigree ids // (default "id"). @@ -223,6 +253,9 @@ protected: vtkUnicodeString UnicodeEscapeCharacter; bool DetectNumericColumns; bool ForceDouble; + bool TrimWhitespacePriorToNumericConversion; + int DefaultIntegerValue; + double DefaultDoubleValue; char* FieldDelimiterCharacters; char StringDelimiter; bool UseStringDelimiter; diff --git a/Infovis/vtkStringToNumeric.cxx b/Infovis/vtkStringToNumeric.cxx index 4fc884acd314d9e26ae053d8beb1368d59e14816..ff3908f6711e938a97114a9ab142d8c798271432 100644 --- a/Infovis/vtkStringToNumeric.cxx +++ b/Infovis/vtkStringToNumeric.cxx @@ -44,6 +44,9 @@ vtkStringToNumeric::vtkStringToNumeric() this->ConvertPointData = true; this->ConvertCellData = true; this->ForceDouble = false; + this->DefaultIntegerValue = 0; + this->DefaultDoubleValue = 0.0; + this->TrimWhitespacePriorToNumericConversion = false; } vtkStringToNumeric::~vtkStringToNumeric() @@ -209,13 +212,28 @@ void vtkStringToNumeric::ConvertArrays(vtkFieldData* fieldData) { str = unicodeArray->GetValue(i).utf8_str(); } + + if (this->TrimWhitespacePriorToNumericConversion) + { + size_t startPos = str.find_first_not_of(" \n\t\r"); + if (startPos == vtkStdString::npos) + { + str = ""; + } + else + { + size_t endPos = str.find_last_not_of(" \n\t\r"); + str = str.substr(startPos, endPos-startPos+1); + } + } + bool ok; if (allInteger) { if (str.length() == 0) { - intArray->SetValue(i, 0); - doubleArray->SetValue(i, 0.0); + intArray->SetValue(i, this->DefaultIntegerValue); + doubleArray->SetValue(i, this->DefaultDoubleValue); continue; } int intValue = vtkVariant(str).ToInt(&ok); @@ -234,7 +252,7 @@ void vtkStringToNumeric::ConvertArrays(vtkFieldData* fieldData) { if (str.length() == 0) { - doubleArray->SetValue(i, 0.0); + doubleArray->SetValue(i, this->DefaultDoubleValue); continue; } double doubleValue = vtkVariant(str).ToDouble(&ok); @@ -325,4 +343,10 @@ void vtkStringToNumeric::PrintSelf(ostream& os, vtkIndent indent) << (this->ConvertCellData ? "on" : "off") << endl; os << indent << "ForceDouble: " << (this->ForceDouble ? "on" : "off") << endl; + os << indent << "DefaultIntegerValue: " + << this->DefaultIntegerValue << endl; + os << indent << "DefaultDoubleValue: " + << this->DefaultDoubleValue << endl; + os << indent << "TrimWhitespacePriorToNumericConversion: " + << (this->TrimWhitespacePriorToNumericConversion ? "on" : "off") << endl; } diff --git a/Infovis/vtkStringToNumeric.h b/Infovis/vtkStringToNumeric.h index b2b48069142b8850173ca227c9ca1dc55d79cb08..e1a269cd79d61d9b69f62c3d4b647c6b2c6c943b 100644 --- a/Infovis/vtkStringToNumeric.h +++ b/Infovis/vtkStringToNumeric.h @@ -41,6 +41,33 @@ public: vtkSetMacro(ForceDouble, bool); vtkGetMacro(ForceDouble, bool); vtkBooleanMacro(ForceDouble, bool); + + // Description: + // Set the default integer value assigned to arrays. Default is 0. + vtkSetMacro(DefaultIntegerValue, int); + vtkGetMacro(DefaultIntegerValue, int); + + // Description: + // Set the default double value assigned to arrays. Default is 0.0 + vtkSetMacro(DefaultDoubleValue, double); + vtkGetMacro(DefaultDoubleValue, double); + + // Description: + // Whether to trim whitespace from strings prior to conversion to a numeric. + // Default is false to preserve backward compatibility. + // + // vtkVariant handles whitespace inconsistently, so trim it before we try to + // convert it. For example: + // + // vtkVariant(" 2.0").ToDouble() == 2.0 <-- leading whitespace is not a problem + // vtkVariant(" 2.0 ").ToDouble() == NaN <-- trailing whitespace is a problem + // vtkVariant(" infinity ").ToDouble() == NaN <-- any whitespace is a problem + // + // In these cases, trimming the whitespace gives us the result we expect: + // 2.0 and INF respectively. + vtkSetMacro(TrimWhitespacePriorToNumericConversion, bool); + vtkGetMacro(TrimWhitespacePriorToNumericConversion, bool); + vtkBooleanMacro(TrimWhitespacePriorToNumericConversion, bool); // Description: // Whether to detect and convert field data arrays. Default is on. @@ -108,6 +135,9 @@ protected: bool ConvertPointData; bool ConvertCellData; bool ForceDouble; + int DefaultIntegerValue; + double DefaultDoubleValue; + bool TrimWhitespacePriorToNumericConversion; // Description: // Count the total number of items (array components) that will need