Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E57SimpleReader: Ensure scaled integer fields are set as best we can when reading #158

Merged
merged 1 commit into from
Nov 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/ReaderImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,6 @@ namespace e57
data3DHeader.pointFields.cartesianZField = proto.isDefined( "cartesianZ" );
data3DHeader.pointFields.cartesianInvalidStateField = proto.isDefined( "cartesianInvalidState" );

data3DHeader.pointFields.pointRangeScaledInteger = E57_NOT_SCALED_USE_FLOAT; // FloatNode
data3DHeader.pointFields.pointRangeMinimum = 0.0;
data3DHeader.pointFields.pointRangeMaximum = 0.0;

Expand All @@ -860,7 +859,11 @@ namespace e57

data3DHeader.pointFields.pointRangeMinimum = floatCartesianX.minimum();
data3DHeader.pointFields.pointRangeMaximum = floatCartesianX.maximum();
data3DHeader.pointFields.pointRangeScaledInteger = E57_NOT_SCALED_USE_FLOAT;

if ( floatCartesianX.precision() == E57_DOUBLE )
{
data3DHeader.pointFields.pointRangeScaledInteger = -1.0;
}
}
}
else if ( proto.isDefined( "sphericalRange" ) )
Expand All @@ -885,7 +888,11 @@ namespace e57

data3DHeader.pointFields.pointRangeMinimum = floatSphericalRange.minimum();
data3DHeader.pointFields.pointRangeMaximum = floatSphericalRange.maximum();
data3DHeader.pointFields.pointRangeScaledInteger = E57_NOT_SCALED_USE_FLOAT;

if ( floatSphericalRange.precision() == E57_DOUBLE )
{
data3DHeader.pointFields.pointRangeScaledInteger = -1.0;
}
}
}

Expand All @@ -894,7 +901,6 @@ namespace e57
data3DHeader.pointFields.sphericalElevationField = proto.isDefined( "sphericalElevation" );
data3DHeader.pointFields.sphericalInvalidStateField = proto.isDefined( "sphericalInvalidState" );

data3DHeader.pointFields.angleScaledInteger = E57_NOT_SCALED_USE_FLOAT; // FloatNode
data3DHeader.pointFields.angleMinimum = 0.0;
data3DHeader.pointFields.angleMaximum = 0.0;

Expand All @@ -920,7 +926,11 @@ namespace e57

data3DHeader.pointFields.angleMinimum = floatSphericalAzimuth.minimum();
data3DHeader.pointFields.angleMaximum = floatSphericalAzimuth.maximum();
data3DHeader.pointFields.angleScaledInteger = E57_NOT_SCALED_USE_FLOAT;

if ( floatSphericalAzimuth.precision() == E57_DOUBLE )
{
data3DHeader.pointFields.angleScaledInteger = -1.0;
}
}
}

Expand Down Expand Up @@ -955,7 +965,6 @@ namespace e57
data3DHeader.pointFields.isTimeStampInvalidField = proto.isDefined( "isTimeStampInvalid" );
data3DHeader.pointFields.timeMaximum = 0.0;
data3DHeader.pointFields.timeMinimum = 0.0;
data3DHeader.pointFields.timeScaledInteger = E57_NOT_SCALED_USE_FLOAT;

if ( proto.isDefined( "timeStamp" ) )
{
Expand All @@ -967,7 +976,7 @@ namespace e57

data3DHeader.pointFields.timeMaximum = static_cast<double>( integerTimeStamp.maximum() );
data3DHeader.pointFields.timeMinimum = static_cast<double>( integerTimeStamp.minimum() );
data3DHeader.pointFields.timeScaledInteger = E57_NOT_SCALED_USE_FLOAT;
data3DHeader.pointFields.timeScaledInteger = -1.0;
}
else if ( timeStampProto.type() == E57_SCALED_INTEGER )
{
Expand All @@ -988,15 +997,13 @@ namespace e57

data3DHeader.pointFields.timeMinimum = floatTimeStamp.minimum();
data3DHeader.pointFields.timeMaximum = floatTimeStamp.maximum();
data3DHeader.pointFields.timeScaledInteger = E57_NOT_SCALED_USE_FLOAT;
}
}

data3DHeader.pointFields.intensityField = proto.isDefined( "intensity" );
data3DHeader.pointFields.isIntensityInvalidField = proto.isDefined( "isIntensityInvalid" );
data3DHeader.intensityLimits.intensityMinimum = 0.0;
data3DHeader.intensityLimits.intensityMaximum = 0.0;
data3DHeader.pointFields.intensityScaledInteger = E57_NOT_SCALED_USE_FLOAT;

if ( scan.isDefined( "intensityLimits" ) )
{
Expand Down
4 changes: 2 additions & 2 deletions src/WriterImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ namespace e57
const double intensityMin = data3DHeader.intensityLimits.intensityMinimum;
const double intensityMax = data3DHeader.intensityLimits.intensityMaximum;

if ( data3DHeader.pointFields.intensityScaledInteger > 0.0 )
if ( data3DHeader.pointFields.intensityScaledInteger > E57_NOT_SCALED_USE_FLOAT )
{
const double scale = data3DHeader.pointFields.intensityScaledInteger;
const double offset = 0.0;
Expand All @@ -539,7 +539,7 @@ namespace e57
intbox.set( "intensityMaximum", ScaledIntegerNode( imf_, rawIntegerMaximum, rawIntegerMinimum,
rawIntegerMaximum, scale, offset ) );
}
else if ( data3DHeader.pointFields.intensityScaledInteger == 0.0 )
else if ( data3DHeader.pointFields.intensityScaledInteger == E57_NOT_SCALED_USE_FLOAT )
{
intbox.set( "intensityMinimum", FloatNode( imf_, intensityMin ) );
intbox.set( "intensityMaximum", FloatNode( imf_, intensityMax ) );
Expand Down
159 changes: 159 additions & 0 deletions test/src/test_SimpleData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#include "gtest/gtest.h"

#include "E57SimpleData.h"
#include "E57SimpleReader.h"
#include "E57SimpleWriter.h"

#include "Helpers.h"
#include "TestData.h"

TEST( SimpleDataHeader, InvalidPointSize )
{
Expand Down Expand Up @@ -61,3 +64,159 @@ TEST( SimpleDataHeader, HeaderMinMaxDouble )
EXPECT_EQ( dataHeader.pointFields.timeMinimum, e57::E57_DOUBLE_MIN );
EXPECT_EQ( dataHeader.pointFields.timeMaximum, e57::E57_DOUBLE_MAX );
}

// Checks that the Data3D header and the the cartesianX FloatNode data are the same when read, written, and read again.
// https://github.com/asmaloney/libE57Format/issues/126
TEST( SimpleData, ReadWrite )
{
e57::Reader *originalReader = nullptr;
e57::E57Root originalFileHeader;
e57::Data3D originalData3DHeader;
e57::Data3DPointsData_d *originalPointsData = nullptr;

// 1. Read in original file
{
E57_ASSERT_NO_THROW( originalReader = new e57::Reader( TestData::Path() + "/self/ColouredCubeDouble.e57", {} ) );

ASSERT_TRUE( originalReader->GetE57Root( originalFileHeader ) );
ASSERT_TRUE( originalReader->ReadData3D( 0, originalData3DHeader ) );

const uint64_t cNumPoints = originalData3DHeader.pointCount;

originalPointsData = new e57::Data3DPointsData_d( originalData3DHeader );

auto vectorReader = originalReader->SetUpData3DPointsData( 0, cNumPoints, *originalPointsData );

const uint64_t cNumRead = vectorReader.read();

vectorReader.close();

EXPECT_EQ( cNumRead, cNumPoints );
}

// 2. Write it out again using the Data3D header from the reader
{
e57::WriterOptions options;
options.guid = originalFileHeader.guid;

e57::Writer *writer = nullptr;
E57_ASSERT_NO_THROW( writer = new e57::Writer( "./ColouredCubeDoubleCopy.e57", options ) );

const int64_t cScanIndex1 = writer->NewData3D( originalData3DHeader );
const uint16_t cNumPoints = originalData3DHeader.pointCount;

auto dataWriter = writer->SetUpData3DPointsData( cScanIndex1, cNumPoints, *originalPointsData );

dataWriter.write( cNumPoints );
dataWriter.close();

delete writer;
}

e57::Reader *copyReader = nullptr;
e57::E57Root copyFileHeader;
e57::Data3D copyData3DHeader;

// 3. Read in what we just wrote
{
E57_ASSERT_NO_THROW( copyReader = new e57::Reader( "./ColouredCubeDoubleCopy.e57", {} ) );

ASSERT_TRUE( copyReader->GetE57Root( copyFileHeader ) );
ASSERT_TRUE( copyReader->ReadData3D( 0, copyData3DHeader ) );

const uint64_t cNumPoints = copyData3DHeader.pointCount;

e57::Data3DPointsData_d copyPointsData( copyData3DHeader );

auto vectorReader = copyReader->SetUpData3DPointsData( 0, cNumPoints, copyPointsData );

const uint64_t cNumRead = vectorReader.read();

vectorReader.close();

EXPECT_EQ( cNumRead, cNumPoints );
}

// 4. Compare the header data
EXPECT_EQ( originalData3DHeader.name, copyData3DHeader.name );
EXPECT_EQ( originalData3DHeader.guid, copyData3DHeader.guid );

EXPECT_EQ( originalData3DHeader.description, copyData3DHeader.description );

EXPECT_EQ( originalData3DHeader.colorLimits, copyData3DHeader.colorLimits );

EXPECT_EQ( originalData3DHeader.pointFields.cartesianXField, copyData3DHeader.pointFields.cartesianXField );
EXPECT_EQ( originalData3DHeader.pointFields.cartesianYField, copyData3DHeader.pointFields.cartesianYField );
EXPECT_EQ( originalData3DHeader.pointFields.cartesianZField, copyData3DHeader.pointFields.cartesianZField );
EXPECT_EQ( originalData3DHeader.pointFields.cartesianInvalidStateField,
copyData3DHeader.pointFields.cartesianInvalidStateField );

EXPECT_EQ( originalData3DHeader.pointFields.sphericalRangeField, copyData3DHeader.pointFields.sphericalRangeField );
EXPECT_EQ( originalData3DHeader.pointFields.sphericalAzimuthField,
copyData3DHeader.pointFields.sphericalAzimuthField );
EXPECT_EQ( originalData3DHeader.pointFields.sphericalElevationField,
copyData3DHeader.pointFields.sphericalElevationField );
EXPECT_EQ( originalData3DHeader.pointFields.sphericalInvalidStateField,
copyData3DHeader.pointFields.sphericalInvalidStateField );

EXPECT_EQ( originalData3DHeader.pointFields.pointRangeMinimum, copyData3DHeader.pointFields.pointRangeMinimum );
EXPECT_EQ( originalData3DHeader.pointFields.pointRangeMaximum, copyData3DHeader.pointFields.pointRangeMaximum );
EXPECT_EQ( originalData3DHeader.pointFields.pointRangeScaledInteger,
copyData3DHeader.pointFields.pointRangeScaledInteger );

EXPECT_EQ( originalData3DHeader.pointFields.angleMinimum, copyData3DHeader.pointFields.angleMinimum );
EXPECT_EQ( originalData3DHeader.pointFields.angleMaximum, copyData3DHeader.pointFields.angleMaximum );
EXPECT_EQ( originalData3DHeader.pointFields.angleScaledInteger, copyData3DHeader.pointFields.angleScaledInteger );

EXPECT_EQ( originalData3DHeader.pointFields.rowIndexField, copyData3DHeader.pointFields.rowIndexField );
EXPECT_EQ( originalData3DHeader.pointFields.rowIndexMaximum, copyData3DHeader.pointFields.rowIndexMaximum );

EXPECT_EQ( originalData3DHeader.pointFields.columnIndexField, copyData3DHeader.pointFields.columnIndexField );
EXPECT_EQ( originalData3DHeader.pointFields.columnIndexMaximum, copyData3DHeader.pointFields.columnIndexMaximum );

EXPECT_EQ( originalData3DHeader.pointFields.returnIndexField, copyData3DHeader.pointFields.returnIndexField );
EXPECT_EQ( originalData3DHeader.pointFields.returnCountField, copyData3DHeader.pointFields.returnCountField );
EXPECT_EQ( originalData3DHeader.pointFields.returnMaximum, copyData3DHeader.pointFields.returnMaximum );

EXPECT_EQ( originalData3DHeader.pointFields.timeStampField, copyData3DHeader.pointFields.timeStampField );
EXPECT_EQ( originalData3DHeader.pointFields.isTimeStampInvalidField,
copyData3DHeader.pointFields.isTimeStampInvalidField );
EXPECT_EQ( originalData3DHeader.pointFields.timeMinimum, copyData3DHeader.pointFields.timeMinimum );
EXPECT_EQ( originalData3DHeader.pointFields.timeMaximum, copyData3DHeader.pointFields.timeMaximum );

EXPECT_EQ( originalData3DHeader.pointFields.intensityField, copyData3DHeader.pointFields.intensityField );
EXPECT_EQ( originalData3DHeader.pointFields.isIntensityInvalidField,
copyData3DHeader.pointFields.isIntensityInvalidField );
EXPECT_EQ( originalData3DHeader.pointFields.intensityScaledInteger,
copyData3DHeader.pointFields.intensityScaledInteger );

EXPECT_EQ( originalData3DHeader.pointFields.colorRedField, copyData3DHeader.pointFields.colorRedField );
EXPECT_EQ( originalData3DHeader.pointFields.colorGreenField, copyData3DHeader.pointFields.colorGreenField );
EXPECT_EQ( originalData3DHeader.pointFields.colorBlueField, copyData3DHeader.pointFields.colorBlueField );
EXPECT_EQ( originalData3DHeader.pointFields.isColorInvalidField, copyData3DHeader.pointFields.isColorInvalidField );

EXPECT_EQ( originalData3DHeader.pointFields.normalXField, copyData3DHeader.pointFields.normalXField );
EXPECT_EQ( originalData3DHeader.pointFields.normalYField, copyData3DHeader.pointFields.normalYField );
EXPECT_EQ( originalData3DHeader.pointFields.normalZField, copyData3DHeader.pointFields.normalZField );

EXPECT_EQ( originalData3DHeader.pointCount, copyData3DHeader.pointCount );

// 5. Compare the cartesianX FloatNode data
e57::CompressedVectorNode originalPointsStructureNode( originalReader->GetRawData3D().get( "/data3D/0/points" ) );
e57::CompressedVectorNode copyPointsStructureNode( copyReader->GetRawData3D().get( "/data3D/0/points" ) );

const e57::StructureNode originalProto( originalPointsStructureNode.prototype() );
const e57::StructureNode copyProto( copyPointsStructureNode.prototype() );

e57::FloatNode originalCartesianXNode( originalProto.get( "cartesianX" ) );
e57::FloatNode copyCartesianXNode( copyProto.get( "cartesianX" ) );

EXPECT_EQ( originalCartesianXNode.precision(), copyCartesianXNode.precision() );
EXPECT_EQ( originalCartesianXNode.minimum(), copyCartesianXNode.minimum() );
EXPECT_EQ( originalCartesianXNode.maximum(), copyCartesianXNode.maximum() );

// 6. Cleanup
delete originalPointsData;
delete originalReader;
delete copyReader;
}